Author: ate
Date: Sun Jul 2 08:10:18 2006
New Revision: 418604
URL: http://svn.apache.org/viewvc?rev=418604&view=rev
Log:
JS2-550: A new Two-way password encoding service allowing decoding of encoded
passwords
This set of changes provides a further enhancement providing a way to lazy
upgrade from one encoding scheme to another.
Furthermore, a few improvements in handling of InternalCredential timestamp
properties.
See: http://issues.apache.org/jira/browse/JS2-550#action_12418846
Added:
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/AlgorithmUpgradeCredentialPasswordEncoder.java
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/AlgorithmUpgradePBEPasswordService.java
portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/security/AlgorithmUpgradePasswordEncodingService.java
Modified:
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/PasswordCredentialValveImpl.java
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/DefaultCredentialHandler.java
portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/security-spi-atn.xml
Modified:
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/PasswordCredentialValveImpl.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/PasswordCredentialValveImpl.java?rev=418604&r1=418603&r2=418604&view=diff
==============================================================================
---
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/PasswordCredentialValveImpl.java
(original)
+++
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/security/impl/PasswordCredentialValveImpl.java
Sun Jul 2 08:10:18 2006
@@ -102,6 +102,7 @@
{
request.setSessionAttribute(CHECKED_KEY,Boolean.TRUE);
if ( pwdCredential.getPreviousAuthenticationDate() !=
null &&
+ pwdCredential.getLastAuthenticationDate() !=
null &&
pwdCredential.getExpirationDate() != null )
{
long expirationTime =
pwdCredential.getExpirationDate().getTime();
Added:
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/AlgorithmUpgradeCredentialPasswordEncoder.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/AlgorithmUpgradeCredentialPasswordEncoder.java?rev=418604&view=auto
==============================================================================
---
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/AlgorithmUpgradeCredentialPasswordEncoder.java
(added)
+++
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/AlgorithmUpgradeCredentialPasswordEncoder.java
Sun Jul 2 08:10:18 2006
@@ -0,0 +1,42 @@
+/* Copyright 2004 Apache Software Foundation
+*
+* Licensed 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.jetspeed.security.spi;
+
+import org.apache.jetspeed.security.PasswordCredential;
+import org.apache.jetspeed.security.SecurityException;
+import org.apache.jetspeed.security.om.InternalCredential;
+
+/**
+ * <p>
+ * AlgorithmUpgradeCredentialPasswordEncoder which is provided with the
InternalCredential as well
+ * to allow for migrating between two different encoding schemes.
+ * </p>
+ * <p>
+ * The extended encode method is *only* called in the context of validating an
existing (old) password,
+ * and not used for creating or updating to a new password directl!
+ * </p>
+ * <p>
+ * After successfull authentication, the recodeIfNeeded method will be called
allowing to migrate to the new encryption scheme.
+ * </p>
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Ate Douma</a>
+ * @version $Id$
+ */
+public interface AlgorithmUpgradeCredentialPasswordEncoder extends
CredentialPasswordEncoder
+{
+ String encode(String userName, String clearTextPassword,
InternalCredential credential) throws SecurityException;
+ void recodeIfNeeded(String userName, String clearTextPassword,
InternalCredential credential) throws SecurityException;
+ boolean usesOldEncodingAlgorithm(PasswordCredential credential);
+}
Added:
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/AlgorithmUpgradePBEPasswordService.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/AlgorithmUpgradePBEPasswordService.java?rev=418604&view=auto
==============================================================================
---
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/AlgorithmUpgradePBEPasswordService.java
(added)
+++
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/AlgorithmUpgradePBEPasswordService.java
Sun Jul 2 08:10:18 2006
@@ -0,0 +1,112 @@
+/* Copyright 2004 Apache Software Foundation
+ *
+ * Licensed 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.jetspeed.security.spi.impl;
+
+import java.security.NoSuchAlgorithmException;
+import java.security.spec.InvalidKeySpecException;
+import java.sql.Timestamp;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.jetspeed.security.AlgorithmUpgradePasswordEncodingService;
+import org.apache.jetspeed.security.PasswordCredential;
+import org.apache.jetspeed.security.SecurityException;
+import org.apache.jetspeed.security.om.InternalCredential;
+import
org.apache.jetspeed.security.spi.AlgorithmUpgradeCredentialPasswordEncoder;
+import org.apache.jetspeed.security.spi.CredentialPasswordEncoder;
+
+/**
+ * <p>
+ * MessageDigestToPBEPasswordUpgradeService allows for migrating from a
MessageDigestCredentialPasswordEncoder
+ * to the PBEPasswordService
+ * </p>
+ *
+ * @author <a href="mailto:[EMAIL PROTECTED]">Ate Douma</a>
+ * @version $Id:$
+ */
+public class AlgorithmUpgradePBEPasswordService extends PBEPasswordService
implements AlgorithmUpgradeCredentialPasswordEncoder,
AlgorithmUpgradePasswordEncodingService
+{
+ private CredentialPasswordEncoder oldEncoder;
+ private Timestamp startPBEPasswordEncoding;
+
+ public AlgorithmUpgradePBEPasswordService(String pbePassword,
CredentialPasswordEncoder oldEncoder, String startPBEPasswordEncoding) throws
InvalidKeySpecException,
+ NoSuchAlgorithmException, ParseException
+ {
+ super(pbePassword);
+ this.oldEncoder = oldEncoder;
+ SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ this.startPBEPasswordEncoding = new
Timestamp(df.parse(startPBEPasswordEncoding).getTime());
+ }
+
+ /* (non-Javadoc)
+ * @see
org.apache.jetspeed.security.AlgorithmUpgradePasswordEncodingService#usesOldEncodingAlgorithm(org.apache.jetspeed.security.PasswordCredential)
+ */
+ public boolean usesOldEncodingAlgorithm(PasswordCredential credential)
+ {
+ return usesOldEncodingAlgorithm(credential.isEnabled(),
credential.getLastAuthenticationDate(),
credential.getPreviousAuthenticationDate());
+ }
+
+ /* (non-Javadoc)
+ * @see
org.apache.jetspeed.security.spi.AlgorithmUpgradeCredentialPasswordEncoder#encode(java.lang.String,
java.lang.String, org.apache.jetspeed.security.om.InternalCredential)
+ */
+ public String encode(String userName, String clearTextPassword,
InternalCredential credential) throws SecurityException
+ {
+ if ( usesOldEncodingAlgorithm(credential.isEnabled(),
credential.getLastAuthenticationDate(),
credential.getPreviousAuthenticationDate()))
+ {
+ return oldEncoder.encode(userName, clearTextPassword);
+ }
+ else
+ {
+ return encode(userName, clearTextPassword);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see
org.apache.jetspeed.security.spi.AlgorithmUpgradeCredentialPasswordEncoder#recodeIfNeeded(java.lang.String,
java.lang.String, org.apache.jetspeed.security.om.InternalCredential)
+ */
+ public void recodeIfNeeded(String userName, String clearTextPassword,
InternalCredential credential) throws SecurityException
+ {
+ if ( usesOldEncodingAlgorithm(credential.isEnabled(),
credential.getLastAuthenticationDate(),
credential.getPreviousAuthenticationDate()))
+ {
+ credential.setValue(encode(userName, clearTextPassword));
+ }
+ }
+
+ private boolean usesOldEncodingAlgorithm(boolean encoded, Timestamp
lastAuthDate, Timestamp prevAuthDate )
+ {
+ if ( encoded )
+ {
+ if ( lastAuthDate != null )
+ {
+ return lastAuthDate.before(startPBEPasswordEncoding);
+ }
+ else if ( prevAuthDate != null )
+ {
+ // password was created, but the user is not authenticated yet
+ return prevAuthDate.before(startPBEPasswordEncoding);
+ }
+ else
+ {
+ // not yet upgraded encoded password
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+}
Modified:
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/DefaultCredentialHandler.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/DefaultCredentialHandler.java?rev=418604&r1=418603&r2=418604&view=diff
==============================================================================
---
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/DefaultCredentialHandler.java
(original)
+++
portals/jetspeed-2/trunk/components/security/src/java/org/apache/jetspeed/security/spi/impl/DefaultCredentialHandler.java
Sun Jul 2 08:10:18 2006
@@ -32,6 +32,7 @@
import org.apache.jetspeed.security.om.InternalUserPrincipal;
import org.apache.jetspeed.security.om.impl.InternalCredentialImpl;
import org.apache.jetspeed.security.spi.CredentialHandler;
+import
org.apache.jetspeed.security.spi.AlgorithmUpgradeCredentialPasswordEncoder;
import org.apache.jetspeed.security.spi.InternalPasswordCredentialInterceptor;
import org.apache.jetspeed.security.spi.PasswordCredentialProvider;
import org.apache.jetspeed.security.spi.SecurityAccess;
@@ -157,7 +158,14 @@
credential.isEncoded() &&
pcProvider.getEncoder() != null )
{
- oldPassword = pcProvider.getEncoder().encode(userName,
oldPassword);
+ if ( pcProvider.getEncoder() instanceof
AlgorithmUpgradeCredentialPasswordEncoder )
+ {
+ oldPassword =
((AlgorithmUpgradeCredentialPasswordEncoder)pcProvider.getEncoder()).encode(userName,oldPassword,
credential);
+ }
+ else
+ {
+ oldPassword =
pcProvider.getEncoder().encode(userName,oldPassword);
+ }
}
}
@@ -219,6 +227,7 @@
ipcInterceptor.beforeSetPassword(internalUser, credentials,
userName, credential, newPassword, oldPassword != null );
}
}
+
if (!create)
{
credential.setValue(newPassword);
@@ -226,7 +235,27 @@
credential.setUpdateRequired(false);
}
- internalUser.setModifiedDate(new Timestamp(new Date().getTime()));
+ long time = new Date().getTime();
+
+ if ( oldPassword == null )
+ {
+ // non-user (admin) modified the password
+
+ // set current time in previous auth date, and clear last
authentication date
+ // !!! While this might be a bit strange logic, it is *required*
for the AlgorithmUpgradePBEPasswordEncodingService
+ // to be able to distinguise password changes from other changes
+ credential.setPreviousAuthenticationDate(new Timestamp(new
Date().getTime()));
+ credential.setLastAuthenticationDate(null);
+ }
+ else
+ {
+ // authenticated password change (by user itself)
+
credential.setPreviousAuthenticationDate(credential.getLastAuthenticationDate());
+ credential.setLastAuthenticationDate(new Timestamp(time));
+ }
+
+ credential.setModifiedDate(new Timestamp(time));
+ internalUser.setModifiedDate(new Timestamp(time));
internalUser.setCredentials(credentials);
// Set the user with the new credentials.
securityAccess.setInternalUserPrincipal(internalUser, false);
@@ -244,9 +273,11 @@
InternalCredential credential =
getPasswordCredential(internalUser, userName );
if ( credential != null && !credential.isExpired() &&
credential.isEnabled() != enabled )
{
+ long time = new Date().getTime();
credential.setEnabled(enabled);
credential.setAuthenticationFailures(0);
- internalUser.setModifiedDate(new Timestamp(new
Date().getTime()));
+ credential.setModifiedDate(new Timestamp(time));
+ internalUser.setModifiedDate(new Timestamp(time));
securityAccess.setInternalUserPrincipal(internalUser, false);
}
}
@@ -280,6 +311,7 @@
// The current
InternalPasswordCredentialStateHandlingInterceptor.afterLoad()
// logic will only set it (back) to true if both prev and last
auth. date is null
credential.setPreviousAuthenticationDate(new Timestamp(time));
+ credential.setModifiedDate(new Timestamp(time));
internalUser.setModifiedDate(new Timestamp(time));
securityAccess.setInternalUserPrincipal(internalUser, false);
}
@@ -335,12 +367,20 @@
InternalCredential credential =
getPasswordCredential(internalUser, userName );
if ( credential != null && credential.isEnabled() &&
!credential.isExpired())
{
+ String encodedPassword = password;
if ( pcProvider.getEncoder() != null && credential.isEncoded())
{
- password =
pcProvider.getEncoder().encode(userName,password);
+ if ( pcProvider.getEncoder() instanceof
AlgorithmUpgradeCredentialPasswordEncoder )
+ {
+ encodedPassword =
((AlgorithmUpgradeCredentialPasswordEncoder)pcProvider.getEncoder()).encode(userName,password,
credential);
+ }
+ else
+ {
+ encodedPassword =
pcProvider.getEncoder().encode(userName,password);
+ }
}
- authenticated = credential.getValue().equals(password);
+ authenticated = credential.getValue().equals(encodedPassword);
boolean update = false;
if ( ipcInterceptor != null )
@@ -351,17 +391,26 @@
authenticated = false;
}
}
+ long time = new Date().getTime();
+
if ( authenticated )
{
credential.setAuthenticationFailures(0);
+
+ if ( pcProvider.getEncoder() != null &&
pcProvider.getEncoder() instanceof AlgorithmUpgradeCredentialPasswordEncoder)
+ {
+
((AlgorithmUpgradeCredentialPasswordEncoder)pcProvider.getEncoder()).recodeIfNeeded(userName,password,credential);
+ }
+
credential.setPreviousAuthenticationDate(credential.getLastAuthenticationDate());
- credential.setLastAuthenticationDate(new
Timestamp(System.currentTimeMillis()));
+ credential.setLastAuthenticationDate(new Timestamp(time));
update = true;
}
if ( update )
{
- internalUser.setModifiedDate(new
Timestamp(System.currentTimeMillis()));
+ credential.setModifiedDate(new Timestamp(time));
+ internalUser.setModifiedDate(new Timestamp(time));
securityAccess.setInternalUserPrincipal(internalUser,
false);
}
}
Added:
portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/security/AlgorithmUpgradePasswordEncodingService.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/security/AlgorithmUpgradePasswordEncodingService.java?rev=418604&view=auto
==============================================================================
---
portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/security/AlgorithmUpgradePasswordEncodingService.java
(added)
+++
portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/security/AlgorithmUpgradePasswordEncodingService.java
Sun Jul 2 08:10:18 2006
@@ -0,0 +1,30 @@
+/* Copyright 2004 Apache Software Foundation
+*
+* Licensed 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.jetspeed.security;
+
+/**
+ * <p>
+ * AlgorithmUpgradePasswordEncodingService allows checking a specific
PasswordCredential if it uses the provided Encoding Algorithm.
+ * </p>
+ * <p>
+ * This service can be used for gradually migrating from a one-way encoding to
a two-way encoding algoritmn.
+ * </p>
+ * @author <a href="mailto:[EMAIL PROTECTED]">Ate Douma</a>
+ * @version $Id$
+ */
+public interface AlgorithmUpgradePasswordEncodingService extends
PasswordEncodingService
+{
+ boolean usesOldEncodingAlgorithm(PasswordCredential passwordCredential);
+}
Modified:
portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/security-spi-atn.xml
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/security-spi-atn.xml?rev=418604&r1=418603&r2=418604&view=diff
==============================================================================
--- portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/security-spi-atn.xml
(original)
+++ portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/security-spi-atn.xml
Sun Jul 2 08:10:18 2006
@@ -47,6 +47,32 @@
</bean>
-->
+ <!-- A Two-way encoding password service which also implements
CredentialPasswordEncoder
+ Furthermore, this extension of the PBEPasswordService supports lazy
upgrading from an old CredentialPasswordEncoder
+ like the default provided MessageDigestCredentialPasswordEncoder
+ ->
+ <bean id="org.apache.jetspeed.security.PasswordEncodingService"
+ name="org.apache.jetspeed.security.spi.CredentialPasswordEncoder"
+
class="org.apache.jetspeed.security.spi.impl.AlgorithmUpgradePBEPasswordService">
+ <constructor-arg index="0">
+ <!- secret PBE key password ->
+ <value>********</value>
+ </constructor-arg>
+ <constructor-arg index="1">
+ <!- old MessageDigestCredentialPasswordEncoder to be upgrading from,
using SHA-1 ->
+ <bean
class="org.apache.jetspeed.security.spi.impl.MessageDigestCredentialPasswordEncoder">
+ <constructor-arg index="0"><value>SHA-1</value></constructor-arg>
+ </bean>
+ </constructor-arg>
+ <constructor-arg index="2">
+ <!- startPBEPasswordEncodingService: date before which old encoded
passwords need to be recoded (on authentication)
+ (SimpleDateFormat) format: yyyy-MM-dd HH:mm:ss
+ ->
+ <value>2006-07-02 15:00:00</value>
+ </constructor-arg>
+ </bean>
+-->
+
<!-- allow multiple InternalPasswordCredentialInterceptors to be used for
DefaultCredentialHandler -->
<bean
id="org.apache.jetspeed.security.spi.InternalPasswordCredentialInterceptor"
class="org.apache.jetspeed.security.spi.impl.InternalPasswordCredentialInterceptorsProxy">
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]