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