HTTPS mit Client-Authentifizierung via Client-Zertifikat (Beispiel mit Spring Boot)

Bealdung hat bietet uns einen wunderbares Tutorial X.509 Authentication in Spring Security zum Thema, welchen ich hier verarbeite/zusammenfasse. Die vollständigen Sourcen sind auf GitHub verfügbar.

Zertifikates & -Stores erstellen

Das Makefile beinhaltet die ganze Magie des

  1. Erstellens eines Keystores (für das Server-Certifikat, das den Server ausweisen wird)
  2. Erstellens eines Certificate Signing Requests
  3. Des selbst signierens desselben CSRs (würde in Scharfem Modus von einer wirklichen Certificate Authority gemacht)
  4. Erstellens eines TrustStores (für die Client-Certificate Trust Authority)
  5. Erstellens eines Client Certificates, exportieren desselbens

Definition von HTTPS des integrated Tomcat

Wird durch diese wenigen config entries in application.properties erreicht:

server.ssl.key-store=../keystore/keystore.jks
server.ssl.key-store-password=changeit
server.ssl.key-alias=localhost
server.ssl.key-password=changeit
server.ssl.enabled=true
server.port=8443
security.user.name=Admin
security.user.password=admin
server.ssl.trust-store=../keystore/truststore.jks
server.ssl.trust-store-password=changeit
server.ssl.client-auth=need

Definition der Zugriffsberechtigung in der SPRING-Boot-Applikation

Die ganze Magie der Zugriffs-Berechtigungs-Verwaltung wird  durch die Annotationen @EnableWebSecurity repektive @EnableGlobalMethodSecurity und das Ableiten von WebSecurityConfigurerAdapter  und dessen überschreibene Methode configure bewerkstelligt.

@SpringBootApplication
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class X509AuthenticationServer extends WebSecurityConfigurerAdapter {
    public static void main(String[] args) {
        SpringApplication.run(X509AuthenticationServer.class, args);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated().and().x509().subjectPrincipalRegex("CN=(.*?)(?:,|$)").userDetailsService(userDetailsService());
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return new UserDetailsService() {
            @Override
            public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
                if (username.equals("cid")) {
                    return new User(username, "", AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER"));
                }
                throw new UsernameNotFoundException("User not found!");
            }
        };
    }
}

Die configure-Methode hat also schon via 

http.authorizeRequests().anyRequest().authenticated().and().x509()

Zugriff auf das vom Web-Server empfangene Zertifikat und kann es auswerten.

 

Client Zertifikat in Firefox registrieren

Siehe Tutorial X.509 Authentication in Spring Security

 

Tomcat 8 mit HTTPS erreichtbar machen – Client Authentication via Zertifikat

A) Zertifikate erstellen

Siehe X.509 Authentication in Spring Security

B) Vorgehensweise via Tomcat-Configuration

In $CATALINA_HOME/conf/settings.xml wurde

<Connector
        protocol="org.apache.coyote.http11.Http11NioProtocol"
        port="8443" maxThreads="200"
        scheme="https" secure="true" SSLEnabled="true"
<!-- Für server auth: --> 
        keystoreFile="conf/keystore.jks" keystorePass="changeit"
<!-- Für client auth: --> 
        truststoreFile="conf/truststore.jks" truststorePass="changeit" 
        clientAuth="true" sslProtocol="TLS"/>

eingefügt.
Dies bewirkt, dass unter Port 8443 ein Zugang angeboten wird, der TLS geschlüsselt wird.
Wenn der andere Connector

<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />

im settings.xml drin bleibt, dass ist per se weiterhin auch die HTTP-Adresse offen.

Die Applikation (falls keine eigene darüber installiert wurde ist das die Tomcat-Welcome-Page) ist also immernoch über

http://localhost:8080 und https://localhost:8443 erreichbar.

Wird aber eine Web-App mit web.xml mit Security constraint, wie z.B. im folgenden installiert, dann wird die definierte URL immer auf HTTPS umgeleitet.

<security-constraint>

    <web-resource-collection>
        <web-resource-name>Secured</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>

    ...

    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>

</security-constraint>

–> Siehe StackOverflow-Artikel über Redirect

Obige Config setzt nicht nur HTTP und Server-Authentication auf, sondern auch Client-Authentication. Das bedeutet, dass wenn man auf https://localhost:8443 zugreifen möchte, man im Browser das Client-Certifikat installieren muss. Ruft man die Seite dann auf, wird einem eine Liste vom möglichen Zerts zur Wahl angeboten.

 

Referenzen:

 

Makefile in Windows ausführen – Linux-Umgebung innerhalb Windows

Problem: Wie führe ich ein Makefile in Windows aus?

Eine Lösung:

  1. Cygwin installieren
  2. Make innnerhalb Cygwin installieren. Dies wird gemacht, indem das Cygwin-Installer EXE (dasjenige, der bereits Cygwin installiert hat) ausgeführt wird. Es wird dann irgendwann eine Vielzahl von Features zur installation angeboten.

Wie erhalte ich von Cygwin Zugriff auf das Windows C-Drive?

cd /cygdrive/c

Stream Grouping Beispiel

public class StreamGroupingExercice {
    public static void main(String[] args) throws IOException {
        List<String> strings = Files.readAllLines(Paths.get("names.txt"));

        List<String> names = strings.stream().flatMap(s -> Arrays.asList(s.split(", ")).stream()).collect(Collectors.toList());

        Map<String, Long> groupedCountedNames = names.stream().peek(item -> System.out.println("Schritt 1: " + item))
                        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting() ));

        assertThat(groupedCountedNames).containsEntry("Hans", 2L);
        assertThat(groupedCountedNames).containsEntry("Paul", 1L);

    }
}
Schließen