1 package org.springframework.security.ui.rememberme;
2
3 import org.springframework.security.Authentication;
4 import org.springframework.security.userdetails.UserDetails;
5 import org.springframework.dao.DataAccessException;
6
7 import org.apache.commons.codec.binary.Base64;
8
9 import javax.servlet.http.HttpServletRequest;
10 import javax.servlet.http.HttpServletResponse;
11 import java.security.SecureRandom;
12 import java.util.Arrays;
13 import java.util.Date;
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 public class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices {
40
41 private PersistentTokenRepository tokenRepository = new InMemoryTokenRepositoryImpl();
42 private SecureRandom random;
43
44 public static final int DEFAULT_SERIES_LENGTH = 16;
45 public static final int DEFAULT_TOKEN_LENGTH = 16;
46
47 private int seriesLength = DEFAULT_SERIES_LENGTH;
48 private int tokenLength = DEFAULT_TOKEN_LENGTH;
49
50 public PersistentTokenBasedRememberMeServices() throws Exception {
51 random = SecureRandom.getInstance("SHA1PRNG");
52 }
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67 protected UserDetails processAutoLoginCookie(String[] cookieTokens, HttpServletRequest request, HttpServletResponse response) {
68
69 if (cookieTokens.length != 2) {
70 throw new InvalidCookieException("Cookie token did not contain " + 2 +
71 " tokens, but contained '" + Arrays.asList(cookieTokens) + "'");
72 }
73
74 final String presentedSeries = cookieTokens[0];
75 final String presentedToken = cookieTokens[1];
76
77 PersistentRememberMeToken token = tokenRepository.getTokenForSeries(presentedSeries);
78
79 if (token == null) {
80
81 throw new RememberMeAuthenticationException("No persistent token found for series id: " + presentedSeries);
82 }
83
84
85 if (!presentedToken.equals(token.getTokenValue())) {
86
87 tokenRepository.removeUserTokens(token.getUsername());
88
89 throw new CookieTheftException(messages.getMessage("PersistentTokenBasedRememberMeServices.cookieStolen",
90 "Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack."));
91 }
92
93 if (token.getDate().getTime() + getTokenValiditySeconds()*1000 < System.currentTimeMillis()) {
94 throw new RememberMeAuthenticationException("Remember-me login has expired");
95 }
96
97
98 if (logger.isDebugEnabled()) {
99 logger.debug("Refreshing persistent login token for user '" + token.getUsername() + "', series '" +
100 token.getSeries() + "'");
101 }
102
103 PersistentRememberMeToken newToken = new PersistentRememberMeToken(token.getUsername(),
104 token.getSeries(), generateTokenData(), new Date());
105
106 try {
107 tokenRepository.updateToken(newToken.getSeries(), newToken.getTokenValue(), newToken.getDate());
108 addCookie(newToken, request, response);
109 } catch (DataAccessException e) {
110 logger.error("Failed to update token: ", e);
111 throw new RememberMeAuthenticationException("Autologin failed due to data access problem");
112 }
113
114 UserDetails user = getUserDetailsService().loadUserByUsername(token.getUsername());
115
116 return user;
117 }
118
119
120
121
122
123
124 protected void onLoginSuccess(HttpServletRequest request, HttpServletResponse response, Authentication successfulAuthentication) {
125 String username = successfulAuthentication.getName();
126
127 logger.debug("Creating new persistent login for user " + username);
128
129 PersistentRememberMeToken persistentToken = new PersistentRememberMeToken(username, generateSeriesData(),
130 generateTokenData(), new Date());
131 try {
132 tokenRepository.createNewToken(persistentToken);
133 addCookie(persistentToken, request, response);
134 } catch (DataAccessException e) {
135 logger.error("Failed to save persistent token ", e);
136
137 }
138 }
139
140 protected String generateSeriesData() {
141 byte[] newSeries = new byte[seriesLength];
142 random.nextBytes(newSeries);
143 return new String(Base64.encodeBase64(newSeries));
144 }
145
146 protected String generateTokenData() {
147 byte[] newToken = new byte[tokenLength];
148 random.nextBytes(newToken);
149 return new String(Base64.encodeBase64(newToken));
150 }
151
152 private void addCookie(PersistentRememberMeToken token, HttpServletRequest request, HttpServletResponse response) {
153 setCookie(new String[] {token.getSeries(), token.getTokenValue()},getTokenValiditySeconds(), request, response);
154 }
155
156 public void setTokenRepository(PersistentTokenRepository tokenRepository) {
157 this.tokenRepository = tokenRepository;
158 }
159
160 public void setSeriesLength(int seriesLength) {
161 this.seriesLength = seriesLength;
162 }
163
164 public void setTokenLength(int tokenLength) {
165 this.tokenLength = tokenLength;
166 }
167 }