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