1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.syncope.sra.security.cas;
20
21 import java.net.URI;
22 import org.apache.syncope.sra.security.web.server.DoNothingIfCommittedServerRedirectStrategy;
23 import org.apache.syncope.sra.session.SessionUtils;
24 import org.jasig.cas.client.Protocol;
25 import org.jasig.cas.client.validation.Assertion;
26 import org.jasig.cas.client.validation.TicketValidationException;
27 import org.jasig.cas.client.validation.TicketValidator;
28 import org.jasig.cas.client.validation.json.Cas30JsonServiceTicketValidator;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31 import org.springframework.security.authentication.BadCredentialsException;
32 import org.springframework.security.authentication.ReactiveAuthenticationManager;
33 import org.springframework.security.core.Authentication;
34 import org.springframework.security.web.server.ServerRedirectStrategy;
35 import org.springframework.security.web.server.WebFilterExchange;
36 import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
37 import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
38 import org.springframework.security.web.server.authentication.ServerAuthenticationSuccessHandler;
39 import org.springframework.security.web.server.util.matcher.AndServerWebExchangeMatcher;
40 import org.springframework.security.web.server.util.matcher.NegatedServerWebExchangeMatcher;
41 import reactor.core.publisher.Mono;
42
43 public class CASAuthenticationWebFilter extends AuthenticationWebFilter {
44
45 private static final Logger LOG = LoggerFactory.getLogger(CASAuthenticationWebFilter.class);
46
47 private final Protocol protocol;
48
49 private final TicketValidator ticketValidator;
50
51 public CASAuthenticationWebFilter(
52 final ReactiveAuthenticationManager authenticationManager,
53 final Protocol protocol,
54 final String casServerUrlPrefix) {
55
56 super(authenticationManager);
57
58 this.protocol = protocol;
59 this.ticketValidator = new Cas30JsonServiceTicketValidator(casServerUrlPrefix);
60
61 setRequiresAuthenticationMatcher(new AndServerWebExchangeMatcher(
62 CASUtils.ticketAvailable(protocol),
63 new NegatedServerWebExchangeMatcher(SessionUtils.authInSession())));
64
65 setServerAuthenticationConverter(validateAssertion());
66
67 setAuthenticationSuccessHandler(redirectToInitialRequestURI());
68 }
69
70 private ServerAuthenticationConverter validateAssertion() {
71 return exchange -> CASUtils.retrieveTicketFromRequest(exchange, protocol).
72 flatMap(ticket -> {
73 try {
74 String serviceUrl = CASUtils.constructServiceUrl(exchange, protocol);
75 LOG.debug("Constructed service url: {}", serviceUrl);
76
77 Assertion assertion = ticketValidator.validate(
78 ticket,
79 CASUtils.constructServiceUrl(exchange, protocol));
80 return Mono.just(new CASAuthenticationToken(assertion));
81 } catch (TicketValidationException e) {
82 LOG.error("Could not validate {}", ticket, e);
83 throw new BadCredentialsException("Could not validate " + ticket);
84 }
85 });
86 }
87
88 private ServerAuthenticationSuccessHandler redirectToInitialRequestURI() {
89 return new ServerAuthenticationSuccessHandler() {
90
91 private final ServerRedirectStrategy redirectStrategy = new DoNothingIfCommittedServerRedirectStrategy();
92
93 @Override
94 public Mono<Void> onAuthenticationSuccess(
95 final WebFilterExchange webFilterExchange, final Authentication authentication) {
96
97 return webFilterExchange.getExchange().getSession().
98 flatMap(session -> redirectStrategy.sendRedirect(
99 webFilterExchange.getExchange(),
100 session.<URI>getRequiredAttribute(SessionUtils.INITIAL_REQUEST_URI)));
101 }
102 };
103 }
104 }