1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.jetspeed.security.spi.impl;
18
19 import java.sql.Timestamp;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.Comparator;
24 import java.util.Date;
25 import java.util.Iterator;
26
27 import org.apache.jetspeed.security.PasswordAlreadyUsedException;
28 import org.apache.jetspeed.security.SecurityException;
29 import org.apache.jetspeed.security.om.InternalCredential;
30 import org.apache.jetspeed.security.om.InternalUserPrincipal;
31 import org.apache.jetspeed.security.om.impl.InternalCredentialImpl;
32
33 /***
34 * <p>
35 * Maintains a configurable FIFO stack of used password credentials for a principal.
36 * It also requires a unique password (with regards to the values currently in the stack) when
37 * a password is changed directly by the user itself.</p>
38 * <p>
39 * The historical passwords are maintained as {@link InternalCredential} instances with as {@link InternalCredential#getClassname() classname}
40 * value {@link #HISTORICAL_PASSWORD_CREDENTIAL} to distinguish them from the current password credential.</p>
41 * <p>
42 * <em>Implementation Note:</em><br>
43 * When a new password is about to be saved, a new <em>copy</em> of the current credential is saved as
44 * a historic password credential. This means that the current password credential <em>instance</em>,
45 * and thus also its {@link InternalCredential#getCredentialId() key}, remains the same.</p>
46 * <p>
47 *
48 * @author <a href="mailto:ate@douma.nu">Ate Douma</a>
49 * @version $Id$
50 */
51 public class PasswordHistoryInterceptor extends AbstractInternalPasswordCredentialInterceptorImpl
52 {
53 private int historySize;
54
55 /***
56 * Value used for {@link InternalCredential#getClassname()} to distinguish from current password credentials
57 */
58 public static final String HISTORICAL_PASSWORD_CREDENTIAL = "org.apache.jetspeed.security.spi.impl.HistoricalPasswordCredentialImpl";
59
60 private static final Comparator internalCredentialCreationDateComparator =
61 new Comparator()
62 {
63 public int compare(Object obj1, Object obj2)
64 {
65 return ((InternalCredential)obj2).getCreationDate().compareTo(((InternalCredential)obj1).getCreationDate());
66 }
67 };
68
69 /***
70 * @param historySize stack size maintained for historical passwords
71 */
72 public PasswordHistoryInterceptor(int historySize)
73 {
74 this.historySize = historySize;
75 }
76
77 /***
78 * @see org.apache.jetspeed.security.spi.InternalPasswordCredentialInterceptor#beforeSetPassword(org.apache.jetspeed.security.om.InternalUserPrincipal, java.util.Collection, java.lang.String, org.apache.jetspeed.security.om.InternalCredential, java.lang.String, boolean)
79 */
80 public void beforeSetPassword(InternalUserPrincipal internalUser, Collection credentials, String userName,
81 InternalCredential credential, String password, boolean authenticated) throws SecurityException
82 {
83 Collection internalCredentials = internalUser.getCredentials();
84 ArrayList historicalPasswordCredentials = new ArrayList();
85 if ( internalCredentials != null )
86 {
87 InternalCredential currCredential;
88 Iterator iter = internalCredentials.iterator();
89
90 while (iter.hasNext())
91 {
92 currCredential = (InternalCredential) iter.next();
93 if (currCredential.getType() == InternalCredential.PRIVATE )
94 {
95 if ((null != currCredential.getClassname())
96 && (currCredential.getClassname().equals(HISTORICAL_PASSWORD_CREDENTIAL)))
97 {
98 historicalPasswordCredentials.add(currCredential);
99 }
100 }
101 }
102 }
103 if (historicalPasswordCredentials.size() > 1)
104 {
105 Collections.sort(historicalPasswordCredentials,internalCredentialCreationDateComparator);
106 }
107
108 int historyCount = historicalPasswordCredentials.size();
109 InternalCredential historicalPasswordCredential;
110 if ( authenticated )
111 {
112
113 for ( int i = 0; i < historyCount && i < historySize; i++ )
114 {
115 historicalPasswordCredential = (InternalCredential)historicalPasswordCredentials.get(i);
116 if ( historicalPasswordCredential.getValue() != null &&
117 historicalPasswordCredential.getValue().equals(password) )
118 {
119 throw new PasswordAlreadyUsedException();
120 }
121 }
122 }
123
124 for ( int i = historySize-1; i < historyCount; i++ )
125 {
126 credentials.remove(historicalPasswordCredentials.get(i));
127 }
128 historicalPasswordCredential = new InternalCredentialImpl(credential,HISTORICAL_PASSWORD_CREDENTIAL);
129 credentials.add(historicalPasswordCredential);
130
131
132 credential.setCreationDate(new Timestamp(new Date().getTime()));
133 }
134 }