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 92ddbc8e4cae2d7546ec2abacbd5ed6ad2d08265..b3fd20a2c70990161d73aad9d88896f2d9b4c367 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 256cc9a0604f9db95131615db0333f740ce2a188..22c93cba30e72b0cdc68e467e421a213c8f37d79 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 0000000000000000000000000000000000000000..4ae3d1c7674f485c7aca11da854dba00cf96845e --- /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 0000000000000000000000000000000000000000..54577f6dbff66bb4f1f72142752471edcab39b0d --- /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 c7031e58fe552167457f2e582e7c58b23280ed51..12d99a2dd174e6da2640fe40dfd7f8b1da6c60f5 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 fe0c6f6f0f61dc80e6d3d5d0199b6f66c8f999e0..4ae121429cfb8077a70a7b0810c5728f995dcc94 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 e58f27da60c3afc8b7e5f8716ebfa8f6b06a6e5f..c3854ecfd209f6d59d3d941f7859917f4b329d23 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 d43f293ffced76d1415f7c16c27a1c3720579d43..9184992cb47e697b9d21ed6853ccfde3ace30a3e 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 0dba6d865a535ae6d4674c9b528e76c0b8438e22..6481b8d00e37057b43431342d7973eee85d0f691 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 7f7d3e353a05e606c06e468b4e79cc5e8621e020..1a8d6436e66aacf3aa045b6df2a207df2b7cbd93 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 0000000000000000000000000000000000000000..99e6479a10502010aec98ee3b26e2f092b7bd750 --- /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); + } +}