From c67052b0702d5a2b0be398f3e8831a4e1596ae29 Mon Sep 17 00:00:00 2001 From: Sonia Zorba <sonia.zorba@inaf.it> Date: Fri, 21 Aug 2020 18:27:03 +0200 Subject: [PATCH] Added endpoint for retrieving member email addresses; CLI improvements --- gms-client/gms-cli/pom.xml | 1 + .../main/java/it/inaf/ia2/gms/cli/CLI.java | 185 ++++++++++++++---- .../it/inaf/ia2/gms/client/GmsClient.java | 16 +- .../inaf/ia2/gms/client/GmsClientBuilder.java | 40 ++++ .../inaf/ia2/gms/client/call/BaseGmsCall.java | 6 +- .../client/call/GetMemberEmailAddresses.java | 50 +++++ .../gms/client/call/HttpClientWrapper.java | 64 ++++++ .../it/inaf/ia2/gms/client/GmsClientTest.java | 6 +- .../client/call/HttpClientWrapperTest.java | 15 ++ gms/pom.xml | 1 + .../controller/JWTWebServiceController.java | 28 +++ .../ia2/gms/manager/MembershipManager.java | 6 +- .../it/inaf/ia2/gms/model/Permission.java | 21 ++ .../java/it/inaf/ia2/gms/model/RapUser.java | 10 +- gms/src/main/resources/application.properties | 2 +- .../it/inaf/ia2/gms/model/PermissionTest.java | 30 +++ 16 files changed, 426 insertions(+), 55 deletions(-) create mode 100644 gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClientBuilder.java create mode 100644 gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/GetMemberEmailAddresses.java create mode 100644 gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/call/HttpClientWrapperTest.java diff --git a/gms-client/gms-cli/pom.xml b/gms-client/gms-cli/pom.xml index 76393e0..cfaad41 100644 --- a/gms-client/gms-cli/pom.xml +++ b/gms-client/gms-cli/pom.xml @@ -22,6 +22,7 @@ </dependency> </dependencies> <build> + <finalName>gms-cli</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> diff --git a/gms-client/gms-cli/src/main/java/it/inaf/ia2/gms/cli/CLI.java b/gms-client/gms-cli/src/main/java/it/inaf/ia2/gms/cli/CLI.java index f522fcd..a237abc 100644 --- a/gms-client/gms-cli/src/main/java/it/inaf/ia2/gms/cli/CLI.java +++ b/gms-client/gms-cli/src/main/java/it/inaf/ia2/gms/cli/CLI.java @@ -1,95 +1,207 @@ package it.inaf.ia2.gms.cli; import it.inaf.ia2.gms.client.GmsClient; +import it.inaf.ia2.gms.client.GmsClientBuilder; import it.inaf.ia2.gms.client.model.Permission; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.io.UncheckedIOException; +import java.util.List; import java.util.Properties; public class CLI { - private final GmsClient client; - public static void main(String[] args) throws Exception { - new CLI().run(args); + new CLI(args).run(); + } + + private final String args[]; + private int argIndex; + + private String gmsBaseUrl; + private String rapBaseUrl; + private String clientId; + private String clientSecret; + private String token; + + private GmsClient client; + + private CLI(String... args) { + this.args = args; + } + + private void run() throws Exception { + if (args.length < 2) { + displayUsage(); + } + + boolean commandParsed = false; + while (argIndex < args.length && !commandParsed) { + switch (args[argIndex]) { + case "--config-file": + loadConfigFromFile(new File(getNextArg())); + break; + case "--token-file": + loadTokenFromFile(new File(getNextArg())); + break; + case "--gms-url": + gmsBaseUrl = getNextArg(); + break; + case "--rap-url": + rapBaseUrl = getNextArg(); + break; + case "--client-id": + clientId = getNextArg(); + break; + case "--client-secret": + clientSecret = getNextArg(); + break; + default: + verifyConfigLoaded(); + createClient(); + parseCommand(); + commandParsed = true; + break; + } + argIndex++; + } + } + + private String getNextArg() { + if (argIndex + 1 == args.length) { + System.err.println("Missing value for option " + args[argIndex]); + System.exit(1); + } + return args[++argIndex]; } - private CLI() throws IOException { + private void verifyConfigLoaded() { + + if (gmsBaseUrl == null) { + // Attempt reading gms.properties in current directory + loadConfigFromFile(new File("gms.properties")); + } + + if (clientId == null && token == null) { + // Attempt loading token.txt in current directory + loadTokenFromFile(new File("token.txt")); + } + + if (token != null && (clientSecret == null || rapBaseUrl == null)) { + System.err.println("Client secret and RAP base URL not configured"); + System.exit(1); + } + } + + private void createClient() { + GmsClientBuilder clientBuilder = new GmsClientBuilder() + .setGmsBaseUrl(gmsBaseUrl); + + if (token != null) { + client = clientBuilder.build(); + client.setAccessToken(token); + } else { + client = clientBuilder.setClientId(clientId) + .setClientSecret(clientSecret) + .setRapBaseUrl(rapBaseUrl) + .build(); + } + } + + private void loadConfigFromFile(File config) { - File config = new File("gms.properties"); if (!config.exists()) { - System.err.println("Unable to find the file gms.properties"); + System.err.println("Config file " + config.getAbsolutePath() + " doesn't exist"); System.exit(1); } Properties properties = new Properties(); try (InputStream in = new FileInputStream(config)) { properties.load(in); + } catch (IOException ex) { + throw new UncheckedIOException(ex); } - String baseUrl = (String) properties.get("base_url"); - if (baseUrl == null) { - System.err.println("Missing base_url in gms.properties"); + gmsBaseUrl = properties.getProperty("gms_url"); + if (gmsBaseUrl == null) { + System.err.println("Missing gms_url in gms.properties"); System.exit(1); } + rapBaseUrl = properties.getProperty("rap_url"); + clientId = properties.getProperty("client_id"); + clientSecret = properties.getProperty("client_secret"); + } + + private void loadTokenFromFile(File tokenFile) { - String token = (String) properties.get("token"); - if (token == null) { - System.err.println("Missing token in gms.properties"); + if (!tokenFile.exists()) { + System.err.println("Token file " + tokenFile.getAbsolutePath() + " doesn't exist"); System.exit(1); } - client = new GmsClient(baseUrl).setAccessToken(token); + try (InputStream in = new FileInputStream(tokenFile)) { + java.util.Scanner s = new java.util.Scanner(in).useDelimiter("\\A"); + token = s.next().trim(); + } catch (IOException ex) { + throw new UncheckedIOException(ex); + } } - public void run(String... args) throws Exception { - if (args.length < 2) { - displayUsage(); - } + private void parseCommand() { - switch (args[0]) { + switch (args[argIndex]) { case "create-group": boolean leaf = false; - if (args.length > 1) { - leaf = Boolean.parseBoolean(args[2]); + if (argIndex + 2 < args.length) { + leaf = Boolean.parseBoolean(args[argIndex + 2]); } - client.createGroup(args[1], leaf); + client.createGroup(args[argIndex + 1], leaf); System.out.println("Group created"); break; case "delete-group": - client.deleteGroup(args[1]); + client.deleteGroup(args[argIndex + 1]); System.out.println("Group deleted"); break; case "add-member": - if (args.length < 3) { + if (argIndex + 2 >= args.length) { displayUsage(); } - client.addMember(args[1], args[2]); + client.addMember(args[argIndex + 1], args[argIndex + 2]); System.out.println("Member added"); break; case "remove-member": - if (args.length < 3) { + if (argIndex + 2 >= args.length) { displayUsage(); } - client.removeMember(args[1], args[2]); + client.removeMember(args[argIndex + 1], args[argIndex + 2]); System.out.println("Member removed"); break; case "add-permission": - if (args.length < 4) { + if (argIndex + 3 >= args.length) { displayUsage(); } - client.addPermission(args[1], args[2], Permission.valueOf(args[3])); + client.addPermission(args[argIndex + 1], args[argIndex + 2], Permission.valueOf(args[argIndex + 3])); System.out.println("Permission added"); break; case "delete-permission": - if (args.length < 4) { + if (argIndex + 2 >= args.length) { displayUsage(); } - client.removePermission(args[1], args[2]); + client.removePermission(args[argIndex + 1], args[argIndex + 2]); System.out.println("Permission removed"); break; + case "get-member-email-addresses": + Permission permission = null; + if (argIndex + 2 < args.length) { + permission = Permission.valueOf(args[argIndex + 2]); + } + List<String> addresses = client.getMemberEmailAddresses(args[argIndex + 1], permission); + for (String address : addresses) { + System.out.println(address); + } + break; default: displayUsage(); break; @@ -97,13 +209,20 @@ public class CLI { } private void displayUsage() { - System.out.println("java -jar gms-client.jar\n" - + " create-group <name1.name2.name3> <leaf>\n" + System.out.println("gms-client\n" + + " [--config-file <file>]\n" + + " [--token-file <file>]\n" + + " [--gms-url <url>]\n" + + " [--rap-url <url>]\n" + + " [--client-id <id>]\n" + + " [--client-secret <secret>]\n" + + " create-group <name1.name2.name3> [<leaf>]\n" + " delete-group <name1.name2.name3>\n" + " add-member <name1.name2.name3> <user_id>\n" + " remove-member <name1.name2.name3> <user_id>\n" + " add-permission <name1.name2.name3> <user_id> <permission>\n" - + " delete-permission <name1.name2.name3> <user_id>"); + + " delete-permission <name1.name2.name3> <user_id>\n" + + " get-member-email-addresses <name1.name2.name3> [<permission>]"); System.exit(0); } } diff --git a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClient.java b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClient.java index 7792277..86a9100 100644 --- a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClient.java +++ b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClient.java @@ -7,6 +7,7 @@ import it.inaf.ia2.gms.client.call.AddPermissionCall; import it.inaf.ia2.gms.client.call.CreateGroupCall; import it.inaf.ia2.gms.client.call.DeleteGroupCall; import it.inaf.ia2.gms.client.call.GetGroupPermissionsCall; +import it.inaf.ia2.gms.client.call.GetMemberEmailAddresses; import it.inaf.ia2.gms.client.call.GetUserGroupsCall; import it.inaf.ia2.gms.client.call.GetUserPermissionsCall; import it.inaf.ia2.gms.client.call.ListGroupsCall; @@ -20,15 +21,10 @@ import java.util.Map; public class GmsClient { - HttpClientWrapper httpClientWrapper; + private final HttpClientWrapper httpClientWrapper; - public GmsClient(String baseUrl) { - - if (!baseUrl.endsWith("/")) { - baseUrl += "/"; - } - - httpClientWrapper = new HttpClientWrapper(baseUrl); + GmsClient(HttpClientWrapper httpClientWrapper) { + this.httpClientWrapper = httpClientWrapper; } public GmsClient setAccessToken(String accessToken) { @@ -83,4 +79,8 @@ public class GmsClient { public void addInvitedRegistration(String token, String email, Map<String, Permission> groupsPermissions) { new AddInvitedRegistrationCall(httpClientWrapper).addInvitedRegistration(token, email, groupsPermissions); } + + public List<String> getMemberEmailAddresses(String groupId, Permission permission) { + return new GetMemberEmailAddresses(httpClientWrapper).getMemberEmailAddresses(groupId, permission); + } } diff --git a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClientBuilder.java b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClientBuilder.java new file mode 100644 index 0000000..002081d --- /dev/null +++ b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/GmsClientBuilder.java @@ -0,0 +1,40 @@ +package it.inaf.ia2.gms.client; + +import it.inaf.ia2.gms.client.call.HttpClientWrapper; + +public class GmsClientBuilder { + + private String gmsBaseUrl; + private String rapBaseUrl; + private String clientId; + private String clientSecret; + + public GmsClientBuilder setGmsBaseUrl(String gmsBaseUrl) { + this.gmsBaseUrl = gmsBaseUrl; + return this; + } + + public GmsClientBuilder setRapBaseUrl(String rapBaseUrl) { + this.rapBaseUrl = rapBaseUrl; + return this; + } + + public GmsClientBuilder setClientId(String clientId) { + this.clientId = clientId; + return this; + } + + public GmsClientBuilder setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + return this; + } + + public GmsClient build() { + HttpClientWrapper clientWrapper = new HttpClientWrapper(gmsBaseUrl); + if (rapBaseUrl != null && clientId != null && clientSecret != null) { + clientWrapper.setRapBaseUrl(rapBaseUrl) + .setClientId(clientId).setClientSecret(clientSecret); + } + return new GmsClient(clientWrapper); + } +} diff --git a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/BaseGmsCall.java b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/BaseGmsCall.java index 6f03160..161de1f 100644 --- a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/BaseGmsCall.java +++ b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/BaseGmsCall.java @@ -27,13 +27,13 @@ public abstract class BaseGmsCall { return clientWrapper.newHttpRequest(endpoint); } - protected void logServerError(HttpRequest request, HttpResponse<String> response) { + protected static void logServerError(HttpRequest request, HttpResponse<String> response) { LOGGER.log(Level.SEVERE, () -> "Error while reading " + request.uri() + "\nServer response status code is " + response.statusCode() - + "\nAServer response text is " + response.body()); + + "\nServer response text is " + response.body()); } - protected void logServerErrorInputStream(HttpRequest request, HttpResponse<InputStream> response) { + protected static void logServerErrorInputStream(HttpRequest request, HttpResponse<InputStream> response) { LOGGER.log(Level.SEVERE, () -> { Scanner s = new Scanner(response.body()).useDelimiter("\\A"); String responseBody = s.hasNext() ? s.next() : ""; diff --git a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/GetMemberEmailAddresses.java b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/GetMemberEmailAddresses.java new file mode 100644 index 0000000..a69913b --- /dev/null +++ b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/GetMemberEmailAddresses.java @@ -0,0 +1,50 @@ +package it.inaf.ia2.gms.client.call; + +import it.inaf.ia2.gms.client.model.Permission; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; + +public class GetMemberEmailAddresses extends BaseGmsCall { + + public GetMemberEmailAddresses(HttpClientWrapper clientWrapper) { + super(clientWrapper); + } + + public List<String> getMemberEmailAddresses(String group, Permission permission) { + + List<String> emailAddresses = new ArrayList<>(); + + String endpoint = "email/" + group; + if (permission != null) { + endpoint += "?permission=" + permission; + } + + HttpRequest request = newHttpRequest(endpoint) + .header("Accept", "text/plain") + .GET() + .build(); + + return getClient().sendAsync(request, HttpResponse.BodyHandlers.ofInputStream()) + .thenApply(response -> { + if (response.statusCode() == 200) { + return response.body(); + } + logServerErrorInputStream(request, response); + throw new IllegalStateException("Unable to retrieve groups"); + }) + .thenApply(inputStream -> { + try (Scanner scan = new Scanner(inputStream)) { + while (scan.hasNextLine()) { + String line = scan.nextLine(); + if (!line.isEmpty()) { + emailAddresses.add(line); + } + } + } + return emailAddresses; + }).join(); + } +} diff --git a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/HttpClientWrapper.java b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/HttpClientWrapper.java index 7bbf781..7d90d72 100644 --- a/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/HttpClientWrapper.java +++ b/gms-client/gms-client-lib/src/main/java/it/inaf/ia2/gms/client/call/HttpClientWrapper.java @@ -4,12 +4,20 @@ import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpRequest.Builder; +import java.net.http.HttpResponse; +import java.util.Base64; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class HttpClientWrapper { private final String baseGmsUri; private final HttpClient client; + private String rapBaseUrl; + private String clientId; + private String clientSecret; + private String accessToken; public HttpClientWrapper(String baseGmsUri) { @@ -29,12 +37,68 @@ public class HttpClientWrapper { return this; } + public HttpClientWrapper setRapBaseUrl(String rapBaseUrl) { + if (!rapBaseUrl.endsWith("/")) { + rapBaseUrl += "/"; + } + this.rapBaseUrl = rapBaseUrl; + return this; + } + + public HttpClientWrapper setClientId(String clientId) { + this.clientId = clientId; + return this; + } + + public HttpClientWrapper setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + return this; + } + Builder newHttpRequest(String endpoint) { + if (accessToken == null) { + accessToken = getAccessTokenFromClientCredentials(); + } return HttpRequest.newBuilder() .uri(URI.create(baseGmsUri + endpoint)) .header("Authorization", "Bearer " + accessToken); } + private String getAccessTokenFromClientCredentials() { + if (rapBaseUrl == null || clientId == null || clientSecret == null) { + throw new IllegalStateException("Access token is null and client credentials are not configured"); + } + + String basicAuthHeader = clientId + ":" + clientSecret; + + HttpRequest tokenRequest = HttpRequest.newBuilder() + .uri(URI.create(rapBaseUrl + "auth/oauth2/token")) + .header("Authorization", "Basic " + Base64.getEncoder().encodeToString(basicAuthHeader.getBytes())) + .header("Accept", "application/json") + .header("Content-Type", "application/x-www-form-urlencoded") + .POST(HttpRequest.BodyPublishers.ofString("grant_type=client_credentials")) + .build(); + + return client.sendAsync(tokenRequest, HttpResponse.BodyHandlers.ofString()) + .thenApply(response -> { + if (response.statusCode() == 200) { + return getAccessTokenFromResponse(response.body()); + } + BaseGmsCall.logServerError(tokenRequest, response); + + throw new IllegalStateException("Unable to retrieve access token"); + }).join(); + } + + protected String getAccessTokenFromResponse(String body) { + Pattern codePattern = Pattern.compile(".*\"access_token\":\\s*\"([^\"]+).*"); + Matcher matcher = codePattern.matcher(body); + if (matcher.find()) { + return matcher.group(1); + } + throw new IllegalStateException("Unable to extract access token from body"); + } + HttpClient getClient() { return client; } diff --git a/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java b/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java index b086de3..ce84caa 100644 --- a/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java +++ b/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/GmsClientTest.java @@ -7,7 +7,6 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; import java.net.http.HttpClient; import java.net.http.HttpRequest; -import java.net.http.HttpRequest.BodyPublisher; import java.net.http.HttpResponse; import java.net.http.HttpResponse.BodySubscriber; import java.net.http.HttpResponse.BodySubscribers; @@ -18,7 +17,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Flow; -import java.util.concurrent.Flow.Subscriber; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; @@ -47,9 +45,9 @@ public class GmsClientTest { httpClient = mock(HttpClient.class); HttpClientWrapper clientWrapper = new MockedHttpClientWrapper(BASE_URL, httpClient); + clientWrapper.setAccessToken("foo"); - client = new GmsClient(BASE_URL); - client.httpClientWrapper = clientWrapper; + client = new GmsClient(clientWrapper); } @Test diff --git a/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/call/HttpClientWrapperTest.java b/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/call/HttpClientWrapperTest.java new file mode 100644 index 0000000..4bc0924 --- /dev/null +++ b/gms-client/gms-client-lib/src/test/java/it/inaf/ia2/gms/client/call/HttpClientWrapperTest.java @@ -0,0 +1,15 @@ +package it.inaf.ia2.gms.client.call; + +import static org.junit.Assert.assertEquals; +import org.junit.Test; + +public class HttpClientWrapperTest { + + @Test + public void testExtractAccessToken() { + String response = "{\"access_token\":\"TEST_TOKEN\",\"token_type\":\"Bearer\",\"expires_in\":3600}"; + + HttpClientWrapper clientWrapper = new HttpClientWrapper("http://localhost"); + assertEquals("TEST_TOKEN", clientWrapper.getAccessTokenFromResponse(response)); + } +} diff --git a/gms/pom.xml b/gms/pom.xml index c799494..afe66f7 100644 --- a/gms/pom.xml +++ b/gms/pom.xml @@ -62,6 +62,7 @@ </dependencies> <build> + <finalName>gms</finalName> <plugins> <plugin> <groupId>com.github.eirslett</groupId> diff --git a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java index a5ff5cf..9677cdf 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java +++ b/gms/src/main/java/it/inaf/ia2/gms/controller/JWTWebServiceController.java @@ -7,6 +7,7 @@ import it.inaf.ia2.gms.manager.InvitedRegistrationManager; import it.inaf.ia2.gms.manager.MembershipManager; import it.inaf.ia2.gms.manager.PermissionsManager; import it.inaf.ia2.gms.model.Permission; +import it.inaf.ia2.gms.model.RapUser; import it.inaf.ia2.gms.model.response.UserPermission; import it.inaf.ia2.gms.persistence.GroupsDAO; import it.inaf.ia2.gms.persistence.PermissionsDAO; @@ -22,9 +23,11 @@ import java.io.PrintWriter; import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; @@ -301,6 +304,31 @@ public class JWTWebServiceController { response.setStatus(HttpServletResponse.SC_CREATED); } + @GetMapping(value = "/email/{group:.+}", produces = MediaType.TEXT_PLAIN_VALUE) + public void getEmailOfMembers(@PathVariable("group") String groupNames, @RequestParam("permission") Optional<Permission> permission, HttpServletResponse response) throws IOException { + + GroupEntity groupEntity = getGroupFromNames(extractGroupNames(groupNames)); + + Set<String> selectedUserIds = null; + if (permission.isPresent()) { + Permission desiredPermission = permission.get(); + selectedUserIds = new HashSet<>(); + for (PermissionEntity groupsPermission : permissionsDAO.getGroupsPermissions(groupEntity.getId())) { + if (Permission.includes(groupsPermission.getPermission(), desiredPermission)) { + selectedUserIds.add(groupsPermission.getUserId()); + } + } + } + + try (PrintWriter pw = new PrintWriter(response.getOutputStream())) { + for (RapUser member : membershipManager.getMembers(groupEntity)) { + if (selectedUserIds == null || selectedUserIds.contains(member.getId())) { + pw.println(member.getPrimaryEmail()); + } + } + } + } + private GroupEntity getGroupFromNames(List<String> groupNames) { if (groupNames.isEmpty()) { return getRoot(); diff --git a/gms/src/main/java/it/inaf/ia2/gms/manager/MembershipManager.java b/gms/src/main/java/it/inaf/ia2/gms/manager/MembershipManager.java index 3f2acf9..022e542 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/manager/MembershipManager.java +++ b/gms/src/main/java/it/inaf/ia2/gms/manager/MembershipManager.java @@ -48,7 +48,7 @@ public class MembershipManager extends UserAwareComponent { Permission groupPermission = permissionsManager.getCurrentUserPermission(group); - if (groupPermission == Permission.TRAVERSE) { + if (!Permission.includes(groupPermission, Permission.VIEW_MEMBERS)) { throw new UnauthorizedException("You don't have the permission to view members"); } @@ -98,8 +98,8 @@ public class MembershipManager extends UserAwareComponent { private Permission verifyUserCanManageMembers(GroupEntity group) { Permission permission = permissionsManager.getCurrentUserPermission(group); - if (permission != Permission.ADMIN && permission != Permission.MANAGE_MEMBERS) { - throw new UnauthorizedException("Missing admin or manage members permissions"); + if (!Permission.includes(permission, Permission.MANAGE_MEMBERS)) { + throw new UnauthorizedException("Missing manage members permissions"); } return permission; } diff --git a/gms/src/main/java/it/inaf/ia2/gms/model/Permission.java b/gms/src/main/java/it/inaf/ia2/gms/model/Permission.java index 166c1dc..8beb45a 100644 --- a/gms/src/main/java/it/inaf/ia2/gms/model/Permission.java +++ b/gms/src/main/java/it/inaf/ia2/gms/model/Permission.java @@ -32,4 +32,25 @@ public enum Permission { return oldPermission; } + + public static boolean includes(Permission permission, Permission permissionToCheck) { + if (permissionToCheck == null) { + throw new IllegalArgumentException("Permission to check cannot be null"); + } + + if (permission == null) { + return false; + } + switch (permissionToCheck) { + case ADMIN: + return permission == ADMIN; + case MANAGE_MEMBERS: + return permission == MANAGE_MEMBERS || permission == ADMIN; + case VIEW_MEMBERS: + return permission != TRAVERSE; + case TRAVERSE: + return true; + } + return false; + } } 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 5ef0ac4..846b317 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 @@ -40,9 +40,7 @@ public class RapUser { } 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(); + displayName = getPrimaryEmail(); } // Adding types @@ -56,4 +54,10 @@ public class RapUser { return displayName; } + + public String getPrimaryEmail() { + Identity primaryIdentity = identities.stream().filter(i -> i.isPrimary()).findFirst() + .orElseThrow(() -> new IllegalStateException("No primary identity for user " + id)); + return primaryIdentity.getEmail(); + } } diff --git a/gms/src/main/resources/application.properties b/gms/src/main/resources/application.properties index 19b3dac..b096d05 100644 --- a/gms/src/main/resources/application.properties +++ b/gms/src/main/resources/application.properties @@ -17,7 +17,7 @@ logging.level.org.springframework.security=DEBUG logging.level.org.springframework.jdbc=TRACE logging.level.org.springframework.web=TRACE -spring.datasource.url=jdbc:postgresql://localhost:5433/postgres +spring.datasource.url=jdbc:postgresql://localhost:5432/gms2 spring.datasource.username=gms spring.datasource.password=gms diff --git a/gms/src/test/java/it/inaf/ia2/gms/model/PermissionTest.java b/gms/src/test/java/it/inaf/ia2/gms/model/PermissionTest.java index 136befa..bf642bd 100644 --- a/gms/src/test/java/it/inaf/ia2/gms/model/PermissionTest.java +++ b/gms/src/test/java/it/inaf/ia2/gms/model/PermissionTest.java @@ -1,6 +1,8 @@ package it.inaf.ia2.gms.model; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -37,4 +39,32 @@ public class PermissionTest { assertEquals(Permission.MANAGE_MEMBERS, Permission.addPermission(Permission.TRAVERSE, Permission.MANAGE_MEMBERS)); assertEquals(Permission.VIEW_MEMBERS, Permission.addPermission(Permission.TRAVERSE, Permission.VIEW_MEMBERS)); } + + @Test + public void includesTest() { + + assertTrue(Permission.includes(Permission.ADMIN, Permission.ADMIN)); + assertFalse(Permission.includes(Permission.MANAGE_MEMBERS, Permission.ADMIN)); + assertFalse(Permission.includes(Permission.VIEW_MEMBERS, Permission.ADMIN)); + assertFalse(Permission.includes(Permission.TRAVERSE, Permission.ADMIN)); + assertFalse(Permission.includes(null, Permission.ADMIN)); + + assertTrue(Permission.includes(Permission.ADMIN, Permission.MANAGE_MEMBERS)); + assertTrue(Permission.includes(Permission.MANAGE_MEMBERS, Permission.MANAGE_MEMBERS)); + assertFalse(Permission.includes(Permission.VIEW_MEMBERS, Permission.MANAGE_MEMBERS)); + assertFalse(Permission.includes(Permission.TRAVERSE, Permission.MANAGE_MEMBERS)); + assertFalse(Permission.includes(null, Permission.MANAGE_MEMBERS)); + + assertTrue(Permission.includes(Permission.ADMIN, Permission.VIEW_MEMBERS)); + assertTrue(Permission.includes(Permission.MANAGE_MEMBERS, Permission.VIEW_MEMBERS)); + assertTrue(Permission.includes(Permission.VIEW_MEMBERS, Permission.VIEW_MEMBERS)); + assertFalse(Permission.includes(Permission.TRAVERSE, Permission.VIEW_MEMBERS)); + assertFalse(Permission.includes(null, Permission.ADMIN)); + + assertTrue(Permission.includes(Permission.ADMIN, Permission.TRAVERSE)); + assertTrue(Permission.includes(Permission.MANAGE_MEMBERS, Permission.TRAVERSE)); + assertTrue(Permission.includes(Permission.VIEW_MEMBERS, Permission.TRAVERSE)); + assertTrue(Permission.includes(Permission.TRAVERSE, Permission.TRAVERSE)); + assertFalse(Permission.includes(null, Permission.TRAVERSE)); + } } -- GitLab