Intial GIT commit
This commit is contained in:
commit
7ab87410ab
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" output="target/classes" path="src/main/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="optional" value="true"/>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
<attribute name="test" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
<attribute name="test" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
|
<attribute name="org.eclipse.jst.component.nondependency" value=""/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="output" path="target/classes"/>
|
||||||
|
</classpath>
|
|
@ -0,0 +1 @@
|
||||||
|
target
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>oidc-library</name>
|
||||||
|
<comment></comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.wst.common.project.facet.core.builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.wst.validation.validationbuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.m2e.core.maven2Builder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
|
||||||
|
<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
<nature>org.eclipse.m2e.core.maven2Nature</nature>
|
||||||
|
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
|
@ -0,0 +1,6 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding//src/main/resources=UTF-8
|
||||||
|
encoding//src/test/java=UTF-8
|
||||||
|
encoding//src/test/resources=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
|
@ -0,0 +1,11 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.8
|
||||||
|
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
|
||||||
|
org.eclipse.jdt.core.compiler.release=disabled
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.8
|
|
@ -0,0 +1,4 @@
|
||||||
|
activeProfiles=gcube-developer
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
|
||||||
|
<wb-module deploy-name="oidc-library">
|
||||||
|
<wb-resource deploy-path="/" source-path="/src/main/java"/>
|
||||||
|
<wb-resource deploy-path="/" source-path="/src/main/resources"/>
|
||||||
|
</wb-module>
|
||||||
|
</project-modules>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<faceted-project>
|
||||||
|
<installed facet="java" version="1.8"/>
|
||||||
|
<installed facet="jst.utility" version="1.0"/>
|
||||||
|
</faceted-project>
|
|
@ -0,0 +1,2 @@
|
||||||
|
disabled=06target
|
||||||
|
eclipse.preferences.version=1
|
|
@ -0,0 +1,81 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<groupId>org.gcube.common</groupId>
|
||||||
|
<artifactId>oidc-library</artifactId>
|
||||||
|
<version>0.2.0</version>
|
||||||
|
<parent>
|
||||||
|
<artifactId>maven-parent</artifactId>
|
||||||
|
<groupId>org.gcube.tools</groupId>
|
||||||
|
<version>1.1.0</version>
|
||||||
|
<relativePath />
|
||||||
|
</parent>
|
||||||
|
<properties>
|
||||||
|
<java-version>1.8</java-version>
|
||||||
|
<keycloak-version>9.0.3</keycloak-version>
|
||||||
|
<slf4j-version>1.7.30</slf4j-version>
|
||||||
|
<log4j-version>1.2.17</log4j-version>
|
||||||
|
</properties>
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
<version>${slf4j-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-log4j12</artifactId>
|
||||||
|
<version>${slf4j-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-admin-client</artifactId>
|
||||||
|
<version>${keycloak-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.bouncycastle</groupId>
|
||||||
|
<artifactId>bcprov-jdk16</artifactId>
|
||||||
|
<version>1.46</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.8</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>log4j</groupId>
|
||||||
|
<artifactId>log4j</artifactId>
|
||||||
|
<version>${log4j-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.keycloak</groupId>
|
||||||
|
<artifactId>keycloak-authz-client</artifactId>
|
||||||
|
<version>${keycloak-version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.googlecode.json-simple</groupId>
|
||||||
|
<artifactId>json-simple</artifactId>
|
||||||
|
<version>1.1</version>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
<build>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-dependency-plugin</artifactId>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>copy-dependencies</id>
|
||||||
|
<phase>package</phase>
|
||||||
|
<goals>
|
||||||
|
<goal>copy-dependencies</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,21 @@
|
||||||
|
package com.nubisware.oidc.gcube;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public abstract class AbstractOIDCToSitesAndRolesMapper implements OIDCToSitesAndRolesMapper {
|
||||||
|
|
||||||
|
protected static final Logger logger = LoggerFactory.getLogger(OIDCToSitesAndRolesMapper.class);
|
||||||
|
|
||||||
|
protected Map<String, List<String>> resourceName2AccessRoles;
|
||||||
|
|
||||||
|
public AbstractOIDCToSitesAndRolesMapper(Map<String, List<String>> resourceName2AccessRoles) {
|
||||||
|
super();
|
||||||
|
this.resourceName2AccessRoles = resourceName2AccessRoles;
|
||||||
|
logger.info("Resource name to access roles: " + resourceName2AccessRoles);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.nubisware.oidc.gcube;
|
||||||
|
|
||||||
|
public class D4ScienceMappings {
|
||||||
|
|
||||||
|
public enum Role {
|
||||||
|
|
||||||
|
MEMBER("Member"),
|
||||||
|
|
||||||
|
ACCOUNTING_MANAGER("Accounting-Manager"),
|
||||||
|
CATALOGUE_ADMIN("Catalogue-Admin"),
|
||||||
|
CATALOGUE_EDITOR("Catalogue-Editor"),
|
||||||
|
DATA_MANAGER("Data-Manager"),
|
||||||
|
DATAMINER_MANAGER("DataMiner-Manager"),
|
||||||
|
INFRASTRUCTURE_MANAGER("Infrastructure-Manager"),
|
||||||
|
VO_ADMIN("VO-Admin"),
|
||||||
|
VRE_DESIGNER("VRE-Designer"),
|
||||||
|
VRE_MANAGER("VRE-Manager");
|
||||||
|
|
||||||
|
private String str;
|
||||||
|
|
||||||
|
Role(String str) {
|
||||||
|
this.str = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String asString() {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Scope {
|
||||||
|
|
||||||
|
BELONGS("belongs");
|
||||||
|
// TODO will be defined late
|
||||||
|
// LIST("list"),
|
||||||
|
// READ("read"),
|
||||||
|
// WRITE("write"),
|
||||||
|
// EXECUTE("execute");
|
||||||
|
|
||||||
|
private String str;
|
||||||
|
|
||||||
|
Scope(String str) {
|
||||||
|
this.str = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String asString() {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
package com.nubisware.oidc.gcube;
|
||||||
|
|
||||||
|
public interface OIDCToSitesAndRolesMapper {
|
||||||
|
|
||||||
|
Site map(String rootSite) throws SitesMapperExecption;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package com.nubisware.oidc.gcube;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class Site {
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
private List<String> roles;
|
||||||
|
private Map<String, Site> children;
|
||||||
|
|
||||||
|
public Site(String name, List<String> roles) {
|
||||||
|
this.name = name;
|
||||||
|
this.roles = roles;
|
||||||
|
this.children = new TreeMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRoles(List<String> roles) {
|
||||||
|
this.roles = roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getRoles() {
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Site> getChildren() {
|
||||||
|
return children;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String dump() {
|
||||||
|
return dump("");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String dump(String indentString) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append(indentString + "name: " + getName() + ", roles: " + getRoles() + "\n");
|
||||||
|
for (String child : getChildren().keySet()) {
|
||||||
|
sb.append(getChildren().get(child).dump(indentString + " "));
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package com.nubisware.oidc.gcube;
|
||||||
|
|
||||||
|
public class SitesMapperExecption extends Exception {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 956917439135370558L;
|
||||||
|
|
||||||
|
public SitesMapperExecption() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public SitesMapperExecption(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SitesMapperExecption(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SitesMapperExecption(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SitesMapperExecption(String message, Throwable cause, boolean enableSuppression,
|
||||||
|
boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.nubisware.oidc.gcube;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class SlashSeparatedContextMapper extends AbstractOIDCToSitesAndRolesMapper {
|
||||||
|
|
||||||
|
private static final String SPLIT_REGEXP = "/";
|
||||||
|
|
||||||
|
private static final int MINIMUM_TOKENS = 2;
|
||||||
|
|
||||||
|
private static final int EMPTY_TOKEN_INDEX = 0;
|
||||||
|
|
||||||
|
private static final int ROOT_VO_TOKEN_INDEX = EMPTY_TOKEN_INDEX + 1;
|
||||||
|
|
||||||
|
private static final int VO_TOKEN_INDEX = ROOT_VO_TOKEN_INDEX + 1;
|
||||||
|
|
||||||
|
private static final int VRE_TOKEN_INDEX = VO_TOKEN_INDEX + 1;
|
||||||
|
|
||||||
|
public SlashSeparatedContextMapper(Map<String, List<String>> resourceName2AccessRoles) {
|
||||||
|
super(resourceName2AccessRoles);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Site map(String rootSite) throws SitesMapperExecption {
|
||||||
|
List<String> sites = new ArrayList<String>(resourceName2AccessRoles.keySet());
|
||||||
|
Collections.sort(sites);
|
||||||
|
// Sorting sites, the containers site should come before contained one
|
||||||
|
Site gwSitesTree = null;
|
||||||
|
for (String site : sites) {
|
||||||
|
logger.info("Checking site: " + site);
|
||||||
|
List<String> roles = resourceName2AccessRoles.get(site);
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Roles for site are: " + roles);
|
||||||
|
}
|
||||||
|
String[] siteTokens = site.split(SPLIT_REGEXP);
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Tokens are: " + siteTokens.length);
|
||||||
|
}
|
||||||
|
if (siteTokens.length < MINIMUM_TOKENS) {
|
||||||
|
throw new SitesMapperExecption(
|
||||||
|
"Found " + siteTokens.length + " tokens only. Minimum should be: " + MINIMUM_TOKENS);
|
||||||
|
}
|
||||||
|
String rootVO = siteTokens[ROOT_VO_TOKEN_INDEX];
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Root VO is: " + rootVO);
|
||||||
|
}
|
||||||
|
if (!rootSite.equals(rootVO)) {
|
||||||
|
logger.info("Skipping evaluation of site tree not belonging to this Root VO: " + rootVO);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
logger.info("Site belongs to this Root VO");
|
||||||
|
}
|
||||||
|
if (siteTokens.length >= VO_TOKEN_INDEX + 1) {
|
||||||
|
if (gwSitesTree == null) {
|
||||||
|
logger.warn(rootVO + " Root VO's permissions are not set for user");
|
||||||
|
gwSitesTree = new Site(rootVO, null);
|
||||||
|
}
|
||||||
|
String vo = siteTokens[VO_TOKEN_INDEX];
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("VO is: " + vo);
|
||||||
|
}
|
||||||
|
if (siteTokens.length == VRE_TOKEN_INDEX + 1) {
|
||||||
|
if (!gwSitesTree.getChildren().containsKey(vo)) {
|
||||||
|
logger.warn(vo + " VO's permissions are not set for user");
|
||||||
|
gwSitesTree.getChildren().put(vo, new Site(vo, null));
|
||||||
|
}
|
||||||
|
String vre = siteTokens[VRE_TOKEN_INDEX];
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("VRE is: " + vre);
|
||||||
|
}
|
||||||
|
logger.info("Adding leaf site: " + vre);
|
||||||
|
gwSitesTree.getChildren().get(vo).getChildren().put(vre, new Site(vre, roles));
|
||||||
|
} else if (!gwSitesTree.getChildren().containsKey(vo)) {
|
||||||
|
logger.info("Creating site for VO: " + vo);
|
||||||
|
gwSitesTree.getChildren().put(vo, new Site(vo, roles));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (gwSitesTree == null) {
|
||||||
|
logger.info("Creating site for Root VO: " + rootVO);
|
||||||
|
gwSitesTree = new Site(rootVO, roles);
|
||||||
|
} else {
|
||||||
|
if (gwSitesTree.getRoles() == null) {
|
||||||
|
logger.info("Setting out of order roles for Root VO");
|
||||||
|
} else {
|
||||||
|
logger.warn("Duplicated roles definition for Root VO");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return gwSitesTree;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.nubisware.oidc.gcube;
|
||||||
|
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.URLDecoder;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
public class URLEncodedContextMapper extends SlashSeparatedContextMapper {
|
||||||
|
|
||||||
|
public URLEncodedContextMapper(Map<String, List<String>> resourceName2AccessRoles) {
|
||||||
|
super(decodeContextNames(resourceName2AccessRoles));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Map<String, List<String>> decodeContextNames(Map<String, List<String>> resourceName2AccessRoles) {
|
||||||
|
Map<String, List<String>> decodedResourceName2AccessRoles = new TreeMap<>();
|
||||||
|
for (String encodedContext : resourceName2AccessRoles.keySet()) {
|
||||||
|
try {
|
||||||
|
decodedResourceName2AccessRoles.put(URLDecoder.decode(encodedContext, "UTF-8"),
|
||||||
|
resourceName2AccessRoles.get(encodedContext));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
logger.error("Cannot URL decode context name: " + encodedContext, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return decodedResourceName2AccessRoles;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
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<String, Object> credentials = new HashMap<>();
|
||||||
|
Configuration configuration = new Configuration("https://nubis2.int.d4science.net/auth", "d4science", "portal",
|
||||||
|
credentials, null);
|
||||||
|
AuthzClient authzClient = AuthzClient.create(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,277 @@
|
||||||
|
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<UserRepresentation> 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<RoleRepresentation> 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<ClientRepresentation> 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<ClientRepresentation> 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<ScopeRepresentation> scopes, Set<String> 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<String> resources,
|
||||||
|
Set<String> scopes,
|
||||||
|
String name, Logic logic, Map<String, Set<String>> 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<String> resources, String name, DecisionStrategy decisionStrategy,
|
||||||
|
Set<String> 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 extends JsonWebToken> T verifyAndGetToken(Class<T> tokenClass, String tokenString, PublicKey publicKey)
|
||||||
|
throws VerificationException {
|
||||||
|
|
||||||
|
return TokenVerifier.create(tokenString, tokenClass).publicKey(publicKey).verify().getToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
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 = "<reponse not provided>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() + ")"
|
||||||
|
: "");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,315 @@
|
||||||
|
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<Role, Scope> 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<Role, RoleResource> 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<Scope, ScopeRepresentation> scopeMap = new HashMap<>();
|
||||||
|
for (Scope scopeToAdd : Scope.values()) {
|
||||||
|
ScopeRepresentation scope = new ScopeRepresentation(scopeToAdd.asString());
|
||||||
|
scopeMap.put(scopeToAdd, scope);
|
||||||
|
}
|
||||||
|
Set<ScopeRepresentation> 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<String> getRoleResourceScopes(String resourceName, Role role) {
|
||||||
|
// TODO Implement when/if needed
|
||||||
|
return Collections.emptySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void configureClientResource(ClientResource client, Map<Role, RoleResource> roleMap,
|
||||||
|
ResourceRepresentation resource) throws KeycloakResourceCreationException {
|
||||||
|
|
||||||
|
String resourceName = resource.getName();
|
||||||
|
Set<String> policies = new HashSet<>();
|
||||||
|
for (Role role : getInvolvedRoles(resourceName)) {
|
||||||
|
Map<String, Set<String>> 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<String> 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<String, Map<String, Set<String>>> usersToContextsAndRoles = exportParser.getAllUserContextsAndRoles();
|
||||||
|
for (String userName : usersToContextsAndRoles.keySet()) {
|
||||||
|
System.out.println("- user: " + userName);
|
||||||
|
UserResource userResource = kh.findUser(realmResource, userName);
|
||||||
|
if (userResource != null) {
|
||||||
|
Map<String, Set<String>> 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<String> getAllUsers() {
|
||||||
|
Set<String> users = new TreeSet<>();
|
||||||
|
Iterator<JsonNode> arrayIterator = rootNode.elements();
|
||||||
|
while (arrayIterator.hasNext()) {
|
||||||
|
JsonNode entry = arrayIterator.next();
|
||||||
|
users.add(entry.get("username").asText());
|
||||||
|
}
|
||||||
|
return users;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getAllContexts() {
|
||||||
|
Set<String> distinctContexts = new TreeSet<>();
|
||||||
|
Iterator<JsonNode> 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<String, Set<String>> getContextsAndRoles(String user) {
|
||||||
|
Iterator<JsonNode> arrayIterator = rootNode.elements();
|
||||||
|
while (arrayIterator.hasNext()) {
|
||||||
|
JsonNode entry = arrayIterator.next();
|
||||||
|
String username = entry.get("username").asText();
|
||||||
|
if (!user.equals(username)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Map<String, Set<String>> contextAndRoles = new TreeMap<>();
|
||||||
|
ObjectNode contextsNode = (ObjectNode) entry.get("contexts");
|
||||||
|
Iterator<String> contextIterator = contextsNode.fieldNames();
|
||||||
|
while (contextIterator.hasNext()) {
|
||||||
|
String context = (String) contextIterator.next();
|
||||||
|
Set<String> 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<String, Map<String, Set<String>>> getAllUserContextsAndRoles() {
|
||||||
|
Map<String, Map<String, Set<String>>> usersToContextAndRoles = new TreeMap<>();
|
||||||
|
Iterator<JsonNode> arrayIterator = rootNode.elements();
|
||||||
|
while (arrayIterator.hasNext()) {
|
||||||
|
JsonNode entry = arrayIterator.next();
|
||||||
|
String username = entry.get("username").asText();
|
||||||
|
Map<String, Set<String>> contextAndRoles = new TreeMap<>();
|
||||||
|
ObjectNode contextsNode = (ObjectNode) entry.get("contexts");
|
||||||
|
Iterator<String> contextIterator = contextsNode.fieldNames();
|
||||||
|
while (contextIterator.hasNext()) {
|
||||||
|
String context = (String) contextIterator.next();
|
||||||
|
Set<String> 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<String, Map<String, Set<String>>> 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());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,209 @@
|
||||||
|
package com.nubisware.oidc.rest;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Base64;
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.json.simple.JSONArray;
|
||||||
|
import org.json.simple.JSONObject;
|
||||||
|
import org.json.simple.parser.JSONParser;
|
||||||
|
import org.json.simple.parser.ParseException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.nubisware.oidc.keycloak.KeycloakHelper;
|
||||||
|
|
||||||
|
public class JWTToken implements Serializable {
|
||||||
|
|
||||||
|
protected static Logger logger = LoggerFactory.getLogger(KeycloakHelper.class);
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -7063122428186284827L;
|
||||||
|
|
||||||
|
private static String SHARE_PREFIX = "USER_";
|
||||||
|
|
||||||
|
public static String OIDC_TOKEN_ATTRIBUTE = SHARE_PREFIX + "OIDC_JWT";
|
||||||
|
public static String RPT_TOKEN_ATTRIBUTE = SHARE_PREFIX + "UMA_RPT_JWT";
|
||||||
|
|
||||||
|
public static final String ACCOUNT_RESOURCE = "account";
|
||||||
|
|
||||||
|
private String raw;
|
||||||
|
private JSONObject token;
|
||||||
|
private JSONObject identity;
|
||||||
|
|
||||||
|
public static JWTToken fromString(String tokenString) {
|
||||||
|
if (tokenString == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return new JWTToken(tokenString);
|
||||||
|
} catch (ParseException e) {
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JWTToken(String raw) throws ParseException {
|
||||||
|
this.raw = raw;
|
||||||
|
this.parse();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void parse() throws ParseException {
|
||||||
|
token = (JSONObject) new JSONParser().parse(this.raw);
|
||||||
|
String[] parts = getAccessTokenString().split("\\.");
|
||||||
|
identity = (JSONObject) new JSONParser().parse(new String(Base64.getDecoder().decode(parts[1])));
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRaw() {
|
||||||
|
return raw;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAccessTokenString() {
|
||||||
|
return (String) token.get("access_token");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getRefreshTokenString() {
|
||||||
|
return (String) token.get("refresh_token");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAsBearer() {
|
||||||
|
return "Bearer " + getAccessTokenString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JSONObject getIdentity() {
|
||||||
|
return identity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getExp() {
|
||||||
|
return (String) getIdentity().get("exp");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getExpAsDate() {
|
||||||
|
return new Date(Long.getLong(getExp()) * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Calendar getExpAsCalendar() {
|
||||||
|
Calendar cal = Calendar.getInstance();
|
||||||
|
cal.setTime(getExpAsDate());
|
||||||
|
return cal;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpired() {
|
||||||
|
return new Date().after(getExpAsDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSub() {
|
||||||
|
return (String) getIdentity().get("sub");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getEmail() {
|
||||||
|
return (String) getIdentity().get("email");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getFamily() {
|
||||||
|
return (String) getIdentity().get("family_name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getGiven() {
|
||||||
|
return (String) getIdentity().get("given_name");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserName() {
|
||||||
|
return (String) getIdentity().get("preferred_username");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return (String) getIdentity().get("name");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected JSONObject getResourceAccess() {
|
||||||
|
return (JSONObject) getIdentity().get("resource_access");
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
protected Iterator<String> getResourceAccessKeys() {
|
||||||
|
return getResourceAccess().keySet().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getResourceAccessRoles(String resource) {
|
||||||
|
JSONArray rolesJsonArray = (JSONArray) ((JSONObject) getResourceAccess().get(resource))
|
||||||
|
.get("roles");
|
||||||
|
List<String> roles = new ArrayList<>(rolesJsonArray.size());
|
||||||
|
for (int i = 0; i < rolesJsonArray.size(); i++) {
|
||||||
|
roles.add((String) rolesJsonArray.get(i));
|
||||||
|
}
|
||||||
|
return roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<String>> getResourceNameToAccessRolesMap(List<String> resourcesToSkip) {
|
||||||
|
Map<String, List<String>> map = new HashMap<>();
|
||||||
|
Iterator<String> resourcesIterator = getResourceAccessKeys();
|
||||||
|
while (resourcesIterator.hasNext()) {
|
||||||
|
String resource = resourcesIterator.next();
|
||||||
|
if (resourcesToSkip.contains(resource)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
map.put(resource, getResourceAccessRoles(resource));
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
"authorization": {
|
||||||
|
"permissions": [
|
||||||
|
{
|
||||||
|
"rsid": "e9afce09-baeb-4569-8e9a-67342ce39cf5",
|
||||||
|
"rsname": "a",
|
||||||
|
"resource_scopes" : []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
protected JSONArray getAuthorizationPermissions() {
|
||||||
|
JSONObject authorization = (JSONObject) getIdentity().get("authorization");
|
||||||
|
return (JSONArray) authorization.get("permissions");
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getAuthorizationPermissionRSNames() {
|
||||||
|
List<String> permissionsRSName = new ArrayList<>();
|
||||||
|
JSONArray permissions = getAuthorizationPermissions();
|
||||||
|
for (int i = 0; i < permissions.size(); i++) {
|
||||||
|
JSONObject permissionsEntry = (JSONObject) permissions.get(i);
|
||||||
|
permissionsRSName.add((String) permissionsEntry.get("rsname"));
|
||||||
|
}
|
||||||
|
return permissionsRSName;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<String> getAuthorizationPermissionRSNameResourceScopes(String rsname) {
|
||||||
|
List<String> scopes = new ArrayList<>();
|
||||||
|
JSONArray permissions = getAuthorizationPermissions();
|
||||||
|
for (int i = 0; i < permissions.size(); i++) {
|
||||||
|
JSONObject permissionsEntry = (JSONObject) permissions.get(i);
|
||||||
|
if (rsname.equals(permissionsEntry.get("rsname"))) {
|
||||||
|
JSONArray scopesJsonArray = (JSONArray) permissionsEntry.get("resource_scopes");
|
||||||
|
if (scopesJsonArray != null) {
|
||||||
|
for (int j = 0; j < scopesJsonArray.size(); j++) {
|
||||||
|
scopes.add((String) scopesJsonArray.get(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return scopes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, List<String>> getAuthorizationPermissionRSNameToResourceScopesMap() {
|
||||||
|
Map<String, List<String>> map = new HashMap<>();
|
||||||
|
for (String aprn : getAuthorizationPermissionRSNames() ) {
|
||||||
|
map.put(aprn, getAuthorizationPermissionRSNameResourceScopes(aprn));
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package com.nubisware.oidc.rest;
|
||||||
|
|
||||||
|
public interface OpenIdConnectConfiguration {
|
||||||
|
|
||||||
|
String getScope();
|
||||||
|
|
||||||
|
String getClientId();
|
||||||
|
|
||||||
|
String getIssuerUrl();
|
||||||
|
|
||||||
|
String getLogoutUrl();
|
||||||
|
|
||||||
|
String getTokenUrl();
|
||||||
|
|
||||||
|
String getAuthorizationUrl();
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,151 @@
|
||||||
|
package com.nubisware.oidc.rest;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class OpenIdConnectRESTHelper {
|
||||||
|
|
||||||
|
protected static final Logger logger = LoggerFactory.getLogger(OpenIdConnectRESTHelper.class);
|
||||||
|
|
||||||
|
public static String buildLoginUrl(String kcLoginUrl, String clientId, String state, String redirectUri)
|
||||||
|
throws UnsupportedEncodingException {
|
||||||
|
|
||||||
|
Map<String, List<String>> params = new HashMap<String, List<String>>();
|
||||||
|
params.put("client_id", Arrays.asList(URLEncoder.encode(clientId, "UTF-8")));
|
||||||
|
params.put("response_type", Arrays.asList("code"));
|
||||||
|
params.put("scope", Arrays.asList("openid"));
|
||||||
|
params.put("state", Arrays.asList(URLEncoder.encode(state, "UTF-8")));
|
||||||
|
params.put("redirect_uri", Arrays.asList(URLEncoder.encode(redirectUri, "UTF-8")));
|
||||||
|
params.put("login", Arrays.asList("true"));
|
||||||
|
String q = mapToQueryString(params);
|
||||||
|
return kcLoginUrl + "?" + q;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String mapToQueryString(Map<String, List<String>> params) {
|
||||||
|
String q = params.entrySet().stream().flatMap(p -> p.getValue().stream().map(v -> p.getKey() + "=" + v))
|
||||||
|
.reduce((p1, p2) -> p1 + "&" + p2).orElse("");
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Query string is: " + q);
|
||||||
|
}
|
||||||
|
System.out.println("Query string is: " + q);
|
||||||
|
return q;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JWTToken queryToken(String clientId, String tokenUrl, String code, String scope,
|
||||||
|
String redirectUri) throws Exception {
|
||||||
|
|
||||||
|
Map<String, List<String>> params = new HashMap<>();
|
||||||
|
params.put("client_id", Arrays.asList(URLEncoder.encode(clientId, "UTF-8")));
|
||||||
|
params.put("grant_type", Arrays.asList("authorization_code"));
|
||||||
|
params.put("scope", Arrays.asList(URLEncoder.encode(scope, "UTF-8")));
|
||||||
|
params.put("code", Arrays.asList(URLEncoder.encode(code, "UTF-8")));
|
||||||
|
params.put("redirect_uri", Arrays.asList(URLEncoder.encode(redirectUri, "UTF-8")));
|
||||||
|
return performQueryTokenWithPOST(tokenUrl, null, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JWTToken performQueryTokenWithPOST(String tokenUrl, String authorization,
|
||||||
|
Map<String, List<String>> params)
|
||||||
|
throws Exception {
|
||||||
|
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug("Querying access token to Keycloak with URL: " + tokenUrl);
|
||||||
|
}
|
||||||
|
URL myurl = new URL(tokenUrl);
|
||||||
|
HttpURLConnection con = (HttpURLConnection) myurl.openConnection();
|
||||||
|
con.setDoOutput(true);
|
||||||
|
con.setDoInput(true);
|
||||||
|
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||||
|
con.setRequestProperty("Accept", "application/json");
|
||||||
|
con.setRequestProperty("Method", "POST");
|
||||||
|
if (authorization != null) {
|
||||||
|
con.setRequestProperty("Authorization", authorization);
|
||||||
|
}
|
||||||
|
System.err.println("Authorization: " + authorization);
|
||||||
|
OutputStream os = con.getOutputStream();
|
||||||
|
os.write(mapToQueryString(params).getBytes("UTF-8"));
|
||||||
|
os.close();
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
int HttpResult = con.getResponseCode();
|
||||||
|
if (logger.isDebugEnabled()) {
|
||||||
|
logger.debug(String.valueOf(con.getResponseCode()));
|
||||||
|
logger.debug(con.getResponseMessage());
|
||||||
|
}
|
||||||
|
if (HttpResult != HttpURLConnection.HTTP_OK) {
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(con.getErrorStream(), "UTF-8"));
|
||||||
|
String line = null;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
sb.append(line + "\n");
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
throw new Exception("Unable to get token " + sb);
|
||||||
|
} else {
|
||||||
|
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
|
||||||
|
String line = null;
|
||||||
|
while ((line = br.readLine()) != null) {
|
||||||
|
sb.append(line + "\n");
|
||||||
|
}
|
||||||
|
br.close();
|
||||||
|
}
|
||||||
|
return JWTToken.fromString(sb.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static JWTToken queryUMAToken(String tokenUrl, String authorizationToken, String audience,
|
||||||
|
List<String> permissions) throws Exception {
|
||||||
|
|
||||||
|
Map<String, List<String>> params = new HashMap<>();
|
||||||
|
params.put("grant_type", Arrays.asList("urn:ietf:params:oauth:grant-type:uma-ticket"));
|
||||||
|
params.put("audience", Arrays.asList(URLEncoder.encode(audience, "UTF-8")));
|
||||||
|
if (permissions != null && !permissions.isEmpty()) {
|
||||||
|
params.put(
|
||||||
|
"permission", permissions.stream().map(s -> {
|
||||||
|
try {
|
||||||
|
return URLEncoder.encode(s, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}).collect(Collectors.toList()));
|
||||||
|
}
|
||||||
|
return performQueryTokenWithPOST(tokenUrl, authorizationToken, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void logout(JWTToken token, String kcLogoutUrl, String portalClientId) throws IOException {
|
||||||
|
Map<String, List<String>> params = new HashMap<>();
|
||||||
|
params.put("client_id", Arrays.asList(URLEncoder.encode(portalClientId, "UTF-8")));
|
||||||
|
params.put("refresh_token", Arrays.asList(token.getRefreshTokenString()));
|
||||||
|
logger.info("Performing logut from Keycloak with URL: " + kcLogoutUrl);
|
||||||
|
URL myurl = new URL(kcLogoutUrl);
|
||||||
|
HttpURLConnection con = (HttpURLConnection) myurl.openConnection();
|
||||||
|
con.setDoOutput(true);
|
||||||
|
con.setDoInput(true);
|
||||||
|
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
|
||||||
|
con.setRequestProperty("Accept", "application/json");
|
||||||
|
con.setRequestProperty("Method", "POST");
|
||||||
|
con.setRequestProperty("Authorization", token.getAsBearer());
|
||||||
|
OutputStream os = con.getOutputStream();
|
||||||
|
os.write(mapToQueryString(params).getBytes("UTF-8"));
|
||||||
|
os.close();
|
||||||
|
int responseCode = con.getResponseCode();
|
||||||
|
if (responseCode == 204) {
|
||||||
|
logger.info("Logout performed correctly");
|
||||||
|
} else {
|
||||||
|
logger.error("Cannot perfrom logout: [" + responseCode + "] " + con.getResponseMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
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, "<h2>" + realm + "</h2><p>Welcome</p>", 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<ScopeRepresentation> 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<String> resources = new HashSet<>(
|
||||||
|
Arrays.asList(resource1.toRepresentation().getName(), resource2.toRepresentation().getName()));
|
||||||
|
|
||||||
|
Map<String, Set<String>> 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<String, Object> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,618 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"username": "nikolaos.drakopoulos",
|
||||||
|
"contexts": {
|
||||||
|
"/gcube": [],
|
||||||
|
"/gcube/devsec": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "roberto.cirillo",
|
||||||
|
"contexts": {
|
||||||
|
"/gcube": [
|
||||||
|
"VO-Admin"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAI5": [
|
||||||
|
"VRE-Designer"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAI4": [
|
||||||
|
"VRE-Designer"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAIVRE3": [
|
||||||
|
"VRE-Designer"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAI3": [
|
||||||
|
"VRE-Designer"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAI2": [
|
||||||
|
"VRE-Designer"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/devVRE": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAIVRE2": [
|
||||||
|
"VRE-Designer"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAITest": [
|
||||||
|
"VRE-Designer"
|
||||||
|
],
|
||||||
|
"/gcube/devNext": [
|
||||||
|
"VO-Admin"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAITest2": [
|
||||||
|
"VRE-Designer"
|
||||||
|
],
|
||||||
|
"/gcube/devsec": [
|
||||||
|
"VO-Admin"
|
||||||
|
],
|
||||||
|
"/gcube/devNext/NextNext": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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/Test4StoHub": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/devVRE": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec": [
|
||||||
|
"VRE-Manager",
|
||||||
|
"VO-Admin"
|
||||||
|
],
|
||||||
|
"/gcube/devNext/NextNext": [
|
||||||
|
"DataMiner-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devNext": [
|
||||||
|
"VRE-Designer",
|
||||||
|
"VRE-Manager",
|
||||||
|
"VO-Admin"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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/NextNext": [
|
||||||
|
"Data-Manager",
|
||||||
|
"Catalogue-Admin",
|
||||||
|
"DataMiner-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devNext": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "ciro.formisano",
|
||||||
|
"contexts": {
|
||||||
|
"/gcube": [],
|
||||||
|
"/gcube/devsec": [],
|
||||||
|
"/gcube/devNext": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "valentina.marioli",
|
||||||
|
"contexts": {
|
||||||
|
"/gcube": [],
|
||||||
|
"/gcube/devsec/devVRE": [],
|
||||||
|
"/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/NextNext": [
|
||||||
|
"Catalogue-Admin"
|
||||||
|
],
|
||||||
|
"/gcube/devNext": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"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/NextNext": [
|
||||||
|
"Data-Manager",
|
||||||
|
"Catalogue-Admin"
|
||||||
|
],
|
||||||
|
"/gcube/devNext": [
|
||||||
|
"VO-Admin"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "leonardo.candela",
|
||||||
|
"contexts": {
|
||||||
|
"/gcube": [],
|
||||||
|
"/gcube/devsec/SAI5": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAI4": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAI3": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAIVRE3": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAI2": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/devVRE": [
|
||||||
|
"VRE-Designer",
|
||||||
|
"VRE-Manager",
|
||||||
|
"Catalogue-Admin"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAIVRE2": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAITest": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devNext": [],
|
||||||
|
"/gcube/devsec/SAITest2": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec": [
|
||||||
|
"VRE-Manager",
|
||||||
|
"VO-Admin"
|
||||||
|
],
|
||||||
|
"/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": [],
|
||||||
|
"/gcube/devsec/SAIVRE2": [],
|
||||||
|
"/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/devsec/Test4StoHub": [],
|
||||||
|
"/gcube": [
|
||||||
|
"Infrastructure-Manager",
|
||||||
|
"VO-Admin"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/devVRE": [
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/SAIVRE2": [],
|
||||||
|
"/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/Test4StoHub": [
|
||||||
|
"VRE-Designer",
|
||||||
|
"VRE-Manager"
|
||||||
|
],
|
||||||
|
"/gcube/devsec/devVRE": [],
|
||||||
|
"/gcube/devsec": [
|
||||||
|
"VRE-Designer"
|
||||||
|
],
|
||||||
|
"/gcube/devNext/NextNext": [],
|
||||||
|
"/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": "m.lettere",
|
||||||
|
"contexts": {
|
||||||
|
"/gcube": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"username": "mauro",
|
||||||
|
"contexts": {
|
||||||
|
"/gcube": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
|
||||||
|
<log4j:configuration
|
||||||
|
xmlns="http://jakarta.apache.org/log4j/"
|
||||||
|
xmlns:log4j="http://jakarta.apache.org/log4j/">
|
||||||
|
|
||||||
|
<appender name="console"
|
||||||
|
class="org.apache.log4j.ConsoleAppender">
|
||||||
|
<layout class="org.apache.log4j.PatternLayout">
|
||||||
|
<param name="ConversionPattern"
|
||||||
|
value="%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n" />
|
||||||
|
</layout>
|
||||||
|
</appender>
|
||||||
|
<logger name="org.gcube" additivity="false">
|
||||||
|
<level value="INFO" />
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</logger>
|
||||||
|
<logger name="org.keycloak" additivity="false">
|
||||||
|
<level value="INFO" />
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</logger>
|
||||||
|
<logger name="org.jboss" additivity="false">
|
||||||
|
<level value="INFO" />
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</logger>
|
||||||
|
<logger name="org.apache.commons.httpclient" additivity="false">
|
||||||
|
<level value="INFO" />
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</logger>
|
||||||
|
<logger name="httpclient.wire" additivity="false">
|
||||||
|
<level value="DEBUG" />
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</logger>
|
||||||
|
<root>
|
||||||
|
<level value="DEBUG" />
|
||||||
|
<appender-ref ref="console" />
|
||||||
|
</root>
|
||||||
|
|
||||||
|
</log4j:configuration>
|
|
@ -0,0 +1,73 @@
|
||||||
|
{
|
||||||
|
"exp": 1586418752,
|
||||||
|
"nbf": 0,
|
||||||
|
"iat": 1586418452,
|
||||||
|
"auth_time": 0,
|
||||||
|
"jti": "caf3c534-b6e0-4475-b643-883d535651f9",
|
||||||
|
"iss": "https://nubis2.int.d4science.net/auth/realms/d4science",
|
||||||
|
"aud": [
|
||||||
|
"/gcube/devsec/devVRE",
|
||||||
|
"account"
|
||||||
|
],
|
||||||
|
"sub": "696f7a5f-8142-4079-95f5-0751a497465b",
|
||||||
|
"typ": "Bearer",
|
||||||
|
"azp": "portal",
|
||||||
|
"nonce": null,
|
||||||
|
"session_state": "1a2d3d4f-0e28-4930-b3c3-a5e3660d87dc",
|
||||||
|
"at_hash": null,
|
||||||
|
"c_hash": null,
|
||||||
|
"name": "Pasquale Pagano",
|
||||||
|
"given_name": "Pasquale",
|
||||||
|
"family_name": "Pagano",
|
||||||
|
"middle_name": null,
|
||||||
|
"nickname": null,
|
||||||
|
"preferred_username": "lino",
|
||||||
|
"profile": null,
|
||||||
|
"picture": null,
|
||||||
|
"website": null,
|
||||||
|
"email": "themaxx76@gmail.com",
|
||||||
|
"email_verified": false,
|
||||||
|
"gender": null,
|
||||||
|
"birthdate": null,
|
||||||
|
"zoneinfo": null,
|
||||||
|
"locale": null,
|
||||||
|
"phone_number": null,
|
||||||
|
"phone_number_verified": null,
|
||||||
|
"address": null,
|
||||||
|
"updated_at": null,
|
||||||
|
"claims_locales": null,
|
||||||
|
"acr": "1",
|
||||||
|
"s_hash": null,
|
||||||
|
"trusted-certs": null,
|
||||||
|
"allowed-origins": [
|
||||||
|
"*"
|
||||||
|
],
|
||||||
|
"realm_access": {
|
||||||
|
"roles": [
|
||||||
|
"offline_access",
|
||||||
|
"uma_authorization"
|
||||||
|
],
|
||||||
|
"verify_caller": null
|
||||||
|
},
|
||||||
|
"resource_access": {
|
||||||
|
"/gcube/devsec/devVRE": {
|
||||||
|
"roles": [
|
||||||
|
"DataManager",
|
||||||
|
"DataProcessor"
|
||||||
|
],
|
||||||
|
"verify_caller": null
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"roles": [
|
||||||
|
"manage-account",
|
||||||
|
"manage-account-links",
|
||||||
|
"view-profile"
|
||||||
|
],
|
||||||
|
"verify_caller": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"authorization": null,
|
||||||
|
"cnf": null,
|
||||||
|
"scope": "profile email",
|
||||||
|
"groups": []
|
||||||
|
}
|
Loading…
Reference in New Issue