001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.controls;
028 import org.opends.messages.Message;
029
030
031
032 import java.util.ArrayList;
033 import java.util.concurrent.locks.Lock;
034
035 import org.opends.server.core.DirectoryServer;
036 import org.opends.server.core.PasswordPolicyState;
037 import org.opends.server.protocols.asn1.ASN1Element;
038 import org.opends.server.protocols.asn1.ASN1OctetString;
039 import org.opends.server.protocols.asn1.ASN1Sequence;
040 import org.opends.server.protocols.ldap.LDAPResultCode;
041 import org.opends.server.types.Control;
042 import org.opends.server.types.DirectoryException;
043 import org.opends.server.types.DN;
044 import org.opends.server.types.Entry;
045 import org.opends.server.types.LDAPException;
046 import org.opends.server.types.LockManager;
047 import org.opends.server.types.ResultCode;
048
049 import static org.opends.server.loggers.debug.DebugLogger.*;
050 import org.opends.server.loggers.debug.DebugTracer;
051 import org.opends.server.types.DebugLogLevel;
052 import static org.opends.messages.ProtocolMessages.*;
053 import static org.opends.server.util.ServerConstants.*;
054 import static org.opends.server.util.StaticUtils.*;
055 import static org.opends.server.util.Validator.*;
056
057
058
059 /**
060 * This class implements version 1 of the proxied authorization control as
061 * defined in early versions of draft-weltman-ldapv3-proxy (this implementation
062 * is based on the "-04" revision). It makes it possible for one user to
063 * request that an operation be performed under the authorization of another.
064 * The target user is specified as a DN in the control value, which
065 * distinguishes it from later versions of the control (which used a different
066 * OID) in which the target user was specified using an authorization ID.
067 */
068 public class ProxiedAuthV1Control
069 extends Control
070 {
071 /**
072 * The tracer object for the debug logger.
073 */
074 private static final DebugTracer TRACER = getTracer();
075
076
077
078
079 // The raw, unprocessed authorization DN from the control value.
080 private ASN1OctetString rawAuthorizationDN;
081
082 // The processed authorization DN from the control value.
083 private DN authorizationDN;
084
085
086
087 /**
088 * Creates a new instance of the proxied authorization v1 control with the
089 * provided information.
090 *
091 * @param rawAuthorizationDN The raw, unprocessed authorization DN from the
092 * control value. It must not be {@code null}.
093 */
094 public ProxiedAuthV1Control(ASN1OctetString rawAuthorizationDN)
095 {
096 super(OID_PROXIED_AUTH_V1, true, encodeValue(rawAuthorizationDN));
097
098
099 this.rawAuthorizationDN = rawAuthorizationDN;
100
101 authorizationDN = null;
102 }
103
104
105
106 /**
107 * Creates a new instance of the proxied authorization v1 control with the
108 * provided information.
109 *
110 * @param authorizationDN The authorization DN from the control value. It
111 * must not be {@code null}.
112 */
113 public ProxiedAuthV1Control(DN authorizationDN)
114 {
115 super(OID_PROXIED_AUTH_V1, true,
116 encodeValue(new ASN1OctetString(authorizationDN.toString())));
117
118
119 this.authorizationDN = authorizationDN;
120
121 rawAuthorizationDN = new ASN1OctetString(authorizationDN.toString());
122 }
123
124
125
126 /**
127 * Creates a new instance of the proxied authorization v1 control with the
128 * provided information.
129 *
130 * @param oid The OID to use for this control.
131 * @param isCritical Indicates whether support for this control
132 * should be considered a critical part of the
133 * server processing.
134 * @param controlValue The encoded value for this control.
135 * @param rawAuthorizationDN The raw, unprocessed authorization DN from the
136 * control value.
137 */
138 private ProxiedAuthV1Control(String oid, boolean isCritical,
139 ASN1OctetString controlValue,
140 ASN1OctetString rawAuthorizationDN)
141 {
142 super(oid, isCritical, controlValue);
143
144
145 this.rawAuthorizationDN = rawAuthorizationDN;
146
147 authorizationDN = null;
148 }
149
150
151
152 /**
153 * Generates an encoded value for this control containing the provided raw
154 * authorization DN.
155 *
156 * @param rawAuthorizationDN The raw, unprocessed authorization DN to use in
157 * the control value. It must not be
158 * {@code null}.
159 *
160 * @return The encoded control value.
161 */
162 private static ASN1OctetString encodeValue(ASN1OctetString rawAuthorizationDN)
163 {
164 ensureNotNull(rawAuthorizationDN);
165
166 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(1);
167 elements.add(rawAuthorizationDN);
168
169 return new ASN1OctetString(new ASN1Sequence(elements).encode());
170 }
171
172
173
174 /**
175 * Creates a new proxied authorization v1 control from the contents of the
176 * provided control.
177 *
178 * @param control The generic control containing the information to use to
179 * create this proxied authorization v1 control. It must not
180 * be {@code null}.
181 *
182 * @return The proxied authorization v1 control decoded from the provided
183 * control.
184 *
185 * @throws LDAPException If this control cannot be decoded as a valid
186 * proxied authorization v1 control.
187 */
188 public static ProxiedAuthV1Control decodeControl(Control control)
189 throws LDAPException
190 {
191 ensureNotNull(control);
192
193 if (! control.isCritical())
194 {
195 Message message = ERR_PROXYAUTH1_CONTROL_NOT_CRITICAL.get();
196 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
197 }
198
199 if (! control.hasValue())
200 {
201 Message message = ERR_PROXYAUTH1_NO_CONTROL_VALUE.get();
202 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
203 }
204
205
206 ASN1OctetString rawAuthorizationDN;
207 try
208 {
209 ArrayList<ASN1Element> elements =
210 ASN1Sequence.decodeAsSequence(control.getValue().value()).elements();
211 if (elements.size() != 1)
212 {
213 Message message =
214 ERR_PROXYAUTH1_INVALID_ELEMENT_COUNT.get(elements.size());
215 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
216 }
217
218 rawAuthorizationDN = elements.get(0).decodeAsOctetString();
219 }
220 catch (LDAPException le)
221 {
222 throw le;
223 }
224 catch (Exception e)
225 {
226 if (debugEnabled())
227 {
228 TRACER.debugCaught(DebugLogLevel.ERROR, e);
229 }
230
231 Message message =
232 ERR_PROXYAUTH1_CANNOT_DECODE_VALUE.get(getExceptionMessage(e));
233 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message, e);
234 }
235
236 return new ProxiedAuthV1Control(control.getOID(), control.isCritical(),
237 control.getValue(), rawAuthorizationDN);
238 }
239
240
241
242 /**
243 * Retrieves the raw, unprocessed authorization DN from the control value.
244 *
245 * @return The raw, unprocessed authorization DN from the control value.
246 */
247 public ASN1OctetString getRawAuthorizationDN()
248 {
249 return rawAuthorizationDN;
250 }
251
252
253
254 /**
255 * Specifies the raw, unprocessed authorization DN for this proxied auth
256 * control.
257 *
258 * @param rawAuthorizationDN The raw, unprocessed authorization DN for this
259 * proxied auth control.
260 */
261 public void setRawAuthorizationDN(ASN1OctetString rawAuthorizationDN)
262 {
263 this.rawAuthorizationDN = rawAuthorizationDN;
264
265 setValue(encodeValue(rawAuthorizationDN));
266 authorizationDN = null;
267 }
268
269
270
271 /**
272 * Retrieves the authorization DN from the control value.
273 *
274 * @return The authorization DN from the control value.
275 *
276 * @throws DirectoryException If a problem occurs while attempting to decode
277 * the raw authorization DN as a DN.
278 */
279 public DN getAuthorizationDN()
280 throws DirectoryException
281 {
282 if (authorizationDN == null)
283 {
284 authorizationDN = DN.decode(rawAuthorizationDN);
285 }
286
287 return authorizationDN;
288 }
289
290
291
292 /**
293 * Specifies the authorization DN for this proxied auth control.
294 *
295 * @param authorizationDN The authorizationDN for this proxied auth control.
296 * It must not be {@code null}.
297 */
298 public void setAuthorizationDN(DN authorizationDN)
299 {
300 ensureNotNull(authorizationDN);
301
302 this.authorizationDN = authorizationDN;
303
304 rawAuthorizationDN = new ASN1OctetString(authorizationDN.toString());
305 setValue(encodeValue(rawAuthorizationDN));
306 }
307
308
309
310 /**
311 * Retrieves the authorization entry for this proxied authorization V1
312 * control. It will also perform any necessary password policy checks to
313 * ensure that the associated user account is suitable for use in performing
314 * this processing.
315 *
316 * @return The entry for user specified as the authorization identity in this
317 * proxied authorization V1 control, or {@code null} if the
318 * authorization DN is the null DN.
319 *
320 * @throws DirectoryException If the target user does not exist or is not
321 * available for use, or if a problem occurs
322 * while making the determination.
323 */
324 public Entry getAuthorizationEntry()
325 throws DirectoryException
326 {
327 DN authzDN = getAuthorizationDN();
328 if (authzDN.isNullDN())
329 {
330 return null;
331 }
332
333
334 // See if the authorization DN is one of the alternate bind DNs for one of
335 // the root users and if so then map it accordingly.
336 DN actualDN = DirectoryServer.getActualRootBindDN(authzDN);
337 if (actualDN != null)
338 {
339 authzDN = actualDN;
340 }
341
342
343 Lock entryLock = null;
344 for (int i=0; i < 3; i++)
345 {
346 entryLock = LockManager.lockRead(authzDN);
347 if (entryLock != null)
348 {
349 break;
350 }
351 }
352
353 if (entryLock == null)
354 {
355 Message message =
356 ERR_PROXYAUTH1_CANNOT_LOCK_USER.get(String.valueOf(authzDN));
357 throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message);
358 }
359
360 try
361 {
362 Entry userEntry = DirectoryServer.getEntry(authzDN);
363 if (userEntry == null)
364 {
365 // The requested user does not exist.
366 Message message =
367 ERR_PROXYAUTH1_NO_SUCH_USER.get(String.valueOf(authzDN));
368 throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message);
369 }
370
371
372 // FIXME -- We should provide some mechanism for enabling debug
373 // processing.
374 PasswordPolicyState pwpState = new PasswordPolicyState(userEntry, false);
375 if (pwpState.isDisabled() || pwpState.isAccountExpired() ||
376 pwpState.lockedDueToFailures() ||
377 pwpState.lockedDueToIdleInterval() ||
378 pwpState.lockedDueToMaximumResetAge() ||
379 pwpState.isPasswordExpired())
380 {
381 Message message =
382 ERR_PROXYAUTH1_UNUSABLE_ACCOUNT.get(String.valueOf(authzDN));
383 throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message);
384 }
385
386
387 // If we've made it here, then the user is acceptable.
388 return userEntry;
389 }
390 finally
391 {
392 LockManager.unlock(authzDN, entryLock);
393 }
394 }
395
396
397
398 /**
399 * Retrieves a string representation of this proxied auth v1 control.
400 *
401 * @return A string representation of this proxied auth v1 control.
402 */
403 public String toString()
404 {
405 StringBuilder buffer = new StringBuilder();
406 toString(buffer);
407 return buffer.toString();
408 }
409
410
411
412 /**
413 * Appends a string representation of this proxied auth v1 control to the
414 * provided buffer.
415 *
416 * @param buffer The buffer to which the information should be appended.
417 */
418 public void toString(StringBuilder buffer)
419 {
420 buffer.append("ProxiedAuthorizationV1Control(authorizationDN=\"");
421 rawAuthorizationDN.toString(buffer);
422 buffer.append("\")");
423 }
424 }
425