001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2006-2008 Sun Microsystems, Inc. 015 * Portions Copyright 2011-2016 ForgeRock AS. 016 */ 017package org.opends.server.controls; 018 019import java.io.IOException; 020import org.forgerock.i18n.LocalizableMessage; 021import org.opends.server.api.AuthenticationPolicyState; 022import org.opends.server.core.DirectoryServer; 023import org.opends.server.core.PasswordPolicyState; 024import org.forgerock.i18n.slf4j.LocalizedLogger; 025import org.forgerock.opendj.io.ASN1; 026import org.forgerock.opendj.io.ASN1Reader; 027import org.forgerock.opendj.io.ASN1Writer; 028import org.opends.server.types.*; 029import org.forgerock.opendj.ldap.DN; 030import org.forgerock.opendj.ldap.ResultCode; 031import org.forgerock.opendj.ldap.ByteString; 032import static org.opends.messages.ProtocolMessages.*; 033import static org.opends.server.util.ServerConstants.*; 034import static org.opends.server.util.StaticUtils.*; 035 036/** 037 * This class implements version 1 of the proxied authorization control as 038 * defined in early versions of draft-weltman-ldapv3-proxy (this implementation 039 * is based on the "-04" revision). It makes it possible for one user to 040 * request that an operation be performed under the authorization of another. 041 * The target user is specified as a DN in the control value, which 042 * distinguishes it from later versions of the control (which used a different 043 * OID) in which the target user was specified using an authorization ID. 044 */ 045public class ProxiedAuthV1Control 046 extends Control 047{ 048 /** ControlDecoder implementation to decode this control from a ByteString. */ 049 private static final class Decoder 050 implements ControlDecoder<ProxiedAuthV1Control> 051 { 052 @Override 053 public ProxiedAuthV1Control decode(boolean isCritical, ByteString value) 054 throws DirectoryException 055 { 056 if (!isCritical) 057 { 058 LocalizableMessage message = ERR_PROXYAUTH1_CONTROL_NOT_CRITICAL.get(); 059 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 060 } 061 062 if (value == null) 063 { 064 LocalizableMessage message = ERR_PROXYAUTH1_NO_CONTROL_VALUE.get(); 065 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message); 066 } 067 068 ASN1Reader reader = ASN1.getReader(value); 069 DN authorizationDN; 070 try 071 { 072 reader.readStartSequence(); 073 authorizationDN = DN.valueOf(reader.readOctetString()); 074 reader.readEndSequence(); 075 } 076 catch (Exception e) 077 { 078 logger.traceException(e); 079 080 LocalizableMessage message = 081 ERR_PROXYAUTH1_CANNOT_DECODE_VALUE.get(getExceptionMessage(e)); 082 throw new DirectoryException(ResultCode.PROTOCOL_ERROR, message, e); 083 } 084 085 return new ProxiedAuthV1Control(isCritical, authorizationDN); 086 } 087 088 @Override 089 public String getOID() 090 { 091 return OID_PROXIED_AUTH_V1; 092 } 093 094 } 095 096 /** The Control Decoder that can be used to decode this control. */ 097 public static final ControlDecoder<ProxiedAuthV1Control> DECODER = 098 new Decoder(); 099 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 100 101 102 103 104 /** The raw, unprocessed authorization DN from the control value. */ 105 private ByteString rawAuthorizationDN; 106 107 /** The processed authorization DN from the control value. */ 108 private DN authorizationDN; 109 110 111 112 /** 113 * Creates a new instance of the proxied authorization v1 control with the 114 * provided information. 115 * 116 * @param rawAuthorizationDN The raw, unprocessed authorization DN from the 117 * control value. It must not be {@code null}. 118 */ 119 public ProxiedAuthV1Control(ByteString rawAuthorizationDN) 120 { 121 this(true, rawAuthorizationDN); 122 } 123 124 125 126 /** 127 * Creates a new instance of the proxied authorization v1 control with the 128 * provided information. 129 * 130 * @param authorizationDN The authorization DN from the control value. It 131 * must not be {@code null}. 132 */ 133 public ProxiedAuthV1Control(DN authorizationDN) 134 { 135 this(true, authorizationDN); 136 } 137 138 139 140 /** 141 * Creates a new instance of the proxied authorization v1 control with the 142 * provided information. 143 * 144 * @param isCritical Indicates whether support for this control 145 * should be considered a critical part of the 146 * server processing. 147 * @param rawAuthorizationDN The raw, unprocessed authorization DN from the 148 * control value. 149 */ 150 public ProxiedAuthV1Control(boolean isCritical, ByteString rawAuthorizationDN) 151 { 152 super(OID_PROXIED_AUTH_V1, isCritical); 153 154 155 this.rawAuthorizationDN = rawAuthorizationDN; 156 157 authorizationDN = null; 158 } 159 160 161 162 /** 163 * Creates a new instance of the proxied authorization v1 control with the 164 * provided information. 165 * 166 * @param isCritical Indicates whether support for this control 167 * should be considered a critical part of the 168 * server processing. 169 * @param authorizationDN The authorization DN from the control value. 170 * It must not be {@code null}. 171 */ 172 public ProxiedAuthV1Control(boolean isCritical, DN authorizationDN) 173 { 174 super(OID_PROXIED_AUTH_V1, isCritical); 175 176 177 this.authorizationDN = authorizationDN; 178 179 rawAuthorizationDN = ByteString.valueOfUtf8(authorizationDN.toString()); 180 } 181 182 183 184 /** 185 * Writes this control's value to an ASN.1 writer. The value (if any) must be 186 * written as an ASN1OctetString. 187 * 188 * @param writer The ASN.1 writer to use. 189 * @throws IOException If a problem occurs while writing to the stream. 190 */ 191 @Override 192 protected void writeValue(ASN1Writer writer) throws IOException { 193 writer.writeStartSequence(ASN1.UNIVERSAL_OCTET_STRING_TYPE); 194 195 writer.writeStartSequence(); 196 writer.writeOctetString(rawAuthorizationDN); 197 writer.writeEndSequence(); 198 199 writer.writeEndSequence(); 200 } 201 202 203 204 /** 205 * Retrieves the raw, unprocessed authorization DN from the control value. 206 * 207 * @return The raw, unprocessed authorization DN from the control value. 208 */ 209 public ByteString getRawAuthorizationDN() 210 { 211 return rawAuthorizationDN; 212 } 213 214 215 216 /** 217 * Retrieves the authorization DN from the control value. 218 * 219 * @return The authorization DN from the control value. 220 * 221 * @throws DirectoryException If a problem occurs while attempting to decode 222 * the raw authorization DN as a DN. 223 */ 224 public DN getAuthorizationDN() 225 throws DirectoryException 226 { 227 if (authorizationDN == null) 228 { 229 authorizationDN = DN.valueOf(rawAuthorizationDN); 230 } 231 232 return authorizationDN; 233 } 234 235 236 237 /** 238 * Retrieves the authorization entry for this proxied authorization V1 239 * control. It will also perform any necessary password policy checks to 240 * ensure that the associated user account is suitable for use in performing 241 * this processing. 242 * 243 * @return The entry for user specified as the authorization identity in this 244 * proxied authorization V1 control, or {@code null} if the 245 * authorization DN is the null DN. 246 * 247 * @throws DirectoryException If the target user does not exist or is not 248 * available for use, or if a problem occurs 249 * while making the determination. 250 */ 251 public Entry getAuthorizationEntry() 252 throws DirectoryException 253 { 254 DN authzDN = getAuthorizationDN(); 255 if (authzDN.isRootDN()) 256 { 257 return null; 258 } 259 260 261 // See if the authorization DN is one of the alternate bind DNs for one of 262 // the root users and if so then map it accordingly. 263 DN actualDN = DirectoryServer.getActualRootBindDN(authzDN); 264 if (actualDN != null) 265 { 266 authzDN = actualDN; 267 } 268 269 270 Entry userEntry = DirectoryServer.getEntry(authzDN); 271 if (userEntry == null) 272 { 273 // The requested user does not exist. 274 LocalizableMessage message = ERR_PROXYAUTH1_NO_SUCH_USER.get(authzDN); 275 throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message); 276 } 277 278 279 // FIXME -- We should provide some mechanism for enabling debug 280 // processing. 281 AuthenticationPolicyState state = AuthenticationPolicyState.forUser( 282 userEntry, false); 283 284 if (state.isDisabled()) 285 { 286 LocalizableMessage message = ERR_PROXYAUTH1_UNUSABLE_ACCOUNT.get(userEntry.getName()); 287 throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message); 288 } 289 290 if (state.isPasswordPolicy()) 291 { 292 PasswordPolicyState pwpState = (PasswordPolicyState) state; 293 if (pwpState.isAccountExpired() || pwpState.isLocked() || pwpState.isPasswordExpired()) 294 { 295 LocalizableMessage message = ERR_PROXYAUTH1_UNUSABLE_ACCOUNT.get(authzDN); 296 throw new DirectoryException(ResultCode.AUTHORIZATION_DENIED, message); 297 } 298 } 299 300 // If we've made it here, then the user is acceptable. 301 return userEntry; 302 } 303 304 305 306 /** 307 * Appends a string representation of this proxied auth v1 control to the 308 * provided buffer. 309 * 310 * @param buffer The buffer to which the information should be appended. 311 */ 312 @Override 313 public void toString(StringBuilder buffer) 314 { 315 buffer.append("ProxiedAuthorizationV1Control(authorizationDN=\""); 316 buffer.append(rawAuthorizationDN); 317 buffer.append("\")"); 318 } 319} 320