diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfiguration.java index 532d9078b5..72b83cb9c1 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfiguration.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/OAuth2ClientConfiguration.java @@ -71,13 +71,19 @@ final class OAuth2ClientConfiguration { @Override public void addArgumentResolvers(List argumentResolvers) { if (this.clientRegistrationRepository != null && this.authorizedClientRepository != null) { - OAuth2AuthorizedClientProvider authorizedClientProvider = + OAuth2AuthorizedClientProviderBuilder authorizedClientProviderBuilder = OAuth2AuthorizedClientProviderBuilder.builder() .authorizationCode() - .refreshToken() - .clientCredentials(configurer -> - Optional.ofNullable(this.accessTokenResponseClient).ifPresent(configurer::accessTokenResponseClient)) - .build(); + .refreshToken(); + + if (this.accessTokenResponseClient != null) { + authorizedClientProviderBuilder.clientCredentials(configurer -> + configurer.accessTokenResponseClient(this.accessTokenResponseClient)); + } else { + authorizedClientProviderBuilder.clientCredentials(); + } + OAuth2AuthorizedClientProvider authorizedClientProvider = authorizedClientProviderBuilder.build(); + DefaultOAuth2AuthorizedClientManager authorizedClientManager = new DefaultOAuth2AuthorizedClientManager( this.clientRegistrationRepository, this.authorizedClientRepository); authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider); diff --git a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java index 42f6437bd1..fdffdd39a7 100644 --- a/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/web/server/ServerHttpSecurity.java @@ -27,7 +27,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.UUID; import java.util.function.Function; import java.util.function.Supplier; @@ -2665,10 +2664,10 @@ public class ServerHttpSecurity { } protected void configure(ServerHttpSecurity http) { - Optional.ofNullable(this.csrfTokenRepository).ifPresent(serverCsrfTokenRepository -> { - this.filter.setCsrfTokenRepository(serverCsrfTokenRepository); - http.logout().addLogoutHandler(new CsrfServerLogoutHandler(serverCsrfTokenRepository)); - }); + if (this.csrfTokenRepository != null) { + this.filter.setCsrfTokenRepository(this.csrfTokenRepository); + http.logout().addLogoutHandler(new CsrfServerLogoutHandler(this.csrfTokenRepository)); + } http.addFilterAt(this.filter, SecurityWebFiltersOrder.CSRF); } @@ -3607,19 +3606,21 @@ public class ServerHttpSecurity { return and(); } - private Optional createLogoutHandler() { + private ServerLogoutHandler createLogoutHandler() { if (this.logoutHandlers.isEmpty()) { - return Optional.empty(); + return null; + } else if (this.logoutHandlers.size() == 1) { + return this.logoutHandlers.get(0); + } else { + return new DelegatingServerLogoutHandler(this.logoutHandlers); } - else if (this.logoutHandlers.size() == 1) { - return Optional.of(this.logoutHandlers.get(0)); - } - - return Optional.of(new DelegatingServerLogoutHandler(this.logoutHandlers)); } protected void configure(ServerHttpSecurity http) { - createLogoutHandler().ifPresent(this.logoutWebFilter::setLogoutHandler); + ServerLogoutHandler logoutHandler = createLogoutHandler(); + if (logoutHandler != null) { + this.logoutWebFilter.setLogoutHandler(logoutHandler); + } http.addFilterAt(this.logoutWebFilter, SecurityWebFiltersOrder.LOGOUT); } diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/web/logout/OidcClientInitiatedLogoutSuccessHandler.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/web/logout/OidcClientInitiatedLogoutSuccessHandler.java index c2cdd76493..0ea7425a81 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/web/logout/OidcClientInitiatedLogoutSuccessHandler.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/oidc/web/logout/OidcClientInitiatedLogoutSuccessHandler.java @@ -18,7 +18,6 @@ package org.springframework.security.oauth2.client.oidc.web.logout; import java.net.URI; import java.nio.charset.StandardCharsets; -import java.util.Optional; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -52,25 +51,34 @@ public final class OidcClientInitiatedLogoutSuccessHandler extends SimpleUrlLogo @Override protected String determineTargetUrl(HttpServletRequest request, HttpServletResponse response, Authentication authentication) { + String targetUrl = null; + URI endSessionEndpoint; + if (authentication instanceof OAuth2AuthenticationToken && authentication.getPrincipal() instanceof OidcUser) { + endSessionEndpoint = this.endSessionEndpoint((OAuth2AuthenticationToken) authentication); + if (endSessionEndpoint != null) { + targetUrl = endpointUri(endSessionEndpoint, authentication); + } + } + if (targetUrl == null) { + targetUrl = super.determineTargetUrl(request, response); + } - return Optional.of(authentication) - .filter(OAuth2AuthenticationToken.class::isInstance) - .filter(token -> authentication.getPrincipal() instanceof OidcUser) - .map(OAuth2AuthenticationToken.class::cast) - .flatMap(this::endSessionEndpoint) - .map(endSessionEndpoint -> endpointUri(endSessionEndpoint, authentication)) - .orElseGet(() -> super.determineTargetUrl(request, response)); + return targetUrl; } - private Optional endSessionEndpoint(OAuth2AuthenticationToken token) { + private URI endSessionEndpoint(OAuth2AuthenticationToken token) { String registrationId = token.getAuthorizedClientRegistrationId(); - return Optional.of( - this.clientRegistrationRepository.findByRegistrationId(registrationId)) - .map(ClientRegistration::getProviderDetails) - .map(ClientRegistration.ProviderDetails::getConfigurationMetadata) - .map(configurationMetadata -> configurationMetadata.get("end_session_endpoint")) - .map(Object::toString) - .map(URI::create); + ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(registrationId); + + URI result = null; + if (clientRegistration != null) { + Object endSessionEndpoint = clientRegistration.getProviderDetails().getConfigurationMetadata().get("end_session_endpoint"); + if (endSessionEndpoint != null) { + result = URI.create(endSessionEndpoint.toString()); + } + } + + return result; } private String endpointUri(URI endSessionEndpoint, Authentication authentication) { diff --git a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java index 846d68867c..071f03cf09 100644 --- a/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java +++ b/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/ClientRegistrations.java @@ -21,7 +21,6 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import com.nimbusds.oauth2.sdk.GrantType; import com.nimbusds.oauth2.sdk.ParseException; @@ -141,8 +140,11 @@ public final class ClientRegistrations { Map configuration = getConfiguration(issuer, oidc(uri), oidcRfc8414(uri), oauth(uri)); AuthorizationServerMetadata metadata = parse(configuration, AuthorizationServerMetadata::parse); ClientRegistration.Builder builder = withProviderConfiguration(metadata, issuer); - return Optional.ofNullable((String) configuration.get("userinfo_endpoint")) - .map(builder::userInfoUri).orElse(builder); + String userinfoEndpoint = (String) configuration.get("userinfo_endpoint"); + if (userinfoEndpoint != null) { + builder.userInfoUri(userinfoEndpoint); + } + return builder; } private static URI oidc(URI issuer) { diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/OAuth2IntrospectionAuthenticationProvider.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/OAuth2IntrospectionAuthenticationProvider.java index 495a6b4943..3260671ac7 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/OAuth2IntrospectionAuthenticationProvider.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/OAuth2IntrospectionAuthenticationProvider.java @@ -16,11 +16,11 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.time.Instant; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; import org.springframework.http.HttpStatus; import org.springframework.security.authentication.AbstractAuthenticationToken; @@ -128,11 +128,12 @@ public final class OAuth2IntrospectionAuthenticationProvider implements Authenti } private Collection extractAuthorities(Map claims) { - Collection scopes = (Collection) claims.get(SCOPE); - return Optional.ofNullable(scopes).orElse(Collections.emptyList()) - .stream() - .map(authority -> new SimpleGrantedAuthority("SCOPE_" + authority)) - .collect(Collectors.toList()); + Collection scopes = (Collection) claims.getOrDefault(SCOPE, Collections.emptyList()); + List authorities = new ArrayList<>(); + for (String scope : scopes) { + authorities.add(new SimpleGrantedAuthority("SCOPE_" + scope)); + } + return authorities; } private static BearerTokenError invalidToken(String message) { diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/OAuth2IntrospectionReactiveAuthenticationManager.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/OAuth2IntrospectionReactiveAuthenticationManager.java index 3f76d53a29..eb7205596b 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/OAuth2IntrospectionReactiveAuthenticationManager.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/authentication/OAuth2IntrospectionReactiveAuthenticationManager.java @@ -17,11 +17,11 @@ package org.springframework.security.oauth2.server.resource.authentication; import java.time.Instant; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; import org.springframework.security.oauth2.core.OAuth2TokenAttributes; import reactor.core.publisher.Mono; @@ -108,11 +108,12 @@ public class OAuth2IntrospectionReactiveAuthenticationManager implements Reactiv } private Collection extractAuthorities(Map claims) { - Collection scopes = (Collection) claims.get(SCOPE); - return Optional.ofNullable(scopes).orElse(Collections.emptyList()) - .stream() - .map(authority -> new SimpleGrantedAuthority("SCOPE_" + authority)) - .collect(Collectors.toList()); + Collection scopes = (Collection) claims.getOrDefault(SCOPE, Collections.emptyList()); + List authorities = new ArrayList<>(); + for (String scope : scopes) { + authorities.add(new SimpleGrantedAuthority("SCOPE_" + scope)); + } + return authorities; } private static BearerTokenError invalidToken(String message) { diff --git a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusOpaqueTokenIntrospector.java b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusOpaqueTokenIntrospector.java index 3788331c4c..c870395c2b 100644 --- a/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusOpaqueTokenIntrospector.java +++ b/oauth2/oauth2-resource-server/src/main/java/org/springframework/security/oauth2/server/resource/introspection/NimbusOpaqueTokenIntrospector.java @@ -22,7 +22,6 @@ import java.time.Instant; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.stream.Collectors; import com.nimbusds.oauth2.sdk.TokenIntrospectionResponse; @@ -124,16 +123,22 @@ public class NimbusOpaqueTokenIntrospector implements OpaqueTokenIntrospector { */ @Override public Map introspect(String token) { - TokenIntrospectionSuccessResponse response = Optional.of(token) - .map(this.requestEntityConverter::convert) - .map(this::makeRequest) - .map(this::adaptToNimbusResponse) - .map(this::parseNimbusResponse) - .map(this::castToNimbusSuccess) - // relying solely on the authorization server to validate this token (not checking 'exp', for example) - .filter(TokenIntrospectionSuccessResponse::isActive) - .orElseThrow(() -> new OAuth2IntrospectionException("Provided token [" + token + "] isn't active")); - return convertClaimsSet(response); + RequestEntity requestEntity = this.requestEntityConverter.convert(token); + if (requestEntity == null) { + throw new OAuth2IntrospectionException("Provided token [" + token + "] isn't active"); + } + + ResponseEntity responseEntity = makeRequest(requestEntity); + HTTPResponse httpResponse = adaptToNimbusResponse(responseEntity); + TokenIntrospectionResponse introspectionResponse = parseNimbusResponse(httpResponse); + TokenIntrospectionSuccessResponse introspectionSuccessResponse = castToNimbusSuccess(introspectionResponse); + + // relying solely on the authorization server to validate this token (not checking 'exp', for example) + if (!introspectionSuccessResponse.isActive()) { + throw new OAuth2IntrospectionException("Provided token [" + token + "] isn't active"); + } + + return convertClaimsSet(introspectionSuccessResponse); } /** diff --git a/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java b/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java index 9ccedc8666..f1ed61ee17 100644 --- a/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java +++ b/web/src/main/java/org/springframework/security/web/server/csrf/CookieServerCsrfTokenRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ package org.springframework.security.web.server.csrf; -import java.util.Optional; import java.util.UUID; import org.springframework.http.HttpCookie; @@ -69,14 +68,17 @@ public final class CookieServerCsrfTokenRepository implements ServerCsrfTokenRep @Override public Mono saveToken(ServerWebExchange exchange, CsrfToken token) { return Mono.fromRunnable(() -> { - Optional tokenValue = Optional.ofNullable(token).map(CsrfToken::getToken); + String tokenValue = token != null ? token.getToken() : ""; + int maxAge = !tokenValue.isEmpty() ? -1 : 0; + String path = this.cookiePath != null ? this.cookiePath : getRequestContext(exchange.getRequest()); + boolean secure = exchange.getRequest().getSslInfo() != null; - ResponseCookie cookie = ResponseCookie.from(this.cookieName, tokenValue.orElse("")) + ResponseCookie cookie = ResponseCookie.from(this.cookieName, tokenValue) .domain(this.cookieDomain) .httpOnly(this.cookieHttpOnly) - .maxAge(tokenValue.map(val -> -1).orElse(0)) - .path(Optional.ofNullable(this.cookiePath).orElseGet(() -> getRequestContext(exchange.getRequest()))) - .secure(Optional.ofNullable(exchange.getRequest().getSslInfo()).map(sslInfo -> true).orElse(false)) + .maxAge(maxAge) + .path(path) + .secure(secure) .build(); exchange.getResponse().addCookie(cookie); diff --git a/web/src/main/java/org/springframework/security/web/server/transport/HttpsRedirectWebFilter.java b/web/src/main/java/org/springframework/security/web/server/transport/HttpsRedirectWebFilter.java index 99d72a22be..41080e2cbe 100644 --- a/web/src/main/java/org/springframework/security/web/server/transport/HttpsRedirectWebFilter.java +++ b/web/src/main/java/org/springframework/security/web/server/transport/HttpsRedirectWebFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,7 +17,6 @@ package org.springframework.security.web.server.transport; import java.net.URI; -import java.util.Optional; import reactor.core.publisher.Mono; @@ -102,10 +101,11 @@ public final class HttpsRedirectWebFilter implements WebFilter { UriComponentsBuilder.fromUri(exchange.getRequest().getURI()); if (port > 0) { - Optional.ofNullable(this.portMapper.lookupHttpsPort(port)) - .map(builder::port) - .orElseThrow(() -> new IllegalStateException( - "HTTP Port '" + port + "' does not have a corresponding HTTPS Port")); + Integer httpsPort = this.portMapper.lookupHttpsPort(port); + if (httpsPort == null) { + throw new IllegalStateException("HTTP Port '" + port + "' does not have a corresponding HTTPS Port"); + } + builder.port(httpsPort); } return builder.scheme("https").build().toUri();