Commit c67052b0 authored by Sonia Zorba's avatar Sonia Zorba
Browse files

Added endpoint for retrieving member email addresses; CLI improvements

parent 909daf60
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
<finalName>gms-cli</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
......
package it.inaf.ia2.gms.cli; package it.inaf.ia2.gms.cli;
import it.inaf.ia2.gms.client.GmsClient; import it.inaf.ia2.gms.client.GmsClient;
import it.inaf.ia2.gms.client.GmsClientBuilder;
import it.inaf.ia2.gms.client.model.Permission; import it.inaf.ia2.gms.client.model.Permission;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.List;
import java.util.Properties; import java.util.Properties;
public class CLI { public class CLI {
private final GmsClient client;
public static void main(String[] args) throws Exception { 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()) { 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); System.exit(1);
} }
Properties properties = new Properties(); Properties properties = new Properties();
try (InputStream in = new FileInputStream(config)) { try (InputStream in = new FileInputStream(config)) {
properties.load(in); properties.load(in);
} catch (IOException ex) {
throw new UncheckedIOException(ex);
} }
String baseUrl = (String) properties.get("base_url"); gmsBaseUrl = properties.getProperty("gms_url");
if (baseUrl == null) { if (gmsBaseUrl == null) {
System.err.println("Missing base_url in gms.properties"); System.err.println("Missing gms_url in gms.properties");
System.exit(1); 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 (!tokenFile.exists()) {
if (token == null) { System.err.println("Token file " + tokenFile.getAbsolutePath() + " doesn't exist");
System.err.println("Missing token in gms.properties");
System.exit(1); 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 { private void parseCommand() {
if (args.length < 2) {
displayUsage();
}
switch (args[0]) { switch (args[argIndex]) {
case "create-group": case "create-group":
boolean leaf = false; boolean leaf = false;
if (args.length > 1) { if (argIndex + 2 < args.length) {
leaf = Boolean.parseBoolean(args[2]); leaf = Boolean.parseBoolean(args[argIndex + 2]);
} }
client.createGroup(args[1], leaf); client.createGroup(args[argIndex + 1], leaf);
System.out.println("Group created"); System.out.println("Group created");
break; break;
case "delete-group": case "delete-group":
client.deleteGroup(args[1]); client.deleteGroup(args[argIndex + 1]);
System.out.println("Group deleted"); System.out.println("Group deleted");
break; break;
case "add-member": case "add-member":
if (args.length < 3) { if (argIndex + 2 >= args.length) {
displayUsage(); displayUsage();
} }
client.addMember(args[1], args[2]); client.addMember(args[argIndex + 1], args[argIndex + 2]);
System.out.println("Member added"); System.out.println("Member added");
break; break;
case "remove-member": case "remove-member":
if (args.length < 3) { if (argIndex + 2 >= args.length) {
displayUsage(); displayUsage();
} }
client.removeMember(args[1], args[2]); client.removeMember(args[argIndex + 1], args[argIndex + 2]);
System.out.println("Member removed"); System.out.println("Member removed");
break; break;
case "add-permission": case "add-permission":
if (args.length < 4) { if (argIndex + 3 >= args.length) {
displayUsage(); 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"); System.out.println("Permission added");
break; break;
case "delete-permission": case "delete-permission":
if (args.length < 4) { if (argIndex + 2 >= args.length) {
displayUsage(); displayUsage();
} }
client.removePermission(args[1], args[2]); client.removePermission(args[argIndex + 1], args[argIndex + 2]);
System.out.println("Permission removed"); System.out.println("Permission removed");
break; 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: default:
displayUsage(); displayUsage();
break; break;
...@@ -97,13 +209,20 @@ public class CLI { ...@@ -97,13 +209,20 @@ public class CLI {
} }
private void displayUsage() { private void displayUsage() {
System.out.println("java -jar gms-client.jar\n" System.out.println("gms-client\n"
+ " create-group <name1.name2.name3> <leaf>\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" + " delete-group <name1.name2.name3>\n"
+ " add-member <name1.name2.name3> <user_id>\n" + " add-member <name1.name2.name3> <user_id>\n"
+ " remove-member <name1.name2.name3> <user_id>\n" + " remove-member <name1.name2.name3> <user_id>\n"
+ " add-permission <name1.name2.name3> <user_id> <permission>\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); System.exit(0);
} }
} }
...@@ -7,6 +7,7 @@ import it.inaf.ia2.gms.client.call.AddPermissionCall; ...@@ -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.CreateGroupCall;
import it.inaf.ia2.gms.client.call.DeleteGroupCall; import it.inaf.ia2.gms.client.call.DeleteGroupCall;
import it.inaf.ia2.gms.client.call.GetGroupPermissionsCall; 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.GetUserGroupsCall;
import it.inaf.ia2.gms.client.call.GetUserPermissionsCall; import it.inaf.ia2.gms.client.call.GetUserPermissionsCall;
import it.inaf.ia2.gms.client.call.ListGroupsCall; import it.inaf.ia2.gms.client.call.ListGroupsCall;
...@@ -20,15 +21,10 @@ import java.util.Map; ...@@ -20,15 +21,10 @@ import java.util.Map;
public class GmsClient { public class GmsClient {
HttpClientWrapper httpClientWrapper; private final HttpClientWrapper httpClientWrapper;
public GmsClient(String baseUrl) { GmsClient(HttpClientWrapper httpClientWrapper) {
this.httpClientWrapper = httpClientWrapper;
if (!baseUrl.endsWith("/")) {
baseUrl += "/";
}
httpClientWrapper = new HttpClientWrapper(baseUrl);
} }
public GmsClient setAccessToken(String accessToken) { public GmsClient setAccessToken(String accessToken) {
...@@ -83,4 +79,8 @@ public class GmsClient { ...@@ -83,4 +79,8 @@ public class GmsClient {
public void addInvitedRegistration(String token, String email, Map<String, Permission> groupsPermissions) { public void addInvitedRegistration(String token, String email, Map<String, Permission> groupsPermissions) {
new AddInvitedRegistrationCall(httpClientWrapper).addInvitedRegistration(token, email, groupsPermissions); new AddInvitedRegistrationCall(httpClientWrapper).addInvitedRegistration(token, email, groupsPermissions);
} }
public List<String> getMemberEmailAddresses(String groupId, Permission permission) {
return new GetMemberEmailAddresses(httpClientWrapper).getMemberEmailAddresses(groupId, permission);
}
} }
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);
}
}
...@@ -27,13 +27,13 @@ public abstract class BaseGmsCall { ...@@ -27,13 +27,13 @@ public abstract class BaseGmsCall {
return clientWrapper.newHttpRequest(endpoint); 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() LOGGER.log(Level.SEVERE, () -> "Error while reading " + request.uri()
+ "\nServer response status code is " + response.statusCode() + "\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, () -> { LOGGER.log(Level.SEVERE, () -> {
Scanner s = new Scanner(response.body()).useDelimiter("\\A"); Scanner s = new Scanner(response.body()).useDelimiter("\\A");
String responseBody = s.hasNext() ? s.next() : ""; String responseBody = s.hasNext() ? s.next() : "";
......
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();
}
}
...@@ -4,12 +4,20 @@ import java.net.URI; ...@@ -4,12 +4,20 @@ import java.net.URI;
import java.net.http.HttpClient; import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpRequest.Builder; 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 { public class HttpClientWrapper {
private final String baseGmsUri; private final String baseGmsUri;
private final HttpClient client; private final HttpClient client;
private String rapBaseUrl;
private String clientId;
private String clientSecret;
private String accessToken; private String accessToken;
public HttpClientWrapper(String baseGmsUri) { public HttpClientWrapper(String baseGmsUri) {
...@@ -29,12 +37,68 @@ public class HttpClientWrapper { ...@@ -29,12 +37,68 @@ public class HttpClientWrapper {
return this; 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) { Builder newHttpRequest(String endpoint) {
if (accessToken == null) {
accessToken = getAccessTokenFromClientCredentials();
}
return HttpRequest.newBuilder() return HttpRequest.newBuilder()
.uri(URI.create(baseGmsUri + endpoint)) .uri(URI.create(baseGmsUri + endpoint))
.header("Authorization", "Bearer " + accessToken); .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");