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.schema;
028 import org.opends.messages.Message;
029
030
031
032 import org.opends.server.admin.std.server.AttributeSyntaxCfg;
033 import org.opends.server.api.ApproximateMatchingRule;
034 import org.opends.server.api.AttributeSyntax;
035 import org.opends.server.api.EqualityMatchingRule;
036 import org.opends.server.api.OrderingMatchingRule;
037 import org.opends.server.api.SubstringMatchingRule;
038 import org.opends.server.config.ConfigException;
039 import org.opends.server.core.DirectoryServer;
040 import org.opends.server.types.ByteString;
041 import org.opends.server.types.DirectoryException;
042
043
044 import org.opends.server.types.ResultCode;
045
046 import static org.opends.server.loggers.ErrorLogger.*;
047 import static org.opends.messages.SchemaMessages.*;
048 import org.opends.messages.MessageBuilder;
049 import static org.opends.server.schema.SchemaConstants.*;
050 import static org.opends.server.util.StaticUtils.*;
051
052
053 /**
054 * This class defines an attribute syntax used for storing values that have been
055 * encoded using a password storage scheme. The format for attribute values
056 * with this syntax is the concatenation of the following elements in the given
057 * order:
058 * <BR>
059 * <UL>
060 * <LI>An opening curly brace ("{") character.</LI>
061 * <LI>The name of the storage scheme used to encode the value.</LI>
062 * <LI>A closing curly brace ("}") character.</LI>
063 * <LI>The encoded value.</LI>
064 * </UL>
065 */
066 public class UserPasswordSyntax
067 extends AttributeSyntax<AttributeSyntaxCfg>
068 {
069 // The default equality matching rule for this syntax.
070 private EqualityMatchingRule defaultEqualityMatchingRule;
071
072
073
074 /**
075 * Creates a new instance of this syntax. Note that the only thing that
076 * should be done here is to invoke the default constructor for the
077 * superclass. All initialization should be performed in the
078 * <CODE>initializeSyntax</CODE> method.
079 */
080 public UserPasswordSyntax()
081 {
082 super();
083 }
084
085
086
087 /**
088 * {@inheritDoc}
089 */
090 public void initializeSyntax(AttributeSyntaxCfg configuration)
091 throws ConfigException
092 {
093 defaultEqualityMatchingRule =
094 DirectoryServer.getEqualityMatchingRule(EMR_USER_PASSWORD_EXACT_OID);
095 if (defaultEqualityMatchingRule == null)
096 {
097 logError(ERR_ATTR_SYNTAX_UNKNOWN_EQUALITY_MATCHING_RULE.get(
098 EMR_USER_PASSWORD_EXACT_NAME, SYNTAX_USER_PASSWORD_NAME));
099 }
100 }
101
102
103
104 /**
105 * Retrieves the common name for this attribute syntax.
106 *
107 * @return The common name for this attribute syntax.
108 */
109 public String getSyntaxName()
110 {
111 return SYNTAX_USER_PASSWORD_NAME;
112 }
113
114
115
116 /**
117 * Retrieves the OID for this attribute syntax.
118 *
119 * @return The OID for this attribute syntax.
120 */
121 public String getOID()
122 {
123 return SYNTAX_USER_PASSWORD_OID;
124 }
125
126
127
128 /**
129 * Retrieves a description for this attribute syntax.
130 *
131 * @return A description for this attribute syntax.
132 */
133 public String getDescription()
134 {
135 return SYNTAX_USER_PASSWORD_DESCRIPTION;
136 }
137
138
139
140 /**
141 * Retrieves the default equality matching rule that will be used for
142 * attributes with this syntax.
143 *
144 * @return The default equality matching rule that will be used for
145 * attributes with this syntax, or <CODE>null</CODE> if equality
146 * matches will not be allowed for this type by default.
147 */
148 public EqualityMatchingRule getEqualityMatchingRule()
149 {
150 return defaultEqualityMatchingRule;
151 }
152
153
154
155 /**
156 * Retrieves the default ordering matching rule that will be used for
157 * attributes with this syntax.
158 *
159 * @return The default ordering matching rule that will be used for
160 * attributes with this syntax, or <CODE>null</CODE> if ordering
161 * matches will not be allowed for this type by default.
162 */
163 public OrderingMatchingRule getOrderingMatchingRule()
164 {
165 // There is no ordering matching rule by default.
166 return null;
167 }
168
169
170
171 /**
172 * Retrieves the default substring matching rule that will be used for
173 * attributes with this syntax.
174 *
175 * @return The default substring matching rule that will be used for
176 * attributes with this syntax, or <CODE>null</CODE> if substring
177 * matches will not be allowed for this type by default.
178 */
179 public SubstringMatchingRule getSubstringMatchingRule()
180 {
181 // There is no substring matching rule by default.
182 return null;
183 }
184
185
186
187 /**
188 * Retrieves the default approximate matching rule that will be used for
189 * attributes with this syntax.
190 *
191 * @return The default approximate matching rule that will be used for
192 * attributes with this syntax, or <CODE>null</CODE> if approximate
193 * matches will not be allowed for this type by default.
194 */
195 public ApproximateMatchingRule getApproximateMatchingRule()
196 {
197 // There is no approximate matching rule by default.
198 return null;
199 }
200
201
202
203 /**
204 * Indicates whether the provided value is acceptable for use in an attribute
205 * with this syntax. If it is not, then the reason may be appended to the
206 * provided buffer.
207 *
208 * @param value The value for which to make the determination.
209 * @param invalidReason The buffer to which the invalid reason should be
210 * appended.
211 *
212 * @return <CODE>true</CODE> if the provided value is acceptable for use with
213 * this syntax, or <CODE>false</CODE> if not.
214 */
215 public boolean valueIsAcceptable(ByteString value,
216 MessageBuilder invalidReason)
217 {
218 // We have to accept any value here because in many cases the value will not
219 // have been encoded by the time this method is called.
220 return true;
221 }
222
223
224
225 /**
226 * Decodes the provided user password value into its component parts.
227 *
228 * @param userPasswordValue The user password value to be decoded.
229 *
230 * @return A two-element string array whose elements are the storage scheme
231 * name (in all lowercase characters) and the encoded value, in that
232 * order.
233 *
234 * @throws DirectoryException If a problem is encountered while attempting
235 * to decode the value.
236 */
237 public static String[] decodeUserPassword(String userPasswordValue)
238 throws DirectoryException
239 {
240 // Make sure that there actually is a value to decode.
241 if ((userPasswordValue == null) || (userPasswordValue.length() == 0))
242 {
243 Message message = ERR_ATTR_SYNTAX_USERPW_NO_VALUE.get();
244 throw new DirectoryException(
245 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
246 }
247
248
249 // The first character of an encoded value must be an opening curly brace.
250 if (userPasswordValue.charAt(0) != '{')
251 {
252 Message message = ERR_ATTR_SYNTAX_USERPW_NO_OPENING_BRACE.get();
253 throw new DirectoryException(
254 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
255 }
256
257
258 // There must be a corresponding closing brace.
259 int closePos = userPasswordValue.indexOf('}');
260 if (closePos < 0)
261 {
262 Message message = ERR_ATTR_SYNTAX_USERPW_NO_CLOSING_BRACE.get();
263 throw new DirectoryException(
264 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
265 }
266
267
268 // Get the storage scheme name and encoded value.
269 String schemeName = userPasswordValue.substring(1, closePos);
270 String encodedValue = userPasswordValue.substring(closePos+1);
271
272 if (schemeName.length() == 0)
273 {
274 Message message = ERR_ATTR_SYNTAX_USERPW_NO_SCHEME.get();
275 throw new DirectoryException(
276 ResultCode.INVALID_ATTRIBUTE_SYNTAX, message);
277 }
278
279
280 return new String[] { toLowerCase(schemeName), encodedValue };
281 }
282
283
284
285 /**
286 * Indicates whether the provided value is encoded using the user password
287 * syntax.
288 *
289 * @param value The value for which to make the determination.
290 *
291 * @return <CODE>true</CODE> if the value appears to be encoded using the
292 * user password syntax, or <CODE>false</CODE> if not.
293 */
294 public static boolean isEncoded(ByteString value)
295 {
296 // If the value is null or empty, then it's not.
297 byte[] valueBytes;
298 if ((value == null) || ((valueBytes = value.value()).length == 0))
299 {
300 return false;
301 }
302
303
304 // If the value doesn't start with an opening curly brace, then it's not.
305 if (valueBytes[0] != '{')
306 {
307 return false;
308 }
309
310
311 // There must be a corresponding closing curly brace, and there must be at
312 // least one character inside the brace.
313 int closingBracePos = -1;
314 for (int i=1; i < valueBytes.length; i++)
315 {
316 if (valueBytes[i] == '}')
317 {
318 closingBracePos = i;
319 break;
320 }
321 }
322
323 if ((closingBracePos < 0) || (closingBracePos == 1))
324 {
325 return false;
326 }
327
328
329 // The closing curly brace must not be the last character of the password.
330 if (closingBracePos == (valueBytes.length - 1))
331 {
332 return false;
333 }
334
335
336 // If we've gotten here, then it looks to be encoded.
337 return true;
338 }
339 }
340