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_PWEXPIRED_CONTROL_BAD_OID; 020import static com.forgerock.opendj.ldap.CoreMessages.ERR_PWEXPIRED_CONTROL_INVALID_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 Netscape password expired response control as defined in 031 * draft-vchu-ldap-pwd-policy. This control indicates to a client that their 032 * password has expired and must be changed. This control always has a value 033 * which is the string {@code "0"}. 034 * 035 * <pre> 036 * Connection connection = ...; 037 * String DN = ...; 038 * char[] password = ...; 039 * 040 * try { 041 * connection.bind(DN, password); 042 * } catch (LdapException e) { 043 * Result result = e.getResult(); 044 * try { 045 * PasswordExpiredResponseControl control = 046 * result.getControl(PasswordExpiredResponseControl.DECODER, 047 * new DecodeOptions()); 048 * if (!(control == null) && control.hasValue()) { 049 * // Password expired 050 * } 051 * } catch (DecodeException de) { 052 * // Failed to decode the response control. 053 * } 054 * } 055 * </pre> 056 * 057 * @see <a 058 * href="http://tools.ietf.org/html/draft-vchu-ldap-pwd-policy">draft-vchu-ldap-pwd-policy 059 * - Password Policy for LDAP Directories </a> 060 */ 061public final class PasswordExpiredResponseControl implements Control { 062 /** The OID for the Netscape password expired response control. */ 063 public static final String OID = "2.16.840.1.113730.3.4.4"; 064 065 private final boolean isCritical; 066 067 private static final PasswordExpiredResponseControl CRITICAL_INSTANCE = 068 new PasswordExpiredResponseControl(true); 069 private static final PasswordExpiredResponseControl NONCRITICAL_INSTANCE = 070 new PasswordExpiredResponseControl(false); 071 072 /** A decoder which can be used for decoding the password expired response control. */ 073 public static final ControlDecoder<PasswordExpiredResponseControl> DECODER = 074 new ControlDecoder<PasswordExpiredResponseControl>() { 075 076 @Override 077 public PasswordExpiredResponseControl decodeControl(final Control control, 078 final DecodeOptions options) throws DecodeException { 079 Reject.ifNull(control); 080 081 if (control instanceof PasswordExpiredResponseControl) { 082 return (PasswordExpiredResponseControl) control; 083 } 084 085 if (!control.getOID().equals(OID)) { 086 final LocalizableMessage message = 087 ERR_PWEXPIRED_CONTROL_BAD_OID.get(control.getOID(), OID); 088 throw DecodeException.error(message); 089 } 090 091 if (control.hasValue()) { 092 try { 093 Integer.parseInt(control.getValue().toString()); 094 } catch (final Exception e) { 095 final LocalizableMessage message = 096 ERR_PWEXPIRED_CONTROL_INVALID_VALUE.get(); 097 throw DecodeException.error(message); 098 } 099 } 100 101 return control.isCritical() ? CRITICAL_INSTANCE : NONCRITICAL_INSTANCE; 102 } 103 104 @Override 105 public String getOID() { 106 return OID; 107 } 108 }; 109 110 private static final ByteString CONTROL_VALUE = ByteString.valueOfUtf8("0"); 111 112 /** 113 * Creates a new Netscape password expired response control. 114 * 115 * @return The new control. 116 */ 117 public static PasswordExpiredResponseControl newControl() { 118 return NONCRITICAL_INSTANCE; 119 } 120 121 private PasswordExpiredResponseControl(final boolean isCritical) { 122 this.isCritical = isCritical; 123 } 124 125 @Override 126 public String getOID() { 127 return OID; 128 } 129 130 @Override 131 public ByteString getValue() { 132 return CONTROL_VALUE; 133 } 134 135 @Override 136 public boolean hasValue() { 137 return true; 138 } 139 140 @Override 141 public boolean isCritical() { 142 return isCritical; 143 } 144 145 @Override 146 public String toString() { 147 final StringBuilder builder = new StringBuilder(); 148 builder.append("PasswordExpiredResponseControl(oid="); 149 builder.append(getOID()); 150 builder.append(", criticality="); 151 builder.append(isCritical()); 152 builder.append(")"); 153 return builder.toString(); 154 } 155}