1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.acegisecurity.providers.cas;
17
18 import junit.framework.TestCase;
19
20 import org.acegisecurity.Authentication;
21 import org.acegisecurity.AuthenticationException;
22 import org.acegisecurity.BadCredentialsException;
23 import org.acegisecurity.GrantedAuthority;
24 import org.acegisecurity.GrantedAuthorityImpl;
25
26 import org.acegisecurity.providers.TestingAuthenticationToken;
27 import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
28 import org.acegisecurity.providers.cas.ticketvalidator.AbstractTicketValidator;
29
30 import org.acegisecurity.ui.cas.CasProcessingFilter;
31
32 import org.acegisecurity.userdetails.User;
33 import org.acegisecurity.userdetails.UserDetails;
34
35 import java.util.HashMap;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Vector;
39
40
41
42
43
44
45
46
47 public class CasAuthenticationProviderTests extends TestCase {
48
49
50 public CasAuthenticationProviderTests() {
51 super();
52 }
53
54 public CasAuthenticationProviderTests(String arg0) {
55 super(arg0);
56 }
57
58
59
60 public static void main(String[] args) {
61 junit.textui.TestRunner.run(CasAuthenticationProviderTests.class);
62 }
63
64 private UserDetails makeUserDetails() {
65 return new User("user", "password", true, true, true, true,
66 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_ONE"), new GrantedAuthorityImpl("ROLE_TWO")});
67 }
68
69 private UserDetails makeUserDetailsFromAuthoritiesPopulator() {
70 return new User("user", "password", true, true, true, true,
71 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A"), new GrantedAuthorityImpl("ROLE_B")});
72 }
73
74 public final void setUp() throws Exception {
75 super.setUp();
76 }
77
78 public void testAuthenticateStateful() throws Exception {
79 CasAuthenticationProvider cap = new CasAuthenticationProvider();
80 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
81 cap.setCasProxyDecider(new MockProxyDecider(true));
82 cap.setKey("qwerty");
83
84 StatelessTicketCache cache = new MockStatelessTicketCache();
85 cap.setStatelessTicketCache(cache);
86 cap.setTicketValidator(new MockTicketValidator(true));
87 cap.afterPropertiesSet();
88
89 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(CasProcessingFilter.CAS_STATEFUL_IDENTIFIER,
90 "ST-123");
91
92 Authentication result = cap.authenticate(token);
93
94
95 assertTrue(cache.getByTicketId("ST-456") == null);
96
97 if (!(result instanceof CasAuthenticationToken)) {
98 fail("Should have returned a CasAuthenticationToken");
99 }
100
101 CasAuthenticationToken casResult = (CasAuthenticationToken) result;
102 assertEquals(makeUserDetailsFromAuthoritiesPopulator(), casResult.getPrincipal());
103 assertEquals("PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt",
104 casResult.getProxyGrantingTicketIou());
105 assertEquals("https://localhost/portal/j_acegi_cas_security_check", casResult.getProxyList().get(0));
106 assertEquals("ST-123", casResult.getCredentials());
107 assertEquals(new GrantedAuthorityImpl("ROLE_A"), casResult.getAuthorities()[0]);
108 assertEquals(new GrantedAuthorityImpl("ROLE_B"), casResult.getAuthorities()[1]);
109 assertEquals(cap.getKey().hashCode(), casResult.getKeyHash());
110
111
112
113 cap.setTicketValidator(new MockTicketValidator(false));
114
115 Authentication laterResult = cap.authenticate(result);
116 assertEquals(result, laterResult);
117 }
118
119 public void testAuthenticateStateless() throws Exception {
120 CasAuthenticationProvider cap = new CasAuthenticationProvider();
121 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
122 cap.setCasProxyDecider(new MockProxyDecider(true));
123 cap.setKey("qwerty");
124
125 StatelessTicketCache cache = new MockStatelessTicketCache();
126 cap.setStatelessTicketCache(cache);
127 cap.setTicketValidator(new MockTicketValidator(true));
128 cap.afterPropertiesSet();
129
130 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(CasProcessingFilter.CAS_STATELESS_IDENTIFIER,
131 "ST-456");
132
133 Authentication result = cap.authenticate(token);
134
135
136 assertTrue(cache.getByTicketId("ST-456") != null);
137
138 if (!(result instanceof CasAuthenticationToken)) {
139 fail("Should have returned a CasAuthenticationToken");
140 }
141
142 assertEquals(makeUserDetailsFromAuthoritiesPopulator(), result.getPrincipal());
143 assertEquals("ST-456", result.getCredentials());
144
145
146
147 cap.setTicketValidator(new MockTicketValidator(false));
148
149
150 Authentication newResult = cap.authenticate(token);
151 assertEquals(makeUserDetailsFromAuthoritiesPopulator(), newResult.getPrincipal());
152 assertEquals("ST-456", newResult.getCredentials());
153 }
154
155 public void testDetectsAMissingTicketId() throws Exception {
156 CasAuthenticationProvider cap = new CasAuthenticationProvider();
157 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
158 cap.setCasProxyDecider(new MockProxyDecider(true));
159 cap.setKey("qwerty");
160
161 StatelessTicketCache cache = new MockStatelessTicketCache();
162 cap.setStatelessTicketCache(cache);
163 cap.setTicketValidator(new MockTicketValidator(true));
164 cap.afterPropertiesSet();
165
166 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(CasProcessingFilter.CAS_STATEFUL_IDENTIFIER,
167 "");
168
169 try {
170 Authentication result = cap.authenticate(token);
171 fail("Should have thrown BadCredentialsException");
172 } catch (BadCredentialsException expected) {
173 assertEquals("Failed to provide a CAS service ticket to validate", expected.getMessage());
174 }
175 }
176
177 public void testDetectsAnInvalidKey() throws Exception {
178 CasAuthenticationProvider cap = new CasAuthenticationProvider();
179 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
180 cap.setCasProxyDecider(new MockProxyDecider(true));
181 cap.setKey("qwerty");
182
183 StatelessTicketCache cache = new MockStatelessTicketCache();
184 cap.setStatelessTicketCache(cache);
185 cap.setTicketValidator(new MockTicketValidator(true));
186 cap.afterPropertiesSet();
187
188 CasAuthenticationToken token = new CasAuthenticationToken("WRONG_KEY", makeUserDetails(), "credentials",
189 new GrantedAuthority[] {new GrantedAuthorityImpl("XX")}, makeUserDetails(), new Vector(), "IOU-xxx");
190
191 try {
192 Authentication result = cap.authenticate(token);
193 fail("Should have thrown BadCredentialsException");
194 } catch (BadCredentialsException expected) {
195 assertEquals("The presented CasAuthenticationToken does not contain the expected key", expected.getMessage());
196 }
197 }
198
199 public void testDetectsMissingAuthoritiesPopulator()
200 throws Exception {
201 CasAuthenticationProvider cap = new CasAuthenticationProvider();
202 cap.setCasProxyDecider(new MockProxyDecider());
203 cap.setKey("qwerty");
204 cap.setStatelessTicketCache(new MockStatelessTicketCache());
205 cap.setTicketValidator(new MockTicketValidator(true));
206
207 try {
208 cap.afterPropertiesSet();
209 fail("Should have thrown IllegalArgumentException");
210 } catch (IllegalArgumentException expected) {
211 assertEquals("A casAuthoritiesPopulator must be set", expected.getMessage());
212 }
213 }
214
215 public void testDetectsMissingKey() throws Exception {
216 CasAuthenticationProvider cap = new CasAuthenticationProvider();
217 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
218 cap.setCasProxyDecider(new MockProxyDecider());
219 cap.setStatelessTicketCache(new MockStatelessTicketCache());
220 cap.setTicketValidator(new MockTicketValidator(true));
221
222 try {
223 cap.afterPropertiesSet();
224 fail("Should have thrown IllegalArgumentException");
225 } catch (IllegalArgumentException expected) {
226 assertEquals("A Key is required so CasAuthenticationProvider can identify tokens it previously authenticated",
227 expected.getMessage());
228 }
229 }
230
231 public void testDetectsMissingProxyDecider() throws Exception {
232 CasAuthenticationProvider cap = new CasAuthenticationProvider();
233 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
234 cap.setKey("qwerty");
235 cap.setStatelessTicketCache(new MockStatelessTicketCache());
236 cap.setTicketValidator(new MockTicketValidator(true));
237
238 try {
239 cap.afterPropertiesSet();
240 fail("Should have thrown IllegalArgumentException");
241 } catch (IllegalArgumentException expected) {
242 assertEquals("A casProxyDecider must be set", expected.getMessage());
243 }
244 }
245
246 public void testDetectsMissingStatelessTicketCache()
247 throws Exception {
248 CasAuthenticationProvider cap = new CasAuthenticationProvider();
249
250 cap.setStatelessTicketCache(null);
251 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
252 cap.setCasProxyDecider(new MockProxyDecider());
253 cap.setKey("qwerty");
254 cap.setTicketValidator(new MockTicketValidator(true));
255
256 try {
257 cap.afterPropertiesSet();
258 fail("Should have thrown IllegalArgumentException");
259 } catch (IllegalArgumentException expected) {
260 assertEquals("A statelessTicketCache must be set", expected.getMessage());
261 }
262 }
263
264 public void testDetectsMissingTicketValidator() throws Exception {
265 CasAuthenticationProvider cap = new CasAuthenticationProvider();
266 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
267 cap.setCasProxyDecider(new MockProxyDecider(true));
268 cap.setKey("qwerty");
269 cap.setStatelessTicketCache(new MockStatelessTicketCache());
270
271 try {
272 cap.afterPropertiesSet();
273 fail("Should have thrown IllegalArgumentException");
274 } catch (IllegalArgumentException expected) {
275 assertEquals("A ticketValidator must be set", expected.getMessage());
276 }
277 }
278
279 public void testGettersSetters() throws Exception {
280 CasAuthenticationProvider cap = new CasAuthenticationProvider();
281 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
282 cap.setCasProxyDecider(new MockProxyDecider());
283 cap.setKey("qwerty");
284 cap.setStatelessTicketCache(new MockStatelessTicketCache());
285 cap.setTicketValidator(new MockTicketValidator(true));
286 cap.afterPropertiesSet();
287
288 assertTrue(cap.getCasAuthoritiesPopulator() != null);
289 assertTrue(cap.getCasProxyDecider() != null);
290 assertEquals("qwerty", cap.getKey());
291 assertTrue(cap.getStatelessTicketCache() != null);
292 assertTrue(cap.getTicketValidator() != null);
293 }
294
295 public void testIgnoresClassesItDoesNotSupport() throws Exception {
296 CasAuthenticationProvider cap = new CasAuthenticationProvider();
297 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
298 cap.setCasProxyDecider(new MockProxyDecider());
299 cap.setKey("qwerty");
300 cap.setStatelessTicketCache(new MockStatelessTicketCache());
301 cap.setTicketValidator(new MockTicketValidator(true));
302 cap.afterPropertiesSet();
303
304 TestingAuthenticationToken token = new TestingAuthenticationToken("user", "password",
305 new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
306 assertFalse(cap.supports(TestingAuthenticationToken.class));
307
308
309 assertEquals(null, cap.authenticate(token));
310 }
311
312 public void testIgnoresUsernamePasswordAuthenticationTokensWithoutCasIdentifiersAsPrincipal()
313 throws Exception {
314 CasAuthenticationProvider cap = new CasAuthenticationProvider();
315 cap.setCasAuthoritiesPopulator(new MockAuthoritiesPopulator());
316 cap.setCasProxyDecider(new MockProxyDecider());
317 cap.setKey("qwerty");
318 cap.setStatelessTicketCache(new MockStatelessTicketCache());
319 cap.setTicketValidator(new MockTicketValidator(true));
320 cap.afterPropertiesSet();
321
322 UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("some_normal_user",
323 "password", new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_A")});
324 assertEquals(null, cap.authenticate(token));
325 }
326
327 public void testSupports() {
328 CasAuthenticationProvider cap = new CasAuthenticationProvider();
329 assertTrue(cap.supports(UsernamePasswordAuthenticationToken.class));
330 assertTrue(cap.supports(CasAuthenticationToken.class));
331 }
332
333
334
335 private class MockAuthoritiesPopulator implements CasAuthoritiesPopulator {
336 public UserDetails getUserDetails(String casUserId)
337 throws AuthenticationException {
338 return makeUserDetailsFromAuthoritiesPopulator();
339 }
340 }
341
342 private class MockProxyDecider implements CasProxyDecider {
343 private boolean acceptProxy;
344
345 public MockProxyDecider(boolean acceptProxy) {
346 this.acceptProxy = acceptProxy;
347 }
348
349 private MockProxyDecider() {
350 super();
351 }
352
353 public void confirmProxyListTrusted(List proxyList)
354 throws ProxyUntrustedException {
355 if (acceptProxy) {
356 return;
357 } else {
358 throw new ProxyUntrustedException("As requested from mock");
359 }
360 }
361 }
362
363 private class MockStatelessTicketCache implements StatelessTicketCache {
364 private Map cache = new HashMap();
365
366 public CasAuthenticationToken getByTicketId(String serviceTicket) {
367 return (CasAuthenticationToken) cache.get(serviceTicket);
368 }
369
370 public void putTicketInCache(CasAuthenticationToken token) {
371 cache.put(token.getCredentials().toString(), token);
372 }
373
374 public void removeTicketFromCache(CasAuthenticationToken token) {
375 throw new UnsupportedOperationException("mock method not implemented");
376 }
377
378 public void removeTicketFromCache(String serviceTicket) {
379 throw new UnsupportedOperationException("mock method not implemented");
380 }
381 }
382
383 private class MockTicketValidator extends AbstractTicketValidator {
384 private boolean returnTicket;
385
386 public MockTicketValidator(boolean returnTicket) {
387 this.returnTicket = returnTicket;
388 }
389
390 private MockTicketValidator() {
391 super();
392 }
393
394 public TicketResponse confirmTicketValid(String serviceTicket)
395 throws AuthenticationException {
396 if (returnTicket) {
397 List list = new Vector();
398 list.add("https://localhost/portal/j_acegi_cas_security_check");
399
400 return new TicketResponse("marissa", list, "PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt");
401 }
402
403 throw new BadCredentialsException("As requested from mock");
404 }
405 }
406 }