commit dcb5b7359959ceb813f9ae49bc5c2954bdbc1960 Author: florian Date: Sun Sep 1 12:16:49 2019 +0200 Init project. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..395babc --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +**/*.class +**/target +**/static +**/.idea +**/*.iml \ No newline at end of file diff --git a/logo.png b/logo.png new file mode 100644 index 0000000..1222005 Binary files /dev/null and b/logo.png differ diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..b613391 --- /dev/null +++ b/pom.xml @@ -0,0 +1,84 @@ + + + 4.0.0 + + org.cerberus + cerberus + 1.0.0-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-parent + 2.1.6.RELEASE + + + + + UTF-8 + UTF-8 + 11 + + + + + org.mindrot + jbcrypt + 0.4 + + + org.mockito + mockito-core + 3.0.0 + test + + + org.postgresql + postgresql + 42.2.6 + + + org.springframework.boot + spring-boot-devtools + runtime + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.springframework.boot + spring-boot-starter-security + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-starter-web + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + + false + + + + + \ No newline at end of file diff --git a/src/main/java/org/cerberus/CerberusApplication.java b/src/main/java/org/cerberus/CerberusApplication.java new file mode 100644 index 0000000..d1dc069 --- /dev/null +++ b/src/main/java/org/cerberus/CerberusApplication.java @@ -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); + } +} diff --git a/src/main/java/org/cerberus/controllers/RobotsTxtController.java b/src/main/java/org/cerberus/controllers/RobotsTxtController.java new file mode 100644 index 0000000..08d6d6c --- /dev/null +++ b/src/main/java/org/cerberus/controllers/RobotsTxtController.java @@ -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); + } + } +} diff --git a/src/main/java/org/cerberus/controllers/UserController.java b/src/main/java/org/cerberus/controllers/UserController.java new file mode 100644 index 0000000..ddd7243 --- /dev/null +++ b/src/main/java/org/cerberus/controllers/UserController.java @@ -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); + } +} diff --git a/src/main/java/org/cerberus/core/config/CustomErrorController.java b/src/main/java/org/cerberus/core/config/CustomErrorController.java new file mode 100644 index 0000000..6159630 --- /dev/null +++ b/src/main/java/org/cerberus/core/config/CustomErrorController.java @@ -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 error(HttpServletRequest request) { + Map 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 getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) { + return errorAttributes.getErrorAttributes(new ServletWebRequest(request), includeStackTrace); + } +} \ No newline at end of file diff --git a/src/main/java/org/cerberus/core/config/JpaConfiguration.java b/src/main/java/org/cerberus/core/config/JpaConfiguration.java new file mode 100644 index 0000000..c107c6d --- /dev/null +++ b/src/main/java/org/cerberus/core/config/JpaConfiguration.java @@ -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(); + } +} diff --git a/src/main/java/org/cerberus/core/config/WebConfiguration.java b/src/main/java/org/cerberus/core/config/WebConfiguration.java new file mode 100644 index 0000000..f57f3a4 --- /dev/null +++ b/src/main/java/org/cerberus/core/config/WebConfiguration.java @@ -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"); + } + }); + } +} diff --git a/src/main/java/org/cerberus/core/config/security/CorsFilter.java b/src/main/java/org/cerberus/core/config/security/CorsFilter.java new file mode 100755 index 0000000..7b2e56d --- /dev/null +++ b/src/main/java/org/cerberus/core/config/security/CorsFilter.java @@ -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 + } + +} diff --git a/src/main/java/org/cerberus/core/config/security/CustomAuthenticationProvider.java b/src/main/java/org/cerberus/core/config/security/CustomAuthenticationProvider.java new file mode 100755 index 0000000..e4f62be --- /dev/null +++ b/src/main/java/org/cerberus/core/config/security/CustomAuthenticationProvider.java @@ -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); + } + +} diff --git a/src/main/java/org/cerberus/core/config/security/RestAuthenticationEntryPoint.java b/src/main/java/org/cerberus/core/config/security/RestAuthenticationEntryPoint.java new file mode 100755 index 0000000..b9b81af --- /dev/null +++ b/src/main/java/org/cerberus/core/config/security/RestAuthenticationEntryPoint.java @@ -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); + } +} diff --git a/src/main/java/org/cerberus/core/config/security/SecurityConfiguration.java b/src/main/java/org/cerberus/core/config/security/SecurityConfiguration.java new file mode 100755 index 0000000..8189f9c --- /dev/null +++ b/src/main/java/org/cerberus/core/config/security/SecurityConfiguration.java @@ -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; + } +} \ No newline at end of file diff --git a/src/main/java/org/cerberus/core/config/security/XSRFTokenFilter.java b/src/main/java/org/cerberus/core/config/security/XSRFTokenFilter.java new file mode 100755 index 0000000..a685a91 --- /dev/null +++ b/src/main/java/org/cerberus/core/config/security/XSRFTokenFilter.java @@ -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); + } +} diff --git a/src/main/java/org/cerberus/core/exceptions/BadRequestException.java b/src/main/java/org/cerberus/core/exceptions/BadRequestException.java new file mode 100644 index 0000000..56de190 --- /dev/null +++ b/src/main/java/org/cerberus/core/exceptions/BadRequestException.java @@ -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); + } +} diff --git a/src/main/java/org/cerberus/core/exceptions/BusinessException.java b/src/main/java/org/cerberus/core/exceptions/BusinessException.java new file mode 100644 index 0000000..ff89a73 --- /dev/null +++ b/src/main/java/org/cerberus/core/exceptions/BusinessException.java @@ -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); + } +} diff --git a/src/main/java/org/cerberus/entities/persistence/Application.java b/src/main/java/org/cerberus/entities/persistence/Application.java new file mode 100644 index 0000000..d3e2079 --- /dev/null +++ b/src/main/java/org/cerberus/entities/persistence/Application.java @@ -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 configurationFileList; + + @ManyToMany + @JoinTable( + name = "administrator", + joinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id"), + inverseJoinColumns = @JoinColumn(name = "application_id", referencedColumnName = "id") + ) + private List 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 getConfigurationFileList() { + return configurationFileList; + } + + public void setConfigurationFileList(List configurationFileList) { + this.configurationFileList = configurationFileList; + } + + public List getAdministratorList() { + return administratorList; + } + + public void setAdministratorList(List administratorList) { + this.administratorList = administratorList; + } +} diff --git a/src/main/java/org/cerberus/entities/persistence/ConfigurationFile.java b/src/main/java/org/cerberus/entities/persistence/ConfigurationFile.java new file mode 100644 index 0000000..463499e --- /dev/null +++ b/src/main/java/org/cerberus/entities/persistence/ConfigurationFile.java @@ -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; + } +} diff --git a/src/main/java/org/cerberus/entities/persistence/User.java b/src/main/java/org/cerberus/entities/persistence/User.java new file mode 100644 index 0000000..5828f69 --- /dev/null +++ b/src/main/java/org/cerberus/entities/persistence/User.java @@ -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 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 getApplicationList() { + return applicationList; + } + + public void setApplicationList(List applicationList) { + this.applicationList = applicationList; + } +} diff --git a/src/main/java/org/cerberus/repositories/UserRepository.java b/src/main/java/org/cerberus/repositories/UserRepository.java new file mode 100644 index 0000000..fc568d4 --- /dev/null +++ b/src/main/java/org/cerberus/repositories/UserRepository.java @@ -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 { + @Query("SELECT u FROM User u WHERE u.email = :email") + Optional findByEmail(@Param("email") String email); +} diff --git a/src/main/java/org/cerberus/services/UserService.java b/src/main/java/org/cerberus/services/UserService.java new file mode 100644 index 0000000..42af00f --- /dev/null +++ b/src/main/java/org/cerberus/services/UserService.java @@ -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 optUser = userRepository.findByEmail(email); + + if(optUser.isEmpty() || !optUser.get().getPassword().equals(password)) { + throw new BadRequestException("Credentials are incorrect."); + } + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..306605a --- /dev/null +++ b/src/main/resources/application.yml @@ -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 \ No newline at end of file diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt new file mode 100644 index 0000000..ef3984f --- /dev/null +++ b/src/main/resources/banner.txt @@ -0,0 +1,15 @@ + *********** + ******************* + *********************** + *********##*****##********* + *****#***###########***#***** ( ) +*****#######*#####*#######***** )\ ( ( ( /( ( ( +****#######################**** (((_) ))\ )( )\()) ))\ )( ( ( +****#*########***########*#**** )\___ /((_|()\((_)\ /((_|()\ )\ )\ +****#*#########*#########*#**** ((/ __(_)) ((_) |(_)(_)) ((_)((_|(_) +******##*#####***#####*##****** | (__/ -_)| '_| '_ \/ -_)| '_| | (_-< +******########***########****** \___\___||_| |_.__/\___||_| \___/__/ + ******#######***#######****** + ******######***######****** + *******###***###******* + ******************* \ No newline at end of file diff --git a/src/main/sql/1.0.0-SNAPSHOT b/src/main/sql/1.0.0-SNAPSHOT new file mode 100644 index 0000000..e0b3402 --- /dev/null +++ b/src/main/sql/1.0.0-SNAPSHOT @@ -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); \ No newline at end of file