001/* 002 * Copyright 2016-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2016-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.ExtendedResult; 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 result that may be used 045 * to provide the client with a TOTP shared secret generated by the server in 046 * response to a {@link GenerateTOTPSharedSecretExtendedRequest}. 047 * <BR> 048 * <BLOCKQUOTE> 049 * <B>NOTE:</B> This class, and other classes within the 050 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 051 * supported for use against Ping Identity, UnboundID, and Alcatel-Lucent 8661 052 * server products. These classes provide support for proprietary 053 * functionality or for external specifications that are not considered stable 054 * or mature enough to be guaranteed to work in an interoperable way with 055 * other types of LDAP servers. 056 * </BLOCKQUOTE> 057 * <BR> 058 * If the extended request was processed successfully, then this result will 059 * have an OID of 1.3.6.1.4.1.30221.2.6.57 and a value with the following 060 * encoding: 061 * <BR><BR> 062 * <PRE> 063 * GenerateTOTPSharedSecretResult ::= SEQUENCE { 064 * totpSharedSecret [0] OCTET STRING } 065 * ... } 066 * </PRE> 067 */ 068@NotMutable() 069@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 070public final class GenerateTOTPSharedSecretExtendedResult 071 extends ExtendedResult 072{ 073 /** 074 * The OID (1.3.6.1.4.1.30221.2.6.57) for the generate TOTP shared secret 075 * extended result. 076 */ 077 public static final String GENERATE_TOTP_SHARED_SECRET_RESULT_OID = 078 "1.3.6.1.4.1.30221.2.6.57"; 079 080 081 082 /** 083 * The BER type for the TOTP shared secret element of the result value 084 * sequence. 085 */ 086 private static final byte TYPE_TOTP_SHARED_SECRET = (byte) 0x80; 087 088 089 090 /** 091 * The serial version UID for this serializable class. 092 */ 093 private static final long serialVersionUID = 8505040895542971346L; 094 095 096 097 // The base32-encoded representation TOTP shared secret generated by the 098 // server. 099 private final String totpSharedSecret; 100 101 102 103 /** 104 * Generates a new generate TOTP shared secret extended result for the case in 105 * which the server was able to generate the requested TOTP shared secret. 106 * 107 * @param messageID The message ID for the LDAP message that is 108 * associated with this LDAP result. 109 * @param totpSharedSecret The base32-encoded representation of the TOTP 110 * shared secret generated by the server. It must 111 * not be {@code null}. 112 * @param responseControls The set of controls from the response, if 113 * available. 114 */ 115 public GenerateTOTPSharedSecretExtendedResult(final int messageID, 116 final String totpSharedSecret, final Control... responseControls) 117 { 118 this(messageID, ResultCode.SUCCESS, null, null, null, totpSharedSecret, 119 responseControls); 120 } 121 122 123 124 /** 125 * Creates a new generate TOTP shared secret extended result with the provided 126 * information. 127 * 128 * @param messageID The message ID for the LDAP message that is 129 * associated with this LDAP result. 130 * @param resultCode The result code from the response. 131 * @param diagnosticMessage The diagnostic message from the response, if 132 * available. 133 * @param matchedDN The matched DN from the response, if available. 134 * @param referralURLs The set of referral URLs from the response, if 135 * available. 136 * @param totpSharedSecret The base32-encoded representation of the TOTP 137 * shared secret generated by the server, if 138 * available. 139 * @param responseControls The set of controls from the response, if 140 * available. 141 */ 142 public GenerateTOTPSharedSecretExtendedResult(final int messageID, 143 final ResultCode resultCode, final String diagnosticMessage, 144 final String matchedDN, final String[] referralURLs, 145 final String totpSharedSecret, final Control... responseControls) 146 { 147 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 148 ((totpSharedSecret == null) 149 ? null 150 : GENERATE_TOTP_SHARED_SECRET_RESULT_OID), 151 encodeValue(totpSharedSecret), responseControls); 152 153 this.totpSharedSecret = totpSharedSecret; 154 155 if (totpSharedSecret == null) 156 { 157 Validator.ensureTrue((resultCode != ResultCode.SUCCESS), 158 "If the result code is SUCCESS, the TOTP shared secret must be " + 159 "non-null"); 160 } 161 } 162 163 164 165 /** 166 * Creates a new generate TOTP shared secret extended result from the provided 167 * extended result. 168 * 169 * @param extendedResult The extended result to be decoded as a generate 170 * TOTP shared secret extended result. It must not be 171 * {@code null}. 172 * 173 * @throws LDAPException If the provided extended result cannot be decoded 174 * as a generate TOTP shared secret result. 175 */ 176 public GenerateTOTPSharedSecretExtendedResult( 177 final ExtendedResult extendedResult) 178 throws LDAPException 179 { 180 super(extendedResult); 181 182 final ASN1OctetString value = extendedResult.getValue(); 183 if (value == null) 184 { 185 totpSharedSecret = null; 186 } 187 else 188 { 189 try 190 { 191 final ASN1Element[] elements = 192 ASN1Sequence.decodeAsSequence(value.getValue()).elements(); 193 totpSharedSecret = 194 ASN1OctetString.decodeAsOctetString(elements[0]).stringValue(); 195 } 196 catch (final Exception e) 197 { 198 Debug.debugException(e); 199 throw new LDAPException(ResultCode.DECODING_ERROR, 200 ERR_GEN_TOTP_SECRET_RESULT_ERROR_DECODING_VALUE.get( 201 StaticUtils.getExceptionMessage(e))); 202 } 203 } 204 } 205 206 207 208 /** 209 * Encodes the provided information into an ASN.1 octet string suitable for 210 * use as the value of this extended result. 211 * 212 * @param totpSharedSecret The base32-encoded representation of the TOTP 213 * shared secret generated by the server, if 214 * available. 215 * 216 * @return The ASN.1 octet string suitable for use as the value of this 217 * extended result, or {@code null} if there should be no value. 218 */ 219 private static ASN1OctetString encodeValue(final String totpSharedSecret) 220 { 221 if (totpSharedSecret == null) 222 { 223 return null; 224 } 225 226 return new ASN1OctetString(new ASN1Sequence(new ASN1OctetString( 227 TYPE_TOTP_SHARED_SECRET, totpSharedSecret)).encode()); 228 } 229 230 231 232 /** 233 * Retrieves the base32-encoded representation of the TOTP shared secret 234 * generated by the server, if available. 235 * 236 * @return The base32-encoded representation of the TOTP shared secret 237 * generated by the server, or {@code null} if none was provided. 238 */ 239 public String getTOTPSharedSecret() 240 { 241 return totpSharedSecret; 242 } 243 244 245 246 /** 247 * {@inheritDoc} 248 */ 249 @Override() 250 public String getExtendedResultName() 251 { 252 return INFO_GEN_TOTP_SECRET_RESULT_NAME.get(); 253 } 254 255 256 257 /** 258 * Appends a string representation of this extended result to the provided 259 * buffer. 260 * 261 * @param buffer The buffer to which a string representation of this 262 * extended result will be appended. 263 */ 264 @Override() 265 public void toString(final StringBuilder buffer) 266 { 267 buffer.append("GenerateTOTPSharedSecretExtendedResult(resultCode="); 268 buffer.append(getResultCode()); 269 270 final int messageID = getMessageID(); 271 if (messageID >= 0) 272 { 273 buffer.append(", messageID="); 274 buffer.append(messageID); 275 } 276 277 final String diagnosticMessage = getDiagnosticMessage(); 278 if (diagnosticMessage != null) 279 { 280 buffer.append(", diagnosticMessage='"); 281 buffer.append(diagnosticMessage); 282 buffer.append('\''); 283 } 284 285 final String matchedDN = getMatchedDN(); 286 if (matchedDN != null) 287 { 288 buffer.append(", matchedDN='"); 289 buffer.append(matchedDN); 290 buffer.append('\''); 291 } 292 293 final String[] referralURLs = getReferralURLs(); 294 if (referralURLs.length > 0) 295 { 296 buffer.append(", referralURLs={"); 297 for (int i=0; i < referralURLs.length; i++) 298 { 299 if (i > 0) 300 { 301 buffer.append(", "); 302 } 303 304 buffer.append('\''); 305 buffer.append(referralURLs[i]); 306 buffer.append('\''); 307 } 308 buffer.append('}'); 309 } 310 311 final Control[] responseControls = getResponseControls(); 312 if (responseControls.length > 0) 313 { 314 buffer.append(", responseControls={"); 315 for (int i=0; i < responseControls.length; i++) 316 { 317 if (i > 0) 318 { 319 buffer.append(", "); 320 } 321 322 buffer.append(responseControls[i]); 323 } 324 buffer.append('}'); 325 } 326 327 buffer.append(')'); 328 } 329}