Add application creation route.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package org.cerberus.controllers;
|
||||
|
||||
import org.cerberus.entities.persistence.Application;
|
||||
import org.cerberus.entities.persistence.User;
|
||||
import org.cerberus.services.ApplicationService;
|
||||
import org.cerberus.services.SecurityService;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/applications")
|
||||
public class ApplicationController {
|
||||
private ApplicationService applicationService;
|
||||
private SecurityService securityService;
|
||||
|
||||
public ApplicationController(ApplicationService applicationService,
|
||||
SecurityService securityService) {
|
||||
this.applicationService = applicationService;
|
||||
this.securityService = securityService;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public Application create(@RequestBody Application application, Principal connectedUser) {
|
||||
User user = securityService.getAdminUser(connectedUser);
|
||||
return applicationService.create(application, user);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,9 @@
|
||||
package org.cerberus.controllers;
|
||||
|
||||
import org.cerberus.core.config.security.CustomAuthenticationProvider;
|
||||
import org.cerberus.entities.dto.SignUpDTO;
|
||||
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.*;
|
||||
@@ -15,6 +11,8 @@ import org.springframework.web.bind.annotation.*;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import static org.springframework.http.HttpStatus.NO_CONTENT;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/users")
|
||||
public class UserController {
|
||||
@@ -25,23 +23,23 @@ public class UserController {
|
||||
}
|
||||
|
||||
@PostMapping("/login")
|
||||
public void login(@RequestBody User user, HttpServletResponse response) {
|
||||
@ResponseStatus(NO_CONTENT)
|
||||
public void login(@RequestBody User user) {
|
||||
userService.authenticate(user);
|
||||
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
}
|
||||
|
||||
@GetMapping("/disconnection")
|
||||
@ResponseStatus(NO_CONTENT)
|
||||
public void disconnection(HttpServletRequest request, HttpServletResponse response) {
|
||||
final Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
if(auth != null) {
|
||||
new SecurityContextLogoutHandler().logout(request, response, auth);
|
||||
}
|
||||
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
}
|
||||
|
||||
@PostMapping("/signup")
|
||||
public void signUp(@RequestBody SignUpDTO inputData, HttpServletResponse response) {
|
||||
@ResponseStatus(NO_CONTENT)
|
||||
public void signUp(@RequestBody SignUpDTO inputData) {
|
||||
userService.signUp(inputData);
|
||||
response.setStatus(HttpServletResponse.SC_NO_CONTENT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.cerberus.core.config.security;
|
||||
|
||||
import org.cerberus.core.constant.RoleSecurity;
|
||||
import org.springframework.boot.autoconfigure.security.SecurityProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
@@ -19,7 +20,10 @@ import static org.springframework.http.HttpMethod.POST;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
@EnableGlobalMethodSecurity(
|
||||
prePostEnabled = true,
|
||||
securedEnabled = true
|
||||
)
|
||||
@Order(SecurityProperties.BASIC_AUTH_ORDER)
|
||||
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@@ -41,8 +45,9 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
// Permits all
|
||||
http.httpBasic()
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers(
|
||||
"/robots.txt"
|
||||
).permitAll()
|
||||
@@ -51,8 +56,10 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
).permitAll()
|
||||
.antMatchers(POST,
|
||||
"/api/users/login",
|
||||
"/api/users/signup"
|
||||
"/api/users/signup",
|
||||
"/api/applications"
|
||||
).permitAll()
|
||||
.antMatchers("/api/**").authenticated()
|
||||
.anyRequest().permitAll()
|
||||
.and()
|
||||
// Allow to avoid login form at authentication failure from Angular app
|
||||
@@ -60,9 +67,8 @@ public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
|
||||
.and()
|
||||
.addFilterAfter(new XSRFTokenFilter(), CsrfFilter.class)
|
||||
.csrf()
|
||||
.csrfTokenRepository(xsrfTokenRepository());
|
||||
http.httpBasic();
|
||||
http.csrf().disable();
|
||||
.csrfTokenRepository(xsrfTokenRepository())
|
||||
.disable();
|
||||
}
|
||||
|
||||
private CsrfTokenRepository xsrfTokenRepository() {
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.cerberus.core.exceptions;
|
||||
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.FORBIDDEN)
|
||||
public class ForbiddenException extends BusinessException {
|
||||
public ForbiddenException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ForbiddenException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package org.cerberus.core.exceptions;
|
||||
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public class InternalServerErrorException extends BusinessException {
|
||||
public InternalServerErrorException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InternalServerErrorException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package org.cerberus.entities.persistence;
|
||||
import org.hibernate.annotations.Proxy;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -19,10 +20,10 @@ public class Application {
|
||||
@Column(nullable = false)
|
||||
private String serviceName;
|
||||
|
||||
@OneToMany(mappedBy = "application")
|
||||
@OneToMany(mappedBy = "application", cascade = CascadeType.ALL)
|
||||
private List<ConfigurationFile> configurationFileList;
|
||||
|
||||
@OneToMany(mappedBy = "application")
|
||||
@OneToMany(mappedBy = "application", cascade = CascadeType.ALL)
|
||||
private List<ApplicationRole> administratorList;
|
||||
|
||||
@PrePersist
|
||||
@@ -55,6 +56,9 @@ public class Application {
|
||||
}
|
||||
|
||||
public List<ConfigurationFile> getConfigurationFileList() {
|
||||
if(configurationFileList == null) {
|
||||
configurationFileList = new LinkedList<>();
|
||||
}
|
||||
return configurationFileList;
|
||||
}
|
||||
|
||||
@@ -63,6 +67,9 @@ public class Application {
|
||||
}
|
||||
|
||||
public List<ApplicationRole> getAdministratorList() {
|
||||
if(administratorList == null) {
|
||||
administratorList = new LinkedList<>();
|
||||
}
|
||||
return administratorList;
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,7 @@ public class ApplicationRole {
|
||||
}
|
||||
|
||||
public void setUser(User user) {
|
||||
getId().setUserId(user.getId());
|
||||
this.user = user;
|
||||
}
|
||||
|
||||
@@ -81,6 +82,7 @@ public class ApplicationRole {
|
||||
}
|
||||
|
||||
public void setApplication(Application application) {
|
||||
getId().setApplicationId(application.getId());
|
||||
this.application = application;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class User {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Boolean getAdmin() {
|
||||
public Boolean isAdmin() {
|
||||
return isAdmin;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.cerberus.repositories;
|
||||
|
||||
import org.cerberus.entities.persistence.Application;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface ApplicationRepository extends JpaRepository<Application, UUID> {
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.cerberus.repositories;
|
||||
|
||||
import org.cerberus.entities.persistence.ApplicationRole;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Repository
|
||||
public interface ApplicationRoleRepository extends JpaRepository<ApplicationRole, UUID> {
|
||||
}
|
||||
@@ -8,8 +8,9 @@ import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, String> {
|
||||
public interface UserRepository extends JpaRepository<User, UUID> {
|
||||
@Query("SELECT u FROM User u WHERE u.email = :email")
|
||||
Optional<User> findByEmail(@Param("email") String email);
|
||||
|
||||
@@ -18,4 +19,7 @@ public interface UserRepository extends JpaRepository<User, String> {
|
||||
|
||||
@Query(value = "SELECT EXISTS(SELECT id FROM \"user\" WHERE email = :email)", nativeQuery = true)
|
||||
boolean isEmailAlreadyExists(@Param("email") String email);
|
||||
|
||||
@Query("SELECT isAdmin FROM User u WHERE u.id = :id")
|
||||
boolean isAdmin(UUID id);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
package org.cerberus.services;
|
||||
|
||||
import org.cerberus.core.constant.Role;
|
||||
import org.cerberus.entities.persistence.Application;
|
||||
import org.cerberus.entities.persistence.ApplicationRole;
|
||||
import org.cerberus.entities.persistence.User;
|
||||
import org.cerberus.repositories.ApplicationRoleRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class ApplicationRoleService {
|
||||
private ApplicationRoleRepository applicationRoleRepository;
|
||||
|
||||
public ApplicationRoleService(ApplicationRoleRepository applicationRoleRepository) {
|
||||
this.applicationRoleRepository = applicationRoleRepository;
|
||||
}
|
||||
|
||||
public void create(Application application, User user, Role role) {
|
||||
ApplicationRole applicationRole = new ApplicationRole();
|
||||
applicationRole.setApplication(application);
|
||||
applicationRole.setUser(user);
|
||||
applicationRole.setRole(role);
|
||||
|
||||
applicationRoleRepository.save(applicationRole);
|
||||
}
|
||||
}
|
||||
40
src/main/java/org/cerberus/services/ApplicationService.java
Normal file
40
src/main/java/org/cerberus/services/ApplicationService.java
Normal file
@@ -0,0 +1,40 @@
|
||||
package org.cerberus.services;
|
||||
|
||||
import org.cerberus.core.constant.Role;
|
||||
import org.cerberus.core.exceptions.InternalServerErrorException;
|
||||
import org.cerberus.entities.persistence.Application;
|
||||
import org.cerberus.entities.persistence.ApplicationRole;
|
||||
import org.cerberus.entities.persistence.User;
|
||||
import org.cerberus.repositories.ApplicationRepository;
|
||||
import org.cerberus.validators.ApplicationValidator;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import static org.cerberus.core.constant.Role.MAINTAINER;
|
||||
|
||||
@Service
|
||||
public class ApplicationService {
|
||||
|
||||
private ApplicationRepository applicationRepository;
|
||||
private ApplicationRoleService applicationRoleService;
|
||||
private ApplicationValidator applicationValidator;
|
||||
|
||||
public ApplicationService(ApplicationRepository applicationRepository,
|
||||
ApplicationRoleService applicationRoleService,
|
||||
ApplicationValidator applicationValidator) {
|
||||
this.applicationRepository = applicationRepository;
|
||||
this.applicationRoleService = applicationRoleService;
|
||||
this.applicationValidator = applicationValidator;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Application create(Application application, User user) {
|
||||
applicationValidator.checkAllAttributsConstraints(application);
|
||||
|
||||
applicationRepository.save(application);
|
||||
// Application creator is by default a maintainer
|
||||
applicationRoleService.create(application, user, MAINTAINER);
|
||||
|
||||
return application;
|
||||
}
|
||||
}
|
||||
42
src/main/java/org/cerberus/services/SecurityService.java
Normal file
42
src/main/java/org/cerberus/services/SecurityService.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package org.cerberus.services;
|
||||
|
||||
import org.cerberus.core.exceptions.ForbiddenException;
|
||||
import org.cerberus.entities.persistence.User;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
public class SecurityService {
|
||||
|
||||
private UserService userService;
|
||||
|
||||
public SecurityService(UserService userService) {
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the connected user if he's an administrator. Otherwise, a {@link ForbiddenException} will be thrown.
|
||||
* @param connectedUser The connectedUser
|
||||
*/
|
||||
public User getAdminUser(Principal connectedUser) {
|
||||
Optional<User> user = getUserByPrincipal(connectedUser);
|
||||
if(user.isEmpty() || !userService.isAdmin(user.get())) {
|
||||
throw new ForbiddenException("Illegal access attempt.");
|
||||
}
|
||||
return user.get();
|
||||
}
|
||||
|
||||
public Optional<User> getUserByPrincipal(final Principal pPrincipal) {
|
||||
Optional<User> result = Optional.empty();
|
||||
|
||||
if(pPrincipal != null) {
|
||||
SecurityContextHolder.getContext().getAuthentication();
|
||||
result = userService.findByEmail(pPrincipal.getName());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package org.cerberus.services;
|
||||
|
||||
import org.cerberus.core.constant.Role;
|
||||
import org.cerberus.core.config.security.CustomAuthenticationProvider;
|
||||
import org.cerberus.core.constant.RoleSecurity;
|
||||
import org.cerberus.core.exceptions.BadRequestException;
|
||||
import org.cerberus.entities.dto.SignUpDTO;
|
||||
import org.cerberus.entities.persistence.ApplicationRole;
|
||||
@@ -36,29 +37,38 @@ public class UserService {
|
||||
}
|
||||
|
||||
public void authenticate(User user) {
|
||||
checkCredentials(user.getEmail(), user.getPassword());
|
||||
User authenticatedUser = checkCredentials(user.getEmail(), user.getPassword());
|
||||
|
||||
authenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(
|
||||
user.getEmail(),
|
||||
user.getPassword(),
|
||||
fetchGrantedAuthorities(user)
|
||||
fetchGrantedAuthorities(authenticatedUser)
|
||||
));
|
||||
}
|
||||
|
||||
void checkCredentials(String email, String password) {
|
||||
User 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.");
|
||||
}
|
||||
|
||||
return optUser.get();
|
||||
}
|
||||
|
||||
Collection<GrantedAuthority> fetchGrantedAuthorities(User user) {
|
||||
return userRepository.getApplicationRolesByEmail(user.getEmail()).stream()
|
||||
Collection<GrantedAuthority> grantedAuthorityCollection = userRepository.getApplicationRolesByEmail(user.getEmail())
|
||||
.stream()
|
||||
.map(ApplicationRole::getRole)
|
||||
.map(Role::name)
|
||||
.map(SimpleGrantedAuthority::new)
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if(user.isAdmin()) {
|
||||
grantedAuthorityCollection.add(new SimpleGrantedAuthority(RoleSecurity.ADMIN));
|
||||
}
|
||||
|
||||
return grantedAuthorityCollection;
|
||||
}
|
||||
|
||||
public void signUp(SignUpDTO inputData) {
|
||||
@@ -70,4 +80,12 @@ public class UserService {
|
||||
|
||||
userRepository.save(signUpMapper.toUser(inputData));
|
||||
}
|
||||
|
||||
public boolean isAdmin(User user) {
|
||||
return userRepository.isAdmin(user.getId());
|
||||
}
|
||||
|
||||
public Optional<User> findByEmail(String email) {
|
||||
return userRepository.findByEmail(email);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.cerberus.validators;
|
||||
|
||||
import org.cerberus.core.exceptions.BadRequestException;
|
||||
import org.cerberus.core.utils.StringUtils;
|
||||
import org.cerberus.entities.persistence.Application;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class ApplicationValidator {
|
||||
|
||||
public void checkAllAttributsConstraints(Application application) {
|
||||
if(StringUtils.isNull(application.getName())
|
||||
|| StringUtils.isNull(application.getServiceName())) {
|
||||
throw new BadRequestException("Please fill up all required fields.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user