0
# Authentication Handlers
1
2
Authentication handlers are core components responsible for validating credentials against various authentication sources such as LDAP directories, databases, web services, and local user stores. The CAS authentication API provides a comprehensive framework for implementing and configuring authentication handlers.
3
4
## Core Handler Interface
5
6
```java { .api }
7
package org.apereo.cas.authentication;
8
9
import java.security.GeneralSecurityException;
10
11
public interface AuthenticationHandler {
12
String getName();
13
boolean supports(Credential credential);
14
AuthenticationHandlerExecutionResult authenticate(Credential credential)
15
throws GeneralSecurityException, PreventedException;
16
Integer getOrder();
17
AuthenticationHandlerStates getState();
18
void setState(AuthenticationHandlerStates state);
19
Predicate<Credential> getCredentialSelectionPredicate();
20
}
21
```
22
23
## Base Handler Implementation
24
25
```java { .api }
26
package org.apereo.cas.authentication;
27
28
import org.apereo.cas.authentication.principal.PrincipalFactory;
29
import org.apereo.cas.services.ServicesManager;
30
31
public abstract class AbstractAuthenticationHandler implements AuthenticationHandler {
32
protected final PrincipalFactory principalFactory;
33
private final ServicesManager servicesManager;
34
private final String name;
35
private final Integer order;
36
private AuthenticationHandlerStates state;
37
38
protected AbstractAuthenticationHandler(String name,
39
ServicesManager servicesManager,
40
PrincipalFactory principalFactory,
41
Integer order) {
42
this.name = name;
43
this.servicesManager = servicesManager;
44
this.principalFactory = principalFactory;
45
this.order = order;
46
this.state = AuthenticationHandlerStates.ACTIVE;
47
}
48
49
public String getName() { return name; }
50
public Integer getOrder() { return order; }
51
public AuthenticationHandlerStates getState() { return state; }
52
public void setState(AuthenticationHandlerStates state) { this.state = state; }
53
54
protected ServicesManager getServicesManager() { return servicesManager; }
55
protected PrincipalFactory getPrincipalFactory() { return principalFactory; }
56
}
57
```
58
59
## Username/Password Authentication
60
61
### Abstract Username/Password Handler
62
63
```java { .api }
64
package org.apereo.cas.authentication.handler.support;
65
66
import org.apereo.cas.authentication.AbstractAuthenticationHandler;
67
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
68
import org.apereo.cas.authentication.Credential;
69
import org.apereo.cas.authentication.credential.UsernamePasswordCredential;
70
import org.apereo.cas.authentication.principal.PrincipalFactory;
71
import org.apereo.cas.services.ServicesManager;
72
73
public abstract class AbstractUsernamePasswordAuthenticationHandler
74
extends AbstractAuthenticationHandler {
75
76
protected AbstractUsernamePasswordAuthenticationHandler(String name,
77
ServicesManager servicesManager,
78
PrincipalFactory principalFactory,
79
Integer order) {
80
super(name, servicesManager, principalFactory, order);
81
}
82
83
public boolean supports(Credential credential) {
84
return credential instanceof UsernamePasswordCredential;
85
}
86
87
public final AuthenticationHandlerExecutionResult authenticate(Credential credential)
88
throws GeneralSecurityException, PreventedException {
89
90
UsernamePasswordCredential usernamePasswordCredential = (UsernamePasswordCredential) credential;
91
String originalPassword = usernamePasswordCredential.toPassword();
92
93
AuthenticationHandlerExecutionResult result =
94
authenticateUsernamePasswordInternal(usernamePasswordCredential, originalPassword);
95
96
return result;
97
}
98
99
protected abstract AuthenticationHandlerExecutionResult
100
authenticateUsernamePasswordInternal(UsernamePasswordCredential credential,
101
String originalPassword)
102
throws GeneralSecurityException, PreventedException;
103
}
104
```
105
106
### Accept Users Handler
107
108
Simple handler that authenticates against a predefined map of users and passwords:
109
110
```java { .api }
111
package org.apereo.cas.authentication;
112
113
import org.apereo.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
114
import org.apereo.cas.authentication.principal.PrincipalFactory;
115
import org.apereo.cas.services.ServicesManager;
116
117
import java.util.Map;
118
119
public class AcceptUsersAuthenticationHandler
120
extends AbstractUsernamePasswordAuthenticationHandler {
121
122
private Map<String, String> users;
123
124
public AcceptUsersAuthenticationHandler(Map<String, String> users) {
125
this(AcceptUsersAuthenticationHandler.class.getSimpleName(),
126
null, new DefaultPrincipalFactory(), null, users);
127
}
128
129
public AcceptUsersAuthenticationHandler(String name,
130
ServicesManager servicesManager,
131
PrincipalFactory principalFactory,
132
Integer order,
133
Map<String, String> users) {
134
super(name, servicesManager, principalFactory, order);
135
this.users = users;
136
}
137
138
protected AuthenticationHandlerExecutionResult
139
authenticateUsernamePasswordInternal(UsernamePasswordCredential credential,
140
String originalPassword)
141
throws GeneralSecurityException {
142
143
String username = credential.getUsername();
144
String password = credential.toPassword();
145
146
String expectedPassword = users.get(username);
147
if (expectedPassword != null && expectedPassword.equals(password)) {
148
Principal principal = principalFactory.createPrincipal(username);
149
return createHandlerResult(credential, principal, null);
150
}
151
152
throw new FailedLoginException();
153
}
154
155
public void setUsers(Map<String, String> users) {
156
this.users = users;
157
}
158
}
159
```
160
161
## Pre/Post Processing Handler
162
163
```java { .api }
164
package org.apereo.cas.authentication.handler.support;
165
166
import org.apereo.cas.authentication.AbstractAuthenticationHandler;
167
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
168
import org.apereo.cas.authentication.Credential;
169
import org.apereo.cas.authentication.PreventedException;
170
171
import java.security.GeneralSecurityException;
172
173
public abstract class AbstractPreAndPostProcessingAuthenticationHandler
174
extends AbstractAuthenticationHandler {
175
176
protected AbstractPreAndPostProcessingAuthenticationHandler(String name,
177
ServicesManager servicesManager,
178
PrincipalFactory principalFactory,
179
Integer order) {
180
super(name, servicesManager, principalFactory, order);
181
}
182
183
public final AuthenticationHandlerExecutionResult authenticate(Credential credential)
184
throws GeneralSecurityException, PreventedException {
185
186
if (!preProcess(credential)) {
187
throw new PreventedException("Pre-processing failed");
188
}
189
190
try {
191
AuthenticationHandlerExecutionResult result = doAuthentication(credential);
192
if (!postProcess(credential, result)) {
193
throw new PreventedException("Post-processing failed");
194
}
195
return result;
196
} catch (Exception e) {
197
handleAuthenticationException(credential, e);
198
throw e;
199
}
200
}
201
202
protected boolean preProcess(Credential credential) { return true; }
203
protected boolean postProcess(Credential credential,
204
AuthenticationHandlerExecutionResult result) { return true; }
205
protected void handleAuthenticationException(Credential credential, Exception e) { }
206
207
protected abstract AuthenticationHandlerExecutionResult doAuthentication(Credential credential)
208
throws GeneralSecurityException, PreventedException;
209
}
210
```
211
212
## Proxy Authentication Handler
213
214
```java { .api }
215
package org.apereo.cas.authentication.handler.support;
216
217
import org.apereo.cas.authentication.AbstractAuthenticationHandler;
218
import org.apereo.cas.authentication.AuthenticationHandlerExecutionResult;
219
import org.apereo.cas.authentication.Credential;
220
import org.apereo.cas.authentication.credential.HttpBasedServiceCredential;
221
import org.apereo.cas.authentication.principal.PrincipalFactory;
222
import org.apereo.cas.services.ServicesManager;
223
224
public class ProxyAuthenticationHandler extends AbstractAuthenticationHandler {
225
226
public ProxyAuthenticationHandler(String name,
227
ServicesManager servicesManager,
228
PrincipalFactory principalFactory,
229
Integer order) {
230
super(name, servicesManager, principalFactory, order);
231
}
232
233
public boolean supports(Credential credential) {
234
return credential instanceof HttpBasedServiceCredential;
235
}
236
237
public AuthenticationHandlerExecutionResult authenticate(Credential credential)
238
throws GeneralSecurityException, PreventedException {
239
240
HttpBasedServiceCredential httpCredential = (HttpBasedServiceCredential) credential;
241
242
if (httpCredential.getService() != null && httpCredential.getCallbackUrl() != null) {
243
Principal principal = principalFactory.createPrincipal(httpCredential.getId());
244
return createHandlerResult(credential, principal, null);
245
}
246
247
throw new FailedLoginException("Invalid HTTP-based service credential");
248
}
249
}
250
```
251
252
## Handler Resolvers
253
254
Handler resolvers determine which authentication handlers should be used for specific authentication requests.
255
256
### Default Handler Resolver
257
258
```java { .api }
259
package org.apereo.cas.authentication.handler;
260
261
import org.apereo.cas.authentication.AuthenticationHandler;
262
import org.apereo.cas.authentication.AuthenticationTransaction;
263
264
import java.util.Set;
265
266
public interface AuthenticationHandlerResolver {
267
Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
268
AuthenticationTransaction transaction);
269
boolean supports(Set<AuthenticationHandler> handlers,
270
AuthenticationTransaction transaction);
271
}
272
273
public class DefaultAuthenticationHandlerResolver implements AuthenticationHandlerResolver {
274
275
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
276
AuthenticationTransaction transaction) {
277
return candidateHandlers.stream()
278
.filter(handler -> handler.getState() == AuthenticationHandlerStates.ACTIVE)
279
.filter(handler -> transaction.getCredentials().stream()
280
.anyMatch(handler::supports))
281
.collect(Collectors.toSet());
282
}
283
284
public boolean supports(Set<AuthenticationHandler> handlers,
285
AuthenticationTransaction transaction) {
286
return true;
287
}
288
}
289
```
290
291
### Credential Type Resolver
292
293
```java { .api }
294
package org.apereo.cas.authentication.handler;
295
296
import org.apereo.cas.authentication.AuthenticationHandler;
297
import org.apereo.cas.authentication.AuthenticationTransaction;
298
import org.apereo.cas.authentication.Credential;
299
300
public class ByCredentialTypeAuthenticationHandlerResolver
301
implements AuthenticationHandlerResolver {
302
303
private Class<? extends Credential> credentialType;
304
305
public ByCredentialTypeAuthenticationHandlerResolver(Class<? extends Credential> credentialType) {
306
this.credentialType = credentialType;
307
}
308
309
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
310
AuthenticationTransaction transaction) {
311
return candidateHandlers.stream()
312
.filter(handler -> transaction.getCredentials().stream()
313
.anyMatch(credential -> credentialType.isInstance(credential) && handler.supports(credential)))
314
.collect(Collectors.toSet());
315
}
316
317
public boolean supports(Set<AuthenticationHandler> handlers,
318
AuthenticationTransaction transaction) {
319
return transaction.getCredentials().stream()
320
.anyMatch(credentialType::isInstance);
321
}
322
}
323
```
324
325
### Credential Source Resolver
326
327
```java { .api }
328
package org.apereo.cas.authentication.handler;
329
330
import org.apereo.cas.authentication.AuthenticationHandler;
331
import org.apereo.cas.authentication.AuthenticationTransaction;
332
import org.apereo.cas.authentication.credential.UsernamePasswordCredential;
333
334
public class ByCredentialSourceAuthenticationHandlerResolver
335
implements AuthenticationHandlerResolver {
336
337
private String source;
338
339
public ByCredentialSourceAuthenticationHandlerResolver(String source) {
340
this.source = source;
341
}
342
343
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
344
AuthenticationTransaction transaction) {
345
return candidateHandlers.stream()
346
.filter(handler -> transaction.getCredentials().stream()
347
.anyMatch(credential -> matchesSource(credential) && handler.supports(credential)))
348
.collect(Collectors.toSet());
349
}
350
351
private boolean matchesSource(Credential credential) {
352
if (credential instanceof UsernamePasswordCredential) {
353
UsernamePasswordCredential upc = (UsernamePasswordCredential) credential;
354
return source.equals(upc.getSource());
355
}
356
return false;
357
}
358
359
public boolean supports(Set<AuthenticationHandler> handlers,
360
AuthenticationTransaction transaction) {
361
return transaction.getCredentials().stream()
362
.anyMatch(this::matchesSource);
363
}
364
}
365
```
366
367
### Registered Service Resolver
368
369
```java { .api }
370
package org.apereo.cas.authentication.handler;
371
372
import org.apereo.cas.authentication.AuthenticationHandler;
373
import org.apereo.cas.authentication.AuthenticationTransaction;
374
import org.apereo.cas.services.RegisteredService;
375
import org.apereo.cas.services.ServicesManager;
376
377
public class RegisteredServiceAuthenticationHandlerResolver
378
implements AuthenticationHandlerResolver {
379
380
private ServicesManager servicesManager;
381
382
public RegisteredServiceAuthenticationHandlerResolver(ServicesManager servicesManager) {
383
this.servicesManager = servicesManager;
384
}
385
386
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
387
AuthenticationTransaction transaction) {
388
Service service = transaction.getService();
389
if (service == null) {
390
return candidateHandlers;
391
}
392
393
RegisteredService registeredService = servicesManager.findServiceBy(service);
394
if (registeredService == null || registeredService.getAuthenticationPolicy() == null) {
395
return candidateHandlers;
396
}
397
398
Set<String> requiredHandlers = registeredService.getAuthenticationPolicy()
399
.getRequiredAuthenticationHandlers();
400
401
if (requiredHandlers.isEmpty()) {
402
return candidateHandlers;
403
}
404
405
return candidateHandlers.stream()
406
.filter(handler -> requiredHandlers.contains(handler.getName()))
407
.collect(Collectors.toSet());
408
}
409
410
public boolean supports(Set<AuthenticationHandler> handlers,
411
AuthenticationTransaction transaction) {
412
return transaction.getService() != null;
413
}
414
}
415
```
416
417
### Groovy Handler Resolver
418
419
```java { .api }
420
package org.apereo.cas.authentication.handler;
421
422
import org.apereo.cas.authentication.AuthenticationHandler;
423
import org.apereo.cas.authentication.AuthenticationTransaction;
424
import org.apereo.cas.util.scripting.ExecutableCompiledGroovyScript;
425
426
public class GroovyAuthenticationHandlerResolver implements AuthenticationHandlerResolver {
427
428
private ExecutableCompiledGroovyScript watchableScript;
429
430
public GroovyAuthenticationHandlerResolver(ExecutableCompiledGroovyScript watchableScript) {
431
this.watchableScript = watchableScript;
432
}
433
434
public Set<AuthenticationHandler> resolve(Set<AuthenticationHandler> candidateHandlers,
435
AuthenticationTransaction transaction) {
436
Object result = watchableScript.execute(candidateHandlers, transaction,
437
AuthenticationHandler.class);
438
439
if (result instanceof Set) {
440
return (Set<AuthenticationHandler>) result;
441
} else if (result instanceof Collection) {
442
return new LinkedHashSet<>((Collection<AuthenticationHandler>) result);
443
}
444
445
return candidateHandlers;
446
}
447
448
public boolean supports(Set<AuthenticationHandler> handlers,
449
AuthenticationTransaction transaction) {
450
return watchableScript != null;
451
}
452
}
453
```
454
455
## JAAS Authentication Support
456
457
The authentication API provides JAAS (Java Authentication and Authorization Service) integration:
458
459
```java { .api }
460
package org.apereo.cas.authentication.handler.support.jaas;
461
462
import javax.security.auth.login.LoginContext;
463
import javax.security.auth.login.LoginException;
464
465
public class JaasAuthenticationHandler extends AbstractUsernamePasswordAuthenticationHandler {
466
467
private String realm;
468
private String kerberosKdcSystemProperty;
469
private String kerberosRealmSystemProperty;
470
471
public JaasAuthenticationHandler(String name,
472
ServicesManager servicesManager,
473
PrincipalFactory principalFactory,
474
Integer order,
475
String realm) {
476
super(name, servicesManager, principalFactory, order);
477
this.realm = realm;
478
}
479
480
protected AuthenticationHandlerExecutionResult
481
authenticateUsernamePasswordInternal(UsernamePasswordCredential credential,
482
String originalPassword)
483
throws GeneralSecurityException {
484
485
try {
486
String username = credential.getUsername();
487
LoginContext loginContext = createLoginContext(credential);
488
loginContext.login();
489
490
Principal principal = principalFactory.createPrincipal(username);
491
return createHandlerResult(credential, principal, null);
492
493
} catch (LoginException e) {
494
throw new FailedLoginException("JAAS authentication failed: " + e.getMessage());
495
}
496
}
497
498
private LoginContext createLoginContext(UsernamePasswordCredential credential)
499
throws LoginException {
500
return new LoginContext(realm, new JaasUsernamePasswordCallbackHandler(
501
credential.getUsername(), credential.getPassword()));
502
}
503
}
504
```
505
506
## Handler Configuration Examples
507
508
### Spring Configuration
509
510
```java { .api }
511
@Configuration
512
@EnableConfigurationProperties(CasConfigurationProperties.class)
513
public class AuthenticationHandlerConfiguration {
514
515
@Bean
516
public AuthenticationHandler acceptUsersAuthenticationHandler() {
517
Map<String, String> users = Map.of(
518
"admin", "password",
519
"user", "secret"
520
);
521
return new AcceptUsersAuthenticationHandler(users);
522
}
523
524
@Bean
525
public AuthenticationHandlerResolver defaultAuthenticationHandlerResolver() {
526
return new DefaultAuthenticationHandlerResolver();
527
}
528
529
@Bean
530
public AuthenticationHandlerResolver credentialTypeResolver() {
531
return new ByCredentialTypeAuthenticationHandlerResolver(
532
UsernamePasswordCredential.class);
533
}
534
}
535
```
536
537
### Programmatic Configuration
538
539
```java { .api }
540
// Create authentication handler
541
AcceptUsersAuthenticationHandler handler = new AcceptUsersAuthenticationHandler(
542
"TestHandler",
543
servicesManager,
544
new DefaultPrincipalFactory(),
545
100,
546
Map.of("testuser", "testpass")
547
);
548
549
// Configure handler state
550
handler.setState(AuthenticationHandlerStates.ACTIVE);
551
552
// Create resolver for specific credential types
553
AuthenticationHandlerResolver resolver =
554
new ByCredentialTypeAuthenticationHandlerResolver(UsernamePasswordCredential.class);
555
556
// Register in execution plan
557
authenticationEventExecutionPlan.registerAuthenticationHandler(handler);
558
authenticationEventExecutionPlan.registerAuthenticationHandlerResolver(resolver);
559
```
560
561
Authentication handlers provide the core credential validation logic in CAS authentication workflows. They can be customized and extended to integrate with virtually any authentication source or protocol, making them a flexible foundation for enterprise authentication requirements.