diff --git a/pom.xml b/pom.xml
index 96f84ae..d38e87b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,31 +29,11 @@
slf4j-log4j12
${slf4j-version}
-
- org.keycloak
- keycloak-admin-client
- ${keycloak-version}
-
-
- org.bouncycastle
- bcprov-jdk15on
- 1.65
-
-
- org.apache.httpcomponents
- httpclient
- 4.5.8
-
log4j
log4j
${log4j-version}
-
- org.keycloak
- keycloak-authz-client
- ${keycloak-version}
-
com.googlecode.json-simple
json-simple
diff --git a/src/main/java/com/nubisware/oidc/keycloak/KeycloakAuthHelper.java b/src/main/java/com/nubisware/oidc/keycloak/KeycloakAuthHelper.java
deleted file mode 100644
index 8eee8f6..0000000
--- a/src/main/java/com/nubisware/oidc/keycloak/KeycloakAuthHelper.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.nubisware.oidc.keycloak;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.keycloak.authorization.client.AuthzClient;
-import org.keycloak.authorization.client.Configuration;
-
-public class KeycloakAuthHelper {
-
- public static void main(String[] args) {
- Map credentials = new HashMap<>();
- Configuration configuration = new Configuration("https://nubis2.int.d4science.net/auth", "d4science", "portal",
- credentials, null);
- AuthzClient authzClient = AuthzClient.create(configuration);
- }
-
-}
diff --git a/src/main/java/com/nubisware/oidc/keycloak/KeycloakHelper.java b/src/main/java/com/nubisware/oidc/keycloak/KeycloakHelper.java
deleted file mode 100644
index 94200e8..0000000
--- a/src/main/java/com/nubisware/oidc/keycloak/KeycloakHelper.java
+++ /dev/null
@@ -1,277 +0,0 @@
-package com.nubisware.oidc.keycloak;
-
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.security.PublicKey;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import javax.ws.rs.core.Response;
-
-import org.jboss.resteasy.client.jaxrs.ResteasyClient;
-import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
-import org.keycloak.OAuth2Constants;
-import org.keycloak.TokenVerifier;
-import org.keycloak.admin.client.Keycloak;
-import org.keycloak.admin.client.KeycloakBuilder;
-import org.keycloak.admin.client.resource.ClientResource;
-import org.keycloak.admin.client.resource.PolicyResource;
-import org.keycloak.admin.client.resource.RealmResource;
-import org.keycloak.admin.client.resource.ResourceResource;
-import org.keycloak.admin.client.resource.RoleResource;
-import org.keycloak.admin.client.resource.RolesResource;
-import org.keycloak.admin.client.resource.UserResource;
-import org.keycloak.common.VerificationException;
-import org.keycloak.jose.jwk.JSONWebKeySet;
-import org.keycloak.jose.jwk.JWK;
-import org.keycloak.jose.jwk.JWKParser;
-import org.keycloak.representations.JsonWebToken;
-import org.keycloak.representations.idm.ClientRepresentation;
-import org.keycloak.representations.idm.RoleRepresentation;
-import org.keycloak.representations.idm.UserRepresentation;
-import org.keycloak.representations.idm.authorization.DecisionStrategy;
-import org.keycloak.representations.idm.authorization.Logic;
-import org.keycloak.representations.idm.authorization.ResourcePermissionRepresentation;
-import org.keycloak.representations.idm.authorization.ResourceRepresentation;
-import org.keycloak.representations.idm.authorization.ResourceServerRepresentation;
-import org.keycloak.representations.idm.authorization.RolePolicyRepresentation;
-import org.keycloak.representations.idm.authorization.ScopeRepresentation;
-import org.keycloak.util.JWKSUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- *
- * @author Mauro Mugnaini (mauro.mugnaini@nubisware.com)
- */
-public class KeycloakHelper {
-
- protected static Logger logger = LoggerFactory.getLogger(KeycloakHelper.class);
-
- private static KeycloakHelper instance;
-
- private String serverUrl;
- private ResteasyClient resteasyClient;
-
- private KeycloakHelper(String serverUrl) throws KeyManagementException, NoSuchAlgorithmException {
- this.serverUrl = serverUrl;
- this.resteasyClient = (ResteasyClient) new ResteasyClientBuilder().build();
- }
-
- public static synchronized KeycloakHelper getInstance(String serverUrl)
- throws KeyManagementException, NoSuchAlgorithmException {
-
- if (instance == null) {
- instance = new KeycloakHelper(serverUrl);
- }
- return instance;
- }
-
- public Keycloak newKeycloakAdmin(String username, String password) throws UnsupportedEncodingException {
- return newKeycloak("master", username, password, "admin-cli");
- }
-
- public Keycloak newKeycloak(String realm, String username, String password, String clientId)
- throws UnsupportedEncodingException {
-
- String encodedClientId = URLEncoder.encode(clientId, "UTF-8");
- return KeycloakBuilder.builder().serverUrl(serverUrl).realm(realm).username(username)
- .password(password).clientId(encodedClientId).resteasyClient(resteasyClient).build();
- }
-
- public Keycloak newKeycloak(String realm, String clientId, String clientSecret) throws UnsupportedEncodingException {
- String encodedClientId = URLEncoder.encode(clientId, "UTF-8");
- return KeycloakBuilder.builder().serverUrl(serverUrl).realm(realm).grantType(OAuth2Constants.CLIENT_CREDENTIALS)
- .clientId(encodedClientId).clientSecret(clientSecret)
- .resteasyClient(resteasyClient).build();
- }
-
- public PublicKey getRealmSigPublicKey(String realm) {
- Response response = resteasyClient.target(serverUrl + "/realms/" + realm + "/protocol/openid-connect/certs")
- .request().get();
-
- JSONWebKeySet jsonWebKeySet = response.readEntity(JSONWebKeySet.class);
- return JWKParser.create(JWKSUtils.getKeyForUse(jsonWebKeySet, JWK.Use.SIG)).toPublicKey();
- }
-
- // Realm is too complex to configure it in depth with this helper. Please do it with the Web UI
- // public RealmResource addRealm(Keycloak keycloak, String realm, String displayName, String displayNameHtml,
- // boolean enabled) throws KeycloakResourceCreationException {
- // if (keycloak.realm(realm) != null) {
- // throw new KeycloakResourceCreationException("Realm already present on server: " + realm, null);
- // }
- // RealmRepresentation newRealmRepresentation = new RealmRepresentation();
- // newRealmRepresentation.setRealm(realm);
- // newRealmRepresentation.setId(realm);
- // newRealmRepresentation.setDisplayName(displayName);
- // newRealmRepresentation.setDisplayNameHtml(displayNameHtml);
- // newRealmRepresentation.setEnabled(enabled);
- // try {
- // keycloak.realms().create(newRealmRepresentation);
- // return keycloak.realms().realm(realm);
- // } catch (ClientErrorException e) {
- // throw new KeycloakResourceCreationException("While creating new realm: " + realm, null);
- // }
- // }
-
- public UserResource findUser(RealmResource realmResource, String username) {
- List results = realmResource.users().search(username);
- return results.size() > 0 ? realmResource.users().get(results.get(0).getId()) : null;
- }
-
- public void mapRoleTo(UserResource userResource, String clientId, RoleResource roleResource) {
- userResource.roles().clientLevel(clientId).add(Collections.singletonList(roleResource.toRepresentation()));
- }
-
- public void mapRoleTo(UserResource userResource, ClientResource client, String roleName) {
- RoleResource roleResource = client.roles().get(roleName);
- userResource.roles().clientLevel(client.toRepresentation().getId())
- .add(Collections.singletonList(roleResource.toRepresentation()));
- }
-
- public List getEffectiveClientRoles(RealmResource realm, UserResource userResource,
- String clientId) {
- ClientRepresentation cr = realm.clients().findByClientId(clientId).get(0);
- return userResource.roles().clientLevel(cr.getId()).listEffective();
- }
-
- public ClientResource addClient(RealmResource realm, String clientId, String name, String description,
- String rootUrl) throws KeycloakResourceCreationException, UnsupportedEncodingException {
-
- // Encoding clientId to be sure blocking chars are not used
- String encodedClientId = URLEncoder.encode(clientId, "UTF-8");
- if (realm.clients().findByClientId(encodedClientId).size() > 0) {
- throw new KeycloakResourceCreationException("Client with same clientId already exists: " + encodedClientId, null);
- }
- ClientRepresentation newClientRepresentation = new ClientRepresentation();
- newClientRepresentation.setClientId(encodedClientId);
- newClientRepresentation.setName(name);
- newClientRepresentation.setDescription(description);
- if (rootUrl != null) {
- newClientRepresentation.setRootUrl(rootUrl);
- }
- newClientRepresentation.setEnabled(true);
- newClientRepresentation.setServiceAccountsEnabled(true);
- newClientRepresentation.setStandardFlowEnabled(true);
- newClientRepresentation.setAuthorizationServicesEnabled(true);
- newClientRepresentation.setPublicClient(false);
- newClientRepresentation.setProtocol("openid-connect");
- newClientRepresentation.setAuthorizationSettings(new ResourceServerRepresentation());
- try (Response response = realm.clients().create(newClientRepresentation)) {
- if (!response.getStatusInfo().equals(Response.Status.CREATED)) {
- throw new KeycloakResourceCreationException("While creating new client: " + clientId, response);
- }
- }
- return realm.clients().get(realm.clients().findByClientId(encodedClientId).get(0).getId());
- }
-
- public ClientResource findClient(RealmResource realm, String clientId) throws UnsupportedEncodingException {
- String encodedClientId = URLEncoder.encode(clientId, "UTF-8");
- List clientsFound = realm.clients().findByClientId(encodedClientId);
- if (clientsFound != null && clientsFound.size() == 1) {
- return realm.clients().get(clientsFound.get(0).getId());
- } else {
- return null;
- }
- }
-
- public void removeClient(RealmResource realm, String clientId) throws UnsupportedEncodingException {
- String encodedClientId = URLEncoder.encode(clientId, "UTF-8");
- List clientsFound = realm.clients().findByClientId(encodedClientId);
- if (clientsFound != null && !clientsFound.isEmpty()) {
- for (ClientRepresentation client : clientsFound) {
- realm.clients().get(client.getId()).remove();
- }
- }
- }
-
- public RoleResource addRole(ClientResource clientResource, boolean clientRole, String id, String name,
- String description, String containerId) {
-
- RolesResource rolesResource = clientResource.roles();
- RoleRepresentation newRoleRepresentation = new RoleRepresentation();
- newRoleRepresentation.setClientRole(clientRole);
- newRoleRepresentation.setId(id);
- newRoleRepresentation.setName(name);
- newRoleRepresentation.setDescription(description);
- if (containerId != null) {
- newRoleRepresentation.setContainerId(containerId);
- }
- rolesResource.create(newRoleRepresentation);
- return rolesResource.get(name);
- }
-
- public ResourceResource addResource(ClientResource clientResource, String name, String type, String displayName,
- boolean ownerManagedAccess, Set scopes, Set uris)
- throws KeycloakResourceCreationException {
-
- ResourceRepresentation newResourceRepresentation = new ResourceRepresentation();
- newResourceRepresentation.setName(name);
- newResourceRepresentation.setType(type);
- newResourceRepresentation.setDisplayName(displayName);
- if (scopes != null && !scopes.isEmpty()) {
- newResourceRepresentation.setScopes(scopes);
- }
- if (uris != null && !uris.isEmpty()) {
- newResourceRepresentation.setUris(uris);
- }
- try (Response response = clientResource.authorization().resources().create(newResourceRepresentation)) {
- if (!response.getStatusInfo().equals(Response.Status.CREATED)) {
- throw new KeycloakResourceCreationException("While creating new client resource: " + name, response);
- }
- return clientResource.authorization().resources()
- .resource(clientResource.authorization().resources().findByName(name).get(0).getId());
- }
- }
-
- public PolicyResource addRoleResourcePolicy(ClientResource clientResource, Set resources,
- Set scopes,
- String name, Logic logic, Map> clientRoles) throws KeycloakResourceCreationException {
-
- RolePolicyRepresentation newRolePolicyRepresentation = new RolePolicyRepresentation();
- newRolePolicyRepresentation.setName(name);
- newRolePolicyRepresentation.setLogic(logic);
- newRolePolicyRepresentation.setResources(resources);
- if (scopes != null && !scopes.isEmpty()) {
- newRolePolicyRepresentation.setScopes(scopes);
- }
- clientRoles.keySet().stream().forEach(
- k -> clientRoles.get(k).stream().forEach(v -> newRolePolicyRepresentation.addClientRole(k, v, true)));
-
- try (Response response = clientResource.authorization().policies().role().create(newRolePolicyRepresentation)) {
- if (!response.getStatusInfo().equals(Response.Status.CREATED)) {
- throw new KeycloakResourceCreationException("While creating client's role resource policy", response);
- }
- return clientResource.authorization().policies()
- .policy(clientResource.authorization().policies().role().findByName(name).getId());
- }
- }
-
- public ResourcePermissionRepresentation addResourcePermission(ClientResource clientResource,
- Set resources, String name, DecisionStrategy decisionStrategy,
- Set policies) throws KeycloakResourceCreationException {
-
- ResourcePermissionRepresentation newRPR = new ResourcePermissionRepresentation();
- newRPR.setName(name);
- newRPR.setResources(resources);
- newRPR.setDecisionStrategy(decisionStrategy);
- newRPR.setPolicies(policies);
- try (Response response = clientResource.authorization().permissions().resource().create(newRPR);) {
- if (!response.getStatusInfo().equals(Response.Status.CREATED)) {
- throw new KeycloakResourceCreationException("While creating client's resource permission", response);
- }
- return clientResource.authorization().permissions().resource().findByName(name);
- }
- }
-
- public T verifyAndGetToken(Class tokenClass, String tokenString, PublicKey publicKey)
- throws VerificationException {
-
- return TokenVerifier.create(tokenString, tokenClass).publicKey(publicKey).verify().getToken();
- }
-
-}
diff --git a/src/main/java/com/nubisware/oidc/keycloak/KeycloakResourceCreationException.java b/src/main/java/com/nubisware/oidc/keycloak/KeycloakResourceCreationException.java
deleted file mode 100644
index 3eb3d11..0000000
--- a/src/main/java/com/nubisware/oidc/keycloak/KeycloakResourceCreationException.java
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.nubisware.oidc.keycloak;
-
-import javax.ws.rs.core.Response;
-import javax.ws.rs.core.Response.StatusType;
-
-public class KeycloakResourceCreationException extends Exception {
-
- private static final long serialVersionUID = 4073975434440358303L;
-
- private StatusType responseStatus;
- private String responseContent;
-
- public KeycloakResourceCreationException() {
- }
-
- public KeycloakResourceCreationException(String message, Throwable cause, boolean enableSuppression,
- boolean writableStackTrace) {
-
- super(message, cause, enableSuppression, writableStackTrace);
- }
-
- public KeycloakResourceCreationException(String message, Throwable cause, Response response) {
- super(message, cause);
- if (response != null) {
- this.responseStatus = response.getStatusInfo();
- this.responseContent = response.readEntity(String.class);
- } else {
- this.responseStatus = null;
- this.responseContent = "";
- }
- }
-
- public KeycloakResourceCreationException(String message, Response response) {
- this(message, null, response);
- }
-
- public StatusType getResponseStatus() {
- return responseStatus;
- }
-
- public int getResponseStatusCode() {
- return responseStatus.getStatusCode();
- }
-
- public String getResponseContent() {
- return responseContent;
- }
-
- @Override
- public String getMessage() {
- return super.getMessage() + (getResponseStatus() != null
- ? "(REST details: [" + getResponseStatusCode() + "] " + getResponseContent() + ")"
- : "");
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/com/nubisware/oidc/keycloak/gcube/ClientsCreatorFromExport.java b/src/main/java/com/nubisware/oidc/keycloak/gcube/ClientsCreatorFromExport.java
deleted file mode 100644
index 451de15..0000000
--- a/src/main/java/com/nubisware/oidc/keycloak/gcube/ClientsCreatorFromExport.java
+++ /dev/null
@@ -1,315 +0,0 @@
-package com.nubisware.oidc.keycloak.gcube;
-
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.keycloak.admin.client.Keycloak;
-import org.keycloak.admin.client.resource.ClientResource;
-import org.keycloak.admin.client.resource.PolicyResource;
-import org.keycloak.admin.client.resource.RealmResource;
-import org.keycloak.admin.client.resource.ResourceResource;
-import org.keycloak.admin.client.resource.RoleResource;
-import org.keycloak.admin.client.resource.UserResource;
-import org.keycloak.representations.idm.authorization.DecisionStrategy;
-import org.keycloak.representations.idm.authorization.Logic;
-import org.keycloak.representations.idm.authorization.ResourceRepresentation;
-import org.keycloak.representations.idm.authorization.ScopeRepresentation;
-import org.xml.sax.SAXException;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.nubisware.oidc.gcube.D4ScienceMappings.Role;
-import com.nubisware.oidc.gcube.D4ScienceMappings.Scope;
-import com.nubisware.oidc.keycloak.KeycloakHelper;
-import com.nubisware.oidc.keycloak.KeycloakResourceCreationException;
-
-public class ClientsCreatorFromExport {
-
- private KeycloakHelper kh;
- private Keycloak keycloak;
- private ExportParser exportParser;
- private String realm;
- // public Map role2Scope;
-
- public ClientsCreatorFromExport(String keycloakURL, String adminUsername, String adminPassword, String realm,
- FileInputStream exportFileFIS) throws SAXException, IOException, ParserConfigurationException,
- KeyManagementException, NoSuchAlgorithmException {
-
- this.exportParser = new ExportParser(exportFileFIS);
- this.kh = KeycloakHelper.getInstance(keycloakURL);
- this.keycloak = kh.newKeycloakAdmin(adminUsername, adminPassword);
- this.realm = realm;
- // role2Scope = new TreeMap<>();
- // role2Scope.put(Role.ACCOUNTING_MANAGER, Scope.BELONGS);
- }
-
- public void createClients() throws KeycloakResourceCreationException, UnsupportedEncodingException {
- RealmResource realmResource = keycloak.realm(realm);
- for (String contextClient : exportParser.getAllContexts()) {
- System.out.println("adding client: " + contextClient);
- ClientResource client = kh.addClient(realmResource, contextClient,
- contextClient,
- contextClient + "'s context", "");
- Map roleMap = new HashMap<>();
- for (Role roleToAdd : Role.values()) {
- System.out.println("\tcreating role: " + roleToAdd);
- RoleResource role = kh.addRole(client, true, roleToAdd.asString(), roleToAdd.asString(),
- roleToAdd.asString() + " role", null);
-
- roleMap.put(roleToAdd, role);
- }
- Map scopeMap = new HashMap<>();
- for (Scope scopeToAdd : Scope.values()) {
- ScopeRepresentation scope = new ScopeRepresentation(scopeToAdd.asString());
- scopeMap.put(scopeToAdd, scope);
- }
- Set resourceScopes = new HashSet<>(scopeMap.values());
-
- String[] resources = getClientResources(contextClient);
- if (resources.length > 0) {
- for (String resourceToAdd : resources) {
- System.out.println("\t\tadding resource: " + resourceToAdd);
- // TODO Set also the resource type
- String type = "urn:" + client.toRepresentation().getClientId() + ":resources:service";
- ResourceResource resource = kh.addResource(client, resourceToAdd, type, resourceToAdd, false,
- resourceScopes,
- null);
-
- configureClientResource(client, roleMap, resource.toRepresentation());
- }
- } else {
- configureClientResource(client, roleMap, client.authorization().resources().resources().get(0));
- }
- }
- }
-
- private String[] getClientResources(String contextClient) {
- // TODO Implement when/if needed
- return new String[] {};
- }
-
- private Role[] getInvolvedRoles(String resourceName) {
- // TODO Implement when/if needed
- return Role.values();
- }
-
- private Set getRoleResourceScopes(String resourceName, Role role) {
- // TODO Implement when/if needed
- return Collections.emptySet();
- }
-
- protected void configureClientResource(ClientResource client, Map roleMap,
- ResourceRepresentation resource) throws KeycloakResourceCreationException {
-
- String resourceName = resource.getName();
- Set policies = new HashSet<>();
- for (Role role : getInvolvedRoles(resourceName)) {
- Map> policyClientRoles = new HashMap<>();
- policyClientRoles.put(client.toRepresentation().getClientId(),
- Collections.singleton(roleMap.get(role).toRepresentation().getName()));
-
- System.out.println("\t\t\tadding role resource policy for role: " + role);
- Set roleResourceScopes = getRoleResourceScopes(resourceName, role);
- PolicyResource newPR = kh.addRoleResourcePolicy(client, Collections.singleton(resourceName),
- roleResourceScopes, role.asString() + "_policy", Logic.POSITIVE,
- policyClientRoles);
-
- policies.add(newPR.toRepresentation().getName());
- }
- System.out.println(
- "\t\t\tdeleting default js policy that is no more needed");
- // This will also the delete default strategy
-
- client.authorization().policies().policy(client.authorization().policies().findByName("Default Policy").getId())
- .remove();
-
- System.out.println(
- "\t\t\tcreating new permission for role policies with affirmative strategy");
-
- kh.addResourcePermission(client, Collections.singleton(resourceName), "Default Permission",
- DecisionStrategy.AFFIRMATIVE, policies);
-
- System.out.println("\t\t\tupdating the default permission on server");
- }
-
- public void deleteClients() {
- RealmResource realmResource = keycloak.realm(realm);
- for (String contextClient : exportParser.getAllContexts()) {
- System.out.println("- deleting: " + contextClient);
- try {
- kh.removeClient(realmResource, contextClient);
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- }
- }
- }
-
- public void mapUsersWithRolesToClients() throws UnsupportedEncodingException {
- RealmResource realmResource = keycloak.realm(realm);
- Map>> usersToContextsAndRoles = exportParser.getAllUserContextsAndRoles();
- for (String userName : usersToContextsAndRoles.keySet()) {
- System.out.println("- user: " + userName);
- UserResource userResource = kh.findUser(realmResource, userName);
- if (userResource != null) {
- Map> userContextsAndRoles = usersToContextsAndRoles.get(userName);
- for (String userContext : userContextsAndRoles.keySet()) {
- String clientId = userContext;
- System.out.println("\tcontext: " + userContext);
- ClientResource clientResource = kh.findClient(realmResource, clientId);
- if (clientResource != null) {
- System.out.println("\t\tmapping default role: " + Role.MEMBER.asString());
- kh.mapRoleTo(userResource, clientResource, Role.MEMBER.asString());
- for (String role : userContextsAndRoles.get(userContext)) {
- System.out.println("\t\tmapping role: " + role);
- kh.mapRoleTo(userResource, clientResource, role);
- }
- } else {
- System.err.println("Client not found on keycloak: " + userContext);
- }
- }
- } else {
- System.err.println("User not found on keycloak: " + userName);
- }
- System.out.println();
- }
- }
-
- public ExportParser getExportParser() {
- return exportParser;
- }
-
- public class ExportParser {
-
- private ArrayNode rootNode;
-
- public ExportParser(FileInputStream exportFileFIS)
- throws SAXException, IOException, ParserConfigurationException {
- ObjectMapper objectMapper = new ObjectMapper();
- rootNode = (ArrayNode) objectMapper.readTree(exportFileFIS);
- }
-
- public Set getAllUsers() {
- Set users = new TreeSet<>();
- Iterator arrayIterator = rootNode.elements();
- while (arrayIterator.hasNext()) {
- JsonNode entry = arrayIterator.next();
- users.add(entry.get("username").asText());
- }
- return users;
- }
-
- public Set getAllContexts() {
- Set distinctContexts = new TreeSet<>();
- Iterator arrayIterator = rootNode.elements();
- while (arrayIterator.hasNext()) {
- JsonNode entry = arrayIterator.next();
- ObjectNode contextsNode = (ObjectNode) entry.get("contexts");
- contextsNode.fieldNames().forEachRemaining(f -> distinctContexts.add(f));
- }
- return distinctContexts;
- }
-
- public Map> getContextsAndRoles(String user) {
- Iterator arrayIterator = rootNode.elements();
- while (arrayIterator.hasNext()) {
- JsonNode entry = arrayIterator.next();
- String username = entry.get("username").asText();
- if (!user.equals(username)) {
- continue;
- }
- Map> contextAndRoles = new TreeMap<>();
- ObjectNode contextsNode = (ObjectNode) entry.get("contexts");
- Iterator contextIterator = contextsNode.fieldNames();
- while (contextIterator.hasNext()) {
- String context = (String) contextIterator.next();
- Set roles = new TreeSet<>();
- ArrayNode rolesNodes = (ArrayNode) contextsNode.get(context);
- rolesNodes.elements().forEachRemaining(r -> roles.add(r.asText()));
- contextAndRoles.put(context, roles);
- }
- return contextAndRoles;
- }
- return Collections.emptyMap();
- }
-
- public Map>> getAllUserContextsAndRoles() {
- Map>> usersToContextAndRoles = new TreeMap<>();
- Iterator arrayIterator = rootNode.elements();
- while (arrayIterator.hasNext()) {
- JsonNode entry = arrayIterator.next();
- String username = entry.get("username").asText();
- Map> contextAndRoles = new TreeMap<>();
- ObjectNode contextsNode = (ObjectNode) entry.get("contexts");
- Iterator contextIterator = contextsNode.fieldNames();
- while (contextIterator.hasNext()) {
- String context = (String) contextIterator.next();
- Set roles = new TreeSet<>();
- ArrayNode rolesNodes = (ArrayNode) contextsNode.get(context);
- rolesNodes.elements().forEachRemaining(r -> roles.add(r.asText()));
- contextAndRoles.put(context, roles);
- }
- usersToContextAndRoles.put(username, contextAndRoles);
- }
- return usersToContextAndRoles;
- }
- }
-
- public static void main(String[] args) throws Exception {
- String serverURL = null;
- String username = null;
- String password = null;
- String realm = null;
- FileInputStream exportFileFIS = null;
- if (args.length < 5) {
- System.err.println("Missing params.\n\nUsage: " + ClientsCreatorFromExport.class.getName()
- + " [serverURL] [username] [password] [realm] [export_file]");
-
- return;
- } else {
- serverURL = args[0];
- username = args[1];
- password = args[2];
- realm = args[3];
- exportFileFIS = new FileInputStream(args[4]);
- }
- ClientsCreatorFromExport creator = new ClientsCreatorFromExport(serverURL, username, password, realm,
- exportFileFIS);
-
- Date start = new Date();
- System.out.println("Start at " + start);
- System.out.println("Deleting clients...");
- creator.deleteClients();
- System.out.println("\n\n * * * Creating clients * * *");
- creator.createClients();
- System.out.println("\n\n * * * Mapping users to client's roles * * *");
- creator.mapUsersWithRolesToClients();
- Date end = new Date();
- System.out.println("Elapsed seconds: " + new Long(end.getTime() - start.getTime()).floatValue() / 1000);
- System.out.println("\nClients: " + creator.getExportParser().getAllContexts().size());
- System.out.println("Users: " + creator.getExportParser().getAllUsers().size());
- Map>> ucar = creator.getExportParser().getAllUserContextsAndRoles();
- float rolesPerUserMean = 0;
- for (String user : ucar.keySet()) {
- for (String context : ucar.get(user).keySet()) {
- rolesPerUserMean += ucar.get(user).get(context).size() + 1;
- }
- }
- System.out.println("Roles per user mean: " + rolesPerUserMean / creator.getExportParser().getAllUsers().size());
- }
-}
diff --git a/src/main/java/com/nubisware/oidc/rest/OpenIdConnectRESTHelper.java b/src/main/java/com/nubisware/oidc/rest/OpenIdConnectRESTHelper.java
index 4c6ef2c..dee201a 100644
--- a/src/main/java/com/nubisware/oidc/rest/OpenIdConnectRESTHelper.java
+++ b/src/main/java/com/nubisware/oidc/rest/OpenIdConnectRESTHelper.java
@@ -45,6 +45,14 @@ public class OpenIdConnectRESTHelper {
return q;
}
+ public static JWTToken queryClientToken(String clientId, String clientSecret, String tokenUrl) throws Exception {
+ Map> params = new HashMap<>();
+ params.put("grant_type", Arrays.asList("client_credentials"));
+ params.put("client_id", Arrays.asList(URLEncoder.encode(clientId, "UTF-8")));
+ params.put("client_secret", Arrays.asList(URLEncoder.encode(clientSecret, "UTF-8")));
+ return performQueryTokenWithPOST(tokenUrl, null, params);
+ }
+
public static JWTToken queryToken(String clientId, String tokenUrl, String code, String scope,
String redirectUri) throws Exception {
diff --git a/src/test/java/com/nubisware/oidc/keycloak/UglyKeycloakHelperTest.java b/src/test/java/com/nubisware/oidc/keycloak/UglyKeycloakHelperTest.java
deleted file mode 100644
index 0c953af..0000000
--- a/src/test/java/com/nubisware/oidc/keycloak/UglyKeycloakHelperTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-package com.nubisware.oidc.keycloak;
-
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.keycloak.admin.client.Keycloak;
-import org.keycloak.admin.client.resource.ClientResource;
-import org.keycloak.admin.client.resource.PolicyResource;
-import org.keycloak.admin.client.resource.RealmResource;
-import org.keycloak.admin.client.resource.ResourceResource;
-import org.keycloak.admin.client.resource.RoleResource;
-import org.keycloak.common.VerificationException;
-import org.keycloak.representations.idm.authorization.DecisionStrategy;
-import org.keycloak.representations.idm.authorization.Logic;
-import org.keycloak.representations.idm.authorization.ScopeRepresentation;
-
-import com.nubisware.oidc.keycloak.KeycloakHelper;
-import com.nubisware.oidc.keycloak.KeycloakResourceCreationException;
-
-public class UglyKeycloakHelperTest {
-
- static String clientPrefix = "client";
- static String realm = "d4science";
-
- public UglyKeycloakHelperTest() {
- }
-
- public static void maino(String[] args) throws KeyManagementException, NoSuchAlgorithmException,
- VerificationException, MalformedURLException, IOException, KeycloakResourceCreationException {
-
- KeycloakHelper kh = KeycloakHelper.getInstance("https://nubis2.int.d4science.net/auth");
- // KeycloakHelper kh = getInstance("http://localhost:8080/auth");
- Keycloak keycloak = kh.newKeycloakAdmin("admin", "4dm1n");
- // Keycloak keycloak = keycloakHelper.newKeycloak(realm, "/gcube/devsec/devVRE",
- // "12184fe2-f174-4c87-afac-b2d2bfaae4c0");
-
- // RealmResource realmResource = kh.addRealm(keycloak, realm, realm, "" + realm + "
Welcome
", true);
- RealmResource realmResource = keycloak.realm(realm);
-
- for (int clientNum = 0; clientNum < 10; clientNum++) {
- String clientName = clientPrefix + clientNum;
- ClientResource client = kh.addClient(realmResource, clientName, clientName, clientName, null);
-
- RoleResource dataManager = kh.addRole(client, true, "Data-Manager", "Data-Manager", "Data-Manager", null);
- RoleResource dataMinerManager = kh.addRole(client, true, "DataMiner-Manager", "DataMiner-Manager",
- "DataMiner-Manager", null);
- ScopeRepresentation read = new ScopeRepresentation("read");
-
- ScopeRepresentation list = new ScopeRepresentation("list");
- ScopeRepresentation write = new ScopeRepresentation("write");
- ScopeRepresentation execute = new ScopeRepresentation("execute");
- Set resourceScopes = new HashSet<>(Arrays.asList(read, write, list, execute));
- ResourceResource resource1 = kh.addResource(client, "resource1", null, "resource1", false, resourceScopes,
- null);
- ResourceResource resource2 = kh.addResource(client, "resource2", null, "resource2", false, resourceScopes,
- null);
- Set resources = new HashSet<>(
- Arrays.asList(resource1.toRepresentation().getName(), resource2.toRepresentation().getName()));
-
- Map> policyClientRoles = new HashMap<>();
- policyClientRoles.put(clientName, Collections.singleton(dataManager.toRepresentation().getName()));
- PolicyResource dataManagerCanRead = kh.addRoleResourcePolicy(client, resources,
- Collections.singleton(list.getName()), "canRead", Logic.POSITIVE,
- policyClientRoles);
-
- kh.addResourcePermission(client, resources, "read", DecisionStrategy.UNANIMOUS,
- Collections.singleton(dataManagerCanRead.toRepresentation().getName()));
-
- }
- //// keycloakHelper.addClient(realmResource, "Gino", "gino", "Gino client", "http://gino.stilla.it");
- // UserResource user = keycloakHelper.findUser(realmResource, "mauro");
- // Map impersonation = user.impersonate();
- // System.out.println(impersonation);
- // Keycloak keycloak = keycloakHelper.newKeycloak(realm, "lino", "lino", "portal");
- // TokenManager tokenManager = keycloak.tokenManager();
- // AccessToken accessToken = keycloakHelper.verifyAndGetToken(AccessToken.class, tokenManager.getAccessTokenString(), keycloakHelper.getRealmSigPublicKey(realm));
- // System.out.println(new ObjectMapper().writeValueAsString(accessToken));
- // for (String resourceAccess : accessToken.getResourceAccess().keySet()) {
- // if ("account".equals(resourceAccess)) {
- // continue;
- // }
- // Access access = accessToken.getResourceAccess(resourceAccess);
- // System.out.println(resourceAccess + " -> " + access.getRoles());
- // }
- // keycloak.realm(realm).
- }
-
- public static void main(String[] args) throws Exception {
- KeycloakHelper kh = KeycloakHelper.getInstance("https://nubis2.int.d4science.net/auth");
- Keycloak keycloak = kh.newKeycloakAdmin("admin", "4dm1n");
- RealmResource realmResource = keycloak.realm(realm);
- for (int clientNum = 0; clientNum < 10; clientNum++) {
- String clientName = clientPrefix + clientNum;
- kh.removeClient(realmResource, clientName);
- }
- }
-}
diff --git a/src/test/java/com/nubisware/oidc/rest/RestHelperTest.java b/src/test/java/com/nubisware/oidc/rest/RestHelperTest.java
new file mode 100644
index 0000000..a8cf2a3
--- /dev/null
+++ b/src/test/java/com/nubisware/oidc/rest/RestHelperTest.java
@@ -0,0 +1,13 @@
+package com.nubisware.oidc.rest;
+
+public class RestHelperTest {
+
+ public RestHelperTest() {
+ }
+
+ public static void main(String[] args) throws Exception {
+ System.out.println(OpenIdConnectRESTHelper.queryClientToken(
+ "vre-folder-manager", "4999c6d6-86fd-4f86-a3f8-30c26a95f551",
+ "https://nubis2.int.d4science.net/auth/realms/d4science/protocol/openid-connect/token").toString());
+ }
+}
diff --git a/src/test/resources/dev2-db.json b/src/test/resources/dev2-db.json
new file mode 100644
index 0000000..f11127b
--- /dev/null
+++ b/src/test/resources/dev2-db.json
@@ -0,0 +1,521 @@
+[
+ {
+ "username": "nikolaos.drakopoulos",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "roberto.cirillo",
+ "contexts": {
+ "/gcube": ["VO-Admin"],
+ "/gcube/devsec/devVRE": [
+ "VRE-Manager",
+ "DataMiner-Manager"
+ ],
+ "/gcube/devsec": ["VO-Admin"],
+ "/gcube/devNext/NextNext": [],
+ "/gcube/devNext": ["VO-Admin"]
+ }
+ },
+ {
+ "username": "alessia.bardi",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "aureliano.gentile",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "ngalante",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "nicolas.bailly",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "taha.imzilen",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "lucio.lelii",
+ "contexts": {
+ "/gcube": ["Infrastructure-Manager"],
+ "/gcube/devsec/devVRE": [
+ "VRE-Manager",
+ "DataMiner-Manager"
+ ],
+ "/gcube/devsec": [
+ "VRE-Manager",
+ "VO-Admin"
+ ],
+ "/gcube/devNext": [
+ "VRE-Designer",
+ "VRE-Manager",
+ "VO-Admin"
+ ],
+ "/gcube/devNext/NextNext": ["DataMiner-Manager"]
+ }
+ },
+ {
+ "username": "paul.taconet",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "gianpaolo.coro",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devsec": ["VO-Admin"],
+ "/gcube/devNext": [],
+ "/gcube/devNext/NextNext": [
+ "Data-Manager",
+ "Catalogue-Admin",
+ "DataMiner-Manager"
+ ]
+ }
+ },
+ {
+ "username": "ciro.formisano",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "valentina.marioli",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": ["VO-Admin"],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "andrea.dellamico",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext/NextNext": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "panagiota.koltsida",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devsec": [
+ "Data-Manager",
+ "VRE-Designer"
+ ],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "konstantinos.giannousis",
+ "contexts": {"/gcube": []}
+ },
+ {
+ "username": "tommaso.piccioli",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "paolo.manghi",
+ "contexts": {"/gcube": []}
+ },
+ {
+ "username": "emmanuel.blondel",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "francesco.mangiacrapa",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": ["Catalogue-Admin"],
+ "/gcube/devsec": [],
+ "/gcube/devNext": [],
+ "/gcube/devNext/NextNext": ["Catalogue-Admin"]
+ }
+ },
+ {
+ "username": "ashtoash",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "anton.ellenbroek",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "pasquale.pagano",
+ "contexts": {
+ "/gcube": ["VO-Admin"],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devsec": [
+ "VRE-Manager",
+ "VO-Admin"
+ ],
+ "/gcube/devNext": ["VO-Admin"],
+ "/gcube/devNext/NextNext": [
+ "Data-Manager",
+ "Catalogue-Admin"
+ ]
+ }
+ },
+ {
+ "username": "leonardo.candela",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [
+ "VRE-Designer",
+ "VRE-Manager",
+ "Catalogue-Admin"
+ ],
+ "/gcube/devsec": [
+ "VRE-Manager",
+ "VO-Admin"
+ ],
+ "/gcube/devNext": [],
+ "/gcube/devNext/NextNext": [
+ "VRE-Manager",
+ "Catalogue-Admin"
+ ]
+ }
+ },
+ {
+ "username": "donatella.castelli",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "julien.barde",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "giancarlo.panichi",
+ "contexts": {
+ "/gcube": ["Infrastructure-Manager"],
+ "/gcube/devsec/devVRE": ["DataMiner-Manager"],
+ "/gcube/devsec": [],
+ "/gcube/devNext": [],
+ "/gcube/devNext/NextNext": [
+ "Data-Manager",
+ "VRE-Manager",
+ "Catalogue-Editor",
+ "DataMiner-Manager"
+ ]
+ }
+ },
+ {
+ "username": "luca.frosini",
+ "contexts": {
+ "/gcube": [
+ "VRE-Manager",
+ "VO-Admin"
+ ],
+ "/gcube/devsec/devVRE": [
+ "VRE-Manager",
+ "Catalogue-Admin"
+ ],
+ "/gcube/devsec": [],
+ "/gcube/devNext": [],
+ "/gcube/devNext/NextNext": [
+ "Catalogue-Admin",
+ "Accounting-Manager"
+ ]
+ }
+ },
+ {
+ "username": "fabio.sinibaldi",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": ["Catalogue-Admin"],
+ "/gcube/devsec": [
+ "VO-Admin",
+ "Catalogue-Admin"
+ ],
+ "/gcube/devNext": [
+ "VRE-Designer",
+ "VRE-Manager",
+ "VO-Admin"
+ ],
+ "/gcube/devNext/NextNext": ["Catalogue-Admin"]
+ }
+ },
+ {
+ "username": "yannis.marketakis",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext/NextNext": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "paolo.fabriani",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "nikolas.laskaris",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "massimiliano.assante",
+ "contexts": {
+ "/gcube": [
+ "Infrastructure-Manager",
+ "VO-Admin"
+ ],
+ "/gcube/devsec/devVRE": ["VRE-Manager"],
+ "/gcube/devsec": [
+ "VRE-Manager",
+ "VO-Admin"
+ ],
+ "/gcube/devNext/NextNext": [],
+ "/gcube/devNext": [
+ "Infrastructure-Manager",
+ "VRE-Manager",
+ "VO-Admin"
+ ]
+ }
+ },
+ {
+ "username": "gkakas",
+ "contexts": {"/gcube": []}
+ },
+ {
+ "username": "gantzoulatos",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "enrico.anello",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "mister.orange",
+ "contexts": {"/gcube": []}
+ },
+ {
+ "username": "mister.blue",
+ "contexts": {"/gcube": []}
+ },
+ {
+ "username": "kostas.kakaletris",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": ["Infrastructure-Manager"],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "leviwesterveld",
+ "contexts": {"/gcube": []}
+ },
+ {
+ "username": "dataminer",
+ "contexts": {}
+ },
+ {
+ "username": "andrea.rossi",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": ["VRE-Designer"],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "efthymios",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "miles",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "kgiannakelos",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "grsf.publisher",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devNext/NextNext": ["Catalogue-Admin"],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "jsonws.user",
+ "contexts": {"/gcube": []}
+ },
+ {
+ "username": "ay",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "salvam",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "nikos",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "statistical.manager",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext": [],
+ "/gcube/devNext/NextNext": ["Data-Manager"]
+ }
+ },
+ {
+ "username": "manuele.simi",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devNext/NextNext": []
+ }
+ },
+ {
+ "username": "vfloros",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": ["Catalogue-Editor"],
+ "/gcube/devsec": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "rob.knapen",
+ "contexts": {"/gcube": []}
+ },
+ {
+ "username": "mister.white",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devNext/NextNext": []
+ }
+ },
+ {
+ "username": "chiamag",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "Marco Lettere Lettere2",
+ "contexts": {"/gcube": []}
+ },
+ {
+ "username": "mauro.mugnaini",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [],
+ "/gcube/devsec": [],
+ "/gcube/devNext/NextNext": [],
+ "/gcube/devNext": []
+ }
+ },
+ {
+ "username": "themaxx7",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec": []
+ }
+ },
+ {
+ "username": "pino",
+ "contexts": {
+ "/gcube": [],
+ "/gcube/devsec/devVRE": [
+ "Data-Manager",
+ "DataMiner-Manager"
+ ],
+ "/gcube/devsec": []
+ }
+ }
+]
\ No newline at end of file