27

Sto lavorando con un'applicazione Spring Boot + Spring Security OAuth2 che credo sia stata ispirata da esempi di Dave Syer. L'applicazione è configurata per essere un server di autorizzazione OAuth2, con un singolo client pubblico che utilizza il flusso di credenziali della password del proprietario della risorsa. Un token di successo è configurato per essere un JWT.Integrazione Spring Security OAuth2 e Spring Social

Il client Angular pubblico invia una richiesta POST a/oauth/token con un'intestazione di autorizzazione di base contenente l'ID client e il segreto (questo era il modo più semplice per ottenere l'autenticazione del client, anche se il segreto non è privato). Il corpo della richiesta contiene nome utente, password e tipo di concessione "password".

Oltre ad essere un server di autenticazione, l'applicazione è un server di risorse RESTful per utenti, team e organizzazioni.

Sto tentando di aggiungere un flusso di autenticazione SSO aggiuntivo utilizzando Spring Social. Ho configurato Spring Social per l'autenticazione tramite provider esterni tramite/auth/[provider]; tuttavia, le seguenti richieste non hanno più impostato correttamente SecurityContext. Forse, il server o il client OAuth di Spring Security sta eseguendo l'override di SecurityContext?

Se riesco a impostare correttamente SecurityContext dopo il flusso Spring Social, ho un nuovo TokenGranter che consente un nuovo tipo di concessione "social" che controlla SecurityContextHolder per l'utente pre-autenticato.

Sono interessato sia a una soluzione al mio problema specifico con SecurityContext (credo che sia un problema con Spring OAuth + Social integration), sia a un approccio diverso per l'autenticazione con provider esterni e ottenere un JWT valido dal nostro server di autenticazione.

Grazie!

+0

Ti capita di avere un codice che puoi condividere? Quello che stai descrivendo è un po 'una sfida da impostare, quindi potremmo trovare una risposta per te più velocemente se ci fosse un codice pronto per iniziare con noi invece di costruire un esempio del genere da soli . –

risposta

3

Per prima cosa, ti consiglio vivamente di allontanarti dalla concessione di password per tale caso d'uso.
I client pubblici (JavaScript, applicazioni installate) non possono mantenere riservato il segreto del cliente, ecco perché NON DEVE essere assegnato a nessuno: ogni visitatore che ispeziona il codice JavaScript può scoprire il segreto e quindi implementare la stessa pagina di autenticazione che hai, memorizzando i tuoi utenti password nel processo.

La concessione implicita è stata creata esattamente per ciò che si sta facendo.
L'utilizzo di un flusso basato sul reindirizzamento ha il vantaggio di lasciare il meccanismo di autenticazione fino al server di autorizzazione, invece di avere ciascuna delle sue applicazioni un pezzo di esso: è principalmente la definizione di Single Sign On (SSO).

Detto questo, la sua domanda è strettamente legata a questo quello che ho appena risposto: Own Spring OAuth2 server together with 3rdparty OAuth providers

Per riassumere la risposta:

Alla fine, si tratta di come il vostro server di autorizzazione mantiene i AuthorizationEndpoint :/oauth/autorizza. Poiché il tuo server di autorizzazione funziona, hai già una classe di configurazione che estende WebSecurityConfigurerAdapter che gestisce la sicurezza per/oauth/authorize con formLogin. È lì che devi integrare le cose sociali.

Semplicemente non è possibile utilizzare una concessione di password per ciò che si sta tentando di ottenere, è necessario che il client pubblico reindirizzi al server di autorizzazione.Il server di autorizzazione verrà quindi reindirizzato al login sociale come meccanismo di sicurezza per l'endpoint /oauth/authorize.

+1

Voglio partecipare a questa conversazione. Mi sono perso. Ho anche un server di autenticazione personalizzato separato ma non capisco come "integrare lo staff sociale" nel mio WebSecurityConfigurerAdapter. Sto pensando di autenticarmi con la piattaforma social e di scambiare questo token per il mio JWT nella fase post authenricate. Grazie! – maret

+0

@maret sei riuscito a trovare la risorsa giusta che spiega questo in dettaglio? – zalis

+0

@zalis Ho deciso di utilizzare Spring OAuth2 con l'ulteriore aiuto di una logica client, che ottiene il token social e lo scambio per il mio token JWT con il mio server di autenticazione. Ma questa soluzione richiede di avere qualche lato server per il tuo cliente. Non so se sarà di aiuto, ma qui ho risposto alla mia domanda (scusa per la formattazione, non so come risolverlo): http: //stackoverflow.com/questions/41578040/spring-oauth2-support -auth-and-resource-access-with-sso-and-custom-auth-se – maret

8

Ho avuto un problema simile su un'applicazione Web generata da JHipster. Alla fine ho deciso di andare con l'opzione SocialAuthenticationFilter da Spring Social (tramite il SpringSocialConfigurer). Dopo un accesso social di successo, il server genera e restituisce automaticamente il "proprio" token di accesso tramite reindirizzamento all'app client.

Ecco la mia prova:

@Configuration 
@EnableResourceServer 
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter implements EnvironmentAware { 

    //... 

    @Inject 
    private AuthorizationServerTokenServices authTokenServices; 

    @Override 
    public void configure(HttpSecurity http) throws Exception { 

     SpringSocialConfigurer socialCfg = new SpringSocialConfigurer(); 
     socialCfg 
      .addObjectPostProcessor(new ObjectPostProcessor<SocialAuthenticationFilter>() { 
       @SuppressWarnings("unchecked") 
       public SocialAuthenticationFilter postProcess(SocialAuthenticationFilter filter){ 
        filter.setAuthenticationSuccessHandler(
          new SocialAuthenticationSuccessHandler(
            authTokenServices, 
            YOUR_APP_CLIENT_ID 
          ) 
         ); 
        return filter; 
       } 
      }); 

     http 
      //... lots of other configuration ... 
      .apply(socialCfg); 
    }   
} 

E la classe SocialAuthenticationSuccessHandler:

public class SocialAuthenticationSuccessHandler implements AuthenticationSuccessHandler { 

    public static final String REDIRECT_PATH_BASE = "/#/login"; 
    public static final String FIELD_TOKEN = "access_token"; 
    public static final String FIELD_EXPIRATION_SECS = "expires_in"; 

    private final Logger log = LoggerFactory.getLogger(getClass()); 
    private final AuthorizationServerTokenServices authTokenServices; 
    private final String localClientId; 

    public SocialAuthenticationSuccessHandler(AuthorizationServerTokenServices authTokenServices, String localClientId){ 
     this.authTokenServices = authTokenServices; 
     this.localClientId = localClientId; 
    } 

    @Override 
    public void onAuthenticationSuccess(HttpServletRequest request, 
      HttpServletResponse response, Authentication authentication) 
        throws IOException, ServletException { 
     log.debug("Social user authenticated: " + authentication.getPrincipal() + ", generating and sending local auth"); 
     OAuth2AccessToken oauth2Token = authTokenServices.createAccessToken(convertAuthentication(authentication)); //Automatically checks validity 
     String redirectUrl = new StringBuilder(REDIRECT_PATH_BASE) 
      .append("?").append(FIELD_TOKEN).append("=") 
      .append(encode(oauth2Token.getValue())) 
      .append("&").append(FIELD_EXPIRATION_SECS).append("=") 
      .append(oauth2Token.getExpiresIn()) 
      .toString(); 
     log.debug("Sending redirection to " + redirectUrl); 
     response.sendRedirect(redirectUrl); 
    } 

    private OAuth2Authentication convertAuthentication(Authentication authentication) { 
     OAuth2Request request = new OAuth2Request(null, localClientId, null, true, null, 
       null, null, null, null); 
     return new OAuth2Authentication(request, 
       //Other option: new UsernamePasswordAuthenticationToken(authentication.getPrincipal(), "N/A", authorities) 
       new PreAuthenticatedAuthenticationToken(authentication.getPrincipal(), "N/A") 
       ); 
    } 

    private String encode(String in){ 
     String res = in; 
     try { 
      res = UriUtils.encode(in, GeneralConstants.ENCODING_UTF8); 
     } catch(UnsupportedEncodingException e){ 
      log.error("ERROR: unsupported encoding: " + GeneralConstants.ENCODING_UTF8, e); 
     } 
     return res; 
    } 
} 

In questo modo il vostro cliente app riceverà token di accesso il vostro web app tramite redirezione alla /#/login?access_token=my_access_token&expires_in=seconds_to_expiration, fino a quando si imposta la corrispondente REDIRECT_PATH_BASE in SocialAuthenticationSuccessHandler.

Spero che aiuti.

+0

Che cos'è esattamente "YOUR_APP_CLIENT_ID"? Qual è la statica 'GeneralConstants.ENCODING_UTF8'? –

+0

'stringa finale statica pubblica ENCODING_UTF8 =" UTF-8 "'. – rbarriuso

+0

Sono riuscito a far partire la mia app dopo aver aggiunto i bean per 'UsersConnectionRepository',' SocialAuthenticationServiceLocator' e 'SocialUserDetailsService'. Ho anche dovuto aggiungere un cast nel metodo 'apply' in questo modo:' .and(). Apply ((SecurityConfigurer ) socialCfg) '. Ma come lo usi ora da HTML? –

0

Ho implementato la primavera oauth2 per proteggere i miei servizi di resto e aggiungere inoltre accesso social e registrazione implicita per il primo accesso. per utente utente è possibile generare il token utilizzando il nome utente e la password solo problema con generare il token per utente sociale. per questo devi implementare il Filtro che intercetterà la tua richiesta/oauth/token prima dell'elaborazione. qui se vuoi generare il token per l'utente social passa il nome utente e il token facebook, qui puoi usare il token facebook come password e generare il token per l'utente di facebook anche. se il token di Facebook è aggiornato, devi anche scrivere un trigger db per aggiornare il tuo token nella tabella utente .... potrebbe essere che ti aiuterà

Problemi correlati