001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2012 profiq s.r.o. 015 * Portions Copyright 2012-2014 ForgeRock AS. 016 */ 017package org.opends.server.extensions; 018 019import org.forgerock.i18n.LocalizableMessage; 020import org.forgerock.i18n.slf4j.LocalizedLogger; 021import org.forgerock.opendj.ldap.ResultCode; 022import 023 org.opends.server.admin.std.server.PasswordExpirationTimeVirtualAttributeCfg; 024import org.opends.server.api.AuthenticationPolicy; 025import org.opends.server.api.VirtualAttributeProvider; 026import org.opends.server.core.PasswordPolicyState; 027import org.opends.server.core.SearchOperation; 028import org.opends.server.schema.GeneralizedTimeSyntax; 029import org.opends.server.types.*; 030import static org.opends.messages.ExtensionMessages.*; 031 032/** 033 * Provider for the password expiration time virtual attribute. 034 */ 035public class PasswordExpirationTimeVirtualAttributeProvider 036 extends VirtualAttributeProvider<PasswordExpirationTimeVirtualAttributeCfg> 037{ 038 039 /** 040 * Debug tracer to log debugging information. 041 */ 042 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 043 044 /** 045 * Default constructor. 046 */ 047 public PasswordExpirationTimeVirtualAttributeProvider() 048 { 049 super(); 050 } 051 052 /** {@inheritDoc} */ 053 @Override 054 public boolean isMultiValued() 055 { 056 return false; 057 } 058 059 /** {@inheritDoc} */ 060 @Override 061 public Attribute getValues(Entry entry, VirtualAttributeRule rule) 062 { 063 // Do not process LDAP operational entries. 064 if (!entry.isSubentry() && !entry.isLDAPSubentry()) 065 { 066 long expirationTime = getPasswordExpirationTime(entry); 067 if (expirationTime == -1) 068 { 069 // It does not expire. 070 return Attributes.empty(rule.getAttributeType()); 071 } 072 return Attributes.create(rule.getAttributeType(), 073 GeneralizedTimeSyntax.createGeneralizedTimeValue(expirationTime)); 074 } 075 076 return Attributes.empty(rule.getAttributeType()); 077 } 078 079 /** {@inheritDoc} */ 080 @Override 081 public boolean isSearchable(VirtualAttributeRule rule, 082 SearchOperation searchOperation, 083 boolean isPreIndexed) 084 { 085 return false; 086 } 087 088 /** {@inheritDoc} */ 089 @Override 090 public void processSearch(VirtualAttributeRule rule, 091 SearchOperation searchOperation) 092 { 093 searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); 094 095 LocalizableMessage message = 096 ERR_PWDEXPTIME_VATTR_NOT_SEARCHABLE.get( 097 rule.getAttributeType().getNameOrOID()); 098 searchOperation.appendErrorMessage(message); 099 } 100 101 /** {@inheritDoc} */ 102 @Override 103 public boolean hasValue(Entry entry, VirtualAttributeRule rule) 104 { 105 // Do not process LDAP operational entries. 106 return !entry.isSubentry() 107 && !entry.isLDAPSubentry() 108 && getPasswordExpirationTime(entry) != -1; 109 } 110 111 /** 112 * Utility method to wrap the PasswordPolicyState.getExpirationTime(). 113 * 114 * @param entry LDAP entry 115 * @return Expiration time in milliseconds since the epoch. 116 */ 117 private long getPasswordExpirationTime(Entry entry) 118 { 119 // Do not process LDAP operational entries. 120 121 AuthenticationPolicy policy = null; 122 123 try 124 { 125 policy = AuthenticationPolicy.forUser(entry, false); 126 } 127 catch (DirectoryException de) 128 { 129 logger.error(de.getMessageObject()); 130 131 logger.traceException(de, "Failed to retrieve password policy for user %s", 132 entry.getName()); 133 } 134 135 if (policy == null) 136 { 137 // No authentication policy: debug log this as an error since all 138 // entries should have at least the default password policy. 139 logger.trace("No applicable password policy for user %s", entry.getName()); 140 } 141 else if (policy.isPasswordPolicy()) 142 { 143 PasswordPolicyState pwpState = null; 144 145 try 146 { 147 pwpState = 148 (PasswordPolicyState) policy.createAuthenticationPolicyState(entry); 149 } 150 catch (DirectoryException de) 151 { 152 logger.error(de.getMessageObject()); 153 154 logger.traceException(de, "Failed to retrieve password policy state for user %s", 155 entry.getName()); 156 } 157 158 return pwpState.getPasswordExpirationTime(); 159 160 } 161 else 162 { 163 // Not a password policy, could be PTA, etc. 164 logger.trace("Authentication policy %s found for user %s is not a password policy", 165 policy.getDN(), entry.getName()); 166 } 167 168 return -1L; 169 } 170}