Single Sign-On semplice con Spring Security OAuth2 (stack legacy)

1. Panoramica

In questo tutorial, discuteremo come implementare SSO - Single Sign On - utilizzando Spring Security OAuth e Spring Boot.

Useremo tre applicazioni separate:

  • Un server di autorizzazione, che è il meccanismo di autenticazione centrale
  • Due applicazioni client: le applicazioni che utilizzano SSO

In poche parole, quando un utente tenta di accedere a una pagina protetta nell'app client, verrà reindirizzato per l'autenticazione prima, tramite il server di autenticazione.

E useremo il tipo di concessione del codice di autorizzazione fuori da OAuth2 per guidare la delega dell'autenticazione.

Nota : questo articolo utilizza il progetto legacy Spring OAuth. Per la versione di questo articolo che utilizza il nuovo stack Spring Security 5, dai un'occhiata al nostro articolo Single Sign-On semplice con Spring Security OAuth2.

2. L'applicazione client

Cominciamo con la nostra applicazione client; ovviamente useremo Spring Boot per ridurre al minimo la configurazione:

2.1. Dipendenze di Maven

Innanzitutto, avremo bisogno delle seguenti dipendenze nel nostro pom.xml :

 org.springframework.boot spring-boot-starter-web   org.springframework.boot spring-boot-starter-security   org.springframework.security.oauth.boot spring-security-oauth2-autoconfigure 2.0.1.RELEASE   org.springframework.boot spring-boot-starter-thymeleaf   org.thymeleaf.extras thymeleaf-extras-springsecurity4 

2.2. Configurazione della protezione

Successivamente, la parte più importante, la configurazione della sicurezza della nostra applicazione client:

@Configuration @EnableOAuth2Sso public class UiSecurityConfig extends WebSecurityConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http.antMatcher("/**") .authorizeRequests() .antMatchers("/", "/login**") .permitAll() .anyRequest() .authenticated(); } }

La parte centrale di questa configurazione è, ovviamente, l' annotazione @ EnableOAuth2Sso che stiamo utilizzando per abilitare Single Sign On.

Si noti che è necessario estendere WebSecurityConfigurerAdapter - senza di esso, tutti i percorsi saranno protetti - in modo che gli utenti vengano reindirizzati all'accesso quando tentano di accedere a qualsiasi pagina. Nel nostro caso qui, l'indice e le pagine di accesso sono le uniche pagine a cui è possibile accedere senza autenticazione.

Infine, abbiamo anche definito un bean RequestContextListener per gestire gli ambiti delle richieste.

E application.yml :

server: port: 8082 servlet: context-path: /ui session: cookie: name: UISESSION security: basic: enabled: false oauth2: client: clientId: SampleClientId clientSecret: secret accessTokenUri: //localhost:8081/auth/oauth/token userAuthorizationUri: //localhost:8081/auth/oauth/authorize resource: userInfoUri: //localhost:8081/auth/user/me spring: thymeleaf: cache: false

Alcune brevi note:

  • abbiamo disabilitato l'autenticazione di base predefinita
  • accessTokenUri è l'URI per ottenere i token di accesso
  • userAuthorizationUri è l'URI di autorizzazione a cui verranno reindirizzati gli utenti
  • userInfoUri l'URI dell'endpoint utente per ottenere i dettagli dell'utente corrente

Si noti inoltre che, nel nostro esempio qui, abbiamo implementato il nostro server di autorizzazione, ma ovviamente possiamo anche utilizzare altri provider di terze parti come Facebook o GitHub.

2.3. Fine frontale

Ora, diamo un'occhiata alla configurazione front-end della nostra applicazione client. Non ci concentreremo su questo qui, principalmente perché ne abbiamo già parlato sul sito.

La nostra applicazione client qui ha un front-end molto semplice; ecco l' indice.html :

 Login

E il securedPage.html :

 Welcome, Name

La pagina securedPage.html richiedeva l'autenticazione degli utenti. Se un utente non autenticato tenta di accedere a securedPage.html , verrà prima reindirizzato alla pagina di accesso.

3. L'Auth Server

Ora parliamo del nostro server di autorizzazione qui.

3.1. Dipendenze di Maven

Per prima cosa, dobbiamo definire le dipendenze nel nostro pom.xml :

 org.springframework.boot spring-boot-starter-web   org.springframework.security.oauth spring-security-oauth2 2.3.3.RELEASE 

3.2. Configurazione OAuth

È importante capire che qui eseguiremo insieme il server di autorizzazione e il server di risorse, come un'unica unità distribuibile.

Cominciamo con la configurazione del nostro Resource Server, che funge anche da applicazione di avvio principale:

@SpringBootApplication @EnableResourceServer public class AuthorizationServerApplication extends SpringBootServletInitializer { public static void main(String[] args) { SpringApplication.run(AuthorizationServerApplication.class, args); } }

Quindi, configureremo il nostro server di autorizzazione:

@Configuration @EnableAuthorizationServer public class AuthServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private BCryptPasswordEncoder passwordEncoder; @Override public void configure( AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.tokenKeyAccess("permitAll()") .checkTokenAccess("isAuthenticated()"); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("SampleClientId") .secret(passwordEncoder.encode("secret")) .authorizedGrantTypes("authorization_code") .scopes("user_info") .autoApprove(true) .redirectUris( "//localhost:8082/ui/login","//localhost:8083/ui2/login"); } }

Si noti come stiamo solo consentendo un semplice client utilizzando l'authorization_code tipo di sovvenzione.

Inoltre, nota come autoApprove è impostato su true in modo da non essere reindirizzati e promossi per approvare manualmente gli ambiti.

3.3. Configurazione della protezione

Innanzitutto, disabiliteremo l'autenticazione di base predefinita, tramite la nostra application.properties :

server.port=8081 server.servlet.context-path=/auth

Passiamo ora alla configurazione e definiamo un semplice meccanismo di login del form:

@Configuration @Order(1) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.requestMatchers() .antMatchers("/login", "/oauth/authorize") .and() .authorizeRequests() .anyRequest().authenticated() .and() .formLogin().permitAll(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("john") .password(passwordEncoder().encode("123")) .roles("USER"); } @Bean public BCryptPasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } }

Si noti che abbiamo utilizzato una semplice autenticazione in memoria, ma possiamo semplicemente sostituirla con un userDetailsService personalizzato .

3.4. Endpoint utente

Infine, creeremo il nostro endpoint utente che abbiamo utilizzato in precedenza nella nostra configurazione:

@RestController public class UserController { @GetMapping("/user/me") public Principal user(Principal principal) { return principal; } }

Naturalmente, questo restituirà i dati dell'utente con una rappresentazione JSON.

4. Conclusione

In questo breve tutorial, ci siamo concentrati sull'implementazione del Single Sign-On utilizzando Spring Security Oauth2 e Spring Boot.

Come sempre, il codice sorgente completo può essere trovato su GitHub.