Add role checking method.

This commit is contained in:
2019-09-02 23:47:35 +02:00
parent 06dadf257f
commit 2111543027
6 changed files with 202 additions and 8 deletions

View File

@@ -4,13 +4,13 @@ import org.cerberus.entities.persistence.Application;
import org.cerberus.entities.persistence.User; import org.cerberus.entities.persistence.User;
import org.cerberus.services.ApplicationService; import org.cerberus.services.ApplicationService;
import org.cerberus.services.SecurityService; import org.cerberus.services.SecurityService;
import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.*;
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; import java.security.Principal;
import static org.cerberus.core.constant.RoleSecurity.ADMIN;
import static org.cerberus.core.constant.RoleSecurity.MAINTAINER;
@RestController @RestController
@RequestMapping("/api/applications") @RequestMapping("/api/applications")
public class ApplicationController { public class ApplicationController {
@@ -28,4 +28,10 @@ public class ApplicationController {
User user = securityService.getAdminUser(connectedUser); User user = securityService.getAdminUser(connectedUser);
return applicationService.create(application, user); return applicationService.create(application, user);
} }
@PutMapping
public Application update(@RequestBody Application application, Principal connectedUser) {
securityService.checkHasAnyRole(connectedUser, application, ADMIN, MAINTAINER);
return applicationService.update(application);
}
} }

View File

@@ -7,6 +7,8 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.UUID; import java.util.UUID;
import static javax.persistence.CascadeType.REMOVE;
@Entity @Entity
@Table(name="application") @Table(name="application")
@Proxy(lazy = false) @Proxy(lazy = false)
@@ -20,10 +22,10 @@ public class Application {
@Column(nullable = false) @Column(nullable = false)
private String serviceName; private String serviceName;
@OneToMany(mappedBy = "application", cascade = CascadeType.ALL) @OneToMany(mappedBy = "application", cascade = { REMOVE })
private List<ConfigurationFile> configurationFileList; private List<ConfigurationFile> configurationFileList;
@OneToMany(mappedBy = "application", cascade = CascadeType.ALL) @OneToMany(mappedBy = "application", cascade = { REMOVE })
private List<ApplicationRole> administratorList; private List<ApplicationRole> administratorList;
@PrePersist @PrePersist

View File

@@ -40,4 +40,10 @@ public class ApplicationService {
return application; return application;
} }
public Application update(Application application) {
applicationValidator.checkAllAttributsConstraints(application);
applicationRepository.save(application);
return application;
}
} }

View File

@@ -1,12 +1,18 @@
package org.cerberus.services; package org.cerberus.services;
import org.cerberus.core.exceptions.ForbiddenException; import org.cerberus.core.exceptions.ForbiddenException;
import org.cerberus.entities.persistence.Application;
import org.cerberus.entities.persistence.User; import org.cerberus.entities.persistence.User;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.security.Principal; import java.security.Principal;
import java.util.Arrays;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import static org.cerberus.core.constant.RoleSecurity.ADMIN;
@Service @Service
public class SecurityService { public class SecurityService {
@@ -29,6 +35,37 @@ public class SecurityService {
return user.get(); return user.get();
} }
/**
* Checks if the connectedUser has at least one of {@code roles} about the {@code application}.
* @param connectedUser The connected user.
* @param application The application about the user should have role.
* @param roles Allowed role to check.
*/
public void checkHasAnyRole(Principal connectedUser, Application application, String... roles) {
Optional<User> user = getUserByPrincipal(connectedUser);
List<String> roleList = Arrays.stream(roles).collect(Collectors.toList());
boolean userHasRole = false;
if(user.isPresent()) {
// Admin is required ?
userHasRole = roleList.contains(ADMIN) && userService.isAdmin(user.get());
if(!userHasRole) {
// Application role required ?
userHasRole = userService.getApplicationRolesByEmail(user.get().getEmail()).stream()
.anyMatch(appRole ->
appRole.getApplication().getId().equals(application.getId())
&& roleList.contains(appRole.getRole().name())
);
}
}
if(!userHasRole) {
throw new ForbiddenException("Illegal access attempt.");
}
}
public Optional<User> getUserByPrincipal(final Principal pPrincipal) { public Optional<User> getUserByPrincipal(final Principal pPrincipal) {
Optional<User> result = Optional.empty(); Optional<User> result = Optional.empty();

View File

@@ -1,7 +1,7 @@
package org.cerberus.services; package org.cerberus.services;
import org.cerberus.core.constant.Role;
import org.cerberus.core.config.security.CustomAuthenticationProvider; import org.cerberus.core.config.security.CustomAuthenticationProvider;
import org.cerberus.core.constant.Role;
import org.cerberus.core.constant.RoleSecurity; import org.cerberus.core.constant.RoleSecurity;
import org.cerberus.core.exceptions.BadRequestException; import org.cerberus.core.exceptions.BadRequestException;
import org.cerberus.entities.dto.SignUpDTO; import org.cerberus.entities.dto.SignUpDTO;
@@ -16,6 +16,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -57,7 +58,7 @@ public class UserService {
} }
Collection<GrantedAuthority> fetchGrantedAuthorities(User user) { Collection<GrantedAuthority> fetchGrantedAuthorities(User user) {
Collection<GrantedAuthority> grantedAuthorityCollection = userRepository.getApplicationRolesByEmail(user.getEmail()) Collection<GrantedAuthority> grantedAuthorityCollection = getApplicationRolesByEmail(user.getEmail())
.stream() .stream()
.map(ApplicationRole::getRole) .map(ApplicationRole::getRole)
.map(Role::name) .map(Role::name)
@@ -71,6 +72,10 @@ public class UserService {
return grantedAuthorityCollection; return grantedAuthorityCollection;
} }
public List<ApplicationRole> getApplicationRolesByEmail(String email) {
return userRepository.getApplicationRolesByEmail(email);
}
public void signUp(SignUpDTO inputData) { public void signUp(SignUpDTO inputData) {
signUpValidator.checkAllAttributsConstraints(inputData); signUpValidator.checkAllAttributsConstraints(inputData);

View File

@@ -0,0 +1,138 @@
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.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import java.security.Principal;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.ThrowableAssert.catchThrowable;
import static org.cerberus.core.constant.Role.MAINTAINER;
import static org.cerberus.core.constant.Role.VIEWER;
import static org.cerberus.core.constant.RoleSecurity.ADMIN;
import static org.mockito.BDDMockito.given;
@RunWith(MockitoJUnitRunner.class)
public class SecurityServiceTest {
private SecurityService service;
@Mock
private UserService userService;
@Before
public void before() {
service = new SecurityService(userService);
}
@Test
public void checkHasAnyRole_should_throw_an_exception_if_no_user_is_connected() {
// when
Throwable throwable = catchThrowable(() -> service.checkHasAnyRole(null, new Application(), ADMIN));
// then
assertThat(throwable).isNotNull()
.extracting("message")
.containsExactly("Illegal access attempt.");
}
@Test
public void checkHasAnyRole_should_throw_an_exception_if_user_has_no_role() {
// given
Principal principal = Mockito.mock(Principal.class);
given(principal.getName()).willReturn("name");
Application application = mockAllAndGetApp(false);
// when
Throwable throwable = catchThrowable(() -> service.checkHasAnyRole(principal, application, ADMIN));
// then
assertThat(throwable).isNotNull()
.extracting("message")
.containsExactly("Illegal access attempt.");
}
@Test
public void checkHasAnyRole_should_not_throw_any_exception_about_admin_role() {
// given
Principal principal = Mockito.mock(Principal.class);
given(principal.getName()).willReturn("name");
Application application = mockAllAndGetApp(true);
// when
service.checkHasAnyRole(principal, application, ADMIN);
}
@Test
public void checkHasAnyRole_should_not_throw_any_exception_about_some_roles() {
// given
Principal principal = Mockito.mock(Principal.class);
given(principal.getName()).willReturn("name");
Application application = mockAllAndGetApp(false, VIEWER);
// when
service.checkHasAnyRole(principal, application, "VIEWER");
}
@Test
public void checkHasAnyRole_should_not_throw_any_exception_about_some_roles2() {
// given
Principal principal = Mockito.mock(Principal.class);
given(principal.getName()).willReturn("name");
Application application = mockAllAndGetApp(false, MAINTAINER);
// when
service.checkHasAnyRole(principal, application, "ADMIN", "MAINTAINER");
}
private Application mockAllAndGetApp(boolean isAdmin, Role... roles) {
List<String> roleList = Arrays.stream(roles).map(Role::name).collect(Collectors.toList());
User user = new User();
user.setEmail("email");
given(userService.findByEmail("name")).willReturn(Optional.of(user));
Application application = new Application();
application.setId(UUID.randomUUID());
if(isAdmin) {
if(!roleList.contains("ADMIN")) {
roleList.add("ADMIN");
}
given(userService.isAdmin(user)).willReturn(true);
}
List<ApplicationRole> appRoleList = roleList.stream()
.map(roleStr -> {
try {
ApplicationRole appRole = new ApplicationRole();
appRole.setRole(Role.valueOf(roleStr));
appRole.setApplication(application);
return appRole;
} catch(IllegalArgumentException e) {
return null;
}
})
.collect(Collectors.toList());
given(userService.getApplicationRolesByEmail("email")).willReturn(appRoleList);
return application;
}
}