001/*
002 * Copyright 2017-2019 Ping Identity Corporation
003 * All Rights Reserved.
004 */
005/*
006 * Copyright (C) 2017-2019 Ping Identity Corporation
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU General Public License (GPLv2 only)
010 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only)
011 * as published by the Free Software Foundation.
012 *
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Public License for more details.
017 *
018 * You should have received a copy of the GNU General Public License
019 * along with this program; if not, see <http://www.gnu.org/licenses>.
020 */
021package com.unboundid.ldap.listener;
022
023
024
025import java.util.List;
026
027import com.unboundid.asn1.ASN1OctetString;
028import com.unboundid.ldap.matchingrules.OctetStringMatchingRule;
029import com.unboundid.ldap.sdk.LDAPException;
030import com.unboundid.ldap.sdk.ReadOnlyEntry;
031import com.unboundid.util.ThreadSafety;
032import com.unboundid.util.ThreadSafetyLevel;
033
034
035
036/**
037 * This class provides a data structure that encapsulates a password used by the
038 * in-memory directory server.  It may be optionally associated with an
039 * {@link InMemoryPasswordEncoder}.
040 */
041@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE)
042public final class InMemoryDirectoryServerPassword
043{
044  // The password as it is (or has the potential to be) stored in the in-memory
045  // directory server.
046  private final ASN1OctetString storedPassword;
047
048  // The password encoder that should be used when interacting with the stored
049  // password.
050  private final InMemoryPasswordEncoder passwordEncoder;
051
052  // The user entry with which the stored password is associated.
053  private final ReadOnlyEntry userEntry;
054
055  // The name of the attribute with which the stored password is associated.
056  private final String attributeName;
057
058
059
060  /**
061   * Creates a new in-memory directory server password with the provided
062   * information.
063   *
064   * @param  storedPassword    The password as it is (or has the potential to
065   *                           be) stored in the in-memory directory server.  It
066   *                           must not be {@code null}.
067   * @param  userEntry         The user entry with which the stored password is
068   *                           associated.  It must not be {@code nulL}.
069   * @param  attributeName     The name of the attribute with which the stored
070   *                           password is associated.  It must not be
071   *                           {@code null}.
072   * @param  passwordEncoders  The set of password encoders configured for the
073   *                           in-memory directory server.  It must not be
074   *                           {@code null} but may be empty.
075   */
076  InMemoryDirectoryServerPassword(final ASN1OctetString storedPassword,
077       final ReadOnlyEntry userEntry, final String attributeName,
078       final List<InMemoryPasswordEncoder> passwordEncoders)
079  {
080    this.storedPassword = storedPassword;
081    this.userEntry = userEntry;
082    this.attributeName = attributeName;
083
084    InMemoryPasswordEncoder encoder = null;
085    for (final InMemoryPasswordEncoder e : passwordEncoders)
086    {
087      if (e.passwordStartsWithPrefix(storedPassword))
088      {
089        encoder = e;
090        break;
091      }
092    }
093
094    passwordEncoder = encoder;
095  }
096
097
098
099  /**
100   * Retrieves the password as it is (or has the potential to be) stored in the
101   * in-memory directory server.  If the {@link #isEncoded()} method returns
102   * {@code true}, then the stored password will be treated as an encoded
103   * password.  Otherwise, it will be treated as a clear-text password with
104   * no encoding or output formatting.
105   *
106   * @return  The password as it is (or has the potential to be) stored in the
107   *          in-memory directory server.
108   */
109  public ASN1OctetString getStoredPassword()
110  {
111    return storedPassword;
112  }
113
114
115
116  /**
117   * Retrieves the name of the attribute with which the stored password is
118   * associated.
119   *
120   * @return  The name of the attribute with which the stored password is
121   *          associated.
122   */
123  public String getAttributeName()
124  {
125    return attributeName;
126  }
127
128
129
130  /**
131   * Indicates whether the stored password is encoded or in the clear.
132   *
133   * @return  {@code true} if the stored password is encoded, or {@code false}
134   *          if it is the clear.
135   */
136  public boolean isEncoded()
137  {
138    return (passwordEncoder != null);
139  }
140
141
142
143  /**
144   * Retrieves the password encoder that should be used to interact with the
145   * stored password.
146   *
147   * @return  The password encoder that should be used to interact with the
148   *          stored password, or {@code null} if the password is not encoded.
149   */
150  public InMemoryPasswordEncoder getPasswordEncoder()
151  {
152    return passwordEncoder;
153  }
154
155
156
157  /**
158   * Retrieves the clear-text representation of the stored password, if it
159   * is possible to obtain it.  If the password is not encoded, then the stored
160   * password will be returned as-is.  If the stored password is encoded, then
161   * the {@link InMemoryPasswordEncoder#extractClearPasswordFromEncodedPassword}
162   * method will be used in an attempt to
163   *
164   * @return  The clear-text representation of the stored password.
165   *
166   * @throws  LDAPException  If the stored password is encoded using a mechanism
167   *                         that does not permit extracting the clear-text
168   *                         password.
169   */
170  public ASN1OctetString getClearPassword()
171         throws LDAPException
172  {
173    if (passwordEncoder == null)
174    {
175      return storedPassword;
176    }
177    else
178    {
179      return passwordEncoder.extractClearPasswordFromEncodedPassword(
180           storedPassword, userEntry);
181    }
182  }
183
184
185
186  /**
187   * Indicates whether this password matches the provided clear-text password.
188   *
189   * @param  clearPassword  The clear-text password for which to make the
190   *                        determination.
191   *
192   * @return  {@code true} if this password matches the provided clear-text
193   *          password, or {@code false} if not.
194   *
195   * @throws  LDAPException  If a problem is encountered while trying to make
196   *                         the determination.
197   */
198  public boolean matchesClearPassword(final ASN1OctetString clearPassword)
199         throws LDAPException
200  {
201    if (passwordEncoder == null)
202    {
203      return OctetStringMatchingRule.getInstance().valuesMatch(clearPassword,
204           storedPassword);
205    }
206    else
207    {
208      return passwordEncoder.clearPasswordMatchesEncodedPassword(clearPassword,
209           storedPassword, userEntry);
210    }
211  }
212}