1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.providers.cas;
17
18 import org.acegisecurity.AcegiMessageSource;
19 import org.acegisecurity.Authentication;
20 import org.acegisecurity.AuthenticationException;
21 import org.acegisecurity.BadCredentialsException;
22 import org.acegisecurity.providers.AuthenticationProvider;
23 import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
24 import org.acegisecurity.ui.cas.CasProcessingFilter;
25 import org.acegisecurity.userdetails.UserDetails;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.springframework.beans.factory.InitializingBean;
29 import org.springframework.context.MessageSource;
30 import org.springframework.context.MessageSourceAware;
31 import org.springframework.context.support.MessageSourceAccessor;
32 import org.springframework.util.Assert;
33
34
35 /***
36 * An {@link AuthenticationProvider} implementation that integrates with Yale
37 * Central Authentication Service (CAS).
38 *
39 * <p>
40 * This <code>AuthenticationProvider</code> is capable of validating {@link
41 * UsernamePasswordAuthenticationToken} requests which contain a
42 * <code>principal</code> name equal to either {@link
43 * CasProcessingFilter#CAS_STATEFUL_IDENTIFIER} or {@link
44 * CasProcessingFilter#CAS_STATELESS_IDENTIFIER}. It can also validate a
45 * previously created {@link CasAuthenticationToken}.
46 * </p>
47 */
48 public class CasAuthenticationProvider implements AuthenticationProvider,
49 InitializingBean, MessageSourceAware {
50
51
52 private static final Log logger = LogFactory.getLog(CasAuthenticationProvider.class);
53
54
55
56 private CasAuthoritiesPopulator casAuthoritiesPopulator;
57 private CasProxyDecider casProxyDecider;
58 protected MessageSourceAccessor messages = AcegiMessageSource.getAccessor();
59 private StatelessTicketCache statelessTicketCache;
60 private String key;
61 private TicketValidator ticketValidator;
62
63
64
65 public void afterPropertiesSet() throws Exception {
66 Assert.notNull(this.casAuthoritiesPopulator,
67 "A casAuthoritiesPopulator must be set");
68 Assert.notNull(this.ticketValidator, "A ticketValidator must be set");
69 Assert.notNull(this.casProxyDecider, "A casProxyDecider must be set");
70 Assert.notNull(this.statelessTicketCache,
71 "A statelessTicketCache must be set");
72 Assert.notNull(key,
73 "A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated");
74 Assert.notNull(this.messages, "A message source must be set");
75 }
76
77 public Authentication authenticate(Authentication authentication)
78 throws AuthenticationException {
79 if (!supports(authentication.getClass())) {
80 return null;
81 }
82
83 if (authentication instanceof UsernamePasswordAuthenticationToken
84 && (!CasProcessingFilter.CAS_STATEFUL_IDENTIFIER.equals(
85 authentication.getPrincipal().toString())
86 && !CasProcessingFilter.CAS_STATELESS_IDENTIFIER.equals(
87 authentication.getPrincipal().toString()))) {
88
89 return null;
90 }
91
92
93 if (authentication instanceof CasAuthenticationToken) {
94 if (this.key.hashCode() == ((CasAuthenticationToken) authentication)
95 .getKeyHash()) {
96 return authentication;
97 } else {
98 throw new BadCredentialsException(messages.getMessage(
99 "CasAuthenticationProvider.incorrectKey",
100 "The presented CasAuthenticationToken does not contain the expected key"));
101 }
102 }
103
104
105 if ((authentication.getCredentials() == null)
106 || "".equals(authentication.getCredentials())) {
107 throw new BadCredentialsException(messages.getMessage(
108 "CasAuthenticationProvider.noServiceTicket",
109 "Failed to provide a CAS service ticket to validate"));
110 }
111
112 boolean stateless = false;
113
114 if (authentication instanceof UsernamePasswordAuthenticationToken
115 && CasProcessingFilter.CAS_STATELESS_IDENTIFIER.equals(
116 authentication.getPrincipal())) {
117 stateless = true;
118 }
119
120 CasAuthenticationToken result = null;
121
122 if (stateless) {
123
124 result = statelessTicketCache.getByTicketId(authentication.getCredentials()
125 .toString());
126 }
127
128 if (result == null) {
129 result = this.authenticateNow(authentication);
130 }
131
132 if (stateless) {
133
134 statelessTicketCache.putTicketInCache(result);
135 }
136
137 return result;
138 }
139
140 private CasAuthenticationToken authenticateNow(
141 Authentication authentication) throws AuthenticationException {
142
143 TicketResponse response = ticketValidator.confirmTicketValid(authentication.getCredentials()
144 .toString());
145
146
147 this.casProxyDecider.confirmProxyListTrusted(response.getProxyList());
148
149
150 UserDetails userDetails = this.casAuthoritiesPopulator.getUserDetails(response
151 .getUser());
152
153
154 return new CasAuthenticationToken(this.key, response.getUser(),
155 authentication.getCredentials(), userDetails.getAuthorities(),
156 userDetails, response.getProxyList(),
157 response.getProxyGrantingTicketIou());
158 }
159
160 public CasAuthoritiesPopulator getCasAuthoritiesPopulator() {
161 return casAuthoritiesPopulator;
162 }
163
164 public CasProxyDecider getCasProxyDecider() {
165 return casProxyDecider;
166 }
167
168 public String getKey() {
169 return key;
170 }
171
172 public StatelessTicketCache getStatelessTicketCache() {
173 return statelessTicketCache;
174 }
175
176 public TicketValidator getTicketValidator() {
177 return ticketValidator;
178 }
179
180 public void setCasAuthoritiesPopulator(
181 CasAuthoritiesPopulator casAuthoritiesPopulator) {
182 this.casAuthoritiesPopulator = casAuthoritiesPopulator;
183 }
184
185 public void setCasProxyDecider(CasProxyDecider casProxyDecider) {
186 this.casProxyDecider = casProxyDecider;
187 }
188
189 public void setKey(String key) {
190 this.key = key;
191 }
192
193 public void setMessageSource(MessageSource messageSource) {
194 this.messages = new MessageSourceAccessor(messageSource);
195 }
196
197 public void setStatelessTicketCache(
198 StatelessTicketCache statelessTicketCache) {
199 this.statelessTicketCache = statelessTicketCache;
200 }
201
202 public void setTicketValidator(TicketValidator ticketValidator) {
203 this.ticketValidator = ticketValidator;
204 }
205
206 public boolean supports(Class authentication) {
207 if (UsernamePasswordAuthenticationToken.class.isAssignableFrom(
208 authentication)) {
209 return true;
210 } else if (CasAuthenticationToken.class.isAssignableFrom(authentication)) {
211 return true;
212 } else {
213 return false;
214 }
215 }
216 }