BAEL-3996_Spring_Security_with_Auth0 (#9300)
* BAEL-3996 - Spring Security with Auth0 * BAEL-3996 - Spring Security with Auth0 code fixes * BAEL-3996 - Spring Security with Auth0 * BAEL-3996 - removed spaces * BAEL-3996 - RequestMapping is updated to GetMapping
This commit is contained in:
parent
745d71b127
commit
7b53c3cb55
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
<module>spring-security-acl</module>
|
<module>spring-security-acl</module>
|
||||||
|
<module>spring-security-auth0</module>
|
||||||
<module>spring-security-angular/server</module>
|
<module>spring-security-angular/server</module>
|
||||||
<module>spring-security-cache-control</module>
|
<module>spring-security-cache-control</module>
|
||||||
<module>spring-security-core</module>
|
<module>spring-security-core</module>
|
||||||
|
75
spring-security-modules/spring-security-auth0/pom.xml
Normal file
75
spring-security-modules/spring-security-auth0/pom.xml
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<artifactId>spring-security-auth0</artifactId>
|
||||||
|
<version>1.0-SNAPSHOT</version>
|
||||||
|
<name>spring-security-auth0</name>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>com.baeldung</groupId>
|
||||||
|
<artifactId>parent-boot-2</artifactId>
|
||||||
|
<version>0.0.1-SNAPSHOT</version>
|
||||||
|
<relativePath>../../parent-boot-2</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-core</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.security</groupId>
|
||||||
|
<artifactId>spring-security-oauth2-resource-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.auth0</groupId>
|
||||||
|
<artifactId>mvc-auth-commons</artifactId>
|
||||||
|
<version>${mvc-auth-commons.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
<version>${json.version}</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<finalName>spring-security-auth0</finalName>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>src/main/resources</directory>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<addResources>true</addResources>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>repackage</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<json.version>20190722</json.version>
|
||||||
|
<mvc-auth-commons.version>1.2.0</mvc-auth-commons.version>
|
||||||
|
</properties>
|
||||||
|
</project>
|
@ -0,0 +1,13 @@
|
|||||||
|
package com.baeldung.auth0;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
public class Application {
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(Application.class, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,114 @@
|
|||||||
|
package com.baeldung.auth0;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
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.web.authentication.logout.LogoutSuccessHandler;
|
||||||
|
|
||||||
|
import com.auth0.AuthenticationController;
|
||||||
|
import com.baeldung.auth0.controller.LogoutController;
|
||||||
|
import com.auth0.jwk.JwkProvider;
|
||||||
|
import com.auth0.jwk.JwkProviderBuilder;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
public class AuthConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
@Value(value = "${com.auth0.domain}")
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
@Value(value = "${com.auth0.clientId}")
|
||||||
|
private String clientId;
|
||||||
|
|
||||||
|
@Value(value = "${com.auth0.clientSecret}")
|
||||||
|
private String clientSecret;
|
||||||
|
|
||||||
|
@Value(value = "${com.auth0.managementApi.clientId}")
|
||||||
|
private String managementApiClientId;
|
||||||
|
|
||||||
|
@Value(value = "${com.auth0.managementApi.clientSecret}")
|
||||||
|
private String managementApiClientSecret;
|
||||||
|
|
||||||
|
@Value(value = "${com.auth0.managementApi.grantType}")
|
||||||
|
private String grantType;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public LogoutSuccessHandler logoutSuccessHandler() {
|
||||||
|
return new LogoutController();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public AuthenticationController authenticationController() throws UnsupportedEncodingException {
|
||||||
|
JwkProvider jwkProvider = new JwkProviderBuilder(domain).build();
|
||||||
|
return AuthenticationController.newBuilder(domain, clientId, clientSecret)
|
||||||
|
.withJwkProvider(jwkProvider)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http.csrf().disable();
|
||||||
|
http
|
||||||
|
.authorizeRequests()
|
||||||
|
.antMatchers("/callback", "/login", "/").permitAll()
|
||||||
|
.anyRequest().authenticated()
|
||||||
|
.and()
|
||||||
|
.formLogin()
|
||||||
|
.loginPage("/login")
|
||||||
|
.and()
|
||||||
|
.logout().logoutSuccessHandler(logoutSuccessHandler()).permitAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDomain() {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientId() {
|
||||||
|
return clientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClientSecret() {
|
||||||
|
return clientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getManagementApiClientId() {
|
||||||
|
return managementApiClientId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getManagementApiClientSecret() {
|
||||||
|
return managementApiClientSecret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGrantType() {
|
||||||
|
return grantType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserInfoUrl() {
|
||||||
|
return "https://" + getDomain() + "/userinfo";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsersUrl() {
|
||||||
|
return "https://" + getDomain() + "/api/v2/users";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUsersByEmailUrl() {
|
||||||
|
return "https://" + getDomain() + "/api/v2/users-by-email?email=";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLogoutUrl() {
|
||||||
|
return "https://" + getDomain() +"/v2/logout";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getContextPath(HttpServletRequest request) {
|
||||||
|
String path = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
package com.baeldung.auth0.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import com.auth0.AuthenticationController;
|
||||||
|
import com.auth0.IdentityVerificationException;
|
||||||
|
import com.auth0.Tokens;
|
||||||
|
import com.auth0.jwt.JWT;
|
||||||
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||||
|
import com.baeldung.auth0.AuthConfig;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class AuthController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthenticationController authenticationController;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthConfig config;
|
||||||
|
|
||||||
|
private static final String AUTH0_TOKEN_URL = "https://dev-example.auth0.com/oauth/token";
|
||||||
|
|
||||||
|
@GetMapping(value = "/login")
|
||||||
|
protected void login(HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||||
|
String redirectUri = config.getContextPath(request) + "/callback";
|
||||||
|
String authorizeUrl = authenticationController.buildAuthorizeUrl(request, response, redirectUri)
|
||||||
|
.withScope("openid email")
|
||||||
|
.build();
|
||||||
|
response.sendRedirect(authorizeUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value="/callback")
|
||||||
|
public void callback(HttpServletRequest request, HttpServletResponse response) throws IOException, IdentityVerificationException {
|
||||||
|
Tokens tokens = authenticationController.handle(request, response);
|
||||||
|
|
||||||
|
DecodedJWT jwt = JWT.decode(tokens.getIdToken());
|
||||||
|
TestingAuthenticationToken authToken2 = new TestingAuthenticationToken(jwt.getSubject(), jwt.getToken());
|
||||||
|
authToken2.setAuthenticated(true);
|
||||||
|
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(authToken2);
|
||||||
|
response.sendRedirect(config.getContextPath(request) + "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getManagementApiToken() {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
|
||||||
|
JSONObject requestBody = new JSONObject();
|
||||||
|
requestBody.put("client_id", config.getManagementApiClientId());
|
||||||
|
requestBody.put("client_secret", config.getManagementApiClientSecret());
|
||||||
|
requestBody.put("audience", "https://dev-example.auth0.com/api/v2/");
|
||||||
|
requestBody.put("grant_type", config.getGrantType());
|
||||||
|
|
||||||
|
HttpEntity<String> request = new HttpEntity<String>(requestBody.toString(), headers);
|
||||||
|
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
HashMap<String, String> result = restTemplate.postForObject(AUTH0_TOKEN_URL, request, HashMap.class);
|
||||||
|
|
||||||
|
return result.get("access_token");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
package com.baeldung.auth0.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import com.auth0.jwt.JWT;
|
||||||
|
import com.auth0.jwt.interfaces.DecodedJWT;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class HomeController {
|
||||||
|
|
||||||
|
@GetMapping(value = "/")
|
||||||
|
@ResponseBody
|
||||||
|
public String home(HttpServletRequest request, HttpServletResponse response, final Authentication authentication) throws IOException {
|
||||||
|
|
||||||
|
if (authentication!= null && authentication instanceof TestingAuthenticationToken) {
|
||||||
|
TestingAuthenticationToken token = (TestingAuthenticationToken) authentication;
|
||||||
|
|
||||||
|
DecodedJWT jwt = JWT.decode(token.getCredentials().toString());
|
||||||
|
String email = jwt.getClaims().get("email").asString();
|
||||||
|
|
||||||
|
return "Welcome, " + email + "!";
|
||||||
|
} else {
|
||||||
|
response.sendRedirect("http://localhost:8080/login");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,35 @@
|
|||||||
|
package com.baeldung.auth0.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
|
||||||
|
import com.baeldung.auth0.AuthConfig;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class LogoutController implements LogoutSuccessHandler {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthConfig config;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse res, Authentication authentication) {
|
||||||
|
if (req.getSession() != null) {
|
||||||
|
req.getSession().invalidate();
|
||||||
|
}
|
||||||
|
String returnTo = config.getContextPath(req);
|
||||||
|
String logoutUrl = config.getLogoutUrl() + "?client_id=" + config.getClientId() + "&returnTo=" +returnTo;
|
||||||
|
try {
|
||||||
|
res.sendRedirect(logoutUrl);
|
||||||
|
} catch(IOException e){
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,57 @@
|
|||||||
|
package com.baeldung.auth0.controller;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
|
||||||
|
import com.auth0.IdentityVerificationException;
|
||||||
|
import com.baeldung.auth0.AuthConfig;
|
||||||
|
import com.baeldung.auth0.service.ApiService;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class UserController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApiService apiService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthConfig config;
|
||||||
|
|
||||||
|
@GetMapping(value="/users")
|
||||||
|
@ResponseBody
|
||||||
|
public ResponseEntity<String> users(HttpServletRequest request, HttpServletResponse response) throws IOException, IdentityVerificationException {
|
||||||
|
ResponseEntity<String> result = apiService.getCall(config.getUsersUrl());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/userByEmail")
|
||||||
|
@ResponseBody
|
||||||
|
public ResponseEntity<String> userByEmail(HttpServletResponse response, @RequestParam String email) {
|
||||||
|
ResponseEntity<String> result = apiService.getCall(config.getUsersByEmailUrl()+email);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping(value = "/createUser")
|
||||||
|
@ResponseBody
|
||||||
|
public ResponseEntity<String> createUser(HttpServletResponse response) {
|
||||||
|
JSONObject request = new JSONObject();
|
||||||
|
request.put("email", "norman.lewis@email.com");
|
||||||
|
request.put("given_name", "Norman");
|
||||||
|
request.put("family_name", "Lewis");
|
||||||
|
request.put("connection", "Username-Password-Authentication");
|
||||||
|
request.put("password", "Pa33w0rd");
|
||||||
|
|
||||||
|
ResponseEntity<String> result = apiService.postCall(config.getUsersUrl(), request.toString());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,44 @@
|
|||||||
|
package com.baeldung.auth0.service;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import com.baeldung.auth0.controller.AuthController;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ApiService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AuthController controller;
|
||||||
|
|
||||||
|
public ResponseEntity<String> getCall(String url) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
headers.set("Authorization", "Bearer "+controller.getManagementApiToken());
|
||||||
|
|
||||||
|
HttpEntity<String> entity = new HttpEntity<String>(headers);
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseEntity<String> postCall(String url, String requestBody) {
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.setContentType(MediaType.APPLICATION_JSON);
|
||||||
|
headers.set("Authorization", "Bearer "+controller.getManagementApiToken());
|
||||||
|
|
||||||
|
HttpEntity<String> request = new HttpEntity<String>(requestBody, headers);
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
ResponseEntity<String> result = restTemplate.postForEntity(url, request, String.class);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
com.auth0.domain: dev-example.auth0.com
|
||||||
|
com.auth0.clientId: exampleClientId
|
||||||
|
com.auth0.clientSecret: exampleClientSecret
|
||||||
|
|
||||||
|
com.auth0.managementApi.clientId: exampleManagementApiClientId
|
||||||
|
com.auth0.managementApi.clientSecret: exampleManagementApiClientSecret
|
||||||
|
com.auth0.managementApi.grantType: client_credentials
|
Loading…
x
Reference in New Issue
Block a user