Browse Source

Simplified federated login in demo sample

Closes gh-1208
pull/1212/head
Joe Grandja 3 years ago
parent
commit
5f606ae757
  1. 13
      docs/src/docs/asciidoc/guides/how-to-social-login.adoc
  2. 14
      samples/demo-authorizationserver/src/main/java/sample/config/DefaultSecurityConfig.java
  3. 86
      samples/demo-authorizationserver/src/main/java/sample/federation/FederatedIdentityAuthenticationEntryPoint.java
  4. 53
      samples/demo-authorizationserver/src/main/java/sample/federation/FederatedIdentityConfigurer.java

13
docs/src/docs/asciidoc/guides/how-to-social-login.adoc

@ -121,23 +121,10 @@ If you configured a `UserDetailsService` when xref:{docs-dir}/getting-started.ad @@ -121,23 +121,10 @@ If you configured a `UserDetailsService` when xref:{docs-dir}/getting-started.ad
The https://github.com/spring-projects/spring-authorization-server/tree/{github-ref}/samples#demo-sample[demo authorization server sample^] demonstrates advanced configuration options for federating identity providers.
Select from the following use cases to see an example of each:
* I want to <<advanced-use-cases-automatically-redirect>>
* I want to <<advanced-use-cases-capture-users>>
* I want to <<advanced-use-cases-map-claims>>
* I want to <<advanced-use-cases-configurer>>
[[advanced-use-cases-automatically-redirect]]
=== Automatically Redirect to a Provider
The following example `AuthenticationEntryPoint` uses a query parameter as a hint from the client to indicate which provider to automatically redirect to for authentication.
For example, assuming Google is configured as a social login provider with a `registrationId` of `google`, a request to `/oauth2/authorize?idp=google&...` will redirect an unauthenticated user to `/oauth2/authorization/google` which will initiate logging in with Google:
.`FederatedIdentityAuthenticationEntryPoint`
[source,java]
----
include::{samples-dir}/demo-authorizationserver/src/main/java/sample/federation/FederatedIdentityAuthenticationEntryPoint.java[tags=imports;class]
----
[[advanced-use-cases-capture-users]]
=== Capture Users in a Database

14
samples/demo-authorizationserver/src/main/java/sample/config/DefaultSecurityConfig.java

@ -15,9 +15,6 @@ @@ -15,9 +15,6 @@
*/
package sample.config;
import sample.federation.FederatedIdentityConfigurer;
import sample.federation.UserRepositoryOAuth2UserHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@ -31,8 +28,6 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager; @@ -31,8 +28,6 @@ import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.session.HttpSessionEventPublisher;
import static org.springframework.security.config.Customizer.withDefaults;
/**
* @author Joe Grandja
* @author Steve Riesenberg
@ -45,17 +40,16 @@ public class DefaultSecurityConfig { @@ -45,17 +40,16 @@ public class DefaultSecurityConfig {
// @formatter:off
@Bean
public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {
FederatedIdentityConfigurer federatedIdentityConfigurer = new FederatedIdentityConfigurer()
.oauth2UserHandler(new UserRepositoryOAuth2UserHandler());
http
.authorizeHttpRequests(authorize ->
authorize
.requestMatchers("/assets/**", "/webjars/**", "/login").permitAll()
.anyRequest().authenticated()
)
.formLogin(withDefaults())
.apply(federatedIdentityConfigurer);
.formLogin(formLogin ->
formLogin.loginPage("/login")
);
return http.build();
}
// @formatter:on

86
samples/demo-authorizationserver/src/main/java/sample/federation/FederatedIdentityAuthenticationEntryPoint.java

@ -1,86 +0,0 @@ @@ -1,86 +0,0 @@
/*
* Copyright 2020-2023 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sample.federation;
// tag::imports[]
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.client.registration.ClientRegistration;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.RedirectStrategy;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.web.util.UriComponentsBuilder;
// end::imports[]
/**
* An {@link AuthenticationEntryPoint} for initiating the login flow to an
* external provider using the {@code idp} query parameter, which represents the
* {@code registrationId} of the desired {@link ClientRegistration}.
*
* @author Steve Riesenberg
* @since 1.1
*/
// tag::class[]
public final class FederatedIdentityAuthenticationEntryPoint implements AuthenticationEntryPoint {
private final RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
private String authorizationRequestUri = OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI
+ "/{registrationId}";
private final AuthenticationEntryPoint delegate;
private final ClientRegistrationRepository clientRegistrationRepository;
public FederatedIdentityAuthenticationEntryPoint(String loginPageUrl, ClientRegistrationRepository clientRegistrationRepository) {
this.delegate = new LoginUrlAuthenticationEntryPoint(loginPageUrl);
this.clientRegistrationRepository = clientRegistrationRepository;
}
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
String idp = request.getParameter("idp");
if (idp != null) {
ClientRegistration clientRegistration = this.clientRegistrationRepository.findByRegistrationId(idp);
if (clientRegistration != null) {
String redirectUri = UriComponentsBuilder.fromHttpRequest(new ServletServerHttpRequest(request))
.replaceQuery(null)
.replacePath(this.authorizationRequestUri)
.buildAndExpand(clientRegistration.getRegistrationId())
.toUriString();
this.redirectStrategy.sendRedirect(request, response, redirectUri);
return;
}
}
this.delegate.commence(request, response, authenticationException);
}
public void setAuthorizationRequestUri(String authorizationRequestUri) {
this.authorizationRequestUri = authorizationRequestUri;
}
}
// end::class[]

53
samples/demo-authorizationserver/src/main/java/sample/federation/FederatedIdentityConfigurer.java

@ -16,12 +16,11 @@ @@ -16,12 +16,11 @@
package sample.federation;
// tag::imports[]
import java.util.function.Consumer;
import org.springframework.context.ApplicationContext;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
import org.springframework.security.oauth2.core.user.OAuth2User;
import org.springframework.util.Assert;
@ -36,36 +35,10 @@ import org.springframework.util.Assert; @@ -36,36 +35,10 @@ import org.springframework.util.Assert;
// tag::class[]
public final class FederatedIdentityConfigurer extends AbstractHttpConfigurer<FederatedIdentityConfigurer, HttpSecurity> {
private String loginPageUrl = "/login";
private String authorizationRequestUri;
private Consumer<OAuth2User> oauth2UserHandler;
private Consumer<OidcUser> oidcUserHandler;
/**
* @param loginPageUrl The URL of the login page, defaults to {@code "/login"}
* @return This configurer for additional configuration
*/
public FederatedIdentityConfigurer loginPageUrl(String loginPageUrl) {
Assert.hasText(loginPageUrl, "loginPageUrl cannot be empty");
this.loginPageUrl = loginPageUrl;
return this;
}
/**
* @param authorizationRequestUri The authorization request URI for initiating
* the login flow with an external IDP, defaults to {@code
* "/oauth2/authorization/{registrationId}"}
* @return This configurer for additional configuration
*/
public FederatedIdentityConfigurer authorizationRequestUri(String authorizationRequestUri) {
Assert.hasText(authorizationRequestUri, "authorizationRequestUri cannot be empty");
this.authorizationRequestUri = authorizationRequestUri;
return this;
}
/**
* @param oauth2UserHandler The {@link Consumer} for performing JIT account provisioning
* with an OAuth 2.0 IDP
@ -91,15 +64,6 @@ public final class FederatedIdentityConfigurer extends AbstractHttpConfigurer<Fe @@ -91,15 +64,6 @@ public final class FederatedIdentityConfigurer extends AbstractHttpConfigurer<Fe
// @formatter:off
@Override
public void init(HttpSecurity http) throws Exception {
ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);
ClientRegistrationRepository clientRegistrationRepository =
applicationContext.getBean(ClientRegistrationRepository.class);
FederatedIdentityAuthenticationEntryPoint authenticationEntryPoint =
new FederatedIdentityAuthenticationEntryPoint(this.loginPageUrl, clientRegistrationRepository);
if (this.authorizationRequestUri != null) {
authenticationEntryPoint.setAuthorizationRequestUri(this.authorizationRequestUri);
}
FederatedIdentityAuthenticationSuccessHandler authenticationSuccessHandler =
new FederatedIdentityAuthenticationSuccessHandler();
if (this.oauth2UserHandler != null) {
@ -110,18 +74,9 @@ public final class FederatedIdentityConfigurer extends AbstractHttpConfigurer<Fe @@ -110,18 +74,9 @@ public final class FederatedIdentityConfigurer extends AbstractHttpConfigurer<Fe
}
http
.exceptionHandling(exceptionHandling ->
exceptionHandling.authenticationEntryPoint(authenticationEntryPoint)
)
.oauth2Login(oauth2Login -> {
oauth2Login.successHandler(authenticationSuccessHandler);
if (this.authorizationRequestUri != null) {
String baseUri = this.authorizationRequestUri.replace("/{registrationId}", "");
oauth2Login.authorizationEndpoint(authorizationEndpoint ->
authorizationEndpoint.baseUri(baseUri)
);
}
});
.oauth2Login(oauth2Login ->
oauth2Login.successHandler(authenticationSuccessHandler)
);
}
// @formatter:on

Loading…
Cancel
Save