001/* 002 * Copyright 2012-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-2018 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.sdk.unboundidds.extensions; 022 023 024 025import com.unboundid.asn1.ASN1Element; 026import com.unboundid.asn1.ASN1OctetString; 027import com.unboundid.asn1.ASN1Sequence; 028import com.unboundid.ldap.sdk.Control; 029import com.unboundid.ldap.sdk.ExtendedRequest; 030import com.unboundid.ldap.sdk.LDAPException; 031import com.unboundid.ldap.sdk.ResultCode; 032import com.unboundid.util.Debug; 033import com.unboundid.util.NotMutable; 034import com.unboundid.util.StaticUtils; 035import com.unboundid.util.ThreadSafety; 036import com.unboundid.util.ThreadSafetyLevel; 037import com.unboundid.util.Validator; 038 039import static com.unboundid.ldap.sdk.unboundidds.extensions.ExtOpMessages.*; 040 041 042 043/** 044 * This class provides an implementation of an extended request which may be 045 * used to validate a TOTP password for a user. Note that this should not be 046 * used as an alternative to authentication because it does not perform password 047 * policy processing. Rather, this extended operation should be used only to 048 * obtain additional assurance about the identity of a user that has already 049 * been authenticated through some other means. 050 * <BR> 051 * <BLOCKQUOTE> 052 * <B>NOTE:</B> This class, and other classes within the 053 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 054 * supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661 055 * server products. These classes provide support for proprietary 056 * functionality or for external specifications that are not considered stable 057 * or mature enough to be guaranteed to work in an interoperable way with 058 * other types of LDAP servers. 059 * </BLOCKQUOTE> 060 * <BR> 061 * The extended request has an OID of 1.3.6.1.4.1.30221.2.6.15 and a value with 062 * the following encoding: 063 * <PRE> 064 * ValidateTOTPPasswordRequest ::= SEQUENCE { 065 * userDN [0] LDAPDN, 066 * totpPassword [1] OCTET STRING, 067 * ... } 068 * </PRE> 069 */ 070@NotMutable() 071@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 072public final class ValidateTOTPPasswordExtendedRequest 073 extends ExtendedRequest 074{ 075 /** 076 * The OID (1.3.6.1.4.1.30221.2.6.15) for the validate TOTP password extended 077 * request. 078 */ 079 public static final String VALIDATE_TOTP_PASSWORD_REQUEST_OID = 080 "1.3.6.1.4.1.30221.2.6.15"; 081 082 083 084 /** 085 * The BER type for the user DN value element. 086 */ 087 private static final byte TYPE_USER_DN = (byte) 0x80; 088 089 090 091 /** 092 * The BER type for the TOTP password value element. 093 */ 094 private static final byte TYPE_TOTP_PASSWORD = (byte) 0x81; 095 096 097 098 /** 099 * The serial version UID for this serializable class. 100 */ 101 private static final long serialVersionUID = -4610279612454559569L; 102 103 104 105 // The DN of the user for whom to validate the TOTP password. 106 private final String userDN; 107 108 // The TOTP password to validate. 109 private final String totpPassword; 110 111 112 113 114 /** 115 * Creates a new validate TOTP password extended request with the provided 116 * information. 117 * 118 * @param userDN The DN of the user for whom to validate the TOTP 119 * password. 120 * @param totpPassword The TOTP password to validate. 121 * @param controls The set of controls to include in the request. 122 */ 123 public ValidateTOTPPasswordExtendedRequest(final String userDN, 124 final String totpPassword, 125 final Control... controls) 126 { 127 super(VALIDATE_TOTP_PASSWORD_REQUEST_OID, 128 encodeValue(userDN, totpPassword), controls); 129 130 Validator.ensureNotNull(userDN); 131 Validator.ensureNotNull(totpPassword); 132 133 this.userDN = userDN; 134 this.totpPassword = totpPassword; 135 } 136 137 138 139 /** 140 * Creates a new validate TOTP password extended request from the provided 141 * generic extended request. 142 * 143 * @param extendedRequest The generic extended request to parse as a 144 * validate TOTP extended request. 145 * 146 * @throws LDAPException If a problem is encountered while attempting to 147 * parse the provided extended request. 148 */ 149 public ValidateTOTPPasswordExtendedRequest( 150 final ExtendedRequest extendedRequest) 151 throws LDAPException 152 { 153 super(extendedRequest); 154 155 final ASN1OctetString value = extendedRequest.getValue(); 156 if (value == null) 157 { 158 throw new LDAPException(ResultCode.DECODING_ERROR, 159 ERR_VALIDATE_TOTP_REQUEST_MISSING_VALUE.get()); 160 } 161 162 try 163 { 164 final ASN1Element[] elements = 165 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 166 userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 167 totpPassword = 168 ASN1OctetString.decodeAsOctetString(elements[1]).stringValue(); 169 } 170 catch (final Exception e) 171 { 172 Debug.debugException(e); 173 throw new LDAPException(ResultCode.DECODING_ERROR, 174 ERR_VALIDATE_TOTP_REQUEST_MALFORMED_VALUE.get( 175 StaticUtils.getExceptionMessage(e)), 176 e); 177 } 178 } 179 180 181 182 /** 183 * Encodes the provided information into a value suitable for use as the value 184 * for this extended request. 185 * 186 * @param userDN The DN of the user for whom to validate the TOTP 187 * password. 188 * @param totpPassword The TOTP password to validate. 189 * 190 * @return The ASN.1 octet string containing the encoded value. 191 */ 192 private static ASN1OctetString encodeValue(final String userDN, 193 final String totpPassword) 194 { 195 return new ASN1OctetString(new ASN1Sequence( 196 new ASN1OctetString(TYPE_USER_DN, userDN), 197 new ASN1OctetString(TYPE_TOTP_PASSWORD, totpPassword)).encode()); 198 } 199 200 201 202 /** 203 * Retrieves the DN of the user for whom to validate the TOTP password. 204 * 205 * @return The DN of the user for whom to validate the TOTP password. 206 */ 207 public String getUserDN() 208 { 209 return userDN; 210 } 211 212 213 214 /** 215 * Retrieves the TOTP password to validate. 216 * 217 * @return The TOTP password to validate. 218 */ 219 public String getTOTPPassword() 220 { 221 return totpPassword; 222 } 223 224 225 226 /** 227 * {@inheritDoc} 228 */ 229 @Override() 230 public ValidateTOTPPasswordExtendedRequest duplicate() 231 { 232 return duplicate(getControls()); 233 } 234 235 236 237 /** 238 * {@inheritDoc} 239 */ 240 @Override() 241 public ValidateTOTPPasswordExtendedRequest duplicate( 242 final Control[] controls) 243 { 244 final ValidateTOTPPasswordExtendedRequest r = 245 new ValidateTOTPPasswordExtendedRequest(userDN, totpPassword, 246 controls); 247 r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 248 return r; 249 } 250 251 252 253 /** 254 * {@inheritDoc} 255 */ 256 @Override() 257 public String getExtendedRequestName() 258 { 259 return INFO_EXTENDED_REQUEST_NAME_VALIDATE_TOTP.get(); 260 } 261 262 263 264 /** 265 * {@inheritDoc} 266 */ 267 @Override() 268 public void toString(final StringBuilder buffer) 269 { 270 buffer.append("ValidateTOTPPasswordExtendedRequest(userDN='"); 271 buffer.append(userDN); 272 buffer.append('\''); 273 274 final Control[] controls = getControls(); 275 if (controls.length > 0) 276 { 277 buffer.append(", controls={"); 278 for (int i=0; i < controls.length; i++) 279 { 280 if (i > 0) 281 { 282 buffer.append(", "); 283 } 284 285 buffer.append(controls[i]); 286 } 287 buffer.append('}'); 288 } 289 290 buffer.append(')'); 291 } 292}