2013-08-15 16 views
5

Stiamo utilizzando le credenziali di risorse-proprietario rilascio (con oauth2:password in security-config.xml Giochiamo fuori questo scenario per spiegare la mia situazione:.Utilizzando Spring Security OAuth2, qual è il modo giusto per aggiornare l'autenticazione memorizzata nel TokenStore?

  1. Bob è stato creato con le autorità ROLE_USER
  2. Bob cerca di accedere a un OAuth2 protetta risorsa
  3. Bob utilizza l'applicazione mobile ufficiale per accedervi, in modo che le credenziali del client siano corrette
  4. token di accesso di Bob viene creato e memorizzato nel TokenStore, digitato sul suo username, client_id e scope. (vedi DefaultAuthenticationKeyGenerator.java)
  5. Il telefono di Bob tenta di chiamare i servizi protetti con questo token di accesso, ma tali servizi richiedono agli utenti di disporre di un authorityROLE_MOBILE_USER.
  6. Bob contatta il proprietario db e ha aggiunto ROLE_MOBLE_USER al suo utente nel database.
  7. Bob tenta di ottenere un altro token di accesso, ma lo DefaultTokenServices restituisce lo stesso token di accesso non funzionante.
  8. L'unico modo per sfruttare il suo nuovo authority è attendere fino a quando il suo vecchio token di accesso scade, in modo che possa ottenere un nuovo token di accesso con il authority corretto.

Ci sono diversi modi per risolvere questo problema.

Per uno, l'app di amministrazione che aggiunge ROLE_MOBILE_USER alle autorità di Bob potrebbe quindi cancellare tutti i token di accesso e le autorizzazioni nel database. In questo modo lo DefaultTokenServices ne creerà solo uno nuovo con le autorizzazioni corrette serializzate come la sua nuova OAuth2Authentication. Tuttavia, potremmo non volere che la webapp di amministrazione riguardi OAuth a questo punto (almeno non ancora). Se possibile, vorremmo mantenere le preoccupazioni delle app di amministrazione il più concisa possibile, e al momento non ci sono dipendenze da oauth.

Ci potrebbe esporre il metodo DELETE al /oauth/access_token endpoint e dire l'applicazione mobile per provare a cancellare quel token di accesso e ri-richiesta di uno, nel caso in cui la stored authorities sono stantio. Questo sembra più un work-around però.

Infine, è possibile serializzare lo authorities nel proprio numero definito AuthenticationKeyGenerator. In pratica, utilizza lo username, client_id, scope e authorities dell'autorizzazione ed esegue lo stesso algoritmo di digest su di essi. In questo modo, quando Bob tenta di accedere, otterrà lo stesso token di accesso, ma l'archivio di token sottostante riconoscerà che ha un'autenticazione diversa (dal gestore di autenticazione nel token granter bean) e aggiorna il suo database. Il problema che ho con questa soluzione è che si basa semplicemente sul comportamento di implementazione dell'archivio dei token sottostante (sebbene sia il InMemoryTokenStore sia lo JdbcTokenStore si comportino in questo modo).

Riesci a pensare a soluzioni migliori/più pulite? Sto pensando troppo a questo?

Grazie in anticipo.

+0

aggiungo che a questo punto usato il 'AuthenticationKeyGenerator' personalizzato e le cose funzionavano correttamente. Desidero ancora una soluzione migliore/più pulita, poiché la chiave viene controllata solo quando al server di autorizzazione viene richiesto un nuovo token, ma il server delle risorse potrebbe ancora utilizzare le vecchie autorizzazioni. – Joe

+0

Ti stai ancora aggrappando a questa soluzione o hai trovato un modo migliore per affrontare il problema? Ho esattamente lo stesso problema adesso e non sono sicuro di come affrontarlo. – rpvilao

+0

Siamo rimasti fedeli a questa soluzione e finora non abbiamo riscontrato problemi. Raccomanderei comunque la prima soluzione e accetto che la modifica dell'autorizzazione di un utente richieda di toccare il database dei token oauth. – Joe

risposta

2

Ho risolto questo problema nella mia app eliminando tutti i token per un determinato utente quando vengono inviate le informazioni di autenticazione.

Utilizzare un bean AuthenticationProvider personalizzato.

@Component("authenticationProvider") 
public class AuthenticationProviderImpl implements AuthenticationProvider 

Autowire nel bean del token store.

@Autowired 
@Qualifier("tokenStore") 
private TokenStore tokenStore; 

Poi nel metodo di autenticazione, rimuovere tutti i gettoni per un dato utente se le credenziali si passano una seconda volta.

@Override 
public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
    UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication; 

    try { 
     //Do authentication 

     //Delete previous tokens 
     Collection<OAuth2AccessToken> tokenCollection = tokenStore.findTokensByUserName(token.getName()); 
     for (OAuth2AccessToken oToken : tokenCollection){ 
      tokenStore.removeAccessToken(oToken); 
     } 

     //return Authentication; 
    } 
} 

maggior parte delle richieste utilizzeranno un token e si bypassare questo del tutto, ma quando sono passati le credenziali, un nuovo token verrà generato. Questo token sarà associato al nuovo oggetto di autenticazione che includerà tutti i nuovi ruoli e le modifiche apportate all'utente.

+0

Capisco questo modo di fare le cose, ma non c'è un modo migliore per farlo? È molto difficile per me credere che gli sviluppatori di oauth2 primaverili non abbiano pensato a questo problema ... Non mi sembra giusto dover far viaggiare di nuovo le credenziali solo per invalidare uno stato precedente perché prima l'app non dovrebbe memorizzare il credenziali e questo è l'intero punto di vista e in secondo luogo non sembra giusto chiedere all'utente le credenziali solo perché non possiamo fare un'operazione di base sul server:/Stai ancora con questa o hai trovato qualche altra soluzione a questo problema? – rpvilao

+0

L'ho risolto allo stesso modo. Penso che ci manchi il supporto per aggiornare l'autenticazione da oauth2. – Gazeciarz

0

Ho avuto lo stesso problema e risolto con questa funzione:

protected void reloadUserFromSecurityContext(SecurityContext securityContext, Person user){ 
    OAuth2Authentication requestingUser = (OAuth2Authentication) securityContext.getUserPrincipal(); 
    Object principal = (PersonUserDetails) requestingUser.getUserAuthentication().getPrincipal(); 
    if(principal instanceof PersonUserDetails) { 
     ((PersonUserDetails) principal).setPerson(user); 
    } 
    OAuth2AuthenticationDetails authDetails = (OAuth2AuthenticationDetails) requestingUser.getDetails(); 
    OAuth2AccessToken tokenStored = jdbcTokenStore.readAccessToken(authDetails.getTokenValue()); 
    jdbcTokenStore.storeAccessToken(tokenStored, requestingUser); 
} 

Questo è un esempio di aggiornamento un attributo per PersonUserDetails oggetto che è in OAuth2Authentication

Problemi correlati