Add role checking method.
This commit is contained in:
@@ -4,13 +4,13 @@ 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 org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import static org.cerberus.core.constant.RoleSecurity.ADMIN;
|
||||
import static org.cerberus.core.constant.RoleSecurity.MAINTAINER;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/applications")
|
||||
public class ApplicationController {
|
||||
@@ -28,4 +28,10 @@ public class ApplicationController {
|
||||
User user = securityService.getAdminUser(connectedUser);
|
||||
return applicationService.create(application, user);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public Application update(@RequestBody Application application, Principal connectedUser) {
|
||||
securityService.checkHasAnyRole(connectedUser, application, ADMIN, MAINTAINER);
|
||||
return applicationService.update(application);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static javax.persistence.CascadeType.REMOVE;
|
||||
|
||||
@Entity
|
||||
@Table(name="application")
|
||||
@Proxy(lazy = false)
|
||||
@@ -20,10 +22,10 @@ public class Application {
|
||||
@Column(nullable = false)
|
||||
private String serviceName;
|
||||
|
||||
@OneToMany(mappedBy = "application", cascade = CascadeType.ALL)
|
||||
@OneToMany(mappedBy = "application", cascade = { REMOVE })
|
||||
private List<ConfigurationFile> configurationFileList;
|
||||
|
||||
@OneToMany(mappedBy = "application", cascade = CascadeType.ALL)
|
||||
@OneToMany(mappedBy = "application", cascade = { REMOVE })
|
||||
private List<ApplicationRole> administratorList;
|
||||
|
||||
@PrePersist
|
||||
|
||||
@@ -40,4 +40,10 @@ public class ApplicationService {
|
||||
|
||||
return application;
|
||||
}
|
||||
|
||||
public Application update(Application application) {
|
||||
applicationValidator.checkAllAttributsConstraints(application);
|
||||
applicationRepository.save(application);
|
||||
return application;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,18 @@
|
||||
package org.cerberus.services;
|
||||
|
||||
import org.cerberus.core.exceptions.ForbiddenException;
|
||||
import org.cerberus.entities.persistence.Application;
|
||||
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.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.cerberus.core.constant.RoleSecurity.ADMIN;
|
||||
|
||||
@Service
|
||||
public class SecurityService {
|
||||
@@ -29,6 +35,37 @@ public class SecurityService {
|
||||
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) {
|
||||
Optional<User> result = Optional.empty();
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package org.cerberus.services;
|
||||
|
||||
import org.cerberus.core.constant.Role;
|
||||
import org.cerberus.core.config.security.CustomAuthenticationProvider;
|
||||
import org.cerberus.core.constant.Role;
|
||||
import org.cerberus.core.constant.RoleSecurity;
|
||||
import org.cerberus.core.exceptions.BadRequestException;
|
||||
import org.cerberus.entities.dto.SignUpDTO;
|
||||
@@ -16,6 +16,7 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@@ -57,7 +58,7 @@ public class UserService {
|
||||
}
|
||||
|
||||
Collection<GrantedAuthority> fetchGrantedAuthorities(User user) {
|
||||
Collection<GrantedAuthority> grantedAuthorityCollection = userRepository.getApplicationRolesByEmail(user.getEmail())
|
||||
Collection<GrantedAuthority> grantedAuthorityCollection = getApplicationRolesByEmail(user.getEmail())
|
||||
.stream()
|
||||
.map(ApplicationRole::getRole)
|
||||
.map(Role::name)
|
||||
@@ -71,6 +72,10 @@ public class UserService {
|
||||
return grantedAuthorityCollection;
|
||||
}
|
||||
|
||||
public List<ApplicationRole> getApplicationRolesByEmail(String email) {
|
||||
return userRepository.getApplicationRolesByEmail(email);
|
||||
}
|
||||
|
||||
public void signUp(SignUpDTO inputData) {
|
||||
signUpValidator.checkAllAttributsConstraints(inputData);
|
||||
|
||||
|
||||
138
src/test/java/org/cerberus/services/SecurityServiceTest.java
Normal file
138
src/test/java/org/cerberus/services/SecurityServiceTest.java
Normal 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user