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-2016 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 org.forgerock.opendj.server.config.server.PasswordExpirationTimeVirtualAttributeCfg; 023import org.opends.server.api.AuthenticationPolicy; 024import org.opends.server.api.VirtualAttributeProvider; 025import org.opends.server.core.PasswordPolicyState; 026import org.opends.server.core.SearchOperation; 027import org.opends.server.schema.GeneralizedTimeSyntax; 028import org.opends.server.types.*; 029 030import static org.opends.messages.ExtensionMessages.*; 031 032/** Provider for the password expiration time virtual attribute. */ 033public class PasswordExpirationTimeVirtualAttributeProvider 034 extends VirtualAttributeProvider<PasswordExpirationTimeVirtualAttributeCfg> 035{ 036 /** Debug tracer to log debugging information. */ 037 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 038 039 /** Default constructor. */ 040 public PasswordExpirationTimeVirtualAttributeProvider() 041 { 042 super(); 043 } 044 045 @Override 046 public boolean isMultiValued() 047 { 048 return false; 049 } 050 051 @Override 052 public Attribute getValues(Entry entry, VirtualAttributeRule rule) 053 { 054 // Do not process LDAP operational entries. 055 if (!entry.isSubentry() && !entry.isLDAPSubentry()) 056 { 057 long expirationTime = getPasswordExpirationTime(entry); 058 if (expirationTime == -1) 059 { 060 // It does not expire. 061 return Attributes.empty(rule.getAttributeType()); 062 } 063 return Attributes.create(rule.getAttributeType(), 064 GeneralizedTimeSyntax.createGeneralizedTimeValue(expirationTime)); 065 } 066 067 return Attributes.empty(rule.getAttributeType()); 068 } 069 070 @Override 071 public boolean isSearchable(VirtualAttributeRule rule, 072 SearchOperation searchOperation, 073 boolean isPreIndexed) 074 { 075 return false; 076 } 077 078 @Override 079 public void processSearch(VirtualAttributeRule rule, 080 SearchOperation searchOperation) 081 { 082 searchOperation.setResultCode(ResultCode.UNWILLING_TO_PERFORM); 083 084 LocalizableMessage message = 085 ERR_PWDEXPTIME_VATTR_NOT_SEARCHABLE.get( 086 rule.getAttributeType().getNameOrOID()); 087 searchOperation.appendErrorMessage(message); 088 } 089 090 @Override 091 public boolean hasValue(Entry entry, VirtualAttributeRule rule) 092 { 093 // Do not process LDAP operational entries. 094 return !entry.isSubentry() 095 && !entry.isLDAPSubentry() 096 && getPasswordExpirationTime(entry) != -1; 097 } 098 099 /** 100 * Utility method to wrap the PasswordPolicyState.getExpirationTime(). 101 * 102 * @param entry LDAP entry 103 * @return Expiration time in milliseconds since the epoch. 104 */ 105 private long getPasswordExpirationTime(Entry entry) 106 { 107 // Do not process LDAP operational entries. 108 109 AuthenticationPolicy policy = null; 110 111 try 112 { 113 policy = AuthenticationPolicy.forUser(entry, false); 114 } 115 catch (DirectoryException de) 116 { 117 logger.error(de.getMessageObject()); 118 119 logger.traceException(de, "Failed to retrieve password policy for user %s", 120 entry.getName()); 121 } 122 123 if (policy == null) 124 { 125 // No authentication policy: debug log this as an error since all 126 // entries should have at least the default password policy. 127 logger.trace("No applicable password policy for user %s", entry.getName()); 128 } 129 else if (policy.isPasswordPolicy()) 130 { 131 PasswordPolicyState pwpState = null; 132 133 try 134 { 135 pwpState = 136 (PasswordPolicyState) policy.createAuthenticationPolicyState(entry); 137 } 138 catch (DirectoryException de) 139 { 140 logger.error(de.getMessageObject()); 141 142 logger.traceException(de, "Failed to retrieve password policy state for user %s", 143 entry.getName()); 144 } 145 146 return pwpState.getPasswordExpirationTime(); 147 } 148 else 149 { 150 // Not a password policy, could be PTA, etc. 151 logger.trace("Authentication policy %s found for user %s is not a password policy", 152 policy.getDN(), entry.getName()); 153 } 154 155 return -1L; 156 } 157}