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
034 import org.opends.server.protocols.asn1.ASN1Element;
035 import org.opends.server.protocols.asn1.ASN1Enumerated;
036 import org.opends.server.protocols.asn1.ASN1Exception;
037 import org.opends.server.protocols.asn1.ASN1Integer;
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.LDAPException;
043
044 import static org.opends.server.loggers.debug.DebugLogger.*;
045 import org.opends.server.loggers.debug.DebugTracer;
046 import org.opends.server.types.DebugLogLevel;
047 import static org.opends.messages.ProtocolMessages.*;
048 import static org.opends.server.util.ServerConstants.*;
049 import static org.opends.server.util.StaticUtils.*;
050
051
052
053 /**
054 * This class implements the password policy response control defined in
055 * draft-behera-ldap-password-policy. The value may have zero, one, or two
056 * elements, which may include flags to indicate a warning and/or an error.
057 */
058 public class PasswordPolicyResponseControl
059 extends Control
060 {
061 /**
062 * The tracer object for the debug logger.
063 */
064 private static final DebugTracer TRACER = getTracer();
065
066
067
068
069 /**
070 * The BER type value for the warning element of the control value.
071 */
072 public static final byte TYPE_WARNING_ELEMENT = (byte) 0xA0;
073
074
075
076 /**
077 * The BER type value for the error element of the control value.
078 */
079 public static final byte TYPE_ERROR_ELEMENT = (byte) 0x81;
080
081
082
083 // The warning value for this password policy response control.
084 private int warningValue;
085
086 // The error type for this password policy response control.
087 private PasswordPolicyErrorType errorType;
088
089 // The warning type for the password policy response control.
090 private PasswordPolicyWarningType warningType;
091
092
093
094 /**
095 * Creates a new instance of the password policy response control with the
096 * default OID and criticality, and without either a warning or an error flag.
097 */
098 public PasswordPolicyResponseControl()
099 {
100 super(OID_PASSWORD_POLICY_CONTROL, false, encodeValue(null, -1, null));
101
102
103 warningType = null;
104 errorType = null;
105 warningValue = -1;
106 }
107
108
109
110 /**
111 * Creates a new instance of this password policy response control with the
112 * default OID and criticality, and with the provided warning and/or error
113 * flag information.
114 *
115 * @param warningType The warning type to use for this password policy
116 * response control, or <CODE>null</CODE> if there
117 * should not be a warning flag.
118 * @param warningValue The warning value to use for this password policy
119 * response control, if applicable.
120 * @param errorType The error type to use for this password policy
121 * response control, or <CODE>null</CODE> if there
122 * should not be an error flag.
123 */
124 public PasswordPolicyResponseControl(PasswordPolicyWarningType warningType,
125 int warningValue,
126 PasswordPolicyErrorType errorType)
127 {
128 super(OID_PASSWORD_POLICY_CONTROL, false,
129 encodeValue(warningType, warningValue, errorType));
130
131
132 this.warningType = warningType;
133 this.warningValue = warningValue;
134 this.errorType = errorType;
135 }
136
137
138
139 /**
140 * Creates a new instance of the password policy request control with the
141 * provided information.
142 *
143 * @param oid The OID to use for this control.
144 * @param isCritical Indicates whether support for this control should be
145 * considered a critical part of the client processing.
146 * @param warningType The warning type to use for this password policy
147 * response control, or <CODE>null</CODE> if there
148 * should not be a warning flag.
149 * @param warningValue The warning value to use for this password policy
150 * response control, if applicable.
151 * @param errorType The error type to use for this password policy
152 * response control, or <CODE>null</CODE> if there
153 * should not be an error flag.
154 */
155 public PasswordPolicyResponseControl(String oid, boolean isCritical,
156 PasswordPolicyWarningType warningType,
157 int warningValue,
158 PasswordPolicyErrorType errorType)
159 {
160 super(oid, isCritical, encodeValue(warningType, warningValue, errorType));
161
162
163 this.warningType = warningType;
164 this.warningValue = warningValue;
165 this.errorType = errorType;
166 }
167
168
169
170 /**
171 * Creates a new instance of the password policy request control with the
172 * provided information.
173 *
174 * @param oid The OID to use for this control.
175 * @param isCritical Indicates whether support for this control should be
176 * considered a critical part of the client processing.
177 * @param warningType The warning type to use for this password policy
178 * response control, or <CODE>null</CODE> if there
179 * should not be a warning flag.
180 * @param warningValue The warning value to use for this password policy
181 * response control, if applicable.
182 * @param errorType The error type to use for this password policy
183 * response control, or <CODE>null</CODE> if there
184 * should not be an error flag.
185 * @param encodedValue The pre-encoded value to use for this control.
186 */
187 private PasswordPolicyResponseControl(String oid, boolean isCritical,
188 PasswordPolicyWarningType warningType,
189 int warningValue,
190 PasswordPolicyErrorType errorType,
191 ASN1OctetString encodedValue)
192 {
193 super(oid, isCritical, encodedValue);
194
195
196 this.warningType = warningType;
197 this.warningValue = warningValue;
198 this.errorType = errorType;
199 }
200
201
202
203 /**
204 * Encodes the provided information into an ASN.1 octet string suitable for
205 * use as the value for this control.
206 *
207 * @param warningType The warning type to use for this password policy
208 * response control, or <CODE>null</CODE> if there
209 * should not be a warning flag.
210 * @param warningValue The warning value to use for this password policy
211 * response control, if applicable.
212 * @param errorType The error type to use for this password policy
213 * response control, or <CODE>null</CODE> if there
214 * should not be an error flag.
215 *
216 * @return An ASN.1 octet string containing the encoded control value.
217 */
218 private static ASN1OctetString encodeValue(
219 PasswordPolicyWarningType warningType,
220 int warningValue,
221 PasswordPolicyErrorType errorType)
222 {
223 ArrayList<ASN1Element> elements = new ArrayList<ASN1Element>(2);
224
225 if (warningType != null)
226 {
227 ASN1Integer warningInteger = new ASN1Integer(warningType.getType(),
228 warningValue);
229 elements.add(new ASN1Element(TYPE_WARNING_ELEMENT,
230 warningInteger.encode()));
231 }
232
233 if (errorType != null)
234 {
235 elements.add(new ASN1Enumerated(TYPE_ERROR_ELEMENT,
236 errorType.intValue()));
237 }
238
239 ASN1Sequence valueSequence = new ASN1Sequence(elements);
240 return new ASN1OctetString(valueSequence.encode());
241 }
242
243
244
245 /**
246 * Creates a new password policy response control from the contents of the
247 * provided control.
248 *
249 * @param control The generic control containing the information to use to
250 * create this password policy response control.
251 *
252 * @return The password policy response control decoded from the provided
253 * control.
254 *
255 * @throws LDAPException If this control cannot be decoded as a valid
256 * password policy response control.
257 */
258 public static PasswordPolicyResponseControl decodeControl(Control control)
259 throws LDAPException
260 {
261 ASN1OctetString controlValue = control.getValue();
262 if (controlValue == null)
263 {
264 // The response control must always have a value.
265 Message message = ERR_PWPOLICYRES_NO_CONTROL_VALUE.get();
266 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
267 }
268
269
270 try
271 {
272 PasswordPolicyWarningType warningType = null;
273 PasswordPolicyErrorType errorType = null;
274 int warningValue = -1;
275
276 ASN1Sequence valueSequence =
277 ASN1Sequence.decodeAsSequence(controlValue.value());
278 for (ASN1Element e : valueSequence.elements())
279 {
280 switch (e.getType())
281 {
282 case TYPE_WARNING_ELEMENT:
283 ASN1Integer integerElement = ASN1Integer.decodeAsInteger(e.value());
284 warningValue = integerElement.intValue();
285 warningType =
286 PasswordPolicyWarningType.valueOf(integerElement.getType());
287 if (warningType == null)
288 {
289 Message message = ERR_PWPOLICYRES_INVALID_WARNING_TYPE.get(
290 byteToHex(integerElement.getType()));
291 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
292 }
293 break;
294
295 case TYPE_ERROR_ELEMENT:
296 int errorValue = e.decodeAsEnumerated().intValue();
297 errorType = PasswordPolicyErrorType.valueOf(errorValue);
298 if (errorType == null)
299 {
300 Message message =
301 ERR_PWPOLICYRES_INVALID_ERROR_TYPE.get(errorValue);
302 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
303 }
304 break;
305
306 default:
307 Message message = ERR_PWPOLICYRES_INVALID_ELEMENT_TYPE.get(
308 byteToHex(e.getType()));
309 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
310 }
311 }
312
313 return new PasswordPolicyResponseControl(control.getOID(),
314 control.isCritical(),
315 warningType, warningValue,
316 errorType, controlValue);
317 }
318 catch (LDAPException le)
319 {
320 throw le;
321 }
322 catch (ASN1Exception ae)
323 {
324 if (debugEnabled())
325 {
326 TRACER.debugCaught(DebugLogLevel.ERROR, ae);
327 }
328
329 Message message = ERR_PWPOLICYRES_DECODE_ERROR.get(ae.getMessage());
330 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
331 }
332 catch (Exception e)
333 {
334 if (debugEnabled())
335 {
336 TRACER.debugCaught(DebugLogLevel.ERROR, e);
337 }
338
339 Message message =
340 ERR_PWPOLICYRES_DECODE_ERROR.get(getExceptionMessage(e));
341 throw new LDAPException(LDAPResultCode.PROTOCOL_ERROR, message);
342 }
343 }
344
345
346
347 /**
348 * Retrieves the password policy warning type contained in this control.
349 *
350 * @return The password policy warning type contained in this control, or
351 * <CODE>null</CODE> if there is no warning type.
352 */
353 public PasswordPolicyWarningType getWarningType()
354 {
355 return warningType;
356 }
357
358
359
360 /**
361 * Retrieves the password policy warning value for this control. The value is
362 * undefined if there is no warning type.
363 *
364 * @return The password policy warning value for this control.
365 */
366 public int getWarningValue()
367 {
368 return warningValue;
369 }
370
371
372
373 /**
374 * Retrieves the password policy error type contained in this control.
375 *
376 * @return The password policy error type contained in this control, or
377 * <CODE>null</CODE> if there is no error type.
378 */
379 public PasswordPolicyErrorType getErrorType()
380 {
381 return errorType;
382 }
383
384
385
386 /**
387 * Retrieves a string representation of this password policy response control.
388 *
389 * @return A string representation of this password policy response control.
390 */
391 public String toString()
392 {
393 StringBuilder buffer = new StringBuilder();
394 toString(buffer);
395 return buffer.toString();
396 }
397
398
399
400 /**
401 * Appends a string representation of this password policy response control to
402 * the provided buffer.
403 *
404 * @param buffer The buffer to which the information should be appended.
405 */
406 public void toString(StringBuilder buffer)
407 {
408 buffer.append("PasswordPolicyResponseControl(");
409
410 if (warningType != null)
411 {
412 buffer.append(warningType.toString());
413 buffer.append("=");
414 buffer.append(warningValue);
415
416 if (errorType != null)
417 {
418 buffer.append(", ");
419 }
420 }
421
422 if (errorType != null)
423 {
424 buffer.append(errorType.toString());
425 }
426
427 buffer.append(")");
428 }
429 }
430