001/* 002 * Copyright 2007-2018 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-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; 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.Extensible; 031import com.unboundid.util.NotMutable; 032import com.unboundid.util.ThreadSafety; 033import com.unboundid.util.ThreadSafetyLevel; 034 035import static com.unboundid.ldap.sdk.LDAPMessages.*; 036import static com.unboundid.util.Debug.*; 037import static com.unboundid.util.StaticUtils.*; 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.length() == 0) 209 { 210 matchedDN = null; 211 } 212 213 String diagnosticMessage = reader.readString(); 214 if (diagnosticMessage.length() == 0) 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<String>(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(toHex(type))); 245 } 246 } 247 248 Control[] controls = NO_CONTROLS; 249 if (messageSequence.hasMoreElements()) 250 { 251 final ArrayList<Control> controlList = new ArrayList<Control>(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 debugException(le); 268 throw le; 269 } 270 catch (final Exception e) 271 { 272 debugException(e); 273 throw new LDAPException(ResultCode.DECODING_ERROR, 274 ERR_BIND_RESULT_CANNOT_DECODE.get(getExceptionMessage(e)), e); 275 } 276 } 277 278 279 280 /** 281 * Retrieves the server SASL credentials from the bind result, if available. 282 * 283 * @return The server SASL credentials from the bind response, or 284 * {@code null} if none were provided. 285 */ 286 public ASN1OctetString getServerSASLCredentials() 287 { 288 return serverSASLCredentials; 289 } 290 291 292 293 /** 294 * {@inheritDoc} 295 */ 296 @Override() 297 public void toString(final StringBuilder buffer) 298 { 299 buffer.append("BindResult(resultCode="); 300 buffer.append(getResultCode()); 301 302 final int messageID = getMessageID(); 303 if (messageID >= 0) 304 { 305 buffer.append(", messageID="); 306 buffer.append(messageID); 307 } 308 309 final String diagnosticMessage = getDiagnosticMessage(); 310 if (diagnosticMessage != null) 311 { 312 buffer.append(", diagnosticMessage='"); 313 buffer.append(diagnosticMessage); 314 buffer.append('\''); 315 } 316 317 final String matchedDN = getMatchedDN(); 318 if (matchedDN != null) 319 { 320 buffer.append(", matchedDN='"); 321 buffer.append(matchedDN); 322 buffer.append('\''); 323 } 324 325 final String[] referralURLs = getReferralURLs(); 326 if (referralURLs.length > 0) 327 { 328 buffer.append(", referralURLs={"); 329 for (int i=0; i < referralURLs.length; i++) 330 { 331 if (i > 0) 332 { 333 buffer.append(", "); 334 } 335 336 buffer.append('\''); 337 buffer.append(referralURLs[i]); 338 buffer.append('\''); 339 } 340 buffer.append('}'); 341 } 342 343 buffer.append(", hasServerSASLCredentials="); 344 buffer.append(serverSASLCredentials != null); 345 346 final Control[] responseControls = getResponseControls(); 347 if (responseControls.length > 0) 348 { 349 buffer.append(", responseControls={"); 350 for (int i=0; i < responseControls.length; i++) 351 { 352 if (i > 0) 353 { 354 buffer.append(", "); 355 } 356 357 buffer.append(responseControls[i]); 358 } 359 buffer.append('}'); 360 } 361 362 buffer.append(')'); 363 } 364}