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