Init project.
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
**/*.class
|
||||||
|
**/target
|
||||||
|
**/static
|
||||||
|
**/.idea
|
||||||
|
**/*.iml
|
||||||
84
pom.xml
Normal file
84
pom.xml
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<?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/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.cerberus</groupId>
|
||||||
|
<artifactId>cerberus</artifactId>
|
||||||
|
<version>1.0.0-SNAPSHOT</version>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-parent</artifactId>
|
||||||
|
<version>2.1.6.RELEASE</version>
|
||||||
|
<relativePath/> <!-- lookup parent from repository -->
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
|
<java.version>11</java.version>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mindrot</groupId>
|
||||||
|
<artifactId>jbcrypt</artifactId>
|
||||||
|
<version>0.4</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.mockito</groupId>
|
||||||
|
<artifactId>mockito-core</artifactId>
|
||||||
|
<version>3.0.0</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.postgresql</groupId>
|
||||||
|
<artifactId>postgresql</artifactId>
|
||||||
|
<version>42.2.6</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-devtools</artifactId>
|
||||||
|
<scope>runtime</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-security</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-test</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-web</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<executable>true</executable>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<version>2.22.2</version>
|
||||||
|
<configuration>
|
||||||
|
<useSystemClassLoader>false</useSystemClassLoader>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
||||||
13
src/main/java/org/cerberus/CerberusApplication.java
Normal file
13
src/main/java/org/cerberus/CerberusApplication.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package org.cerberus;
|
||||||
|
|
||||||
|
import org.springframework.boot.SpringApplication;
|
||||||
|
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
@SpringBootApplication
|
||||||
|
@EnableAutoConfiguration
|
||||||
|
public class CerberusApplication {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SpringApplication.run(CerberusApplication.class, args);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.cerberus.controllers;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
public class RobotsTxtController {
|
||||||
|
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(RobotsTxtController.class);
|
||||||
|
|
||||||
|
@RequestMapping(value = "/robots.txt")
|
||||||
|
public void robots(HttpServletResponse response) {
|
||||||
|
try {
|
||||||
|
response.getWriter().write("User-agent: *\nDisallow: /\n");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
LOG.info("Error during robots.txt serving.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/org/cerberus/controllers/UserController.java
Normal file
41
src/main/java/org/cerberus/controllers/UserController.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package org.cerberus.controllers;
|
||||||
|
|
||||||
|
import org.cerberus.core.config.security.CustomAuthenticationProvider;
|
||||||
|
import org.cerberus.entities.persistence.User;
|
||||||
|
import org.cerberus.repositories.UserRepository;
|
||||||
|
import org.cerberus.services.UserService;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/users")
|
||||||
|
public class UserController {
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
|
public UserController(UserService userService) {
|
||||||
|
this.userService = userService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/login")
|
||||||
|
public void login(@RequestBody User user, HttpServletResponse response) {
|
||||||
|
userService.authenticate(user);
|
||||||
|
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/disconnection")
|
||||||
|
public void disconnection(final HttpServletRequest request, final HttpServletResponse response) {
|
||||||
|
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if(auth != null) {
|
||||||
|
new SecurityContextLogoutHandler().logout(request, response, auth);
|
||||||
|
}
|
||||||
|
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package org.cerberus.core.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.web.servlet.error.ErrorAttributes;
|
||||||
|
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller that catch errors from spring rest or spring security and others, and transform them to JSON response.
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/error")
|
||||||
|
public class CustomErrorController implements ErrorController {
|
||||||
|
|
||||||
|
private final ErrorAttributes errorAttributes;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public CustomErrorController(ErrorAttributes errorAttributes) {
|
||||||
|
Assert.notNull(errorAttributes, "ErrorAttributes must not be null");
|
||||||
|
this.errorAttributes = errorAttributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getErrorPath() {
|
||||||
|
return "/error";
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping
|
||||||
|
public Map<String, Object> error(HttpServletRequest request) {
|
||||||
|
Map<String, Object> body = getErrorAttributes(request, getTraceParameter(request));
|
||||||
|
String trace = (String) body.get("trace");
|
||||||
|
if (trace != null) {
|
||||||
|
String[] lines = trace.split("\n\t");
|
||||||
|
body.put("trace", lines);
|
||||||
|
}
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getTraceParameter(HttpServletRequest request) {
|
||||||
|
String parameter = request.getParameter("trace");
|
||||||
|
if (parameter == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !"false".equals(parameter.toLowerCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
|
||||||
|
return errorAttributes.getErrorAttributes(new ServletWebRequest(request), includeStackTrace);
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/org/cerberus/core/config/JpaConfiguration.java
Normal file
41
src/main/java/org/cerberus/core/config/JpaConfiguration.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package org.cerberus.core.config;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.boot.autoconfigure.domain.EntityScan;
|
||||||
|
import org.springframework.boot.jdbc.DataSourceBuilder;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.PropertySource;
|
||||||
|
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||||
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
|
||||||
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EntityScan("org.cerberus.entities.persistence")
|
||||||
|
@EnableTransactionManagement
|
||||||
|
@EnableJpaRepositories("org.cerberus.repositories")
|
||||||
|
@PropertySource("classpath:application.yml")
|
||||||
|
public class JpaConfiguration {
|
||||||
|
@Value("${spring.jpa.datasource.driverClassName}")
|
||||||
|
private String driverClassName;
|
||||||
|
|
||||||
|
@Value("${spring.jpa.datasource.url}")
|
||||||
|
private String url;
|
||||||
|
|
||||||
|
@Value("${spring.jpa.datasource.username}")
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@Value("${spring.jpa.datasource.password}")
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Bean(name = "dataSource")
|
||||||
|
public DataSource getDataSource() {
|
||||||
|
return DataSourceBuilder.create()
|
||||||
|
.username(username)
|
||||||
|
.password(password)
|
||||||
|
.url(url)
|
||||||
|
.driverClassName(driverClassName)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
34
src/main/java/org/cerberus/core/config/WebConfiguration.java
Normal file
34
src/main/java/org/cerberus/core/config/WebConfiguration.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package org.cerberus.core.config;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
import org.springframework.web.servlet.resource.PathResourceResolver;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This configuration class serves Angular app if the url isn't available in sprint REST module.
|
||||||
|
*
|
||||||
|
* @author florian
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class WebConfiguration implements WebMvcConfigurer {
|
||||||
|
@Override
|
||||||
|
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||||
|
registry.addResourceHandler("/**/*")
|
||||||
|
.addResourceLocations("classpath:/static/")
|
||||||
|
.resourceChain(true)
|
||||||
|
.addResolver(new PathResourceResolver() {
|
||||||
|
@Override
|
||||||
|
protected Resource getResource(String resourcePath, Resource location) throws IOException {
|
||||||
|
Resource requestedResource = location.createRelative(resourcePath);
|
||||||
|
return requestedResource.exists() && requestedResource.isReadable() ? requestedResource
|
||||||
|
: new ClassPathResource("/static/index.html");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/main/java/org/cerberus/core/config/security/CorsFilter.java
Executable file
38
src/main/java/org/cerberus/core/config/security/CorsFilter.java
Executable file
@@ -0,0 +1,38 @@
|
|||||||
|
package org.cerberus.core.config.security;
|
||||||
|
|
||||||
|
import org.springframework.core.Ordered;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
|
public class CorsFilter implements Filter {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(FilterConfig filterConfig) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
|
||||||
|
throws IOException, ServletException {
|
||||||
|
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||||
|
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
httpResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT, PATCH, HEAD");
|
||||||
|
httpResponse.addHeader("Access-Control-Allow-Headers", "Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers");
|
||||||
|
httpResponse.addHeader("Access-Control-Expose-Headers", "Access-Control-Allow-Origin, Access-Control-Allow-Credentials");
|
||||||
|
httpResponse.addHeader("Access-Control-Allow-Credentials", "true");
|
||||||
|
httpResponse.addIntHeader("Access-Control-Max-Age", 10);
|
||||||
|
chain.doFilter(request, httpResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package org.cerberus.core.config.security;
|
||||||
|
|
||||||
|
import org.springframework.security.authentication.AuthenticationProvider;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class CustomAuthenticationProvider implements AuthenticationProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
|
||||||
|
// Creation of the authentication bean with its roles
|
||||||
|
Authentication auth = new UsernamePasswordAuthenticationToken(authentication.getName(),
|
||||||
|
authentication.getCredentials(), new ArrayList<>());
|
||||||
|
|
||||||
|
// Set the auth bean in spring security context
|
||||||
|
SecurityContextHolder.getContext().setAuthentication(auth);
|
||||||
|
|
||||||
|
return auth;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(Class<?> authentication) {
|
||||||
|
return authentication.equals(UsernamePasswordAuthenticationToken.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.cerberus.core.config.security;
|
||||||
|
|
||||||
|
import org.springframework.security.core.AuthenticationException;
|
||||||
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authentication entry point configured in
|
||||||
|
* {@link SecurityConfiguration#configure(org.springframework.security.config.annotation.web.builders.HttpSecurity)}
|
||||||
|
* to avoid yo get a login form at authentication failure from Angular app.
|
||||||
|
*
|
||||||
|
* @author takiguchi
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
|
||||||
|
@Override
|
||||||
|
public void commence(HttpServletRequest request, HttpServletResponse response,
|
||||||
|
AuthenticationException authException) throws IOException {
|
||||||
|
response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
}
|
||||||
72
src/main/java/org/cerberus/core/config/security/SecurityConfiguration.java
Executable file
72
src/main/java/org/cerberus/core/config/security/SecurityConfiguration.java
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
package org.cerberus.core.config.security;
|
||||||
|
|
||||||
|
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.core.annotation.Order;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||||
|
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.csrf.CsrfFilter;
|
||||||
|
import org.springframework.security.web.csrf.CsrfTokenRepository;
|
||||||
|
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||||
|
|
||||||
|
import static org.springframework.http.HttpMethod.GET;
|
||||||
|
import static org.springframework.http.HttpMethod.POST;
|
||||||
|
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@EnableWebSecurity
|
||||||
|
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||||
|
@Order(SecurityProperties.BASIC_AUTH_ORDER)
|
||||||
|
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
|
private static final String XSRF_REPOSITORY_HEADER_NAME = "X-XSRF-TOKEN";
|
||||||
|
|
||||||
|
private CustomAuthenticationProvider authenticationProvider;
|
||||||
|
private RestAuthenticationEntryPoint authenticationEntryPoint;
|
||||||
|
|
||||||
|
public SecurityConfiguration(CustomAuthenticationProvider authenticationProvider,
|
||||||
|
RestAuthenticationEntryPoint authenticationEntryPoint) {
|
||||||
|
this.authenticationProvider = authenticationProvider;
|
||||||
|
this.authenticationEntryPoint = authenticationEntryPoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(AuthenticationManagerBuilder auth) {
|
||||||
|
auth.authenticationProvider(authenticationProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
http.authorizeRequests()
|
||||||
|
// Permits all
|
||||||
|
.antMatchers(
|
||||||
|
"/robots.txt"
|
||||||
|
).permitAll()
|
||||||
|
.antMatchers(GET,
|
||||||
|
"/api/users/disconnection"
|
||||||
|
).permitAll()
|
||||||
|
.antMatchers(POST,
|
||||||
|
"/api/users/login"
|
||||||
|
).permitAll()
|
||||||
|
.anyRequest().permitAll()
|
||||||
|
.and()
|
||||||
|
// Allow to avoid login form at authentication failure from Angular app
|
||||||
|
.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint)
|
||||||
|
.and()
|
||||||
|
.addFilterAfter(new XSRFTokenFilter(), CsrfFilter.class)
|
||||||
|
.csrf()
|
||||||
|
.csrfTokenRepository(xsrfTokenRepository());
|
||||||
|
http.httpBasic();
|
||||||
|
http.csrf().disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
private CsrfTokenRepository xsrfTokenRepository() {
|
||||||
|
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
|
||||||
|
repository.setHeaderName(XSRF_REPOSITORY_HEADER_NAME);
|
||||||
|
return repository;
|
||||||
|
}
|
||||||
|
}
|
||||||
33
src/main/java/org/cerberus/core/config/security/XSRFTokenFilter.java
Executable file
33
src/main/java/org/cerberus/core/config/security/XSRFTokenFilter.java
Executable file
@@ -0,0 +1,33 @@
|
|||||||
|
package org.cerberus.core.config.security;
|
||||||
|
|
||||||
|
import org.springframework.security.web.csrf.CsrfToken;
|
||||||
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
import org.springframework.web.util.WebUtils;
|
||||||
|
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.Cookie;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public class XSRFTokenFilter extends OncePerRequestFilter {
|
||||||
|
private static final String XSRF_TOKEN_PATH = "/";
|
||||||
|
private static final String XSRF_TOKEN = "XSRF-TOKEN";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
|
||||||
|
throws ServletException, IOException {
|
||||||
|
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
|
||||||
|
if(csrf != null) {
|
||||||
|
Cookie cookie = WebUtils.getCookie(request, XSRF_TOKEN);
|
||||||
|
String token = csrf.getToken();
|
||||||
|
if(cookie == null || token != null && !token.equals(cookie.getValue())) {
|
||||||
|
cookie = new Cookie(XSRF_TOKEN, token);
|
||||||
|
cookie.setPath(XSRF_TOKEN_PATH);
|
||||||
|
response.addCookie(cookie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.cerberus.core.exceptions;
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
|
|
||||||
|
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
|
||||||
|
public class BadRequestException extends BusinessException {
|
||||||
|
public BadRequestException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BadRequestException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
package org.cerberus.core.exceptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract class for all business exception that could be thrown at any time.
|
||||||
|
*/
|
||||||
|
abstract class BusinessException extends RuntimeException {
|
||||||
|
BusinessException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
BusinessException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
package org.cerberus.entities.persistence;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Generated;
|
||||||
|
import org.hibernate.annotations.GenerationTime;
|
||||||
|
import org.hibernate.annotations.Proxy;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name="application")
|
||||||
|
@Proxy(lazy = false)
|
||||||
|
public class Application {
|
||||||
|
@Id
|
||||||
|
@Generated(GenerationTime.ALWAYS)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String serviceName;
|
||||||
|
|
||||||
|
@OneToMany(mappedBy = "application")
|
||||||
|
private List<ConfigurationFile> configurationFileList;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "administrator",
|
||||||
|
joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "application_id", referencedColumnName = "id")
|
||||||
|
)
|
||||||
|
private List<User> administratorList;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServiceName() {
|
||||||
|
return serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setServiceName(String serviceName) {
|
||||||
|
this.serviceName = serviceName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<ConfigurationFile> getConfigurationFileList() {
|
||||||
|
return configurationFileList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConfigurationFileList(List<ConfigurationFile> configurationFileList) {
|
||||||
|
this.configurationFileList = configurationFileList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<User> getAdministratorList() {
|
||||||
|
return administratorList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAdministratorList(List<User> administratorList) {
|
||||||
|
this.administratorList = administratorList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package org.cerberus.entities.persistence;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Generated;
|
||||||
|
import org.hibernate.annotations.GenerationTime;
|
||||||
|
import org.hibernate.annotations.Proxy;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name="configuration_file")
|
||||||
|
@Proxy(lazy = false)
|
||||||
|
public class ConfigurationFile {
|
||||||
|
@Id
|
||||||
|
@Generated(GenerationTime.ALWAYS)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "application_id")
|
||||||
|
private Application application;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPath(String path) {
|
||||||
|
this.path = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Application getApplication() {
|
||||||
|
return application;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApplication(Application application) {
|
||||||
|
this.application = application;
|
||||||
|
}
|
||||||
|
}
|
||||||
87
src/main/java/org/cerberus/entities/persistence/User.java
Normal file
87
src/main/java/org/cerberus/entities/persistence/User.java
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package org.cerberus.entities.persistence;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Generated;
|
||||||
|
import org.hibernate.annotations.GenerationTime;
|
||||||
|
import org.hibernate.annotations.Proxy;
|
||||||
|
|
||||||
|
import javax.persistence.*;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Entity
|
||||||
|
@Table(name="`user`")
|
||||||
|
@Proxy(lazy = false)
|
||||||
|
public class User {
|
||||||
|
@Id
|
||||||
|
@Generated(GenerationTime.ALWAYS)
|
||||||
|
private String id;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@Column(nullable = false)
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Column(name = "inscription_date", nullable = false)
|
||||||
|
@Generated(GenerationTime.ALWAYS)
|
||||||
|
private LocalDate inscriptionDate;
|
||||||
|
|
||||||
|
@ManyToMany
|
||||||
|
@JoinTable(
|
||||||
|
name = "administrator",
|
||||||
|
joinColumns = @JoinColumn(name = "application_id", referencedColumnName = "id"),
|
||||||
|
inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")
|
||||||
|
)
|
||||||
|
private List<Application> applicationList;
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(String id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEmail(String email) {
|
||||||
|
this.email = email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPassword() {
|
||||||
|
return password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassword(String password) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LocalDate getInscriptionDate() {
|
||||||
|
return inscriptionDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setInscriptionDate(LocalDate inscriptionDate) {
|
||||||
|
this.inscriptionDate = inscriptionDate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Application> getApplicationList() {
|
||||||
|
return applicationList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setApplicationList(List<Application> applicationList) {
|
||||||
|
this.applicationList = applicationList;
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/main/java/org/cerberus/repositories/UserRepository.java
Normal file
13
src/main/java/org/cerberus/repositories/UserRepository.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package org.cerberus.repositories;
|
||||||
|
|
||||||
|
import org.cerberus.entities.persistence.User;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public interface UserRepository extends JpaRepository<User, String> {
|
||||||
|
@Query("SELECT u FROM User u WHERE u.email = :email")
|
||||||
|
Optional<User> findByEmail(@Param("email") String email);
|
||||||
|
}
|
||||||
42
src/main/java/org/cerberus/services/UserService.java
Normal file
42
src/main/java/org/cerberus/services/UserService.java
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
package org.cerberus.services;
|
||||||
|
|
||||||
|
import org.cerberus.core.config.security.CustomAuthenticationProvider;
|
||||||
|
import org.cerberus.core.exceptions.BadRequestException;
|
||||||
|
import org.cerberus.entities.persistence.User;
|
||||||
|
import org.cerberus.repositories.UserRepository;
|
||||||
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.swing.text.html.Option;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class UserService {
|
||||||
|
private CustomAuthenticationProvider authenticationProvider;
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
public UserService(CustomAuthenticationProvider authenticationProvider, UserRepository userRepository) {
|
||||||
|
this.authenticationProvider = authenticationProvider;
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void authenticate(User user) {
|
||||||
|
checkCredentials(user.getEmail(), user.getPassword());
|
||||||
|
|
||||||
|
authenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(
|
||||||
|
user.getEmail(),
|
||||||
|
user.getPassword(),
|
||||||
|
Collections.singleton(new SimpleGrantedAuthority("APPLICATION_ADMIN"))
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
void checkCredentials(String email, String password) {
|
||||||
|
Optional<User> optUser = userRepository.findByEmail(email);
|
||||||
|
|
||||||
|
if(optUser.isEmpty() || !optUser.get().getPassword().equals(password)) {
|
||||||
|
throw new BadRequestException("Credentials are incorrect.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
src/main/resources/application.yml
Normal file
26
src/main/resources/application.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
logging:
|
||||||
|
level:
|
||||||
|
org:
|
||||||
|
hibernate:
|
||||||
|
SQL: DEBUG
|
||||||
|
|
||||||
|
server:
|
||||||
|
# use-forward-headers=true
|
||||||
|
error:
|
||||||
|
whitelabel:
|
||||||
|
enabled: false # Disable html error responses.
|
||||||
|
port: 8080
|
||||||
|
|
||||||
|
spring:
|
||||||
|
jpa:
|
||||||
|
datasource:
|
||||||
|
driverClassName: org.postgresql.Driver
|
||||||
|
url: jdbc:postgresql://localhost:5432/db_cerberus
|
||||||
|
username: cerberus
|
||||||
|
password: P@ssword
|
||||||
|
open-in-view: false
|
||||||
|
# Because detection is disabled you have to set correct dialect by hand.
|
||||||
|
database-platform: org.hibernate.dialect.PostgreSQL9Dialect
|
||||||
|
# Disable feature detection by this undocumented parameter.
|
||||||
|
# Check the org.hibernate.engine.jdbc.internal.JdbcServiceImpl.configure method for more details.
|
||||||
|
properties.hibernate.temp.use_jdbc_metadata_defaults: false
|
||||||
15
src/main/resources/banner.txt
Normal file
15
src/main/resources/banner.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
***********
|
||||||
|
*******************
|
||||||
|
***********************
|
||||||
|
*********##*****##*********
|
||||||
|
*****#***###########***#***** ( )
|
||||||
|
*****#######*#####*#######***** )\ ( ( ( /( ( (
|
||||||
|
****#######################**** (((_) ))\ )( )\()) ))\ )( ( (
|
||||||
|
****#*########***########*#**** )\___ /((_|()\((_)\ /((_|()\ )\ )\
|
||||||
|
****#*#########*#########*#**** ((/ __(_)) ((_) |(_)(_)) ((_)((_|(_)
|
||||||
|
******##*#####***#####*##****** | (__/ -_)| '_| '_ \/ -_)| '_| | (_-<
|
||||||
|
******########***########****** \___\___||_| |_.__/\___||_| \___/__/
|
||||||
|
******#######***#######******
|
||||||
|
******######***######******
|
||||||
|
*******###***###*******
|
||||||
|
*******************
|
||||||
34
src/main/sql/1.0.0-SNAPSHOT
Normal file
34
src/main/sql/1.0.0-SNAPSHOT
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
CREATE TABLE "user" (
|
||||||
|
id uuid DEFAULT uuid_generate_v4(),
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
email VARCHAR NOT NULL UNIQUE,
|
||||||
|
password VARCHAR NOT NULL,
|
||||||
|
inscription_date DATE DEFAULT current_date,
|
||||||
|
CONSTRAINT user_pk PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE application (
|
||||||
|
id uuid DEFAULT uuid_generate_v4(),
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
service_name VARCHAR NOT NULL,
|
||||||
|
CONSTRAINT application_pk PRIMARY KEY (id)
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE configuration_file (
|
||||||
|
id uuid DEFAULT uuid_generate_v4(),
|
||||||
|
path VARCHAR NOT NULL,
|
||||||
|
application_id uuid NOT NULL,
|
||||||
|
CONSTRAINT configuration_file_pk PRIMARY KEY (id),
|
||||||
|
CONSTRAINT configuration_file_application_id_fk FOREIGN KEY (application_id) REFERENCES application (id)
|
||||||
|
);
|
||||||
|
CREATE INDEX configuration_file_application_id_idx ON configuration_file(application_id);
|
||||||
|
|
||||||
|
CREATE TABLE administrator (
|
||||||
|
user_id uuid NOT NULL,
|
||||||
|
application_id uuid NOT NULL,
|
||||||
|
CONSTRAINT administrator_pk PRIMARY KEY (user_id, application_id),
|
||||||
|
CONSTRAINT administrator_user_id FOREIGN KEY (user_id) REFERENCES "user" (id),
|
||||||
|
CONSTRAINT administrator_application_id FOREIGN KEY (application_id) REFERENCES application (id)
|
||||||
|
);
|
||||||
|
CREATE INDEX administrator_user_id_idx ON administrator(user_id);
|
||||||
|
CREATE INDEX administrator_application_id_idx ON administrator(application_id);
|
||||||
Reference in New Issue
Block a user