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