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 2010 Sun Microsystems, Inc. 015 * Portions Copyright 2014-2016 ForgeRock AS. 016 */ 017package org.forgerock.opendj.ldap.controls; 018 019import static com.forgerock.opendj.ldap.CoreMessages.ERR_PWPOLICYREQ_CONTROL_BAD_OID; 020import static com.forgerock.opendj.ldap.CoreMessages.ERR_PWPOLICYREQ_CONTROL_HAS_VALUE; 021 022import org.forgerock.i18n.LocalizableMessage; 023import org.forgerock.opendj.ldap.ByteString; 024import org.forgerock.opendj.ldap.DecodeException; 025import org.forgerock.opendj.ldap.DecodeOptions; 026 027import org.forgerock.util.Reject; 028 029/** 030 * The password policy request control as defined in 031 * draft-behera-ldap-password-policy. 032 * <p> 033 * This control may be sent with any request in order to convey to the server 034 * that this client is aware of, and can process the password policy response 035 * control. When a server receives this control, it will return the password 036 * policy response control when appropriate and with the proper data. 037 * 038 * <pre> 039 * Connection connection = ...; 040 * String DN = ...; 041 * char[] password = ...; 042 * 043 * try { 044 * BindRequest request = Requests.newSimpleBindRequest(DN, password) 045 * .addControl(PasswordPolicyRequestControl.newControl(true)); 046 * 047 * BindResult result = connection.bind(request); 048 * 049 * PasswordPolicyResponseControl control = 050 * result.getControl(PasswordPolicyResponseControl.DECODER, 051 * new DecodeOptions()); 052 * if (!(control == null) && !(control.getWarningType() == null)) { 053 * // Password policy warning, use control.getWarningType(), 054 * // and control.getWarningValue(). 055 * } 056 * } catch (LdapException e) { 057 * Result result = e.getResult(); 058 * try { 059 * PasswordPolicyResponseControl control = 060 * result.getControl(PasswordPolicyResponseControl.DECODER, 061 * new DecodeOptions()); 062 * if (!(control == null)) { 063 * // Password policy error, use control.getErrorType(). 064 * } 065 * } catch (DecodeException de) { 066 * // Failed to decode the response control. 067 * } 068 * } catch (DecodeException e) { 069 * // Failed to decode the response control. 070 * } 071 * </pre> 072 * 073 * @see PasswordPolicyResponseControl 074 * @see <a href="http://tools.ietf.org/html/draft-behera-ldap-password-policy"> 075 * draft-behera-ldap-password-policy - Password Policy for LDAP Directories 076 * </a> 077 */ 078public final class PasswordPolicyRequestControl implements Control { 079 /** The OID for the password policy control from draft-behera-ldap-password-policy. */ 080 public static final String OID = "1.3.6.1.4.1.42.2.27.8.5.1"; 081 082 private final boolean isCritical; 083 084 private static final PasswordPolicyRequestControl CRITICAL_INSTANCE = 085 new PasswordPolicyRequestControl(true); 086 private static final PasswordPolicyRequestControl NONCRITICAL_INSTANCE = 087 new PasswordPolicyRequestControl(false); 088 089 /** A decoder which can be used for decoding the password policy request control. */ 090 public static final ControlDecoder<PasswordPolicyRequestControl> DECODER = 091 new ControlDecoder<PasswordPolicyRequestControl>() { 092 093 @Override 094 public PasswordPolicyRequestControl decodeControl(final Control control, 095 final DecodeOptions options) throws DecodeException { 096 Reject.ifNull(control); 097 098 if (control instanceof PasswordPolicyRequestControl) { 099 return (PasswordPolicyRequestControl) control; 100 } 101 102 if (!control.getOID().equals(OID)) { 103 final LocalizableMessage message = 104 ERR_PWPOLICYREQ_CONTROL_BAD_OID.get(control.getOID(), OID); 105 throw DecodeException.error(message); 106 } 107 108 if (control.hasValue()) { 109 final LocalizableMessage message = ERR_PWPOLICYREQ_CONTROL_HAS_VALUE.get(); 110 throw DecodeException.error(message); 111 } 112 113 return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE; 114 } 115 116 @Override 117 public String getOID() { 118 return OID; 119 } 120 }; 121 122 /** 123 * Creates a new password policy request control having the provided 124 * criticality. 125 * 126 * @param isCritical 127 * {@code true} if it is unacceptable to perform the operation 128 * without applying the semantics of this control, or 129 * {@code false} if it can be ignored. 130 * @return The new control. 131 */ 132 public static PasswordPolicyRequestControl newControl(final boolean isCritical) { 133 return isCritical ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE; 134 } 135 136 private PasswordPolicyRequestControl(final boolean isCritical) { 137 this.isCritical = isCritical; 138 } 139 140 @Override 141 public String getOID() { 142 return OID; 143 } 144 145 @Override 146 public ByteString getValue() { 147 return null; 148 } 149 150 @Override 151 public boolean hasValue() { 152 return false; 153 } 154 155 @Override 156 public boolean isCritical() { 157 return isCritical; 158 } 159 160 @Override 161 public String toString() { 162 final StringBuilder builder = new StringBuilder(); 163 builder.append("PasswordPolicyRequestControl(oid="); 164 builder.append(getOID()); 165 builder.append(", criticality="); 166 builder.append(isCritical()); 167 builder.append(")"); 168 return builder.toString(); 169 } 170 171}