001/* 002 * Copyright 2007-2014 UnboundID Corp. 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright (C) 2008-2014 UnboundID Corp. 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 com.unboundid.asn1.ASN1OctetString; 026import com.unboundid.util.NotMutable; 027import com.unboundid.util.StaticUtils; 028import com.unboundid.util.ThreadSafety; 029import com.unboundid.util.ThreadSafetyLevel; 030 031 032 033/** 034 * This class provides a SASL EXTERNAL bind request implementation as described 035 * in <A HREF="http://www.ietf.org/rfc/rfc4422.txt">RFC 4422</A>. The 036 * EXTERNAL mechanism is used to authenticate using information that is 037 * available outside of the LDAP layer (e.g., a certificate presented by the 038 * client during SSL or StartTLS negotiation). 039 * <BR><BR> 040 * <H2>Example</H2> 041 * The following example demonstrates the process for performing an EXTERNAL 042 * bind against a directory server: 043 * <PRE> 044 * EXTERNALBindRequest bindRequest = new EXTERNALBindRequest(""); 045 * BindResult bindResult; 046 * try 047 * { 048 * bindResult = connection.bind(bindRequest); 049 * // If we get here, then the bind was successful. 050 * } 051 * catch (LDAPException le) 052 * { 053 * // The bind failed for some reason. 054 * bindResult = new BindResult(le.toLDAPResult()); 055 * ResultCode resultCode = le.getResultCode(); 056 * String errorMessageFromServer = le.getDiagnosticMessage(); 057 * } 058 * </PRE> 059 */ 060@NotMutable() 061@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 062public final class EXTERNALBindRequest 063 extends SASLBindRequest 064{ 065 /** 066 * The name for the EXTERNAL SASL mechanism. 067 */ 068 public static final String EXTERNAL_MECHANISM_NAME = "EXTERNAL"; 069 070 071 072 /** 073 * The serial version UID for this serializable class. 074 */ 075 private static final long serialVersionUID = 7520760039662616663L; 076 077 078 079 // The message ID from the last LDAP message sent from this request. 080 private int messageID = -1; 081 082 // The authorization ID to send to the server in the bind request. It may be 083 // null, empty, or non-empty. 084 private final String authzID; 085 086 087 088 /** 089 * Creates a new SASL EXTERNAL bind request with no authorization ID and no 090 * controls. 091 */ 092 public EXTERNALBindRequest() 093 { 094 this(null, StaticUtils.NO_CONTROLS); 095 } 096 097 098 099 /** 100 * Creates a new SASL EXTERNAL bind request with the specified authorization 101 * ID and no controls. 102 * 103 * @param authzID The authorization ID to use for the bind request. It may 104 * be {@code null} if the client should not send any 105 * authorization ID at all (which may be required by some 106 * servers). It may be an empty string if the server should 107 * determine the authorization identity from what it knows 108 * about the client (e.g., a client certificate). It may be 109 * a non-empty string if the authorization identity should 110 * be different from the authentication identity. 111 */ 112 public EXTERNALBindRequest(final String authzID) 113 { 114 this(authzID, StaticUtils.NO_CONTROLS); 115 } 116 117 118 119 120 /** 121 * Creates a new SASL EXTERNAL bind request with the provided set of controls. 122 * 123 * @param controls The set of controls to include in this SASL EXTERNAL 124 * bind request. 125 */ 126 public EXTERNALBindRequest(final Control... controls) 127 { 128 this(null, controls); 129 } 130 131 132 133 134 /** 135 * Creates a new SASL EXTERNAL bind request with the provided set of controls. 136 * 137 * 138 * @param authzID The authorization ID to use for the bind request. It may 139 * be {@code null} if the client should not send any 140 * authorization ID at all (which may be required by some 141 * servers). It may be an empty string if the server should 142 * determine the authorization identity from what it knows 143 * about the client (e.g., a client certificate). It may be 144 * a non-empty string if the authorization identity should 145 * be different from the authentication identity. 146 * @param controls The set of controls to include in this SASL EXTERNAL 147 * bind request. 148 */ 149 public EXTERNALBindRequest(final String authzID, final Control... controls) 150 { 151 super(controls); 152 153 this.authzID = authzID; 154 } 155 156 157 158 /** 159 * Retrieves the authorization ID that should be included in the bind request, 160 * if any. 161 * 162 * @return The authorization ID that should be included in the bind request, 163 * or {@code null} if the bind request should be sent without an 164 * authorization ID (which is a form that some servers require). It 165 * may be an empty string if the authorization identity should be the 166 * same as the authentication identity and should be determined from 167 * what the server already knows about the client. 168 */ 169 public String getAuthorizationID() 170 { 171 return authzID; 172 } 173 174 175 176 /** 177 * {@inheritDoc} 178 */ 179 @Override() 180 public String getSASLMechanismName() 181 { 182 return EXTERNAL_MECHANISM_NAME; 183 } 184 185 186 187 /** 188 * Sends this bind request to the target server over the provided connection 189 * and returns the corresponding response. 190 * 191 * @param connection The connection to use to send this bind request to the 192 * server and read the associated response. 193 * @param depth The current referral depth for this request. It should 194 * always be one for the initial request, and should only 195 * be incremented when following referrals. 196 * 197 * @return The bind response read from the server. 198 * 199 * @throws LDAPException If a problem occurs while sending the request or 200 * reading the response. 201 */ 202 @Override() 203 protected BindResult process(final LDAPConnection connection, final int depth) 204 throws LDAPException 205 { 206 // Create the LDAP message. 207 messageID = connection.nextMessageID(); 208 209 final ASN1OctetString creds; 210 if (authzID == null) 211 { 212 creds = null; 213 } 214 else 215 { 216 creds = new ASN1OctetString(authzID); 217 } 218 219 return sendBindRequest(connection, "", creds, getControls(), 220 getResponseTimeoutMillis(connection)); 221 } 222 223 224 225 /** 226 * {@inheritDoc} 227 */ 228 @Override() 229 public EXTERNALBindRequest getRebindRequest(final String host, final int port) 230 { 231 return new EXTERNALBindRequest(authzID, getControls()); 232 } 233 234 235 236 /** 237 * {@inheritDoc} 238 */ 239 @Override() 240 public int getLastMessageID() 241 { 242 return messageID; 243 } 244 245 246 247 /** 248 * {@inheritDoc} 249 */ 250 @Override() 251 public EXTERNALBindRequest duplicate() 252 { 253 return duplicate(getControls()); 254 } 255 256 257 258 /** 259 * {@inheritDoc} 260 */ 261 @Override() 262 public EXTERNALBindRequest duplicate(final Control[] controls) 263 { 264 final EXTERNALBindRequest bindRequest = 265 new EXTERNALBindRequest(authzID, controls); 266 bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null)); 267 return bindRequest; 268 } 269 270 271 272 /** 273 * {@inheritDoc} 274 */ 275 @Override() 276 public void toString(final StringBuilder buffer) 277 { 278 buffer.append("EXTERNALBindRequest("); 279 280 boolean added = false; 281 if (authzID != null) 282 { 283 buffer.append("authzID='"); 284 buffer.append(authzID); 285 buffer.append('\''); 286 added = true; 287 } 288 289 final Control[] controls = getControls(); 290 if (controls.length > 0) 291 { 292 if (added) 293 { 294 buffer.append(", "); 295 } 296 297 buffer.append("controls={"); 298 for (int i=0; i < controls.length; i++) 299 { 300 if (i > 0) 301 { 302 buffer.append(", "); 303 } 304 305 buffer.append(controls[i]); 306 } 307 buffer.append('}'); 308 } 309 310 buffer.append(')'); 311 } 312}