/** * Configures the log in page to redirect to, the authentication failure page, and when authentication is * performed. The default is that Spring Security will generate a log in page at "/login" and a log out page at * "/logout". If this is customized: * <ul> * <li>The default log in & log out page are no longer provided</li> * <li>The application must render a log in page at the provided URL</li> * <li>The application must render an authentication error page at the provided URL + "?error"</li> * <li>Authentication will occur for POST to the provided URL</li> * </ul> * @param loginPage the url to redirect to which provides a form to log in (i.e. "/login") * @return the {@link FormLoginSpec} to continue configuring * @see #authenticationEntryPoint(ServerAuthenticationEntryPoint) * @see #requiresAuthenticationMatcher(ServerWebExchangeMatcher) * @see #authenticationFailureHandler(ServerAuthenticationFailureHandler) */ public FormLoginSpec loginPage(String loginPage) { this.defaultEntryPoint = new RedirectServerAuthenticationEntryPoint(loginPage); this.authenticationEntryPoint = this.defaultEntryPoint; this.requiresAuthenticationMatcher = ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, loginPage); this.authenticationFailureHandler = new RedirectServerAuthenticationFailureHandler(loginPage + "?error"); return this; }
private ServerAuthenticationEntryPoint redirectServerAuthenticationEntryPoint(String location) { return new RedirectServerAuthenticationEntryPoint(location); }
protected void configure(ServerHttpSecurity http) { MediaTypeServerWebExchangeMatcher restMatcher = new MediaTypeServerWebExchangeMatcher( MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA, MediaType.TEXT_XML); restMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL)); ServerHttpSecurity.this.defaultEntryPoints.add(new DelegateEntry(restMatcher, this.entryPoint)); AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter( this.authenticationManager); authenticationFilter.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(this.entryPoint)); authenticationFilter.setAuthenticationConverter(new ServerHttpBasicAuthenticationConverter()); if (this.securityContextRepository != null) { authenticationFilter.setSecurityContextRepository(this.securityContextRepository); } http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.HTTP_BASIC); }
protected void configure(ServerHttpSecurity http) { if (this.authenticationEntryPoint == null) { this.isEntryPointExplicit = false; loginPage("/login"); } else { this.isEntryPointExplicit = true; } if (http.requestCache != null) { ServerRequestCache requestCache = http.requestCache.requestCache; this.defaultSuccessHandler.setRequestCache(requestCache); if (this.defaultEntryPoint != null) { this.defaultEntryPoint.setRequestCache(requestCache); } } MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher( MediaType.TEXT_HTML); htmlMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL)); ServerHttpSecurity.this.defaultEntryPoints.add(0, new DelegateEntry(htmlMatcher, this.authenticationEntryPoint)); AuthenticationWebFilter authenticationFilter = new AuthenticationWebFilter( this.authenticationManager); authenticationFilter.setRequiresAuthenticationMatcher(this.requiresAuthenticationMatcher); authenticationFilter.setAuthenticationFailureHandler(this.authenticationFailureHandler); authenticationFilter.setAuthenticationConverter(new ServerFormLoginAuthenticationConverter()); authenticationFilter.setAuthenticationSuccessHandler(this.authenticationSuccessHandler); authenticationFilter.setSecurityContextRepository(this.securityContextRepository); http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.FORM_LOGIN); }
protected void configure(ServerHttpSecurity http) { ReactiveClientRegistrationRepository clientRegistrationRepository = getClientRegistrationRepository(); ServerOAuth2AuthorizedClientRepository authorizedClientRepository = getAuthorizedClientRepository(); OAuth2AuthorizationRequestRedirectWebFilter oauthRedirectFilter = getRedirectWebFilter(); ReactiveAuthenticationManager manager = getAuthenticationManager(); AuthenticationWebFilter authenticationFilter = new OAuth2LoginAuthenticationWebFilter(manager, authorizedClientRepository); authenticationFilter.setRequiresAuthenticationMatcher(getAuthenticationMatcher()); authenticationFilter.setServerAuthenticationConverter(getAuthenticationConverter(clientRegistrationRepository)); RedirectServerAuthenticationSuccessHandler redirectHandler = new RedirectServerAuthenticationSuccessHandler(); authenticationFilter.setAuthenticationSuccessHandler(redirectHandler); authenticationFilter.setAuthenticationFailureHandler(new ServerAuthenticationFailureHandler() { @Override public Mono<Void> onAuthenticationFailure(WebFilterExchange webFilterExchange, AuthenticationException exception) { return Mono.error(exception); } }); authenticationFilter.setSecurityContextRepository(new WebSessionServerSecurityContextRepository()); MediaTypeServerWebExchangeMatcher htmlMatcher = new MediaTypeServerWebExchangeMatcher( MediaType.TEXT_HTML); htmlMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL)); Map<String, String> urlToText = http.oauth2Login.getLinks(); if (urlToText.size() == 1) { http.defaultEntryPoints.add(new DelegateEntry(htmlMatcher, new RedirectServerAuthenticationEntryPoint(urlToText.keySet().iterator().next()))); } else { http.defaultEntryPoints.add(new DelegateEntry(htmlMatcher, new RedirectServerAuthenticationEntryPoint("/login"))); } http.addFilterAt(oauthRedirectFilter, SecurityWebFiltersOrder.HTTP_BASIC); http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.AUTHENTICATION); }
protected void configure(ServerHttpSecurity http) { this.bearerTokenServerWebExchangeMatcher.setBearerTokenConverter(bearerTokenConverter); registerDefaultAccessDeniedHandler(http); registerDefaultAuthenticationEntryPoint(http); registerDefaultCsrfOverride(http); ReactiveAuthenticationManager authenticationManager = getAuthenticationManager(); AuthenticationWebFilter oauth2 = new AuthenticationWebFilter(authenticationManager); oauth2.setServerAuthenticationConverter(bearerTokenConverter); oauth2.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(entryPoint)); http .addFilterAt(oauth2, SecurityWebFiltersOrder.AUTHENTICATION); }
@Override public Mono<MatchResult> matches(ServerWebExchange exchange) { return this.bearerTokenConverter.convert(exchange) .flatMap(this::nullAuthentication) .onErrorResume(e -> notMatch()); }
public OAuth2AuthorizationCodeGrantWebFilter( ReactiveAuthenticationManager authenticationManager, ServerAuthenticationConverter authenticationConverter, ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { Assert.notNull(authenticationManager, "authenticationManager cannot be null"); Assert.notNull(authenticationConverter, "authenticationConverter cannot be null"); Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null"); this.authenticationManager = authenticationManager; this.authorizedClientRepository = authorizedClientRepository; this.requiresAuthenticationMatcher = new PathPatternParserServerWebExchangeMatcher("/{action}/oauth2/code/{registrationId}"); this.authenticationConverter = authenticationConverter; this.authenticationSuccessHandler = new RedirectServerAuthenticationSuccessHandler(); this.authenticationFailureHandler = (webFilterExchange, exception) -> Mono.error(exception); }
@Override protected Mono<Void> onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) { OAuth2LoginAuthenticationToken authenticationResult = (OAuth2LoginAuthenticationToken) authentication; OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient( authenticationResult.getClientRegistration(), authenticationResult.getName(), authenticationResult.getAccessToken(), authenticationResult.getRefreshToken()); OAuth2AuthenticationToken result = new OAuth2AuthenticationToken( authenticationResult.getPrincipal(), authenticationResult.getAuthorities(), authenticationResult.getClientRegistration().getRegistrationId()); return this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, authenticationResult, webFilterExchange.getExchange()) .then(super.onAuthenticationSuccess(result, webFilterExchange)); } }
private Mono<Void> authenticate(ServerWebExchange exchange, WebFilterChain chain, Authentication token) { WebFilterExchange webFilterExchange = new WebFilterExchange(exchange, chain); return this.authenticationManager.authenticate(token) .switchIfEmpty(Mono.defer(() -> Mono.error(new IllegalStateException("No provider found for " + token.getClass())))) .flatMap(authentication -> onAuthenticationSuccess(authentication, webFilterExchange)) .onErrorResume(AuthenticationException.class, e -> this.authenticationFailureHandler .onAuthenticationFailure(webFilterExchange, e)); }
private Mono<Void> onAuthenticationSuccess(Authentication authentication, WebFilterExchange webFilterExchange) { OAuth2AuthorizationCodeAuthenticationToken authenticationResult = (OAuth2AuthorizationCodeAuthenticationToken) authentication; OAuth2AuthorizedClient authorizedClient = new OAuth2AuthorizedClient( authenticationResult.getClientRegistration(), authenticationResult.getName(), authenticationResult.getAccessToken(), authenticationResult.getRefreshToken()); return this.authenticationSuccessHandler .onAuthenticationSuccess(webFilterExchange, authentication) .then(ReactiveSecurityContextHolder.getContext() .map(SecurityContext::getAuthentication) .defaultIfEmpty(this.anonymousToken) .flatMap(principal -> this.authorizedClientRepository.saveAuthorizedClient(authorizedClient, principal, webFilterExchange.getExchange())) ); } }
@Test public void basicWithCustomRealmName() { this.http.securityContextRepository(new WebSessionServerSecurityContextRepository()); HttpBasicServerAuthenticationEntryPoint authenticationEntryPoint = new HttpBasicServerAuthenticationEntryPoint(); authenticationEntryPoint.setRealm("myrealm"); this.http.httpBasic().authenticationEntryPoint(authenticationEntryPoint); this.http.authenticationManager(this.authenticationManager); ServerHttpSecurity.AuthorizeExchangeSpec authorize = this.http.authorizeExchange(); authorize.anyExchange().authenticated(); WebTestClient client = buildClient(); EntityExchangeResult<String> result = client.get() .uri("/") .exchange() .expectStatus().isUnauthorized() .expectHeader().value(HttpHeaders.WWW_AUTHENTICATE, value -> assertThat(value).contains("myrealm")) .expectBody(String.class) .returnResult(); assertThat(result.getResponseCookies().getFirst("SESSION")).isNull(); }
protected void configure(ServerHttpSecurity http) { if (authenticationFilter == null) { authenticationFilter = new AnonymousAuthenticationWebFilter(getKey(), principal, authorities); } http.addFilterAt(authenticationFilter, SecurityWebFiltersOrder.ANONYMOUS_AUTHENTICATION); }
@Bean SecurityWebFilterChain springSecurity(ServerHttpSecurity http) throws Exception { // @formatter:off http .authorizeExchange() .pathMatchers("/authenticated").authenticated() .pathMatchers("/unobtainable").hasAuthority("unobtainable") .and() .oauth2ResourceServer() .accessDeniedHandler(new HttpStatusServerAccessDeniedHandler(HttpStatus.BANDWIDTH_LIMIT_EXCEEDED)) .authenticationEntryPoint(new HttpStatusServerEntryPoint(HttpStatus.I_AM_A_TEAPOT)) .jwt() .publicKey(publicKey()); // @formatter:on return http.build(); } }
@Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { return this.requiresAuthenticationMatcher.matches(exchange) .filter( matchResult -> matchResult.isMatch()) .flatMap( matchResult -> this.authenticationConverter.convert(exchange)) .switchIfEmpty(chain.filter(exchange).then(Mono.empty())) .flatMap( token -> authenticate(exchange, chain, token)); }
public OAuth2AuthorizationCodeGrantWebFilter( ReactiveAuthenticationManager authenticationManager, ReactiveClientRegistrationRepository clientRegistrationRepository, ServerOAuth2AuthorizedClientRepository authorizedClientRepository) { Assert.notNull(authenticationManager, "authenticationManager cannot be null"); Assert.notNull(clientRegistrationRepository, "clientRegistrationRepository cannot be null"); Assert.notNull(authorizedClientRepository, "authorizedClientRepository cannot be null"); this.authenticationManager = authenticationManager; this.authorizedClientRepository = authorizedClientRepository; this.requiresAuthenticationMatcher = new PathPatternParserServerWebExchangeMatcher("/{action}/oauth2/code/{registrationId}"); this.authenticationConverter = new ServerOAuth2AuthorizationCodeAuthenticationTokenConverter(clientRegistrationRepository); this.authenticationSuccessHandler = new RedirectServerAuthenticationSuccessHandler(); this.authenticationFailureHandler = (webFilterExchange, exception) -> Mono.error(exception); }
@Test public void oauth2ClientWhenCustomObjectsThenUsed() { this.spring.register(ClientRegistrationConfig.class, OAuth2ClientCustomConfig.class, AuthorizedClientController.class).autowire(); OAuth2ClientCustomConfig config = this.spring.getContext().getBean(OAuth2ClientCustomConfig.class); ServerAuthenticationConverter converter = config.authenticationConverter; ReactiveAuthenticationManager manager = config.manager; OAuth2AuthorizationExchange exchange = TestOAuth2AuthorizationExchanges.success(); OAuth2AccessToken accessToken = TestOAuth2AccessTokens.noScopes(); OAuth2AuthorizationCodeAuthenticationToken result = new OAuth2AuthorizationCodeAuthenticationToken(this.registration, exchange, accessToken); when(converter.convert(any())).thenReturn(Mono.just(new TestingAuthenticationToken("a", "b", "c"))); when(manager.authenticate(any())).thenReturn(Mono.just(result)); this.client.get() .uri("/authorize/oauth2/code/registration-id") .exchange() .expectStatus().is3xxRedirection(); verify(converter).convert(any()); verify(manager).authenticate(any()); }
@Test public void authenticationSuccess() { SecurityWebFilterChain securityWebFilter = this.http .authorizeExchange() .anyExchange().authenticated() .and() .formLogin() .authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/custom")) .and() .build(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(securityWebFilter) .build(); WebDriver driver = WebTestClientHtmlUnitDriverBuilder .webTestClientSetup(webTestClient) .build(); DefaultLoginPage loginPage = DefaultLoginPage.to(driver) .assertAt(); HomePage homePage = loginPage.loginForm() .username("user") .password("password") .submit(HomePage.class); assertThat(driver.getCurrentUrl()).endsWith("/custom"); }
@Test public void oauth2LoginWhenCustomObjectsThenUsed() { this.spring.register(OAuth2LoginWithSingleClientRegistrations.class, OAuth2LoginMockAuthenticationManagerConfig.class).autowire(); WebTestClient webTestClient = WebTestClientBuilder .bindToWebFilters(this.springSecurity) .build(); OAuth2LoginMockAuthenticationManagerConfig config = this.spring.getContext() .getBean(OAuth2LoginMockAuthenticationManagerConfig.class); ServerAuthenticationConverter converter = config.authenticationConverter; ReactiveAuthenticationManager manager = config.manager; ServerWebExchangeMatcher matcher = config.matcher; ServerOAuth2AuthorizationRequestResolver resolver = config.resolver; OAuth2AuthorizationExchange exchange = TestOAuth2AuthorizationExchanges.success(); OAuth2User user = TestOAuth2Users.create(); OAuth2AccessToken accessToken = TestOAuth2AccessTokens.noScopes(); OAuth2LoginAuthenticationToken result = new OAuth2LoginAuthenticationToken(github, exchange, user, user.getAuthorities(), accessToken); when(converter.convert(any())).thenReturn(Mono.just(new TestingAuthenticationToken("a", "b", "c"))); when(manager.authenticate(any())).thenReturn(Mono.just(result)); when(matcher.matches(any())).thenReturn(ServerWebExchangeMatcher.MatchResult.match()); when(resolver.resolve(any())).thenReturn(Mono.empty()); webTestClient.get() .uri("/login/oauth2/code/github") .exchange() .expectStatus().is3xxRedirection(); verify(converter).convert(any()); verify(manager).authenticate(any()); verify(matcher).matches(any()); verify(resolver).resolve(any()); }
when(converter.convert(any())).thenReturn(Mono.just(token));