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