2015-11-19 24 views
7

Sto creando alcuni servizi Web riposanti e sto utilizzando Spring-Boot per creare un contenitore tomcat incorporato.Implementazione SSL a 2 vie con avvio a molla

Uno dei requisiti è che questo implementa SSL a 2 vie. Sono stato a guardare l'oggetto HttpSecurity e riesco a farlo funzionare solo i webservices su un canale SSL utilizza questo: -

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

    System.out.println("CONFIGURED"); 

    http 
     // ... 
     .requiresChannel() 
      .anyRequest().requiresSecure(); 
} 

Quello che non riesco a trovare è un modo di rendere il webservice accessibile solo alle applicazioni che forniscono un certificato cliente valido.

Ho solo una conoscenza di base di SSL quindi anche un puntatore generale nella giusta direzione sarebbe apprezzato.

Il server su cui viene distribuito avrà un mix di applicazioni - questo è l'unico che deve essere bloccato con SSL a 2 vie. Quello che cerco davvero è un modo per bloccare una singola applicazione per accettare solo certificati client.

+0

Grazie per la risposta. Il collegamento fornito sembra essere il blocco completo del tomcat 7, tuttavia il server su cui verrà distribuito è una risorsa condivisa, quindi avrà un mix di elementi protetti e non protetti su di esso. Quello che cerco davvero è un modo per bloccare una singola app Web utilizzando Spring Security e i certificati client. –

+0

Quindi è forse il contenitore di tomcat incorporato di Spring Boot che devo esaminare di più. –

risposta

4

Si potrebbe configurare clientAuth=want, vedere Apache Tomcat 8 Configuration Reference:

Impostare true se si desidera che lo stack SSL per richiedere una catena di certificato valido dal client prima di accettare una connessione. Impostare su want se si desidera che lo stack SSL richieda un certificato client, ma non fallisce se uno non viene presentato. Un valore false (che è l'impostazione predefinita) non richiede una catena di certificati a meno che il client non richieda una risorsa protetta da un vincolo di sicurezza che utilizza l'autenticazione CLIENT-CERT.

e poi leggere il certificato client con Spring Security - X.509 Authentication:

È anche possibile utilizzare SSL con "autenticazione reciproca"; il server richiederà quindi un certificato valido dal client come parte dell'handshake SSL. Il server autentificherà il client verificando che il suo certificato sia firmato da un'autorità accettabile. Se è stato fornito un certificato valido, è possibile ottenerlo tramite l'API servlet in un'applicazione. Il modulo Spring Security X.509 estrae il certificato utilizzando un filtro. Associa il certificato a un utente dell'applicazione e carica la serie di autorizzazioni concesse da parte dell'utente per l'utilizzo con l'infrastruttura Spring Security standard.

e

clientAuth può anche essere impostato per want se si vuole ancora le connessioni SSL per avere successo anche se il client non fornisce un certificato. I client che non presentano un certificato non potranno accedere ad alcun oggetto protetto da Spring Security a meno che non si utilizzi un meccanismo di autenticazione non X.509, come l'autenticazione del modulo.

4

Mi sono imbattuto in un problema simile e ho pensato di condividere la soluzione con cui sono arrivato.

In primo luogo, è necessario comprendere che l'autenticazione del certificato SSL verrà gestita sul lato del server Web (spiegazione di esempio con l'impostazione "clientAuth = want"). Quindi, l'app Web deve essere configurata per gestire il certificato fornito (e consentito), mapparlo a un utente, ecc.

La leggera differenza che ho con voi è che sto impacchettando la mia applicazione di avvio a molla in un archivio WAR, che viene quindi distribuito su un server di applicazioni Tomcat esistente.

file di configurazione server.xml di mio Tomcat definisce un connettore HTTPS come segue:

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" 
    maxThreads="150" SSLEnabled="true" scheme="https" secure="true" 
    keystoreFile="/opt/tomcat/conf/key-stores/ssl-keystore.jks" 
    keystorePass=“some-complex-password“ 
    clientAuth="want" sslProtocol="TLS" 
    truststoreFile="/opt/tomcat/conf/trust-stores/ssl-truststore.jks" 
    truststorePass=“some-other-complex-password” /> 

piccolo commento per evitare qualsiasi confusione: keystoreFile contiene la/privato coppia di chiavi certificato utilizzato per SSL (solo), mentre truststoreFile contiene i certificati CA consentiti per l'autenticazione SSL client (si noti che è anche possibile aggiungere i certificati client direttamente a tale trust store).

Se stai usando un contenitore Tomcat incorporato con l'applicazione di avvio di primavera, si dovrebbe essere in grado di configurare queste impostazioni nelle proprietà della propria applicazione di file, utilizzando la seguente chiave di proprietà/valori:

server.ssl.key-store=/opt/tomcat/conf/key-stores/ssl-keystore.jks 
server.ssl.key-store-password=some-complex-password 
server.ssl.trust-store=/opt/tomcat/conf/trust-stores/ssl-truststore.jks 
server.ssl.trust-store-password=some-other-complex-password 
server.ssl.client-auth=want 

Poi, sulla mia web app, dichiaro una configurazione SSL specifica come segue:

@Configuration 
@EnableWebSecurity 
//In order to use @PreAuthorise() annotations later on... 
@EnableGlobalMethodSecurity(prePostEnabled = true) 
public class SSLAuthConfiguration extends WebSecurityConfigurerAdapter { 

@Value("${allowed.user}") 
private String ALLOWED_USER; 

@Value("${server.ssl.client.regex}") 
private String CN_REGEX; 

@Autowired 
private UserDetailsService userDetailsService; 

@Override 
protected void configure (final HttpSecurity http) throws Exception { 
    http 
     .csrf().disable() 
     .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
     .and() 
      .authorizeRequests() 
      .antMatchers("/url-path-to-protect").authenticated() //Specify the URL path(s) requiring authentication... 
     .and() 
      .x509() //... and that x509 authentication is enabled 
       .subjectPrincipalRegex(CN_REGEX) 
       .userDetailsService(userDetailsService); 
} 

@Autowired 
//Simplified case, where the application has only one user... 
public void configureGlobal (final AuthenticationManagerBuilder auth) throws Exception { 
    //... whose username is defined in the application's properties. 
    auth 
     .inMemoryAuthentication() 
      .withUser(ALLOWED_USER).password("").roles("SSL_USER"); 
} 

}

ho quindi bisogno di dichiarare l'UserDetailsService b ean (ad es. nella classe principale della mia Applicazione):

@Value("${allowed.user}") 
private String ALLOWED_USER; 

@Bean 
public UserDetailsService userDetailsService() { 

    return new UserDetailsService() { 

     @Override 
     public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException { 
      if (username.equals(ALLOWED_USER)) { 
       final User user = new User(username, "", AuthorityUtils.createAuthorityList("ROLE_SSL_USER")); 
       return user; 
      } 
      return null; 
     } 
    }; 
} 

E il gioco è fatto! Posso quindi aggiungere le annotazioni @PreAuthorize ("hasRole ('ROLE_SSL_USER')") ai metodi che voglio proteggere.

In sintesi le cose un po ', il flusso di autenticazione sarà la seguente:

  1. utente fornisce certificato SSL;
  2. Tomcat esegue la convalida del relativo negozio di fiducia;
  3. Il WebSecurityConfigurerAdapter personalizzato recupera un "nome utente" dal CN del certificato;
  4. L'applicazione autentica l'utente associato al nome utente recuperato;
  5. A livello di metodo, se annotato con @PreAuthorize ("hasRole ('SSL_USER')"), l'applicazione controllerà se l'utente ha il ruolo richiesto.
Problemi correlati