diff --git a/pom.xml b/pom.xml index 9be9e1ef25..d797240169 100644 --- a/pom.xml +++ b/pom.xml @@ -99,6 +99,7 @@ spring-security-rest-custom spring-security-rest-digest-auth spring-security-rest-full + spring-security-x509 spring-thymeleaf spring-zuul jsf diff --git a/spring-security-x509/basic-secured-server/pom.xml b/spring-security-x509/basic-secured-server/pom.xml new file mode 100644 index 0000000000..87fdd64727 --- /dev/null +++ b/spring-security-x509/basic-secured-server/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + basic-secured-server + 0.0.1-SNAPSHOT + jar + + basic-secured-server + Spring x.509 Authentication Demo + + + com.baeldung + spring-security-x509 + 0.0.1-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-security-x509/basic-secured-server/src/main/java/com/baeldung/spring/security/x509/UserController.java b/spring-security-x509/basic-secured-server/src/main/java/com/baeldung/spring/security/x509/UserController.java new file mode 100644 index 0000000000..af1c103739 --- /dev/null +++ b/spring-security-x509/basic-secured-server/src/main/java/com/baeldung/spring/security/x509/UserController.java @@ -0,0 +1,21 @@ +package com.baeldung.spring.security.x509; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.security.Principal; + +@Controller +public class UserController { + @PreAuthorize("hasAuthority('ROLE_USER')") + @RequestMapping(value = "/user") + public String user(Model model, Principal principal) { + UserDetails currentUser = (UserDetails) ((Authentication) principal).getPrincipal(); + model.addAttribute("username", currentUser.getUsername()); + return "user"; + } +} diff --git a/spring-security-x509/basic-secured-server/src/main/java/com/baeldung/spring/security/x509/X509AuthenticationServer.java b/spring-security-x509/basic-secured-server/src/main/java/com/baeldung/spring/security/x509/X509AuthenticationServer.java new file mode 100644 index 0000000000..edcacfda15 --- /dev/null +++ b/spring-security-x509/basic-secured-server/src/main/java/com/baeldung/spring/security/x509/X509AuthenticationServer.java @@ -0,0 +1,22 @@ +package com.baeldung.spring.security.x509; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +@SpringBootApplication +@EnableWebSecurity +public class X509AuthenticationServer extends WebSecurityConfigurerAdapter { + public static void main(String[] args) { + SpringApplication.run(X509AuthenticationServer.class, args); + } +} diff --git a/spring-security-x509/basic-secured-server/src/main/resources/application.properties b/spring-security-x509/basic-secured-server/src/main/resources/application.properties new file mode 100644 index 0000000000..f293d6712d --- /dev/null +++ b/spring-security-x509/basic-secured-server/src/main/resources/application.properties @@ -0,0 +1,8 @@ +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 \ No newline at end of file diff --git a/spring-security-x509/basic-secured-server/src/main/resources/templates/user.html b/spring-security-x509/basic-secured-server/src/main/resources/templates/user.html new file mode 100644 index 0000000000..3e36d7b644 --- /dev/null +++ b/spring-security-x509/basic-secured-server/src/main/resources/templates/user.html @@ -0,0 +1,9 @@ + + + + X.509 Authentication Demo + + +

Hello !

+ + diff --git a/spring-security-x509/basic-secured-server/src/test/java/com/baeldung/spring/security/x509/X509AuthenticationServerTests.java b/spring-security-x509/basic-secured-server/src/test/java/com/baeldung/spring/security/x509/X509AuthenticationServerTests.java new file mode 100644 index 0000000000..0b9a11552a --- /dev/null +++ b/spring-security-x509/basic-secured-server/src/test/java/com/baeldung/spring/security/x509/X509AuthenticationServerTests.java @@ -0,0 +1,14 @@ +package com.baeldung.spring.security.x509; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class X509AuthenticationServerTests { + @Test + public void contextLoads() { + } +} diff --git a/spring-security-x509/client-auth-server/pom.xml b/spring-security-x509/client-auth-server/pom.xml new file mode 100644 index 0000000000..56cef8ea07 --- /dev/null +++ b/spring-security-x509/client-auth-server/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + client-auth-server + 0.0.1-SNAPSHOT + jar + + client-auth-server + Spring x.509 Client Authentication Demo + + + com.baeldung + spring-security-x509 + 0.0.1-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + diff --git a/spring-security-x509/client-auth-server/src/main/java/com/baeldung/spring/security/x509/UserController.java b/spring-security-x509/client-auth-server/src/main/java/com/baeldung/spring/security/x509/UserController.java new file mode 100644 index 0000000000..af1c103739 --- /dev/null +++ b/spring-security-x509/client-auth-server/src/main/java/com/baeldung/spring/security/x509/UserController.java @@ -0,0 +1,21 @@ +package com.baeldung.spring.security.x509; + +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.web.bind.annotation.RequestMapping; + +import java.security.Principal; + +@Controller +public class UserController { + @PreAuthorize("hasAuthority('ROLE_USER')") + @RequestMapping(value = "/user") + public String user(Model model, Principal principal) { + UserDetails currentUser = (UserDetails) ((Authentication) principal).getPrincipal(); + model.addAttribute("username", currentUser.getUsername()); + return "user"; + } +} diff --git a/spring-security-x509/client-auth-server/src/main/java/com/baeldung/spring/security/x509/X509AuthenticationServer.java b/spring-security-x509/client-auth-server/src/main/java/com/baeldung/spring/security/x509/X509AuthenticationServer.java new file mode 100644 index 0000000000..7d8413589e --- /dev/null +++ b/spring-security-x509/client-auth-server/src/main/java/com/baeldung/spring/security/x509/X509AuthenticationServer.java @@ -0,0 +1,43 @@ +package com.baeldung.spring.security.x509; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import org.springframework.security.core.authority.AuthorityUtils; +import org.springframework.security.core.userdetails.User; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; + +@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!"); + } + }; + } +} diff --git a/spring-security-x509/client-auth-server/src/main/resources/application.properties b/spring-security-x509/client-auth-server/src/main/resources/application.properties new file mode 100644 index 0000000000..174eba9f98 --- /dev/null +++ b/spring-security-x509/client-auth-server/src/main/resources/application.properties @@ -0,0 +1,11 @@ +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 \ No newline at end of file diff --git a/spring-security-x509/client-auth-server/src/main/resources/keystore.jks b/spring-security-x509/client-auth-server/src/main/resources/keystore.jks new file mode 100644 index 0000000000..044a820c39 Binary files /dev/null and b/spring-security-x509/client-auth-server/src/main/resources/keystore.jks differ diff --git a/spring-security-x509/client-auth-server/src/main/resources/templates/user.html b/spring-security-x509/client-auth-server/src/main/resources/templates/user.html new file mode 100644 index 0000000000..a35b18bacc --- /dev/null +++ b/spring-security-x509/client-auth-server/src/main/resources/templates/user.html @@ -0,0 +1,9 @@ + + + + X.509 Authentication Demo + + +

Hello !

+ + diff --git a/spring-security-x509/client-auth-server/src/test/java/com/baeldung/spring/security/x509/X509AuthenticationServerTests.java b/spring-security-x509/client-auth-server/src/test/java/com/baeldung/spring/security/x509/X509AuthenticationServerTests.java new file mode 100644 index 0000000000..0b9a11552a --- /dev/null +++ b/spring-security-x509/client-auth-server/src/test/java/com/baeldung/spring/security/x509/X509AuthenticationServerTests.java @@ -0,0 +1,14 @@ +package com.baeldung.spring.security.x509; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class X509AuthenticationServerTests { + @Test + public void contextLoads() { + } +} diff --git a/spring-security-x509/keystore/Makefile b/spring-security-x509/keystore/Makefile new file mode 100644 index 0000000000..5321be9de3 --- /dev/null +++ b/spring-security-x509/keystore/Makefile @@ -0,0 +1,88 @@ +PASSWORD=changeit +KEYSTORE=keystore.jks +HOSTNAME=localhost +CLIENTNAME=cid + +# CN = Common Name +# OU = Organization Unit +# O = Organization Name +# L = Locality Name +# ST = State Name +# C = Country (2-letter Country Code) +# E = Email +DNAME_CA='CN=Baeldung CA,OU=baeldung.com,O=Baeldung,L=SomeCity,ST=SomeState,C=CC' +# For server certificates, the Common Name (CN) must be the hostname +DNAME_HOST='CN=$(HOSTNAME),OU=baeldung.com,O=Baeldung,L=SomeCity,ST=SomeState,C=CC' +DNAME_CLIENT='CN=$(CLIENTNAME),OU=baeldung.com,O=Baeldung,L=SomeCity,ST=SomeState,C=CC' +TRUSTSTORE=truststore.jks + +all: clean create-keystore add-host create-truststore add-client + +create-keystore: + # Generate a certificate authority (CA) + keytool -genkey -alias ca -ext BC=ca:true \ + -keyalg RSA -keysize 4096 -sigalg SHA512withRSA -keypass $(PASSWORD) \ + -validity 3650 -dname $(DNAME_CA) \ + -keystore $(KEYSTORE) -storepass $(PASSWORD) + +add-host: + # Generate a host certificate + keytool -genkey -alias $(HOSTNAME) \ + -keyalg RSA -keysize 4096 -sigalg SHA512withRSA -keypass $(PASSWORD) \ + -validity 3650 -dname $(DNAME_HOST) \ + -keystore $(KEYSTORE) -storepass $(PASSWORD) + # Generate a host certificate signing request + keytool -certreq -alias $(HOSTNAME) -ext BC=ca:true \ + -keyalg RSA -keysize 4096 -sigalg SHA512withRSA \ + -validity 3650 -file "$(HOSTNAME).csr" \ + -keystore $(KEYSTORE) -storepass $(PASSWORD) + # Generate signed certificate with the certificate authority + keytool -gencert -alias ca \ + -validity 3650 -sigalg SHA512withRSA \ + -infile "$(HOSTNAME).csr" -outfile "$(HOSTNAME).crt" -rfc \ + -keystore $(KEYSTORE) -storepass $(PASSWORD) + # Import signed certificate into the keystore + keytool -import -trustcacerts -alias $(HOSTNAME) \ + -file "$(HOSTNAME).crt" \ + -keystore $(KEYSTORE) -storepass $(PASSWORD) + +export-authority: + # Export certificate authority + keytool -export -alias ca -file ca.crt -rfc \ + -keystore $(KEYSTORE) -storepass $(PASSWORD) + + +create-truststore: export-authority + # Import certificate authority into a new truststore + keytool -import -trustcacerts -noprompt -alias ca -file ca.crt \ + -keystore $(TRUSTSTORE) -storepass $(PASSWORD) + +add-client: + # Generate client certificate + keytool -genkey -alias $(CLIENTNAME) \ + -keyalg RSA -keysize 4096 -sigalg SHA512withRSA -keypass $(PASSWORD) \ + -validity 3650 -dname $(DNAME_CLIENT) \ + -keystore $(TRUSTSTORE) -storepass $(PASSWORD) + # Generate a host certificate signing request + keytool -certreq -alias $(CLIENTNAME) -ext BC=ca:true \ + -keyalg RSA -keysize 4096 -sigalg SHA512withRSA \ + -validity 3650 -file "$(CLIENTNAME).csr" \ + -keystore $(TRUSTSTORE) -storepass $(PASSWORD) + # Generate signed certificate with the certificate authority + keytool -gencert -alias ca \ + -validity 3650 -sigalg SHA512withRSA \ + -infile "$(CLIENTNAME).csr" -outfile "$(CLIENTNAME).crt" -rfc \ + -keystore $(KEYSTORE) -storepass $(PASSWORD) + # Import signed certificate into the truststore + keytool -import -trustcacerts -alias $(CLIENTNAME) \ + -file "$(CLIENTNAME).crt" \ + -keystore $(TRUSTSTORE) -storepass $(PASSWORD) + # Export private certificate for importing into a browser + keytool -importkeystore -srcalias $(CLIENTNAME) \ + -srckeystore $(TRUSTSTORE) -srcstorepass $(PASSWORD) \ + -destkeystore "$(CLIENTNAME).p12" -deststorepass $(PASSWORD) \ + -deststoretype PKCS12 + +clean: + # Remove generated artifacts + find . ! -name Makefile -type f -exec rm -f {} \; diff --git a/spring-security-x509/keystore/keystore.jks b/spring-security-x509/keystore/keystore.jks new file mode 100644 index 0000000000..044a820c39 Binary files /dev/null and b/spring-security-x509/keystore/keystore.jks differ diff --git a/spring-security-x509/pom.xml b/spring-security-x509/pom.xml new file mode 100644 index 0000000000..8a9fd200a8 --- /dev/null +++ b/spring-security-x509/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + com.baeldung + spring-security-x509 + 0.0.1-SNAPSHOT + pom + + + basic-secured-server + client-auth-server + + + + org.springframework.boot + spring-boot-starter-parent + 1.4.0.RELEASE + + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-thymeleaf + + + + org.springframework.boot + spring-boot-starter-test + test + + +