2015-01-13 18 views
5

La mia applicazione fornisce OAuth2 servizio token identica a questa condizione nel seguente progetto github: https://github.com/iainporter/oauth2-providerPrimavera Secuirty OAuth 2 - molteplici servizi di autenticazione di utenti

Si basa sulla Primavera di sicurezza OAuth2.

ho fornito la mia implementazione personalizzata di UserDetailsService:

<bean id="userService" class="org.example.core.service.DBUserServiceImpl" /> 

e il seguente gestore di autenticazione utente:

<sec:authentication-manager alias="userAuthenticationManager"> 
    <sec:authentication-provider user-service-ref="userService"> 
     <sec:password-encoder ref="passwordEncoder" /> 
    </sec:authentication-provider> 
</sec:authentication-manager> 

Ora vorrei fornire altri metodi di autenticazione degli utenti (diversi UserDetailsService), per esempio:

<bean id="otherUserService" class="org.example.core.service.LDAPUserServiceImpl" /> 

Sfortunatamente I di non trovi un modo come farlo nella documentazione. Al livello di richiesta Vorrei distinguere quale metodo (quale servizio utente) da utilizzare per uno:

  • parametro di query
  • intestazione http (ad esempio RealmName)

risposta

5

È necessario utilizzare DelegatingAuthenticationEntryPoint per configurare più punti di ingresso. Ciò significa che puoi avere diversi modi di autenticarsi. Di seguito è riportato il codice di esempio:

dbuser punto di ingresso:

public class DBUserAuthencticationEntryPoint extends BasicAuthenticationEntryPoint { 

    @Override 
    public void commence(HttpServletRequest request, 
      HttpServletResponse response, AuthenticationException authException) 
      throws IOException, ServletException { 
     super.commence(request, response, authException); 
    } 
} 

LDAP punto di ingresso:

public class LDAPAuthencticationEntryPoint extends BasicAuthenticationEntryPoint { 

    @Override 
    public void commence(HttpServletRequest request, 
      HttpServletResponse response, AuthenticationException authException) 
      throws IOException, ServletException { 
     super.commence(request, response, authException); 
    } 
} 

Poi è necessario creare RequestMatcher s di scegliere il punto di ingresso corretta (in base al nome dell'intestazione/regno):

dbuser richiesta matcher:

RequestMatcher dbUserMatcher = new RequestMatcher() {  
    @Override 
    public boolean matches(HttpServletRequest request) { 
     // Logic to identify a DBUser kind of reqeust 
    } 
}; 

LDAP utente requset matcher:

RequestMatcher ldapMatcher = new RequestMatcher() {  
    @Override 
    public boolean matches(HttpServletRequest request) { 
     // Logic to identify a LDAP kind of reqeust 
    } 
}; 

Ora abbiamo bisogno di aggiungere queste matchers e punti di ingresso per DelegatingAuthenticationEntryPoint. In runtime DelegatingAuthenticationEntryPoint preleva il punto di ingresso e fa l'autenticazione basata sul matcher che restituisce true.

DBUserAuthencticationEntryPoint dbUserEntryPoint = new DBUserAuthencticationEntryPoint(); 
LDAPAuthencticationEntryPoint ldapEntryPoint = new LDAPAuthencticationEntryPoint(); 

LinkedHashMap<RequestMatcher,AuthenticationEntryPoint> entryPoints = new LinkedHashMap<RequestMatcher,AuthenticationEntryPoint>(); 
entryPoints.put(ldapMatcher, ldapEntryPoint); 
entryPoints.put(dbUserMatcher, dbUserEntryPoint); 

DelegatingAuthenticationEntryPoint delegatingAuthenticationEntryPoint = new DelegatingAuthenticationEntryPoint(entryPoints); 

ora Mappa del DelegatingAuthenticationEntryPoint al HttpSecurity nel metodo configure():

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http. 
      authorizeRequests(). 
       regexMatchers("/login.*").permitAll(). 
       regexMatchers("/api.*").fullyAuthenticated().   
     and(). 
      formLogin().loginPage("/login"). 
     and(). 
      exceptionHandling().authenticationEntryPoint(delegatingAuthenticationEntryPoint); 
    } 
} 

Configurazione del gestore fornitore:

@Bean 
public AuthenticationManager authenticationManager() { 
    return new ProviderManager(Arrays.asList(provider1, provider2); 
} 
+0

OK, questo sarà lavoro se riesco a reindirizzare alle mie pagine di autenticazione personalizzate (ad esempio, a seconda dell'intestazione HTTP RealmName). Purtroppo non fornisco pagine di autenticazione, ma solo API OAuth. Quindi, quando arriva la richiesta, devo scegliere il provider di autenticazione appropriato basandosi sull'intestazione RealmName e autenticarsi utilizzando le credenziali dall'intestazione http di autorizzazione. – Konrad

+0

No, funzionerà con qualsiasi tipo di processo di autenticazione. Ho appena effettuato il login basato sulla forma per scopi dimostrativi. Rimuovere il codice di accesso basato su modulo e impostare il provider di autenticazione chiamando 'http.authenticationProvider (authenticationProvider)' – Mithun

+0

OK, ma poi mi piacerebbe utilizzare il flusso Oauth standard e dire org.springframework.security.authentication.ProviderManager al gestore di autenticazione specifico dell'utente . Non riesco a farlo dal punto di ingresso dell'autenticazione. – Konrad

2

ho trovato soluzione diversa rispetto alla soluzione fornita da Mithun.

contesto di applicazione contiene User Manager autenticazione avviata con diversi provider di autenticazione:

<sec:authentication-manager alias="userAuthenticationManager"> 
    <sec:authentication-provider ref="customerAuthProvider" /> 
    <sec:authentication-provider ref="adminAuthProvider" /> 
</sec:authentication-manager> 

dove customerAuthProvider e adminAuthProvider sono estensioni di DaoAuthenticationProvider con diversi UserDetails Servizio:

<bean id="customerAuthProvider" class="org.example.security.authentication.provider.CustomerAuthenticationProvider"> 
    <property name="userDetailsService" ref="userService" /> 
    <property name="passwordEncoder" ref="passwordEncoder" /> 
</bean> 

<bean id="adminAuthProvider" class="org.example.security.authentication.provider.AdminAuthenticationProvider"> 
    <property name="userDetailsService" ref="otherUserService" /> 
</bean> 

Tutto quello che dovete fare è quello di sovrascrivi il metodo "supporta" che indica se il provider di autenticazione corrente è in grado di gestire un'autenticazione specifica:

public class CustomerAuthenticationProvider extends DaoAuthenticationProvider { 

    @Override 
    public boolean supports (Class<?> authentication) { 
     return CustomerUsernamePasswordAuthenticationToken.isAssignableFrom(authentication); 
    } 
} 

public class AdminAuthenticationProvider extends DaoAuthenticationProvider { 

    @Override 
    public boolean supports (Class<?> authentication) { 
     return AdminUsernamePasswordAuthenticationToken.isAssignableFrom(authentication); 
    } 
} 

Alla fine è necessario estendere token granter. Nel mio caso ho esteso ResourceOwnerPasswordTokenGranter il che significa che supporta la "password" concessione:

<oauth:authorization-server client-details-service-ref="client-details-service" token-services-ref="tokenServices"> 
    <oauth:refresh-token/> 
    <oauth:custom-grant token-granter-ref="customPasswordTokenGranter"/> 
</oauth:authorization-server> 

È possibile utilizzare TokenRequest oggetto di distinguere quale classe di autenticazione istanziare (AdminUsernamePasswordAuthenticationToken o CustomerUsernamePasswordAuthenticationToken)

public class CustomResourceOwnerPasswordTokenGranter extends ResourceOwnerPasswordTokenGranter { 

    protected OAuth2Authentication getOAuth2Authentication (ClientDetails client, TokenRequest tokenRequest) { 
     Map parameters = tokenRequest.getRequestParameters(); 
     String username = (String) parameters.get("username"); 
     String password = (String) parameters.get("password"); 

     String realmName = (String) parameters.get("realm_name"); 

     Authentication userAuth = createAuthentication(username, password, realmName); 
     try { 
      userAuth = this.authenticationManager.authenticate(userAuth); 
     } catch (AccountStatusException ase) { 
      throw new InvalidGrantException(ase.getMessage()); 
     } catch (BadCredentialsException e) { 
      throw new InvalidGrantException(e.getMessage()); 
     } 
     if ((userAuth == null) || (! (userAuth.isAuthenticated()))) { 
      throw new InvalidGrantException("Could not authenticate user: " + username); 
     } 

     OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest); 
     return new OAuth2Authentication(storedOAuth2Request, userAuth); 
    } 

    private Authentication createAuthentication (String username, String password, String realmName) throws InvalidGrantException { 
     // TODO: decide basing on realm name 
    } 
} 
Problemi correlati