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