2013-03-20 20 views
5

Ho due set di URL: un set è l'API REST, il secondo è il sito web piuttosto ordinario. Voglio applicare diverse regole di sicurezza per l'API REST in modo che l'utente/script che ha occasionalmente invocato API REST risponda con codice 401 (l'autenticazione di base va bene) o solo 403.Spring Security - configurazione separata per REST API e altri URL

Quindi voglio consentire accesso all'API REST per:

  • l'utente che ha effettuato l'accesso (per javascript nella pagina del sito che richiama l'API REST condivide quindi la stessa sessione).
  • uno script che richiama l'API REST con credenziali di autenticazione di base nell'intestazione dell'autenticazione WWW.

Al momento sto cercando di capire quale configurazione renderà la primavera "capire" ciò che voglio. Sono venuto con la seguente configurazione:

<beans:beans xmlns="http://www.springframework.org/schema/security" 
      xmlns:beans="http://www.springframework.org/schema/beans" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
      xsi:schemaLocation=" 
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd 
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 
    <http pattern="/" security="none" /> 
    <http pattern="/static/**" security="none" /> 

    <!-- REST API --> 
    <http pattern="/rest/*" use-expressions="true"> 
     <http-basic /> 
     <intercept-url pattern="/*" access="isAuthenticated()" /> 
    </http> 

    <!-- Site --> 
    <http access-denied-page="/WEB-INF/views/errors/403.jsp" use-expressions="true"> 
     <intercept-url pattern="/index.html" access="hasRole('ROLE_USER') or hasRole('ROLE_ANONYMOUS')" /> 
     <intercept-url pattern="/login.html" access="hasRole('ROLE_USER') or hasRole('ROLE_ANONYMOUS')" /> 
     <intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')" /> 
     <intercept-url pattern="/**" access="hasRole('ROLE_USER')" /> 
     <form-login login-page="/login.html" 
        default-target-url="/index.html" 
        authentication-failure-url="/login.html?error=1" /> 

     <logout logout-url="/logout.do" logout-success-url="/index.html" /> 

     <anonymous username="guest" granted-authority="ROLE_ANONYMOUS" /> 
     <remember-me /> 
    </http> 

    <authentication-manager> 
     <authentication-provider> 
      <user-service> 
       <user name="admin" password="2" authorities="ROLE_ADMIN,ROLE_USER" /> 
       <user name="alex" password="1" authorities="ROLE_USER" /> 
      </user-service> 
     </authentication-provider> 
    </authentication-manager> 
</beans:beans> 

Purtroppo non solo l'autenticazione di base non funziona con questa configurazione, ma non v'è alcuna 403 risposte per le domande presentate dagli utenti anonimi - risposte di applicazione con reindirizzamento 302 Trovato che avevo piace disabilitare per gli URL API REST.

Ho provato ad aggiungere punto di ingresso personalizzato per REST API:

<beans:bean id="ep403" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/> 


<!-- REST API --> 
<http pattern="/rest/*" entry-point-ref="ep403" use-expressions="true"> 
    <intercept-url pattern="/*" access="hasRole('ROLE_USER')" /> 
    <http-basic /> 
</http> 

, ma questo non funziona neanche.

Riassumendo quello che voglio ottenere:

  • Consenti all'utente autorizzato ad accedere API REST (impianto di autorizzazione dovrebbe tener conto la sessione utente nei cookie).
  • Consenti allo script di accedere all'API REST se specifica il token di autenticazione corretto e non specifica la sessione nei cookie.

UPDATE

Dopo aver scavato in interni Primavera di sicurezza ho trovato il codice che decide se negare certa richiesta o meno. Questo è un cosiddetto "Voters di decisione di accesso", fondamentalmente tutti applicati a determinate richieste e se un elettore di decisione di accesso in una catena vota per negare l'accesso a determinate risorse la richiesta viene in definitiva negata.

Da qui il problema originale potrebbe essere risolto con l'introduzione di speciali decisione degli elettori di accesso che si comporta nel modo seguente: si cerca di estrarre ruolo associato dalla sessione (se del caso presente nella richiesta) e procede a passo di autorizzazione con questo ruolo; se non è presente alcuna sessione, tenta di autenticare l'utente con le credenziali nell'intestazione WWW-Authenticate e quindi passa alla fase di autorizzazione con i ruoli associati all'utente specificato.

risposta

3

Ripubblicare come soluzione bluastra @ suggerito :) Spero che questo aiuti qualcuno.

Ho trovato una soluzione semplice per quello. Ho appena mappato un controller di riposo a due serie distinte di URL e assegnato ogni set al gestore di autenticazione distinti nella configurazione di sicurezza a molla:

<!-- Defines custom security policy for Stateful REST API --> 
<beans:bean id="nonRedirectingAccessDeniedHandler" class="org.springframework.security.web.access.AccessDeniedHandlerImpl"/> 
<beans:bean id="forbiddenEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint"/> 

<!-- Stateful REST API --> 
<http pattern="/rest/stateful/**" use-expressions="true" entry-point-ref="forbiddenEntryPoint"> 
    <access-denied-handler ref="nonRedirectingAccessDeniedHandler"/> 
    <intercept-url pattern="/rest/stateful/**" access="isAuthenticated()" /> 
</http> 

<!-- Stateless REST API --> 
<http pattern="/rest/stateless/**" use-expressions="true" create-session="stateless"> 
    <http-basic/> 
    <intercept-url pattern="/rest/stateless/**" access="isAuthenticated()" /> 
</http> 

Sembra un buon approccio a questo problema perché in futuro si potrebbe voler estendere l'API REST "stateful" -user o "stateless" -script con gli URL univoci specifici per i casi di utilizzo degli utenti o degli script.

Nel mio caso ciò può accadere quando le modifiche UX richiederanno all'API REST di fornire alcuni nuovi metodi progettati per implementare uno specifico scenario dell'interfaccia utente e alcuni scenari di script potrebbero richiedere alcuni URL aggiunti esclusivamente per supportare l'interazione client script-to-server.

0

tenta di modificare pattern="/rest/*"-pattern="/rest/**" e pattern="/*"-pattern="/**" per REST API:

<http pattern="/rest/**" use-expressions="true"> 
    <intercept-url pattern="/**" access="isAuthenticated()" /> 
    <http-basic /> 
</http> 
+0

Grazie, crea-session fa il trucco, ma sebbene questo faccia funzionare l'autenticazione di base, un'autenticazione per sessione si è rifiutata di funzionare (in altre parole javascript sulla pagina non sarà in grado di accedere all'API REST). – Alex

+0

Sì è vero. Cambiare i modelli è stato utile? –

+0

Il pattern non ha molta influenza dato che ora ho uno schema url REST API molto semplice (come/rest/book? Name = X - al momento sono bloccato con onere oneroso e non penso di estenderlo) . Ovviamente il mio pattern non funzionerà per gli URL con nidificazione profonda come/rest/one/two, grazie per averlo indicato. create-session = "stateless" rende l'autenticazione di base funzionante per entrambi i pattern, ma fa in modo che la molla ignori la sessione autorizzata esistente per entrambi i pattern. – Alex

2

È possibile utilizzare intercettori per controllare gli URL avere /rest/ modello.

<mvc:interceptors> 
     <mvc:interceptor> 
      <mvc:mapping path="/rest/**"/> 
      <bean class="com.your.class.name.Interceptor></bean> 
     </mvc:interceptor> 
</mvc:interceptors> 

Per questo aggiungere la riga in basso nella parte di intestazione del XML, vale a dire

<beans xmlns="http://www.springframework.org/schema/beans" 
    xmlns:mvc="http://www.springframework.org/schema/mvc" 

Ora, nel controllo Interceptor classe di tutto ciò è necessario e questa classe dovrebbe implementare Primavera HandlerInterceptor.

public class Interceptor implements HandlerInterceptor{ 

    @Override 
    public boolean preHandle(HttpServletRequest request, 
          HttpServletResponse response, 
          Object handler) throws Exception { 
     //do what you need to check when the request arrives 
     //do authentications here 
     //return true if success 
     //else false 
    } 

    @Override 
    public void postHandle(HttpServletRequest request, 
          HttpServletResponse response, 
          Object handler, 
          ModelAndView modelAndView) throws Exception { 

    } 

    @Override 
    public void afterCompletion(HttpServletRequest request, 
           HttpServletResponse response, 
           Object handler, 
           Exception ex) throws Exception {  
    } 

} 

Leggi this per ulteriori dettagli sui metodi. Puoi anche vedere this

+0

Non sono sicuro di averti capito bene. Se ho capito bene il tuo approccio, questo mi imporrà di implementare tutta la necessaria logica di autorizzazione nell'intercettatore proposto, così la configurazione della sicurezza sarà distribuita su security-context.xml e su un intercettore personalizzato. Sembra un po 'spaventoso. Bene, se questa è l'unica soluzione mi piacerebbe riconsiderare il mio approccio per l'autenticazione e l'autorizzazione per quanto riguarda gli URL REST. – Alex

+0

sì hai capito bene .. come stai facendo correntemente le autorizzazioni ?? – Anubhab

+0

Al momento penso di farlo sul lato del bilanciamento del carico. Questo è un approccio abbastanza duro e fragile da seguire, ma funziona. Allo stesso tempo, sto cercando attivamente un'adeguata soluzione di sicurezza a molla per questo problema. Potrei riconsiderare il mio approccio in modo da eliminare l'autenticazione di base e includere l'URL di accesso separato per gli script che utilizzano l'API REST. – Alex

Problemi correlati