001/* 002 * Copyright 2007-2019 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-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; 022 023 024 025import java.util.ArrayList; 026 027import com.unboundid.asn1.ASN1OctetString; 028import com.unboundid.asn1.ASN1StreamReader; 029import com.unboundid.asn1.ASN1StreamReaderSequence; 030import com.unboundid.util.Debug; 031import com.unboundid.util.Extensible; 032import com.unboundid.util.NotMutable; 033import com.unboundid.util.StaticUtils; 034import com.unboundid.util.ThreadSafety; 035import com.unboundid.util.ThreadSafetyLevel; 036 037import static com.unboundid.ldap.sdk.LDAPMessages.*; 038 039 040 041/** 042 * This class provides a data structure for holding information about the result 043 * of processing a bind operation. It provides generic bind response elements 044 * as described in the {@link LDAPResult} class, but may be overridden to 045 * provide more detailed information for specific types of bind requests. 046 */ 047@Extensible() 048@NotMutable() 049@ThreadSafety(level=ThreadSafetyLevel.COMPLETELY_THREADSAFE) 050public class BindResult 051 extends LDAPResult 052{ 053 /** 054 * The BER type for the server SASL credentials element in the bind result. 055 */ 056 private static final byte TYPE_SERVER_SASL_CREDENTIALS = (byte) 0x87; 057 058 059 060 /** 061 * The serial version UID for this serializable class. 062 */ 063 private static final long serialVersionUID = 2211625049303605730L; 064 065 066 067 // The server SASL credentials from the response, if available. 068 private final ASN1OctetString serverSASLCredentials; 069 070 071 072 /** 073 * Creates a new bind result with the provided information. 074 * 075 * @param messageID The message ID for the LDAP message that is 076 * associated with this bind result. 077 * @param resultCode The result code from the response. 078 * @param diagnosticMessage The diagnostic message from the response, if 079 * available. 080 * @param matchedDN The matched DN from the response, if available. 081 * @param referralURLs The set of referral URLs from the response, if 082 * available. 083 * @param responseControls The set of controls from the response, if 084 * available. 085 */ 086 public BindResult(final int messageID, final ResultCode resultCode, 087 final String diagnosticMessage, final String matchedDN, 088 final String[] referralURLs, 089 final Control[] responseControls) 090 { 091 this(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 092 responseControls, null); 093 } 094 095 096 097 /** 098 * Creates a new bind result with the provided information. 099 * 100 * @param messageID The message ID for the LDAP message that is 101 * associated with this bind result. 102 * @param resultCode The result code from the response. 103 * @param diagnosticMessage The diagnostic message from the response, if 104 * available. 105 * @param matchedDN The matched DN from the response, if 106 * available. 107 * @param referralURLs The set of referral URLs from the response, 108 * if available. 109 * @param responseControls The set of controls from the response, if 110 * available. 111 * @param serverSASLCredentials The server SASL credentials from the 112 * response, if available. 113 */ 114 public BindResult(final int messageID, final ResultCode resultCode, 115 final String diagnosticMessage, final String matchedDN, 116 final String[] referralURLs, 117 final Control[] responseControls, 118 final ASN1OctetString serverSASLCredentials) 119 { 120 super(messageID, resultCode, diagnosticMessage, matchedDN, referralURLs, 121 responseControls); 122 123 this.serverSASLCredentials = serverSASLCredentials; 124 } 125 126 127 128 /** 129 * Creates a new bind result from the provided generic LDAP result. 130 * 131 * @param ldapResult The LDAP result to use to create this bind result. 132 */ 133 public BindResult(final LDAPResult ldapResult) 134 { 135 super(ldapResult); 136 137 serverSASLCredentials = null; 138 } 139 140 141 142 /** 143 * Creates a new bind result from the provided {@code LDAPException}. 144 * 145 * @param exception The {@code LDAPException} to use to create this bind 146 * result. 147 */ 148 public BindResult(final LDAPException exception) 149 { 150 super(exception.toLDAPResult()); 151 152 if (exception instanceof LDAPBindException) 153 { 154 serverSASLCredentials = 155 ((LDAPBindException) exception).getServerSASLCredentials(); 156 } 157 else 158 { 159 serverSASLCredentials = null; 160 } 161 } 162 163 164 165 /** 166 * Creates a new bind result from the provided bind result. This constructor 167 * may be used in creating custom subclasses. 168 * 169 * @param bindResult The bind result to use to create this bind result. 170 */ 171 protected BindResult(final BindResult bindResult) 172 { 173 super(bindResult); 174 175 serverSASLCredentials = bindResult.serverSASLCredentials; 176 } 177 178 179 180 /** 181 * Creates a new bind result object with the provided message ID and with the 182 * protocol op and controls read from the given ASN.1 stream reader. 183 * 184 * @param messageID The LDAP message ID for the LDAP message that is 185 * associated with this bind result. 186 * @param messageSequence The ASN.1 stream reader sequence used in the 187 * course of reading the LDAP message elements. 188 * @param reader The ASN.1 stream reader from which to read the 189 * protocol op and controls. 190 * 191 * @return The decoded bind result. 192 * 193 * @throws LDAPException If a problem occurs while reading or decoding data 194 * from the ASN.1 stream reader. 195 */ 196 static BindResult readBindResultFrom(final int messageID, 197 final ASN1StreamReaderSequence messageSequence, 198 final ASN1StreamReader reader) 199 throws LDAPException 200 { 201 try 202 { 203 final ASN1StreamReaderSequence protocolOpSequence = 204 reader.beginSequence(); 205 final ResultCode resultCode = ResultCode.valueOf(reader.readEnumerated()); 206 207 String matchedDN = reader.readString(); 208 if (matchedDN.isEmpty()) 209 { 210 matchedDN = null; 211 } 212 213 String diagnosticMessage = reader.readString(); 214 if (diagnosticMessage.isEmpty()) 215 { 216 diagnosticMessage = null; 217 } 218 219 String[] referralURLs = null; 220 ASN1OctetString serverSASLCredentials = null; 221 while (protocolOpSequence.hasMoreElements()) 222 { 223 final byte type = (byte) reader.peek(); 224 switch (type) 225 { 226 case TYPE_REFERRAL_URLS: 227 final ArrayList<String> refList = new ArrayList<>(1); 228 final ASN1StreamReaderSequence refSequence = reader.beginSequence(); 229 while (refSequence.hasMoreElements()) 230 { 231 refList.add(reader.readString()); 232 } 233 referralURLs = new String[refList.size()]; 234 refList.toArray(referralURLs); 235 break; 236 237 case TYPE_SERVER_SASL_CREDENTIALS: 238 serverSASLCredentials = 239 new ASN1OctetString(type, reader.readBytes()); 240 break; 241 242 default: 243 throw new LDAPException(ResultCode.DECODING_ERROR, 244 ERR_BIND_RESULT_INVALID_ELEMENT.get(StaticUtils.toHex(type))); 245 } 246 } 247 248 Control[] controls = NO_CONTROLS; 249 if (messageSequence.hasMoreElements()) 250 { 251 final ArrayList<Control> controlList = new ArrayList<>(1); 252 final ASN1StreamReaderSequence controlSequence = reader.beginSequence(); 253 while (controlSequence.hasMoreElements()) 254 { 255 controlList.add(Control.readFrom(reader)); 256 } 257 258 controls = new Control[controlList.size()]; 259 controlList.toArray(controls); 260 } 261 262 return new BindResult(messageID, resultCode, diagnosticMessage, matchedDN, 263 referralURLs, controls, serverSASLCredentials); 264 } 265 catch (final LDAPException le) 266 { 267 Debug.debugException(le); 268 throw le; 269 } 270 catch (final Exception e) 271 { 272 Debug.debugException(e); 273 throw new LDAPException(ResultCode.DECODING_ERROR, 274 ERR_BIND_RESULT_CANNOT_DECODE.get( 275 StaticUtils.getExceptionMessage(e)), 276 e); 277 } 278 } 279 280 281 282 /** 283 * Retrieves the server SASL credentials from the bind result, if available. 284 * 285 * @return The server SASL credentials from the bind response, or 286 * {@code null} if none were provided. 287 */ 288 public ASN1OctetString getServerSASLCredentials() 289 { 290 return serverSASLCredentials; 291 } 292 293 294 295 /** 296 * {@inheritDoc} 297 */ 298 @Override() 299 public void toString(final StringBuilder buffer) 300 { 301 buffer.append("BindResult(resultCode="); 302 buffer.append(getResultCode()); 303 304 final int messageID = getMessageID(); 305 if (messageID >= 0) 306 { 307 buffer.append(", messageID="); 308 buffer.append(messageID); 309 } 310 311 final String diagnosticMessage = getDiagnosticMessage(); 312 if (diagnosticMessage != null) 313 { 314 buffer.append(", diagnosticMessage='"); 315 buffer.append(diagnosticMessage); 316 buffer.append('\''); 317 } 318 319 final String matchedDN = getMatchedDN(); 320 if (matchedDN != null) 321 { 322 buffer.append(", matchedDN='"); 323 buffer.append(matchedDN); 324 buffer.append('\''); 325 } 326 327 final String[] referralURLs = getReferralURLs(); 328 if (referralURLs.length > 0) 329 { 330 buffer.append(", referralURLs={"); 331 for (int i=0; i < referralURLs.length; i++) 332 { 333 if (i > 0) 334 { 335 buffer.append(", "); 336 } 337 338 buffer.append('\''); 339 buffer.append(referralURLs[i]); 340 buffer.append('\''); 341 } 342 buffer.append('}'); 343 } 344 345 buffer.append(", hasServerSASLCredentials="); 346 buffer.append(serverSASLCredentials != null); 347 348 final Control[] responseControls = getResponseControls(); 349 if (responseControls.length > 0) 350 { 351 buffer.append(", responseControls={"); 352 for (int i=0; i < responseControls.length; i++) 353 { 354 if (i > 0) 355 { 356 buffer.append(", "); 357 } 358 359 buffer.append(responseControls[i]); 360 } 361 buffer.append('}'); 362 } 363 364 buffer.append(')'); 365 } 366}