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

Removed Spring dependency to gms-client-lib (used built-in...

Removed Spring dependency to gms-client-lib (used built-in java.net.HttpClient); used access token instead of BasicAuth; Added missing endpoints in GMS JWT web service controller
parent 67337ee0
......@@ -7,21 +7,10 @@
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<spring.version>5.1.8.RELEASE</spring.version>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
......
package it.inaf.ia2.gms.client;
import it.inaf.ia2.gms.client.model.Group;
import it.inaf.ia2.gms.client.model.Member;
import it.inaf.ia2.gms.client.call.HttpClientWrapper;
import it.inaf.ia2.gms.client.call.AddMemberCall;
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.GetUserGroupsCall;
import it.inaf.ia2.gms.client.call.ListGroupsCall;
import it.inaf.ia2.gms.client.call.RemoveMemberCall;
import it.inaf.ia2.gms.client.call.RemovePermissionCall;
import it.inaf.ia2.gms.client.model.Permission;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
public class GmsClient {
private final String baseUrl;
private final String authHeader;
private RestTemplate restTemplate;
HttpClientWrapper httpClientWrapper;
public GmsClient(String baseUrl, String clientId, String clientSecret) {
public GmsClient(String baseUrl) {
if (!baseUrl.endsWith("/")) {
baseUrl += "/";
}
baseUrl += "ws/basic";
baseUrl += "ws/jwt";
this.baseUrl = baseUrl;
String auth = clientId + ":" + clientSecret;
byte[] encodedAuth = Base64.getEncoder().encode(
auth.getBytes(StandardCharsets.UTF_8));
authHeader = "Basic " + new String(encodedAuth);
restTemplate = new RestTemplate();
httpClientWrapper = new HttpClientWrapper(baseUrl);
}
/**
* For testing purpose.
*/
protected void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
public GmsClient setAccessToken(String accessToken) {
httpClientWrapper.setAccessToken(accessToken);
return this;
}
public Group addGroup(List<String> names) {
String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
.pathSegment("group")
.toUriString();
HttpEntity<List<String>> httpEntity = getEntity(names);
return restTemplate.exchange(url, HttpMethod.POST, httpEntity, Group.class).getBody();
public List<String> getMyGroups(String prefix) {
return new GetUserGroupsCall(httpClientWrapper).getUserGroups(prefix);
}
public void removeGroup(List<String> names) {
String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
.pathSegment("group")
.queryParam("names", names.toArray())
.toUriString();
restTemplate.exchange(url, HttpMethod.DELETE, getEntity(), Void.class);
public List<String> listGroups(String prefix) {
return new ListGroupsCall(httpClientWrapper).listGroups(prefix);
}
public Member addMember(List<String> names, String userId) {
String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
.pathSegment("member")
.toUriString();
Map<String, Object> params = new HashMap<>();
params.put("names", names);
params.put("userId", userId);
HttpEntity<Map<String, Object>> httpEntity = getEntity(params);
return restTemplate.exchange(url, HttpMethod.POST, httpEntity, Member.class).getBody();
public List<String> getUserGroups(String userId, String prefix) {
return new GetUserGroupsCall(httpClientWrapper).getUserGroups(userId, prefix);
}
public void removeMember(List<String> names, String userId) {
String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
.pathSegment("member")
.queryParam("names", names.toArray())
.queryParam("userId", userId)
.toUriString();
restTemplate.exchange(url, HttpMethod.DELETE, getEntity(), Void.class);
public void createGroup(String completeGroupName, boolean leaf) {
new CreateGroupCall(httpClientWrapper).createGroup(completeGroupName, leaf);
}
public Permission addPermission(List<String> names, String userId, String permission) {
String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
.pathSegment("permission")
.toUriString();
Map<String, Object> params = new HashMap<>();
params.put("names", names);
params.put("userId", userId);
params.put("permission", permission);
HttpEntity<Map<String, Object>> httpEntity = getEntity(params);
return restTemplate.exchange(url, HttpMethod.POST, httpEntity, Permission.class).getBody();
public void deleteGroup(String completeGroupName) {
new DeleteGroupCall(httpClientWrapper).deleteGroup(completeGroupName);
}
public void removePermission(List<String> names, String userId) {
String url = UriComponentsBuilder.fromHttpUrl(baseUrl)
.pathSegment("permission")
.queryParam("names", names.toArray())
.queryParam("userId", userId)
.toUriString();
restTemplate.exchange(url, HttpMethod.DELETE, getEntity(), Void.class);
public void addMember(String completeGroupName, String userId) {
new AddMemberCall(httpClientWrapper).addMember(completeGroupName, userId);
}
private HttpEntity<?> getEntity() {
return new HttpEntity<>(getHeaders());
public void removeMember(String completeGroupName, String userId) {
new RemoveMemberCall(httpClientWrapper).removeMember(completeGroupName, userId);
}
private <T> HttpEntity<T> getEntity(T body) {
return new HttpEntity<>(body, getHeaders());
public void addPermission(String completeGroupName, String userId, Permission permission) {
new AddPermissionCall(httpClientWrapper).addPermission(completeGroupName, userId, permission);
}
private HttpHeaders getHeaders() {
return new HttpHeaders() {
{
set("Authorization", authHeader);
}
};
public void removePermission(String completeGroupName, String userId) {
new RemovePermissionCall(httpClientWrapper).removePermission(completeGroupName, userId);
}
}
package it.inaf.ia2.gms.client.call;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
public class AddMemberCall extends BaseGmsCall {
public AddMemberCall(HttpClientWrapper clientWrapper) {
super(clientWrapper);
}
public boolean addMember(String completeGroupName, String userId) {
String endpoint = "membership";
if (completeGroupName != null && !completeGroupName.isBlank()) {
endpoint += "/" + completeGroupName;
}
HttpRequest groupsRequest = newHttpRequest(endpoint)
.header("Accept", "text/plain")
.POST(BodyPublishers.ofString("user_id=" + userId))
.build();
return getClient().sendAsync(groupsRequest, HttpResponse.BodyHandlers.ofInputStream())
.thenApply(response -> {
if (response.statusCode() == 200) {
return true;
}
logServerErrorInputStream(groupsRequest, response);
throw new IllegalStateException("Unable to add member to group");
}).join();
}
}
package it.inaf.ia2.gms.client.call;
import it.inaf.ia2.gms.client.model.Permission;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublisher;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
public class AddPermissionCall extends BaseGmsCall {
public AddPermissionCall(HttpClientWrapper clientWrapper) {
super(clientWrapper);
}
public boolean addPermission(String completeGroupName, String userId, Permission permission) {
String endpoint = "permission";
if (completeGroupName != null && !completeGroupName.isBlank()) {
endpoint += "/" + completeGroupName;
}
BodyPublisher requestBody = BodyPublishers.ofString(
"user_id=" + userId + "&permission=" + permission);
HttpRequest groupsRequest = newHttpRequest(endpoint)
.header("Accept", "text/plain")
.POST(requestBody)
.build();
return getClient().sendAsync(groupsRequest, HttpResponse.BodyHandlers.ofInputStream())
.thenApply(response -> {
if (response.statusCode() == 200) {
return true;
}
logServerErrorInputStream(groupsRequest, response);
throw new IllegalStateException("Unable to add permission");
}).join();
}
}
package it.inaf.ia2.gms.client.call;
import java.io.InputStream;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.Builder;
import java.net.http.HttpResponse;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
public abstract class BaseGmsCall {
private static final Logger LOGGER = Logger.getLogger(BaseGmsCall.class.getName());
protected final HttpClientWrapper clientWrapper;
public BaseGmsCall(HttpClientWrapper clientWrapper) {
this.clientWrapper = clientWrapper;
}
protected HttpClient getClient() {
return clientWrapper.getClient();
}
protected Builder newHttpRequest(String endpoint) {
return clientWrapper.newHttpRequest(endpoint);
}
protected 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());
}
protected 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() : "";
return "Error while reading " + request.uri()
+ "\nServer response status code is " + response.statusCode()
+ "\nServer response text is " + responseBody;
});
}
}
package it.inaf.ia2.gms.client.call;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
public class CreateGroupCall extends BaseGmsCall {
public CreateGroupCall(HttpClientWrapper clientWrapper) {
super(clientWrapper);
}
public boolean createGroup(String completeGroupName, boolean leaf) {
HttpRequest groupsRequest = newHttpRequest(completeGroupName)
.header("Accept", "text/plain")
.POST(BodyPublishers.ofString("leaf=" + leaf))
.build();
return getClient().sendAsync(groupsRequest, HttpResponse.BodyHandlers.ofInputStream())
.thenApply(response -> {
if (response.statusCode() == 200) {
return true;
}
logServerErrorInputStream(groupsRequest, response);
throw new IllegalStateException("Unable to create group");
}).join();
}
}
package it.inaf.ia2.gms.client.call;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
public class DeleteGroupCall extends BaseGmsCall {
public DeleteGroupCall(HttpClientWrapper clientWrapper) {
super(clientWrapper);
}
public boolean deleteGroup(String completeGroupName) {
HttpRequest groupsRequest = newHttpRequest(completeGroupName)
.header("Accept", "text/plain")
.DELETE()
.build();
return getClient().sendAsync(groupsRequest, HttpResponse.BodyHandlers.ofInputStream())
.thenApply(response -> {
if (response.statusCode() == 204) {
return true;
}
logServerErrorInputStream(groupsRequest, response);
throw new IllegalStateException("Unable to delete group");
}).join();
}
}
package it.inaf.ia2.gms.client.call;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class GetUserGroupsCall extends BaseGmsCall {
public GetUserGroupsCall(HttpClientWrapper clientWrapper) {
super(clientWrapper);
}
/**
* Returns the groups the user belongs to. If a groupsPrefix (parent group)
* is specified, the prefix is removed from the list.
*/
public List<String> getUserGroups(String prefix) {
List<String> groups = new ArrayList<>();
HttpRequest groupsRequest = newHttpRequest("search")
.header("Accept", "text/plain")
.GET()
.build();
return getClient().sendAsync(groupsRequest, HttpResponse.BodyHandlers.ofInputStream())
.thenApply(response -> {
if (response.statusCode() == 200) {
return response.body();
}
logServerErrorInputStream(groupsRequest, 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()) {
if (prefix == null || prefix.isEmpty()) {
groups.add(line);
} else {
if (line.startsWith(prefix)) {
line = line.substring(prefix.length());
groups.add(line);
}
}
}
}
}
return groups;
}).join();
}
public List<String> getUserGroups(String userId, String prefix) {
List<String> groups = new ArrayList<>();
String endpoint = "membership";
if (prefix != null && !prefix.isBlank()) {
endpoint += "/" + prefix;
}
endpoint += "?user_id=" + userId;
HttpRequest groupsRequest = newHttpRequest(endpoint)
.header("Accept", "text/plain")
.GET()
.build();
return getClient().sendAsync(groupsRequest, HttpResponse.BodyHandlers.ofInputStream())
.thenApply(response -> {
if (response.statusCode() == 200) {
return response.body();
}
logServerErrorInputStream(groupsRequest, 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()) {
groups.add(line);
}
}
}
return groups;
}).join();
}
}
package it.inaf.ia2.gms.client.call;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.Builder;
public class HttpClientWrapper {
private final String baseGmsUri;
private final HttpClient client;
private String accessToken;
public HttpClientWrapper(String baseGmsUri) {
String uri = baseGmsUri;
if (!uri.endsWith("/")) {
uri += "/";
}
this.baseGmsUri = uri;
this.client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.ALWAYS)
.build();
}
public HttpClientWrapper setAccessToken(String accessToken) {
this.accessToken = accessToken;
return this;
}
Builder newHttpRequest(String endpoint) {
return HttpRequest.newBuilder()
.uri(URI.create(baseGmsUri + endpoint))
.header("Authorization", "Bearer " + accessToken);
}
HttpClient getClient() {
return client;
}
}
package it.inaf.ia2.gms.client.call;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class ListGroupsCall extends BaseGmsCall {
public ListGroupsCall(HttpClientWrapper clientWrapper) {
super(clientWrapper);
}
/**
* Returns the list of the groups in a given parent group (if the user has
* the privileges to see that information). The prefix is removed by the
* service.
*/
public List<String> listGroups(String prefix) {
List<String> groups = new ArrayList<>();
String uri = "list";
if (prefix != null && !prefix.isBlank()) {
uri += "/" + prefix;
}
HttpRequest groupsRequest = newHttpRequest(uri)
.header("Accept", "text/plain")
.GET()
.build();
return getClient().sendAsync(groupsRequest, HttpResponse.BodyHandlers.ofInputStream())
.thenApply(response -> {
if (response.statusCode() == 200) {
return response.body();
}
logServerErrorInputStream(groupsRequest, response);
throw new IllegalStateException("Unable to list groups");
})
.thenApply(inputStream -> {
try (Scanner scan = new Scanner(inputStream)) {
while (scan.hasNextLine()) {
String line = scan.nextLine();
if (!line.isEmpty()) {