From 0c7fdc60f3ede3ced3c2cc5307ed86af03b3ce9d Mon Sep 17 00:00:00 2001 From: Sonia Zorba <sonia.zorba@inaf.it> Date: Tue, 6 Aug 2019 10:17:54 +0200 Subject: [PATCH] Added PermissionsController and search user functionality --- .../it/inaf/ia2/gms/authn/SessionData.java | 2 +- .../ia2/gms/controller/GroupsController.java | 3 - .../gms/controller/PermissionsController.java | 36 +++++++++ .../ia2/gms/controller/UsersController.java | 23 ++++++ .../java/it/inaf/ia2/gms/model/Identity.java | 27 +++++++ .../it/inaf/ia2/gms/model/IdentityType.java | 15 ++++ .../java/it/inaf/ia2/gms/model/RapUser.java | 38 ++++++--- .../persistence/PermissionsRepository.java | 6 ++ .../java/it/inaf/ia2/gms/rap/RapClient.java | 16 ++++ .../ia2/gms/service/PermissionsService.java | 20 ++++- .../PermissionsServiceIntegrationTest.java | 79 +++++++++++++++++++ 11 files changed, 249 insertions(+), 16 deletions(-) create mode 100644 gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java create mode 100644 gms/src/main/java/it/inaf/ia2/gms/controller/UsersController.java create mode 100644 gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java diff --git a/gms/src/main/java/it/inaf/ia2/gms/authn/SessionData.java b/gms/src/main/java/it/inaf/ia2/gms/authn/SessionData.java index 92ddbc8..b3fd20a 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/authn/SessionData.java +++ b/gms/src/main/java/it/inaf/ia2/gms/authn/SessionData.java @@ -26,7 +26,7 @@ public class SessionData { public void init() { CustomAuthenticationData authn = (CustomAuthenticationData) ((OAuth2Authentication) request.getUserPrincipal()).getUserAuthentication(); userId = (String) authn.getPrincipal(); - accessToken = (String) authn.getAttributes().get("access_token"); + accessToken = (String) authn.getAccessToken().getValue(); if (!usersRepository.findById(userId).isPresent()) { User user = new User(); diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java index 256cc9a..22c93cb 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/GroupsController.java @@ -1,7 +1,6 @@ package it.inaf.ia2.gms.controller; import it.inaf.ia2.gms.authn.SessionData; -import it.inaf.ia2.gms.exception.BadRequestException; import it.inaf.ia2.gms.model.CreateGroupRequest; import it.inaf.ia2.gms.model.GroupNode; import it.inaf.ia2.gms.model.GroupsModelRequest; @@ -14,9 +13,7 @@ import it.inaf.ia2.gms.persistence.model.User; import it.inaf.ia2.gms.service.GroupsModelService; import it.inaf.ia2.gms.service.GroupsService; import it.inaf.ia2.gms.service.UsersService; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java new file mode 100644 index 0000000..4ae3d1c --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/PermissionsController.java @@ -0,0 +1,36 @@ +package it.inaf.ia2.gms.controller; + +import it.inaf.ia2.gms.authn.SessionData; +import it.inaf.ia2.gms.model.Permission; +import it.inaf.ia2.gms.persistence.model.User; +import it.inaf.ia2.gms.service.PermissionsService; +import it.inaf.ia2.gms.service.UsersService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class PermissionsController { + + @Autowired + private SessionData session; + + @Autowired + private UsersService usersService; + + @Autowired + private PermissionsService permissionsService; + + @DeleteMapping(value = "/permission", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public ResponseEntity deletePermission(@RequestParam("user") String userId, @RequestParam("group") String group, @RequestParam("permission") Permission permission) { + User user = getUser(); + return null; + } + + private User getUser() { + return usersService.getUserById(session.getUserId()); + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/UsersController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/UsersController.java new file mode 100644 index 0000000..54577f6 --- /dev/null +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/UsersController.java @@ -0,0 +1,23 @@ +package it.inaf.ia2.gms.controller; + +import it.inaf.ia2.gms.model.RapUser; +import it.inaf.ia2.gms.rap.RapClient; +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class UsersController { + + @Autowired + private RapClient rapClient; + + @GetMapping(value = "users", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE, produces = MediaType.APPLICATION_JSON_UTF8_VALUE) + public ResponseEntity<List<RapUser>> searchUsers(@RequestParam("search") String searchText) { + return ResponseEntity.ok(rapClient.searchUsers(searchText)); + } +} diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java b/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java index c7031e5..12d99a2 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java +++ b/gms/src/main/java/it/inaf/ia2/gms/model/Identity.java @@ -4,6 +4,9 @@ public class Identity { private IdentityType type; private String email; + private String name; + private String surname; + private boolean primary; public IdentityType getType() { return type; @@ -20,4 +23,28 @@ public class Identity { public void setEmail(String email) { this.email = email; } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getSurname() { + return surname; + } + + public void setSurname(String surname) { + this.surname = surname; + } + + public boolean isPrimary() { + return primary; + } + + public void setPrimary(boolean primary) { + this.primary = primary; + } } diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/IdentityType.java b/gms/src/main/java/it/inaf/ia2/gms/model/IdentityType.java index fe0c6f6..4ae1214 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/model/IdentityType.java +++ b/gms/src/main/java/it/inaf/ia2/gms/model/IdentityType.java @@ -1,5 +1,9 @@ package it.inaf.ia2.gms.model; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; +import java.util.Arrays; + public enum IdentityType { EDU_GAIN("EduGAIN"), @@ -19,4 +23,15 @@ public enum IdentityType { public String getValue() { return value; } + + @JsonCreator + public static IdentityType forValue(String value) { + return Arrays.stream(IdentityType.values()) + .filter(it -> value.equals(it.value)).findFirst().get(); + } + + @JsonValue + public String toValue() { + return value; + } } diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java b/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java index e58f27d..c3854ec 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java +++ b/gms/src/main/java/it/inaf/ia2/gms/model/RapUser.java @@ -1,11 +1,12 @@ package it.inaf.ia2.gms.model; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; public class RapUser { private String id; - private String displayName; private List<Identity> identities; public String getId() { @@ -16,14 +17,6 @@ public class RapUser { this.id = id; } - public String getDisplayName() { - return displayName; - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - public List<Identity> getIdentities() { return identities; } @@ -31,4 +24,31 @@ public class RapUser { public void setIdentities(List<Identity> identities) { this.identities = identities; } + + public String getDisplayName() { + + String displayName = null; + + // trying to extract name and surname + for (Identity identity : identities) { + if (identity.getName() != null && identity.getSurname() != null) { + displayName = String.format("%s %s", identity.getName(), identity.getSurname()); + if (identity.isPrimary()) { // prefer always primary + break; + } + } + } + + if (displayName == null) { // No name and surname --> using primary email + Identity primaryIdentity = identities.stream().filter(i -> i.isPrimary()).findFirst() + .orElseThrow(() -> new IllegalStateException("No primary identity for user " + id)); + displayName = primaryIdentity.getEmail(); + } + + // Adding types + Set<String> types = identities.stream().map(i -> i.getType().getValue()).collect(Collectors.toSet()); + displayName += String.format(" (%s)", String.join(",", types)); + + return displayName; + } } diff --git a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsRepository.java b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsRepository.java index d43f293..9184992 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsRepository.java +++ b/gms/src/main/java/it/inaf/ia2/gms/persistence/PermissionsRepository.java @@ -1,12 +1,15 @@ package it.inaf.ia2.gms.persistence; +import it.inaf.ia2.gms.model.Permission; import it.inaf.ia2.gms.persistence.model.Group; import it.inaf.ia2.gms.persistence.model.User; import it.inaf.ia2.gms.persistence.model.UserGroupPermission; import it.inaf.ia2.gms.persistence.model.UserGroupPermissionId; import java.util.List; +import java.util.Optional; import javax.transaction.Transactional; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @Repository @@ -16,4 +19,7 @@ public interface PermissionsRepository extends JpaRepository<UserGroupPermission List<UserGroupPermission> findBy_user(User user); List<UserGroupPermission> findBy_group(Group group); + + @Query("SELECT u FROM UserGroupPermission u WHERE u._user.id = ?1 AND u._group.id = ?2 AND u.permission = ?3") + Optional<UserGroupPermission> findPermission(String userId, String groupId, Permission permission); } diff --git a/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java b/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java index 0dba6d8..6481b8d 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java +++ b/gms/src/main/java/it/inaf/ia2/gms/rap/RapClient.java @@ -2,6 +2,7 @@ package it.inaf.ia2.gms.rap; import it.inaf.ia2.gms.authn.SessionData; import it.inaf.ia2.gms.model.RapUser; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; @@ -29,11 +30,26 @@ public class RapClient { public List<RapUser> getUsers(Set<String> identifiers) { + if (identifiers.isEmpty()) { + return new ArrayList<>(); + } + String url = rapBaseUrl + "/user?identifiers=" + String.join(",", identifiers); return rapRestTemplate.exchange(url, HttpMethod.GET, getEntity(), new ParameterizedTypeReference<List<RapUser>>() { }).getBody(); } + public List<RapUser> searchUsers(String searchText) { + + if (searchText == null || searchText.trim().isEmpty()) { + return new ArrayList<>(); + } + + String url = rapBaseUrl + "/user?search=" + searchText; + return rapRestTemplate.exchange(url, HttpMethod.GET, getEntity(), new ParameterizedTypeReference<List<RapUser>>() { + }).getBody(); + } + private HttpEntity<?> getEntity() { return getEntity(null); } diff --git a/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java b/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java index 7f7d3e3..1a8d643 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java +++ b/gms/src/main/java/it/inaf/ia2/gms/service/PermissionsService.java @@ -1,5 +1,7 @@ package it.inaf.ia2.gms.service; +import it.inaf.ia2.gms.exception.BadRequestException; +import it.inaf.ia2.gms.model.Permission; import it.inaf.ia2.gms.model.RapUser; import it.inaf.ia2.gms.model.UserPermission; import it.inaf.ia2.gms.persistence.PermissionsRepository; @@ -18,11 +20,14 @@ import org.springframework.stereotype.Service; @Service public class PermissionsService { - @Autowired - private PermissionsRepository permissionsRepository; + private final PermissionsRepository permissionsRepository; + private final RapClient rapClient; @Autowired - private RapClient rapClient; + public PermissionsService(PermissionsRepository permissionsRepository, RapClient rapClient) { + this.permissionsRepository = permissionsRepository; + this.rapClient = rapClient; + } public List<UserPermission> getUserPermissions(Group group) { @@ -49,4 +54,13 @@ public class PermissionsService { return result; } + + public void deletePermission(String userId, String groupId, Permission permission) { + + UserGroupPermission ugp = permissionsRepository.findPermission(userId, groupId, permission) + .orElseThrow(() -> new BadRequestException("Permission not found (UserId=" + + userId + ", GroupId=" + groupId + ", Permission=" + permission + ")")); + + permissionsRepository.delete(ugp); + } } diff --git a/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java b/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java new file mode 100644 index 0000000..99e6479 --- /dev/null +++ b/gms/src/test/java/it/inaf/ia2/gms/service/PermissionsServiceIntegrationTest.java @@ -0,0 +1,79 @@ +package it.inaf.ia2.gms.service; + +import it.inaf.ia2.gms.model.Permission; +import it.inaf.ia2.gms.model.RapUser; +import it.inaf.ia2.gms.model.UserPermission; +import it.inaf.ia2.gms.persistence.GroupsRepository; +import it.inaf.ia2.gms.persistence.PermissionsRepository; +import it.inaf.ia2.gms.persistence.UsersRepository; +import it.inaf.ia2.gms.persistence.model.Group; +import it.inaf.ia2.gms.persistence.model.User; +import it.inaf.ia2.gms.persistence.model.UserGroupPermission; +import it.inaf.ia2.gms.rap.RapClient; +import java.util.Collections; +import java.util.List; +import static org.junit.Assert.assertEquals; +import org.junit.Test; +import org.junit.runner.RunWith; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.junit4.SpringRunner; + +@DataJpaTest +@AutoConfigureTestDatabase +@RunWith(SpringRunner.class) +public class PermissionsServiceIntegrationTest { + + private static final String USER_ID = "USER_ID"; + + @Autowired + private UsersRepository usersRepository; + + @Autowired + private GroupsRepository groupsRepository; + + @Autowired + private PermissionsRepository permissionsRepository; + + @MockBean + private RapClient rapClient; + + @Test + public void permissionsRetrievalTest() { + + // Mock RAP client + RapUser rapUser = new RapUser(); + rapUser.setId(USER_ID); + when(rapClient.getUsers(any())).thenReturn(Collections.singletonList(rapUser)); + + PermissionsService permissionsService = new PermissionsService(permissionsRepository, rapClient); + + // Create user + User user = new User(); + user.setId(USER_ID); + user = usersRepository.save(user); + + Group root = new Group(); + root.setId(GroupsService.ROOT); + root.setName(GroupsService.ROOT); + root = groupsRepository.save(root); + + UserGroupPermission superAdminPermission = new UserGroupPermission(); + superAdminPermission.setUser(user); + superAdminPermission.setGroup(root); + superAdminPermission.setPermission(Permission.ADMIN); + permissionsRepository.save(superAdminPermission); + + List<UserPermission> permissions = permissionsService.getUserPermissions(root); + + assertEquals(1, permissions.size()); + assertEquals(Permission.ADMIN, permissions.get(0).getPermission()); + assertEquals(USER_ID, permissions.get(0).getUser().getId()); + + permissionsService.deletePermission(USER_ID, GroupsService.ROOT, Permission.ADMIN); + } +} -- GitLab