001/* 002 * Copyright 2015-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2015-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.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 that can be used 045 * to consume a single-use token that was generated and provided to the user 046 * through the deliver single-use token extended operation. Once a token has 047 * been consumed, it cannot be used again, although a new token can be generated 048 * and delivered to the user if necessary. 049 * <BR> 050 * <BLOCKQUOTE> 051 * <B>NOTE:</B> This class, and other classes within the 052 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 053 * supported for use against Ping Identity, UnboundID, and 054 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 055 * for proprietary functionality or for external specifications that are not 056 * considered stable or mature enough to be guaranteed to work in an 057 * interoperable way with other types of LDAP servers. 058 * </BLOCKQUOTE> 059 * <BR> 060 * This extended request has an OID of "1.3.6.1.4.1.30221.2.6.51" and it must 061 * have a value with the following encoding: 062 * <PRE> 063 * ConsumeSingleUseTokenRequestValue ::= SEQUENCE { 064 * userDN LDAPDN, 065 * tokenID OCTET STRING, 066 * tokenValue OCTET STRING 067 * ... } 068 * </PRE> 069 * 070 * @see DeliverSingleUseTokenExtendedResult 071 */ 072@NotMutable() 073@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 074public final class ConsumeSingleUseTokenExtendedRequest 075 extends ExtendedRequest 076{ 077 /** 078 * The OID (1.3.6.1.4.1.30221.2.6.51) for the consume single-use token 079 * extended request. 080 */ 081 public static final String CONSUME_SINGLE_USE_TOKEN_REQUEST_OID = 082 "1.3.6.1.4.1.30221.2.6.51"; 083 084 085 086 /** 087 * The serial version UID for this serializable class. 088 */ 089 private static final long serialVersionUID = -3162206445662323272L; 090 091 092 093 // The identifier for the token to consume. 094 private final String tokenID; 095 096 // The value for the single-use token to consume. 097 private final String tokenValue; 098 099 // The DN of the user whose account contains the token to consume. 100 private final String userDN; 101 102 103 104 /** 105 * Creates a new consume single-use token extended request with the provided 106 * information. 107 * 108 * @param userDN The DN of the user whose account contains the token to 109 * consume. It must not be {@code null}. 110 * @param tokenID The identifier for the token to consume. It must not 111 * be {@code null}. 112 * @param tokenValue The value for the single-use token to consume. It 113 * must not be {@code null}. 114 * @param controls An optional set of controls to include in the request. 115 * It may be {@code null} or empty if no controls are 116 * required. 117 */ 118 public ConsumeSingleUseTokenExtendedRequest(final String userDN, 119 final String tokenID, 120 final String tokenValue, 121 final Control... controls) 122 { 123 super(CONSUME_SINGLE_USE_TOKEN_REQUEST_OID, 124 encodeValue(userDN, tokenID, tokenValue), 125 controls); 126 127 this.userDN = userDN; 128 this.tokenID = tokenID; 129 this.tokenValue = tokenValue; 130 } 131 132 133 134 /** 135 * Decodes the provided extended request as a consume single-use token 136 * extended request. 137 * 138 * @param request The extended request to decode as a consume single-use 139 * token extended request. 140 * 141 * @throws LDAPException If the provided extended request cannot be decoded 142 * as a consume single-use token request. 143 */ 144 public ConsumeSingleUseTokenExtendedRequest(final ExtendedRequest request) 145 throws LDAPException 146 { 147 super(request); 148 149 final ASN1OctetString value = request.getValue(); 150 if (value == null) 151 { 152 throw new LDAPException(ResultCode.DECODING_ERROR, 153 ERR_CONSUME_SINGLE_USE_TOKEN_REQUEST_NO_VALUE.get()); 154 } 155 156 try 157 { 158 final ASN1Element[] elements = 159 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 160 userDN = ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 161 tokenID = ASN1OctetString.decodeAsOctetString(elements[1]).stringValue(); 162 tokenValue = 163 ASN1OctetString.decodeAsOctetString(elements[2]).stringValue(); 164 } 165 catch (final Exception e) 166 { 167 Debug.debugException(e); 168 throw new LDAPException(ResultCode.DECODING_ERROR, 169 ERR_CONSUME_SINGLE_USE_TOKEN_REQUEST_CANNOT_DECODE.get( 170 StaticUtils.getExceptionMessage(e)), 171 e); 172 } 173 } 174 175 176 177 /** 178 * Encodes the provided information into an ASN.1 octet string suitable for 179 * use as the value of the extended request. 180 * 181 * @param userDN The DN of the user whose account contains the token to 182 * consume. It must not be {@code null}. 183 * @param tokenID The identifier for the token to consume. It must not 184 * be {@code null}. 185 * @param tokenValue The value for the single-use token to consume. It 186 * must not be {@code null}. 187 * 188 * @return An ASN.1 octet string containing the encoded value. 189 */ 190 private static ASN1OctetString encodeValue(final String userDN, 191 final String tokenID, final String tokenValue) 192 { 193 Validator.ensureNotNull(userDN); 194 Validator.ensureNotNull(tokenID); 195 Validator.ensureNotNull(tokenValue); 196 197 final ASN1Sequence valueSequence = new ASN1Sequence( 198 new ASN1OctetString(userDN), 199 new ASN1OctetString(tokenID), 200 new ASN1OctetString(tokenValue)); 201 return new ASN1OctetString(valueSequence.encode()); 202 } 203 204 205 206 /** 207 * Retrieves the DN of the user whose account contains the token to consume. 208 * 209 * @return The DN of the user whose account contains the token to consume. 210 */ 211 public String getUserDN() 212 { 213 return userDN; 214 } 215 216 217 218 /** 219 * Retrieves the identifier for the token to consume. 220 * 221 * @return The identifier for the token to consume. 222 */ 223 public String getTokenID() 224 { 225 return tokenID; 226 } 227 228 229 230 /** 231 * Retrieves the value for the token to consume. 232 * 233 * @return The value for the token to consume. 234 */ 235 public String getTokenValue() 236 { 237 return tokenValue; 238 } 239 240 241 242 /** 243 * {@inheritDoc}. 244 */ 245 @Override() 246 public ConsumeSingleUseTokenExtendedRequest duplicate() 247 { 248 return duplicate(getControls()); 249 } 250 251 252 253 /** 254 * {@inheritDoc}. 255 */ 256 @Override() 257 public ConsumeSingleUseTokenExtendedRequest duplicate( 258 final Control[] controls) 259 { 260 final ConsumeSingleUseTokenExtendedRequest r = 261 new ConsumeSingleUseTokenExtendedRequest(userDN, tokenID, tokenValue, 262 controls); 263 r.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 264 return r; 265 } 266 267 268 269 /** 270 * {@inheritDoc} 271 */ 272 @Override() 273 public String getExtendedRequestName() 274 { 275 return INFO_EXTENDED_REQUEST_NAME_CONSUME_SINGLE_USE_TOKEN.get(); 276 } 277 278 279 280 /** 281 * {@inheritDoc} 282 */ 283 @Override() 284 public void toString(final StringBuilder buffer) 285 { 286 buffer.append("ConsumeSingleUseTokenExtendedRequest(userDN='"); 287 buffer.append(userDN); 288 buffer.append("', tokenID='"); 289 buffer.append(tokenID); 290 buffer.append('\''); 291 292 final Control[] controls = getControls(); 293 if (controls.length > 0) 294 { 295 buffer.append(", controls={"); 296 for (int i=0; i < controls.length; i++) 297 { 298 if (i > 0) 299 { 300 buffer.append(", "); 301 } 302 303 buffer.append(controls[i]); 304 } 305 buffer.append('}'); 306 } 307 308 buffer.append(')'); 309 } 310}