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