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