You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by ka...@apache.org on 2010/07/13 20:35:08 UTC
svn commit: r963807 -
/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/PasswordUtil.java
Author: kayyagari
Date: Tue Jul 13 18:35:07 2010
New Revision: 963807
URL: http://svn.apache.org/viewvc?rev=963807&view=rev
Log:
o a utility class containing methods related to processing passwords
Added:
directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/PasswordUtil.java
Added: directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/PasswordUtil.java
URL: http://svn.apache.org/viewvc/directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/PasswordUtil.java?rev=963807&view=auto
==============================================================================
--- directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/PasswordUtil.java (added)
+++ directory/apacheds/trunk/core/src/main/java/org/apache/directory/server/core/authn/PasswordUtil.java Tue Jul 13 18:35:07 2010
@@ -0,0 +1,249 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.directory.server.core.authn;
+
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.directory.shared.ldap.constants.LdapSecurityConstants;
+import org.apache.directory.shared.ldap.entry.EntryAttribute;
+import org.apache.directory.shared.ldap.entry.Value;
+import org.apache.directory.shared.ldap.util.DateUtils;
+import org.apache.directory.shared.ldap.util.StringTools;
+import org.apache.directory.shared.ldap.util.UnixCrypt;
+
+/**
+ * A utility class containing methods related to processing passwords.
+ *
+ * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
+ */
+public class PasswordUtil
+{
+ /**
+ * Get the algorithm from the stored password.
+ * It can be found on the beginning of the stored password, between
+ * curly brackets.
+ * @param credentials the credentials of the user
+ * @return the name of the algorithm to use
+ */
+ public static LdapSecurityConstants findAlgorithm( byte[] credentials )
+ {
+ if ( ( credentials == null ) || ( credentials.length == 0 ) )
+ {
+ return null;
+ }
+
+ if ( credentials[0] == '{' )
+ {
+ // get the algorithm
+ int pos = 1;
+
+ while ( pos < credentials.length )
+ {
+ if ( credentials[pos] == '}' )
+ {
+ break;
+ }
+
+ pos++;
+ }
+
+ if ( pos < credentials.length )
+ {
+ if ( pos == 1 )
+ {
+ // We don't have an algorithm : return the credentials as is
+ return null;
+ }
+
+ String algorithm = new String( credentials, 1, pos - 1 ).toLowerCase();
+
+ return LdapSecurityConstants.getAlgorithm( algorithm );
+ }
+ else
+ {
+ // We don't have an algorithm
+ return null;
+ }
+ }
+ else
+ {
+ // No '{algo}' part
+ return null;
+ }
+ }
+
+
+ /**
+ * encrypts the given credentials based on the algorithm name and optional salt
+ *
+ * @param credentials the credentials to be encrypted
+ * @param algorithm the algorithm to be used for encrypting the credentials
+ * @param salt value to be used as salt (optional)
+ * @return the encrypted credentials
+ */
+ public static byte[] encryptPassword( byte[] credentials, LdapSecurityConstants algorithm, byte[] salt )
+ {
+ switch ( algorithm )
+ {
+ case HASH_METHOD_SHA:
+ case HASH_METHOD_SSHA:
+ return digest( LdapSecurityConstants.HASH_METHOD_SHA, credentials, salt );
+
+ case HASH_METHOD_SHA256:
+ return digest( LdapSecurityConstants.HASH_METHOD_SHA256, credentials, salt );
+
+ case HASH_METHOD_MD5:
+ case HASH_METHOD_SMD5:
+ return digest( LdapSecurityConstants.HASH_METHOD_MD5, credentials, salt );
+
+ case HASH_METHOD_CRYPT:
+ if ( salt == null )
+ {
+ salt = new byte[2];
+ SecureRandom sr = new SecureRandom();
+ int i1 = sr.nextInt( 64 );
+ int i2 = sr.nextInt( 64 );
+
+ salt[0] = ( byte ) ( i1 < 12 ? ( i1 + '.' ) : i1 < 38 ? ( i1 + 'A' - 12 ) : ( i1 + 'a' - 38 ) );
+ salt[1] = ( byte ) ( i2 < 12 ? ( i2 + '.' ) : i2 < 38 ? ( i2 + 'A' - 12 ) : ( i2 + 'a' - 38 ) );
+ }
+
+ String saltWithCrypted = UnixCrypt.crypt( StringTools.utf8ToString( credentials ), StringTools
+ .utf8ToString( salt ) );
+ String crypted = saltWithCrypted.substring( 2 );
+
+ return StringTools.getBytesUtf8( crypted );
+
+ default:
+ return credentials;
+ }
+ }
+
+
+ /**
+ * Compute the hashed password given an algorithm, the credentials and
+ * an optional salt.
+ *
+ * @param algorithm the algorithm to use
+ * @param password the credentials
+ * @param salt the optional salt
+ * @return the digested credentials
+ */
+ private static byte[] digest( LdapSecurityConstants algorithm, byte[] password, byte[] salt )
+ {
+ MessageDigest digest;
+
+ try
+ {
+ digest = MessageDigest.getInstance( algorithm.getName() );
+ }
+ catch ( NoSuchAlgorithmException e1 )
+ {
+ return null;
+ }
+
+ if ( salt != null )
+ {
+ digest.update( password );
+ digest.update( salt );
+ return digest.digest();
+ }
+ else
+ {
+ return digest.digest( password );
+ }
+ }
+
+
+ /**
+ * checks if the given password's change time is older than the max age
+ *
+ * @param pwdChangedZtime time when the password was last changed
+ * @param pwdMaxAgeSec the max age value in seconds
+ * @return true if expired, false otherwise
+ */
+ public static boolean isPwdExpired( String pwdChangedZtime, int pwdMaxAgeSec )
+ {
+ Date pwdChangeDate = DateUtils.getDate( pwdChangedZtime );
+
+ long time = pwdMaxAgeSec * 1000;
+ time += pwdChangeDate.getTime();
+
+ Date expiryDate = new Date( time );
+ Date now = new Date();
+
+ boolean expired = false;
+
+ if( expiryDate.equals( now ) || expiryDate.after( now ) )
+ {
+ expired = true;
+ }
+
+ return expired;
+ }
+
+
+ /**
+ * purges failure timestamps which are older than the configured interval
+ * (section 7.6 in the draft)
+ */
+ public static void purgeFailureTimes( PasswordPolicyConfiguration config, EntryAttribute pwdFailTimeAt )
+ {
+ long interval = config.getPwdFailureCountInterval();
+
+ if( interval == 0 )
+ {
+ return;
+ }
+
+ Iterator<Value<?>> itr = pwdFailTimeAt.getAll();
+ interval *= 1000;
+
+ long currentTime = System.currentTimeMillis();
+ List<Value<?>> valList = new ArrayList<Value<?>>();
+
+ while( itr.hasNext() )
+ {
+ Value<?> val = itr.next();
+ String failureTime = val.getString();
+ long time = DateUtils.getDate( failureTime ).getTime();
+ time += interval;
+
+ if( currentTime > time )
+ {
+ valList.add( val );
+ }
+ }
+
+ for( Value<?> val : valList )
+ {
+ pwdFailTimeAt.remove( val );
+ }
+ }
+
+}