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