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.oauth2;
20
21 import java.util.Set;
22 import org.apache.syncope.sra.ApplicationContextUtils;
23 import org.apache.syncope.sra.SRAProperties;
24 import org.apache.syncope.sra.security.LogoutRouteMatcher;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27 import org.springframework.cache.CacheManager;
28 import org.springframework.context.ApplicationContext;
29 import org.springframework.context.ConfigurableApplicationContext;
30 import org.springframework.http.MediaType;
31 import org.springframework.security.authentication.DelegatingReactiveAuthenticationManager;
32 import org.springframework.security.authentication.ReactiveAuthenticationManager;
33 import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
34 import org.springframework.security.config.web.server.ServerHttpSecurity;
35 import org.springframework.security.oauth2.client.InMemoryReactiveOAuth2AuthorizedClientService;
36 import org.springframework.security.oauth2.client.ReactiveOAuth2AuthorizedClientService;
37 import org.springframework.security.oauth2.client.authentication.OAuth2LoginReactiveAuthenticationManager;
38 import org.springframework.security.oauth2.client.endpoint.WebClientReactiveAuthorizationCodeTokenResponseClient;
39 import org.springframework.security.oauth2.client.oidc.authentication.OidcAuthorizationCodeReactiveAuthenticationManager;
40 import org.springframework.security.oauth2.client.oidc.userinfo.OidcReactiveOAuth2UserService;
41 import org.springframework.security.oauth2.client.registration.ReactiveClientRegistrationRepository;
42 import org.springframework.security.oauth2.client.userinfo.DefaultReactiveOAuth2UserService;
43 import org.springframework.security.oauth2.client.web.server.AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository;
44 import org.springframework.security.oauth2.client.web.server.OAuth2AuthorizationRequestRedirectWebFilter;
45 import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizationCodeAuthenticationTokenConverter;
46 import org.springframework.security.oauth2.client.web.server.ServerOAuth2AuthorizedClientRepository;
47 import org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter;
48 import org.springframework.security.web.server.DelegatingServerAuthenticationEntryPoint.DelegateEntry;
49 import org.springframework.security.web.server.ServerAuthenticationEntryPoint;
50 import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
51 import org.springframework.security.web.server.authentication.RedirectServerAuthenticationEntryPoint;
52 import org.springframework.security.web.server.authentication.RedirectServerAuthenticationSuccessHandler;
53 import org.springframework.security.web.server.authentication.logout.LogoutWebFilter;
54 import org.springframework.security.web.server.context.WebSessionServerSecurityContextRepository;
55 import org.springframework.security.web.server.util.matcher.MediaTypeServerWebExchangeMatcher;
56 import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher;
57 import reactor.core.publisher.Mono;
58
59 public final class OAuth2SecurityConfigUtils {
60
61 private static final Logger LOG = LoggerFactory.getLogger(OAuth2SecurityConfigUtils.class);
62
63 private static ReactiveAuthenticationManager authenticationManager(final SRAProperties.AMType amType) {
64 WebClientReactiveAuthorizationCodeTokenResponseClient client =
65 new WebClientReactiveAuthorizationCodeTokenResponseClient();
66 ReactiveAuthenticationManager authenticationManager =
67 new OAuth2LoginReactiveAuthenticationManager(client, new DefaultReactiveOAuth2UserService());
68
69 if (SRAProperties.AMType.OIDC == amType) {
70 OidcAuthorizationCodeReactiveAuthenticationManager oidc =
71 new OidcAuthorizationCodeReactiveAuthenticationManager(client, new OidcReactiveOAuth2UserService());
72 authenticationManager = new DelegatingReactiveAuthenticationManager(oidc, authenticationManager);
73 }
74
75 return authenticationManager;
76 }
77
78 public static void forLogin(
79 final ServerHttpSecurity http,
80 final SRAProperties.AMType amType,
81 final ApplicationContext ctx) {
82
83 ReactiveClientRegistrationRepository clientRegistrationRepository =
84 ctx.getBean(ReactiveClientRegistrationRepository.class);
85
86 ReactiveOAuth2AuthorizedClientService authorizedClientService =
87 new InMemoryReactiveOAuth2AuthorizedClientService(clientRegistrationRepository);
88 ServerOAuth2AuthorizedClientRepository authorizedClientRepository =
89 new AuthenticatedPrincipalServerOAuth2AuthorizedClientRepository(authorizedClientService);
90
91 OAuth2AuthorizationRequestRedirectWebFilter authRequestRedirectFilter =
92 new OAuth2AuthorizationRequestRedirectWebFilter(clientRegistrationRepository);
93 http.addFilterAt(authRequestRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC);
94
95 AuthenticationWebFilter authenticationFilter =
96 new OAuth2LoginAuthenticationWebFilter(authenticationManager(amType), authorizedClientRepository);
97 authenticationFilter.setRequiresAuthenticationMatcher(
98 new PathPatternParserServerWebExchangeMatcher("/login/oauth2/code/{registrationId}"));
99 authenticationFilter.setServerAuthenticationConverter(
100 new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter(clientRegistrationRepository));
101 authenticationFilter.setAuthenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler());
102 authenticationFilter.setAuthenticationFailureHandler((exchange, ex) -> Mono.error(ex));
103 authenticationFilter.setSecurityContextRepository(new WebSessionServerSecurityContextRepository());
104 http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION);
105
106 MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher(MediaType.TEXT_HTML);
107 htmlMatcher.setIgnoredMediaTypes(Set.of(MediaType.ALL));
108 ServerAuthenticationEntryPoint entrypoint =
109 new RedirectServerAuthenticationEntryPoint("/oauth2/authorization/" + amType.name());
110 http.exceptionHandling().authenticationEntryPoint(new DelegateEntry(htmlMatcher, entrypoint).getEntryPoint());
111 }
112
113 public static void forLogout(
114 final ServerHttpSecurity.AuthorizeExchangeSpec builder,
115 final SRAProperties.AMType amType,
116 final CacheManager cacheManager,
117 final LogoutRouteMatcher logoutRouteMatcher,
118 final ConfigurableApplicationContext ctx) {
119
120 LogoutWebFilter logoutWebFilter = new LogoutWebFilter();
121 logoutWebFilter.setRequiresLogoutMatcher(logoutRouteMatcher);
122 logoutWebFilter.setLogoutHandler(new OAuth2SessionRemovalServerLogoutHandler(cacheManager));
123
124 if (SRAProperties.AMType.OIDC == amType) {
125 try {
126 OidcClientInitiatedServerLogoutSuccessHandler handler = ApplicationContextUtils.getOrCreateBean(
127 ctx,
128 OidcClientInitiatedServerLogoutSuccessHandler.class.getName(),
129 OidcClientInitiatedServerLogoutSuccessHandler.class);
130 logoutWebFilter.setLogoutSuccessHandler(handler);
131 } catch (ClassNotFoundException e) {
132 LOG.error("While creating instance of {}",
133 OidcClientInitiatedServerLogoutSuccessHandler.class.getName(), e);
134 }
135 }
136
137 builder.and().logout().disable().addFilterAt(logoutWebFilter, SecurityWebFiltersOrder.LOGOUT);
138 }
139
140 private OAuth2SecurityConfigUtils() {
141
142 }
143 }