001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.extensions;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.ArrayList;
033 import java.util.List;
034 import java.util.Set;
035
036 import org.opends.server.admin.server.ConfigurationChangeListener;
037 import org.opends.server.admin.std.server.AttributeValuePasswordValidatorCfg;
038 import org.opends.server.admin.std.server.PasswordValidatorCfg;
039 import org.opends.server.api.PasswordValidator;
040 import org.opends.server.types.Attribute;
041 import org.opends.server.types.AttributeType;
042 import org.opends.server.types.AttributeValue;
043 import org.opends.server.types.ConfigChangeResult;
044 import org.opends.server.types.ByteString;
045 import org.opends.server.types.Entry;
046 import org.opends.server.types.Operation;
047 import org.opends.server.types.ResultCode;
048
049 import static org.opends.messages.ExtensionMessages.*;
050 import org.opends.messages.MessageBuilder;
051
052
053 /**
054 * This class provides an OpenDS password validator that may be used to ensure
055 * that proposed passwords are not contained in another attribute in the user's
056 * entry.
057 */
058 public class AttributeValuePasswordValidator
059 extends PasswordValidator<AttributeValuePasswordValidatorCfg>
060 implements ConfigurationChangeListener<
061 AttributeValuePasswordValidatorCfg>
062 {
063 // The current configuration for this password validator.
064 private AttributeValuePasswordValidatorCfg currentConfig;
065
066
067
068 /**
069 * Creates a new instance of this attribute value password validator.
070 */
071 public AttributeValuePasswordValidator()
072 {
073 super();
074
075 // No implementation is required here. All initialization should be
076 // performed in the initializePasswordValidator() method.
077 }
078
079
080
081 /**
082 * {@inheritDoc}
083 */
084 @Override()
085 public void initializePasswordValidator(
086 AttributeValuePasswordValidatorCfg configuration)
087 {
088 configuration.addAttributeValueChangeListener(this);
089 currentConfig = configuration;
090 }
091
092
093
094 /**
095 * {@inheritDoc}
096 */
097 @Override()
098 public void finalizePasswordValidator()
099 {
100 currentConfig.removeAttributeValueChangeListener(this);
101 }
102
103
104
105 /**
106 * {@inheritDoc}
107 */
108 @Override()
109 public boolean passwordIsAcceptable(ByteString newPassword,
110 Set<ByteString> currentPasswords,
111 Operation operation, Entry userEntry,
112 MessageBuilder invalidReason)
113 {
114 // Get a handle to the current configuration.
115 AttributeValuePasswordValidatorCfg config = currentConfig;
116
117
118 // Get the string representation (both forward and reversed) for the
119 // password.
120 String password = newPassword.stringValue();
121 String reversed = new StringBuilder(password).reverse().toString();
122
123
124 // If we should check a specific set of attributes, then do that now.
125 // Otherwise, check all user attributes.
126 Set<AttributeType> matchAttributes = config.getMatchAttribute();
127 if ((matchAttributes == null) || matchAttributes.isEmpty())
128 {
129 matchAttributes = userEntry.getUserAttributes().keySet();
130 }
131
132 for (AttributeType t : matchAttributes)
133 {
134 List<Attribute> attrList = userEntry.getAttribute(t);
135 if ((attrList == null) || attrList.isEmpty())
136 {
137 continue;
138 }
139
140 AttributeValue vf = new AttributeValue(t, password);
141 AttributeValue vr = new AttributeValue(t, reversed);
142
143 for (Attribute a : attrList)
144 {
145 if (a.hasValue(vf) ||
146 (config.isTestReversedPassword() && a.hasValue(vr)))
147 {
148
149 invalidReason.append(ERR_ATTRVALUE_VALIDATOR_PASSWORD_IN_ENTRY.get());
150 return false;
151 }
152 }
153 }
154
155
156 // If we've gotten here, then the password is acceptable.
157 return true;
158 }
159
160
161
162 /**
163 * {@inheritDoc}
164 */
165 @Override()
166 public boolean isConfigurationAcceptable(PasswordValidatorCfg configuration,
167 List<Message> unacceptableReasons)
168 {
169 AttributeValuePasswordValidatorCfg config =
170 (AttributeValuePasswordValidatorCfg) configuration;
171 return isConfigurationChangeAcceptable(config, unacceptableReasons);
172 }
173
174
175
176 /**
177 * {@inheritDoc}
178 */
179 public boolean isConfigurationChangeAcceptable(
180 AttributeValuePasswordValidatorCfg configuration,
181 List<Message> unacceptableReasons)
182 {
183 // If we've gotten this far, then we'll accept the change.
184 return true;
185 }
186
187
188
189 /**
190 * {@inheritDoc}
191 */
192 public ConfigChangeResult applyConfigurationChange(
193 AttributeValuePasswordValidatorCfg configuration)
194 {
195 ResultCode resultCode = ResultCode.SUCCESS;
196 boolean adminActionRequired = false;
197 ArrayList<Message> messages = new ArrayList<Message>();
198
199
200 currentConfig = configuration;
201
202 return new ConfigChangeResult(resultCode, adminActionRequired, messages);
203 }
204 }
205