keycloak-uncached
Changes
integration/as7-eap6/adapter/pom.xml 85(+85 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java 87(+87 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java 163(+163 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSecurityContextHelper.java 138(+138 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/AuthServerConfig.java 279(+279 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java 213(+213 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java 139(+139 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticationServerValve.java 1050(+1050 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java 303(+303 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java 320(+320 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/UserSessionManagement.java 111(+111 -0)
integration/pom.xml 21(+21 -0)
pom.xml 12(+12 -0)
services/pom.xml 36(+36 -0)
services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java 84(+40 -44)
services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java 94(+42 -52)
services/src/main/java/org/keycloak/services/models/relationships/ResourceRelationship.java 106(+62 -44)
Details
diff --git a/core/src/main/java/org/keycloak/SkeletonKeyContextResolver.java b/core/src/main/java/org/keycloak/SkeletonKeyContextResolver.java
index 3bca480..9b83907 100755
--- a/core/src/main/java/org/keycloak/SkeletonKeyContextResolver.java
+++ b/core/src/main/java/org/keycloak/SkeletonKeyContextResolver.java
@@ -36,7 +36,7 @@ public class SkeletonKeyContextResolver implements ContextResolver<ObjectMapper>
@Override
public ObjectMapper getContext(Class<?> type)
{
- if (type.getPackage().getName().startsWith("org.jboss.resteasy.skeleton.key")) return mapper;
+ if (type.getPackage().getName().startsWith(getClass().getPackage().getName())) return mapper;
return null;
}
}
integration/as7-eap6/adapter/pom.xml 85(+85 -0)
diff --git a/integration/as7-eap6/adapter/pom.xml b/integration/as7-eap6/adapter/pom.xml
new file mode 100755
index 0000000..b4ad78f
--- /dev/null
+++ b/integration/as7-eap6/adapter/pom.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0"?>
+<project>
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.0-alpha-1</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-as7-adapter</artifactId>
+ <name>Keycloak AS7 Integration</name>
+ <description/>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <version>3.1.2.GA</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-core</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>jose-jwt</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <scope>provided</scope>
+ <version>1.0.0.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-jaxrs</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>resteasy-client</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.jboss.web</groupId>
+ <artifactId>jbossweb</artifactId>
+ <version>7.0.17.Final</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.as</groupId>
+ <artifactId>jboss-as-web</artifactId>
+ <version>7.1.2.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>org.picketbox</groupId>
+ <artifactId>picketbox</artifactId>
+ <scope>provided</scope>
+ <version>4.0.7.Final</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/Actions.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/Actions.java
new file mode 100755
index 0000000..65c9ddb
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/Actions.java
@@ -0,0 +1,14 @@
+package org.keycloak.adapters.as7;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface Actions
+{
+ public static final String J_OAUTH_ADMIN_FORCED_LOGOUT = "j_oauth_admin_forced_logout";
+ public static final String J_OAUTH_LOGOUT = "j_oauth_logout";
+ public static final String J_OAUTH_RESOLVE_ACCESS_CODE = "j_oauth_resolve_access_code";
+ public static final String J_OAUTH_REMOTE_LOGOUT = "j_oauth_remote_logout";
+ public static final String J_OAUTH_TOKEN_GRANT = "j_oauth_token_grant";
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java
new file mode 100755
index 0000000..2f7e95c
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/BearerTokenAuthenticatorValve.java
@@ -0,0 +1,87 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.authenticator.AuthenticatorBase;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.LoginConfig;
+import org.jboss.logging.Logger;
+import org.keycloak.ResourceMetadata;
+import org.keycloak.adapters.as7.config.ManagedResourceConfig;
+import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+
+import javax.security.auth.login.LoginException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+/**
+ * Uses a configured remote auth server to do Bearer token authentication only. SkeletonKeyTokens are used
+ * to provide user data and role mappings.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class BearerTokenAuthenticatorValve extends AuthenticatorBase implements LifecycleListener
+{
+ private static final Logger log = Logger.getLogger(BearerTokenAuthenticatorValve.class);
+ protected ManagedResourceConfig remoteSkeletonKeyConfig;
+ protected ResourceMetadata resourceMetadata;
+
+ @Override
+ public void start() throws LifecycleException
+ {
+ super.start();
+ StandardContext standardContext = (StandardContext)context;
+ standardContext.addLifecycleListener(this);
+ }
+
+ @Override
+ public void lifecycleEvent(LifecycleEvent event)
+ {
+ if (event.getType() == Lifecycle.AFTER_START_EVENT) init();
+ }
+
+ protected void init()
+ {
+ ManagedResourceConfigLoader managedResourceConfigLoader = new ManagedResourceConfigLoader(context);
+ resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
+ remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
+ }
+
+ @Override
+ public void invoke(Request request, Response response) throws IOException, ServletException
+ {
+ try
+ {
+ super.invoke(request, response);
+ }
+ finally
+ {
+ ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
+ }
+ }
+
+ @Override
+ protected boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException
+ {
+ try
+ {
+ CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, !remoteSkeletonKeyConfig.isCancelPropagation(), true);
+ if (bearer.login(request, response))
+ {
+ return true;
+ }
+ return false;
+ }
+ catch (LoginException e)
+ {
+ }
+ return false;
+ }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java
new file mode 100755
index 0000000..7d14c1d
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaBearerTokenAuthenticator.java
@@ -0,0 +1,163 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.connector.Request;
+import org.jboss.logging.Logger;
+import org.keycloak.RSATokenVerifier;
+import org.keycloak.ResourceMetadata;
+import org.keycloak.SkeletonKeyPrincipal;
+import org.keycloak.SkeletonKeySession;
+import org.keycloak.VerificationException;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+
+import javax.security.auth.login.LoginException;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CatalinaBearerTokenAuthenticator
+{
+ protected ResourceMetadata resourceMetadata;
+ protected boolean challenge;
+ protected Logger log = Logger.getLogger(CatalinaBearerTokenAuthenticator.class);
+ protected String tokenString;
+ protected SkeletonKeyToken token;
+ private Principal principal;
+ protected boolean propagateToken;
+
+ public CatalinaBearerTokenAuthenticator(ResourceMetadata resourceMetadata, boolean propagateToken, boolean challenge)
+ {
+ this.resourceMetadata = resourceMetadata;
+ this.challenge = challenge;
+ this.propagateToken = propagateToken;
+ }
+
+ public ResourceMetadata getResourceMetadata()
+ {
+ return resourceMetadata;
+ }
+
+ public String getTokenString()
+ {
+ return tokenString;
+ }
+
+ public SkeletonKeyToken getToken()
+ {
+ return token;
+ }
+
+ public Principal getPrincipal()
+ {
+ return principal;
+ }
+
+ public boolean login(Request request, HttpServletResponse response) throws LoginException, IOException
+ {
+ String authHeader = request.getHeader("Authorization");
+ if (authHeader == null)
+ {
+ if (challenge)
+ {
+ challengeResponse(response, null, null);
+ return false;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ String[] split = authHeader.trim().split("\\s+");
+ if (split == null || split.length != 2) challengeResponse(response, null, null);
+ if (!split[0].equalsIgnoreCase("Bearer")) challengeResponse(response, null, null);
+
+
+ tokenString = split[1];
+
+ try
+ {
+ token = RSATokenVerifier.verifyToken(tokenString, resourceMetadata);
+ }
+ catch (VerificationException e)
+ {
+ log.error("Failed to verify token", e);
+ challengeResponse(response, "invalid_token", e.getMessage());
+ }
+ boolean verifyCaller = false;
+ Set<String> roles = null;
+ if (resourceMetadata.getResourceName() != null)
+ {
+ SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
+ if (access != null) roles = access.getRoles();
+ verifyCaller = token.isVerifyCaller(resourceMetadata.getResourceName());
+ }
+ else
+ {
+ verifyCaller = token.isVerifyCaller();
+ SkeletonKeyToken.Access access = token.getRealmAccess();
+ if (access != null) roles = access.getRoles();
+ }
+ String surrogate = null;
+ if (verifyCaller)
+ {
+ if (token.getTrustedCertificates() == null || token.getTrustedCertificates().size() == 0)
+ {
+ response.sendError(400);
+ throw new LoginException("No trusted certificates in token");
+ }
+ // for now, we just make sure JBoss Web did two-way SSL
+ // assume JBoss Web verifies the client cert
+ X509Certificate[] chain = request.getCertificateChain();
+ if (chain == null || chain.length == 0)
+ {
+ response.sendError(400);
+ throw new LoginException("No certificates provided by jboss web to verify the caller");
+ }
+ surrogate = chain[0].getSubjectX500Principal().getName();
+ }
+ SkeletonKeyPrincipal skeletonKeyPrincipal = new SkeletonKeyPrincipal(token.getPrincipal(), surrogate);
+ principal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), skeletonKeyPrincipal, roles);
+ request.setUserPrincipal(principal);
+ request.setAuthType("OAUTH_BEARER");
+ if (propagateToken)
+ {
+ SkeletonKeySession skSession = new SkeletonKeySession(tokenString, resourceMetadata);
+ request.setAttribute(SkeletonKeySession.class.getName(), skSession);
+ ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
+ }
+
+ return true;
+ }
+
+
+ protected void challengeResponse(HttpServletResponse response, String error, String description) throws LoginException
+ {
+ StringBuilder header = new StringBuilder("Bearer realm=\"");
+ header.append(resourceMetadata.getRealm()).append("\"");
+ if (error != null)
+ {
+ header.append(", error=\"").append(error).append("\"");
+ }
+ if (description != null)
+ {
+ header.append(", error_description=\"").append(description).append("\"");
+ }
+ response.setHeader("WWW-Authenticate", header.toString());
+ try
+ {
+ response.sendError(401);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ throw new LoginException("Challenged");
+ }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSecurityContextHelper.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSecurityContextHelper.java
new file mode 100755
index 0000000..bf783bd
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSecurityContextHelper.java
@@ -0,0 +1,138 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Realm;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.jboss.as.web.security.JBossGenericPrincipal;
+import org.jboss.security.NestableGroup;
+import org.jboss.security.SecurityConstants;
+import org.jboss.security.SecurityContext;
+import org.jboss.security.SecurityContextAssociation;
+import org.jboss.security.SimpleGroup;
+import org.jboss.security.SimplePrincipal;
+
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class CatalinaSecurityContextHelper
+{
+ public GenericPrincipal createPrincipal(Realm realm, Principal identity, Collection<String> roleSet)
+ {
+ Subject subject = new Subject();
+ String credentials = "";
+ Set<Principal> principals = subject.getPrincipals();
+ principals.add(identity);
+ Group[] roleSets = getRoleSets(roleSet);
+ for(int g = 0; g < roleSets.length; g ++)
+ {
+ Group group = roleSets[g];
+ String name = group.getName();
+ Group subjectGroup = createGroup(name, principals);
+ if( subjectGroup instanceof NestableGroup)
+ {
+ /* A NestableGroup only allows Groups to be added to it so we
+ need to add a SimpleGroup to subjectRoles to contain the roles
+ */
+ SimpleGroup tmp = new SimpleGroup("Roles");
+ subjectGroup.addMember(tmp);
+ subjectGroup = tmp;
+ }
+ // Copy the group members to the Subject group
+ Enumeration<? extends Principal> members = group.members();
+ while( members.hasMoreElements() )
+ {
+ Principal role = (Principal) members.nextElement();
+ subjectGroup.addMember(role);
+ }
+ }
+ // add the CallerPrincipal group if none has been added in getRoleSets
+ Group callerGroup = new SimpleGroup(SecurityConstants.CALLER_PRINCIPAL_GROUP);
+ callerGroup.addMember(identity);
+ principals.add(callerGroup);
+ SecurityContext sc = SecurityContextAssociation.getSecurityContext();
+ Principal userPrincipal = getPrincipal(subject);
+ sc.getUtil().createSubjectInfo(userPrincipal, credentials, subject);
+ List<String> rolesAsStringList = new ArrayList<String>();
+ rolesAsStringList.addAll(roleSet);
+ return new JBossGenericPrincipal(realm, userPrincipal.getName(), null, rolesAsStringList,
+ userPrincipal, null, credentials, null, subject);
+
+ }
+ /**
+ * Get the Principal given the authenticated Subject. Currently the first principal that is not of type {@code Group} is
+ * considered or the single principal inside the CallerPrincipal group.
+ *
+ * @param subject
+ * @return the authenticated principal
+ */
+ protected Principal getPrincipal(Subject subject) {
+ Principal principal = null;
+ Principal callerPrincipal = null;
+ if (subject != null) {
+ Set<Principal> principals = subject.getPrincipals();
+ if (principals != null && !principals.isEmpty()) {
+ for (Principal p : principals) {
+ if (!(p instanceof Group) && principal == null) {
+ principal = p;
+ }
+ if (p instanceof Group) {
+ Group g = Group.class.cast(p);
+ if (g.getName().equals(SecurityConstants.CALLER_PRINCIPAL_GROUP) && callerPrincipal == null) {
+ Enumeration<? extends Principal> e = g.members();
+ if (e.hasMoreElements())
+ callerPrincipal = e.nextElement();
+ }
+ }
+ }
+ }
+ }
+ return callerPrincipal == null ? principal : callerPrincipal;
+ }
+
+ protected Group createGroup(String name, Set<Principal> principals)
+ {
+ Group roles = null;
+ Iterator<Principal> iter = principals.iterator();
+ while( iter.hasNext() )
+ {
+ Object next = iter.next();
+ if( (next instanceof Group) == false )
+ continue;
+ Group grp = (Group) next;
+ if( grp.getName().equals(name) )
+ {
+ roles = grp;
+ break;
+ }
+ }
+ // If we did not find a group create one
+ if( roles == null )
+ {
+ roles = new SimpleGroup(name);
+ principals.add(roles);
+ }
+ return roles;
+ }
+
+ protected Group[] getRoleSets(Collection<String> roleSet)
+ {
+ SimpleGroup roles = new SimpleGroup("Roles");
+ Group[] roleSets = {roles};
+ for (String role : roleSet)
+ {
+ roles.addMember(new SimplePrincipal(role));
+ }
+ return roleSets;
+ }
+
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/AuthServerConfig.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/AuthServerConfig.java
new file mode 100755
index 0000000..73372e3
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/AuthServerConfig.java
@@ -0,0 +1,279 @@
+package org.keycloak.adapters.as7.config;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class AuthServerConfig
+{
+ @JsonProperty("realm")
+ protected String realm;
+
+ @JsonProperty("realm-private-key")
+ protected String realmPrivateKey;
+
+ @JsonProperty("realm-public-key")
+ protected String realmPublicKey;
+
+ @JsonProperty("realm-keystore")
+ protected String realmKeyStore;
+
+ @JsonProperty("realm-keystore-password")
+ protected String realmKeystorePassword;
+
+ @JsonProperty("realm-key-alias")
+ protected String realmKeyAlias;
+
+ @JsonProperty("realm-private-key-password")
+ protected String realmPrivateKeyPassword;
+
+ @JsonProperty("access-code-lifetime")
+ protected int accessCodeLifetime;
+
+ @JsonProperty("token-lifetime")
+ protected int tokenLifetime;
+
+ @JsonProperty("admin-role")
+ protected String adminRole;
+
+ @JsonProperty("login-role")
+ protected String loginRole;
+
+ @JsonProperty("oauth-client-role")
+ protected String clientRole;
+
+ @JsonProperty("wildcard-role")
+ protected String wildcardRole;
+
+ @JsonProperty("cancel-propagation")
+ protected boolean cancelPropagation;
+
+ @JsonProperty("sso-disabled")
+ protected boolean ssoDisabled;
+
+ // these properties are optional and used to provide connection metadata when the server wants to make
+ // remote SSL connections
+
+ protected String truststore;
+ @JsonProperty("truststore-password")
+ protected String truststorePassword;
+ @JsonProperty("client-keystore")
+ protected String clientKeystore;
+ @JsonProperty("client-keystore-password")
+ protected String clientKeystorePassword;
+ @JsonProperty("client-key-password")
+ protected String clientKeyPassword;
+
+ protected List<String> resources = new ArrayList<String>();
+
+
+ public String getRealm()
+ {
+ return realm;
+ }
+
+ public void setRealm(String realm)
+ {
+ this.realm = realm;
+ }
+
+ public String getRealmPrivateKey()
+ {
+ return realmPrivateKey;
+ }
+
+ public void setRealmPrivateKey(String realmPrivateKey)
+ {
+ this.realmPrivateKey = realmPrivateKey;
+ }
+
+ public String getRealmPublicKey()
+ {
+ return realmPublicKey;
+ }
+
+ public void setRealmPublicKey(String realmPublicKey)
+ {
+ this.realmPublicKey = realmPublicKey;
+ }
+
+ public int getAccessCodeLifetime()
+ {
+ return accessCodeLifetime;
+ }
+
+ public void setAccessCodeLifetime(int accessCodeLifetime)
+ {
+ this.accessCodeLifetime = accessCodeLifetime;
+ }
+
+ public String getTruststore()
+ {
+ return truststore;
+ }
+
+ public void setTruststore(String truststore)
+ {
+ this.truststore = truststore;
+ }
+
+ public String getTruststorePassword()
+ {
+ return truststorePassword;
+ }
+
+ public void setTruststorePassword(String truststorePassword)
+ {
+ this.truststorePassword = truststorePassword;
+ }
+
+ public String getClientKeystore()
+ {
+ return clientKeystore;
+ }
+
+ public void setClientKeystore(String clientKeystore)
+ {
+ this.clientKeystore = clientKeystore;
+ }
+
+ public String getClientKeystorePassword()
+ {
+ return clientKeystorePassword;
+ }
+
+ public void setClientKeystorePassword(String clientKeystorePassword)
+ {
+ this.clientKeystorePassword = clientKeystorePassword;
+ }
+
+ public String getClientKeyPassword()
+ {
+ return clientKeyPassword;
+ }
+
+ public void setClientKeyPassword(String clientKeyPassword)
+ {
+ this.clientKeyPassword = clientKeyPassword;
+ }
+
+ public boolean isCancelPropagation()
+ {
+ return cancelPropagation;
+ }
+
+ public void setCancelPropagation(boolean cancelPropagation)
+ {
+ this.cancelPropagation = cancelPropagation;
+ }
+
+ public boolean isSsoDisabled()
+ {
+ return ssoDisabled;
+ }
+
+ public void setSsoDisabled(boolean ssoDisabled)
+ {
+ this.ssoDisabled = ssoDisabled;
+ }
+
+ public List<String> getResources()
+ {
+ return resources;
+ }
+
+ public String getAdminRole()
+ {
+ return adminRole;
+ }
+
+ public void setAdminRole(String adminRole)
+ {
+ this.adminRole = adminRole;
+ }
+
+ public String getLoginRole()
+ {
+ return loginRole;
+ }
+
+ public void setLoginRole(String loginRole)
+ {
+ this.loginRole = loginRole;
+ }
+
+ public String getClientRole()
+ {
+ return clientRole;
+ }
+
+ public void setClientRole(String clientRole)
+ {
+ this.clientRole = clientRole;
+ }
+
+ public String getWildcardRole()
+ {
+ return wildcardRole;
+ }
+
+ public void setWildcardRole(String wildcardRole)
+ {
+ this.wildcardRole = wildcardRole;
+ }
+
+ public String getRealmKeyStore()
+ {
+ return realmKeyStore;
+ }
+
+ public void setRealmKeyStore(String realmKeyStore)
+ {
+ this.realmKeyStore = realmKeyStore;
+ }
+
+ public String getRealmKeystorePassword()
+ {
+ return realmKeystorePassword;
+ }
+
+ public void setRealmKeystorePassword(String realmKeystorePassword)
+ {
+ this.realmKeystorePassword = realmKeystorePassword;
+ }
+
+ public String getRealmKeyAlias()
+ {
+ return realmKeyAlias;
+ }
+
+ public void setRealmKeyAlias(String realmKeyAlias)
+ {
+ this.realmKeyAlias = realmKeyAlias;
+ }
+
+ public String getRealmPrivateKeyPassword()
+ {
+ return realmPrivateKeyPassword;
+ }
+
+ public void setRealmPrivateKeyPassword(String realmPrivateKeyPassword)
+ {
+ this.realmPrivateKeyPassword = realmPrivateKeyPassword;
+ }
+
+ public int getTokenLifetime()
+ {
+ return tokenLifetime;
+ }
+
+ public void setTokenLifetime(int tokenLifetime)
+ {
+ this.tokenLifetime = tokenLifetime;
+ }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java
new file mode 100755
index 0000000..e1bef4b
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfig.java
@@ -0,0 +1,213 @@
+package org.keycloak.adapters.as7.config;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.annotate.JsonPropertyOrder;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@JsonPropertyOrder({"realm", "resource", "realm-public-key", "admin-role", "auth-url", "code-url", "truststore", "truststore-password", "client-id", "client-credentials"})
+public class ManagedResourceConfig
+{
+ @JsonProperty("realm")
+ protected String realm;
+ @JsonProperty("resource")
+ protected String resource;
+
+ @JsonProperty("realm-public-key")
+ protected String realmKey;
+
+ @JsonProperty("admin-role")
+ protected String adminRole;
+
+ @JsonProperty("auth-url")
+ protected String authUrl;
+ @JsonProperty("code-url")
+ protected String codeUrl;
+
+ @JsonProperty("allow-any-hostname")
+ protected boolean allowAnyHostname;
+
+ @JsonProperty("truststore")
+ protected String truststore;
+
+ @JsonProperty("truststore-password")
+ protected String truststorePassword;
+ @JsonProperty("client-id")
+ protected String clientId;
+ @JsonProperty("client-keystore")
+ protected String clientKeystore;
+ @JsonProperty("client-keystore-password")
+ protected String clientKeystorePassword;
+ @JsonProperty("client-key-password")
+ protected String clientKeyPassword;
+
+ @JsonProperty("client-credentials")
+ protected Map<String, String> clientCredentials = new HashMap<String, String>();
+
+ @JsonProperty("connection-pool-size")
+ protected int connectionPoolSize;
+
+ @JsonProperty("cancel-propagation")
+ protected boolean cancelPropagation;
+
+
+ public String getRealm()
+ {
+ return realm;
+ }
+
+ public void setRealm(String realm)
+ {
+ this.realm = realm;
+ }
+
+ public String getResource()
+ {
+ return resource;
+ }
+
+ public void setResource(String resource)
+ {
+ this.resource = resource;
+ }
+
+ public String getRealmKey()
+ {
+ return realmKey;
+ }
+
+ public void setRealmKey(String realmKey)
+ {
+ this.realmKey = realmKey;
+ }
+
+ public String getAuthUrl()
+ {
+ return authUrl;
+ }
+
+ public void setAuthUrl(String authUrl)
+ {
+ this.authUrl = authUrl;
+ }
+
+ public String getCodeUrl()
+ {
+ return codeUrl;
+ }
+
+ public void setCodeUrl(String codeUrl)
+ {
+ this.codeUrl = codeUrl;
+ }
+
+ public boolean isAllowAnyHostname()
+ {
+ return allowAnyHostname;
+ }
+
+ public void setAllowAnyHostname(boolean allowAnyHostname)
+ {
+ this.allowAnyHostname = allowAnyHostname;
+ }
+
+ public String getTruststore()
+ {
+ return truststore;
+ }
+
+ public void setTruststore(String truststore)
+ {
+ this.truststore = truststore;
+ }
+
+ public String getTruststorePassword()
+ {
+ return truststorePassword;
+ }
+
+ public void setTruststorePassword(String truststorePassword)
+ {
+ this.truststorePassword = truststorePassword;
+ }
+
+ public String getClientId()
+ {
+ return clientId;
+ }
+
+ public void setClientId(String clientId)
+ {
+ this.clientId = clientId;
+ }
+
+ public Map<String, String> getClientCredentials()
+ {
+ return clientCredentials;
+ }
+
+ public String getClientKeystore()
+ {
+ return clientKeystore;
+ }
+
+ public void setClientKeystore(String clientKeystore)
+ {
+ this.clientKeystore = clientKeystore;
+ }
+
+ public String getClientKeystorePassword()
+ {
+ return clientKeystorePassword;
+ }
+
+ public void setClientKeystorePassword(String clientKeystorePassword)
+ {
+ this.clientKeystorePassword = clientKeystorePassword;
+ }
+
+ public String getClientKeyPassword()
+ {
+ return clientKeyPassword;
+ }
+
+ public void setClientKeyPassword(String clientKeyPassword)
+ {
+ this.clientKeyPassword = clientKeyPassword;
+ }
+
+ public int getConnectionPoolSize()
+ {
+ return connectionPoolSize;
+ }
+
+ public void setConnectionPoolSize(int connectionPoolSize)
+ {
+ this.connectionPoolSize = connectionPoolSize;
+ }
+
+ public boolean isCancelPropagation()
+ {
+ return cancelPropagation;
+ }
+
+ public void setCancelPropagation(boolean cancelPropagation)
+ {
+ this.cancelPropagation = cancelPropagation;
+ }
+
+ public String getAdminRole()
+ {
+ return adminRole;
+ }
+
+ public void setAdminRole(String adminRole)
+ {
+ this.adminRole = adminRole;
+ }
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java
new file mode 100755
index 0000000..75339d1
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/config/ManagedResourceConfigLoader.java
@@ -0,0 +1,139 @@
+package org.keycloak.adapters.as7.config;
+
+import org.apache.catalina.Context;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.jboss.logging.Logger;
+import org.keycloak.EnvUtil;
+import org.keycloak.PemUtils;
+import org.keycloak.ResourceMetadata;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.PublicKey;
+
+public class ManagedResourceConfigLoader
+{
+ static final Logger log = Logger.getLogger(ManagedResourceConfigLoader.class);
+ protected ManagedResourceConfig remoteSkeletonKeyConfig;
+ protected ResourceMetadata resourceMetadata;
+
+ public ManagedResourceConfigLoader(Context context)
+ {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
+ InputStream is = null;
+ String path = context.getServletContext().getInitParameter("skeleton.key.config.file");
+ if (path == null)
+ {
+ is = context.getServletContext().getResourceAsStream("/WEB-INF/resteasy-oauth.json");
+ }
+ else
+ {
+ try
+ {
+ is = new FileInputStream(path);
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ remoteSkeletonKeyConfig = null;
+ try
+ {
+ remoteSkeletonKeyConfig = mapper.readValue(is, ManagedResourceConfig.class);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ String name = remoteSkeletonKeyConfig.getResource();
+ String realm = remoteSkeletonKeyConfig.getRealm();
+ if (realm == null) throw new RuntimeException("Must set 'realm' in config");
+
+ String realmKeyPem = remoteSkeletonKeyConfig.getRealmKey();
+ if (realmKeyPem == null)
+ {
+ throw new IllegalArgumentException("You must set the realm-public-key");
+ }
+
+ PublicKey realmKey = null;
+ try
+ {
+ realmKey = PemUtils.decodePublicKey(realmKeyPem);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ resourceMetadata = new ResourceMetadata();
+ resourceMetadata.setRealm(realm);
+ resourceMetadata.setResourceName(name);
+ resourceMetadata.setRealmKey(realmKey);
+
+
+ String truststore = remoteSkeletonKeyConfig.getTruststore();
+ if (truststore != null)
+ {
+ truststore = EnvUtil.replace(truststore);
+ String truststorePassword = remoteSkeletonKeyConfig.getTruststorePassword();
+ KeyStore trust = null;
+ try
+ {
+ trust = loadKeyStore(truststore, truststorePassword);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to load truststore", e);
+ }
+ resourceMetadata.setTruststore(trust);
+ }
+ String clientKeystore = remoteSkeletonKeyConfig.getClientKeystore();
+ String clientKeyPassword = null;
+ if (clientKeystore != null)
+ {
+ clientKeystore = EnvUtil.replace(clientKeystore);
+ String clientKeystorePassword = remoteSkeletonKeyConfig.getClientKeystorePassword();
+ KeyStore serverKS = null;
+ try
+ {
+ serverKS = loadKeyStore(clientKeystore, clientKeystorePassword);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to load keystore", e);
+ }
+ resourceMetadata.setClientKeystore(serverKS);
+ clientKeyPassword = remoteSkeletonKeyConfig.getClientKeyPassword();
+ resourceMetadata.setClientKeyPassword(clientKeyPassword);
+ }
+
+ }
+ public static KeyStore loadKeyStore(String filename, String password) throws Exception
+ {
+ KeyStore trustStore = KeyStore.getInstance(KeyStore
+ .getDefaultType());
+ File truststoreFile = new File(filename);
+ FileInputStream trustStream = new FileInputStream(truststoreFile);
+ trustStore.load(trustStream, password.toCharArray());
+ trustStream.close();
+ return trustStore;
+ }
+
+ public ManagedResourceConfig getRemoteSkeletonKeyConfig()
+ {
+ return remoteSkeletonKeyConfig;
+ }
+
+ public ResourceMetadata getResourceMetadata()
+ {
+ return resourceMetadata;
+ }
+
+}
\ No newline at end of file
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticationServerValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticationServerValve.java
new file mode 100755
index 0000000..abc1dca
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthAuthenticationServerValve.java
@@ -0,0 +1,1050 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.authenticator.Constants;
+import org.apache.catalina.authenticator.FormAuthenticator;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.bouncycastle.openssl.PEMWriter;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.ObjectWriter;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.jose.jws.JWSBuilder;
+import org.jboss.resteasy.jose.jws.JWSInput;
+import org.jboss.resteasy.jose.jws.crypto.RSAProvider;
+import org.jboss.resteasy.jwt.JsonSerialization;
+import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
+import org.jboss.resteasy.plugins.server.servlet.ServletUtil;
+import org.keycloak.EnvUtil;
+import org.keycloak.PemUtils;
+import org.keycloak.ResourceMetadata;
+import org.keycloak.SkeletonKeySession;
+import org.keycloak.adapters.as7.config.AuthServerConfig;
+import org.keycloak.adapters.as7.config.ManagedResourceConfig;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.jboss.resteasy.spi.ResteasyUriInfo;
+import org.jboss.resteasy.util.BasicAuthHelper;
+
+import javax.security.auth.login.LoginException;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.UriBuilder;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.cert.Certificate;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * Turns a web deployment into an authentication server that follwos the OAuth 2 protocol and Skeleton Key bearer tokens.
+ * Authentication store is backed by a JBoss security domain.
+ * <p/>
+ * Servlet FORM authentication that uses the local security domain to authenticate and for role mappings.
+ * <p/>
+ * Supports bearer token creation and authentication. The client asking for access must be set up as a valid user
+ * within the security domain.
+ * <p/>
+ * If no an OAuth access request, this works like normal FORM authentication and authorization.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class OAuthAuthenticationServerValve extends FormAuthenticator implements LifecycleListener
+{
+
+
+ public static class AccessCode
+ {
+ protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
+ protected long expiration;
+ protected SkeletonKeyToken token;
+ protected String client;
+ protected boolean sso;
+ protected String redirect;
+
+ public boolean isExpired()
+ {
+ return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public long getExpiration()
+ {
+ return expiration;
+ }
+
+ public void setExpiration(long expiration)
+ {
+ this.expiration = expiration;
+ }
+
+ public SkeletonKeyToken getToken()
+ {
+ return token;
+ }
+
+ public void setToken(SkeletonKeyToken token)
+ {
+ this.token = token;
+ }
+
+ public String getClient()
+ {
+ return client;
+ }
+
+ public void setClient(String client)
+ {
+ this.client = client;
+ }
+
+ public boolean isSso()
+ {
+ return sso;
+ }
+
+ public void setSso(boolean sso)
+ {
+ this.sso = sso;
+ }
+
+ public String getRedirect()
+ {
+ return redirect;
+ }
+
+ public void setRedirect(String redirect)
+ {
+ this.redirect = redirect;
+ }
+ }
+
+ protected ConcurrentHashMap<String, AccessCode> accessCodeMap = new ConcurrentHashMap<String, AccessCode>();
+ private static final Logger log = Logger.getLogger(OAuthAuthenticationServerValve.class);
+
+ private static AtomicLong counter = new AtomicLong(1);
+
+ private static String generateId()
+ {
+ return counter.getAndIncrement() + "." + UUID.randomUUID().toString();
+ }
+
+ protected AuthServerConfig skeletonKeyConfig;
+ protected PrivateKey realmPrivateKey;
+ protected PublicKey realmPublicKey;
+ protected String realmPublicKeyPem;
+ protected ResteasyProviderFactory providers;
+ protected ResourceMetadata resourceMetadata;
+ protected UserSessionManagement userSessionManagement = new UserSessionManagement();
+ protected ObjectMapper mapper;
+ protected ObjectWriter accessTokenResponseWriter;
+ protected ObjectWriter mapWriter;
+
+ private static KeyStore loadKeyStore(String filename, String password) throws Exception
+ {
+ KeyStore trustStore = KeyStore.getInstance(KeyStore
+ .getDefaultType());
+ File truststoreFile = new File(filename);
+ FileInputStream trustStream = new FileInputStream(truststoreFile);
+ trustStore.load(trustStream, password.toCharArray());
+ trustStream.close();
+ return trustStore;
+ }
+
+ @Override
+ public void start() throws LifecycleException
+ {
+ super.start();
+ StandardContext standardContext = (StandardContext) context;
+ standardContext.addLifecycleListener(this);
+ }
+
+ @Override
+ public void lifecycleEvent(LifecycleEvent event)
+ {
+ if (event.getType() == Lifecycle.AFTER_START_EVENT) init();
+ }
+
+ protected void init()
+ {
+ mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
+ accessTokenResponseWriter = mapper.writerWithType(AccessTokenResponse.class);
+ mapWriter = mapper.writerWithType(mapper.getTypeFactory().constructMapType(Map.class, String.class, String.class));
+
+ InputStream is = null;
+ String path = context.getServletContext().getInitParameter("skeleton.key.config.file");
+ if (path == null)
+ {
+ is = context.getServletContext().getResourceAsStream("/WEB-INF/resteasy-oauth.json");
+ }
+ else
+ {
+ try
+ {
+ is = new FileInputStream(path);
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ try
+ {
+ skeletonKeyConfig = mapper.readValue(is, AuthServerConfig.class);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ if (skeletonKeyConfig.getLoginRole() == null)
+ {
+ throw new RuntimeException("You must define the login-role in your config file");
+ }
+ if (skeletonKeyConfig.getClientRole() == null)
+ {
+ throw new RuntimeException("You must define the oauth-client-role in your config file");
+ }
+ if (skeletonKeyConfig.getRealmPrivateKey() != null)
+ {
+ try
+ {
+ realmPrivateKey = PemUtils.decodePrivateKey(skeletonKeyConfig.getRealmPrivateKey());
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ if (skeletonKeyConfig.getRealmPublicKey() != null)
+ {
+ try
+ {
+ realmPublicKey = PemUtils.decodePublicKey(skeletonKeyConfig.getRealmPublicKey());
+ realmPublicKeyPem = skeletonKeyConfig.getRealmPublicKey();
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ if (skeletonKeyConfig.getRealmKeyStore() != null)
+ {
+ if (skeletonKeyConfig.getRealmKeyAlias() == null) throw new RuntimeException("Must define realm-key-alias");
+ String keystorePath = EnvUtil.replace(skeletonKeyConfig.getRealmKeyStore());
+ try
+ {
+ KeyStore ks = loadKeyStore(keystorePath, skeletonKeyConfig.getRealmKeystorePassword());
+ if (realmPrivateKey == null)
+ {
+ realmPrivateKey = (PrivateKey) ks.getKey(skeletonKeyConfig.getRealmKeyAlias(), skeletonKeyConfig.getRealmPrivateKeyPassword().toCharArray());
+ }
+ if (realmPublicKey == null)
+ {
+ Certificate cert = ks.getCertificate(skeletonKeyConfig.getRealmKeyAlias());
+ realmPublicKey = cert.getPublicKey();
+ }
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ if (realmPublicKey == null) throw new RuntimeException("You have not declared a keystore or public key");
+ if (realmPrivateKey == null) throw new RuntimeException("You have not declared a keystore or private key");
+ if (realmPublicKeyPem == null)
+ {
+ StringWriter sw = new StringWriter();
+ PEMWriter writer = new PEMWriter(sw);
+ try
+ {
+ writer.writeObject(realmPublicKey);
+ writer.flush();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ realmPublicKeyPem = sw.toString();
+ realmPublicKeyPem = PemUtils.removeBeginEnd(realmPublicKeyPem);
+ }
+ providers = new ResteasyProviderFactory();
+ ClassLoader old = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(OAuthAuthenticationServerValve.class.getClassLoader());
+ try
+ {
+ ResteasyProviderFactory.getInstance(); // initialize builtins
+ RegisterBuiltin.register(providers);
+ }
+ finally
+ {
+ Thread.currentThread().setContextClassLoader(old);
+ }
+ resourceMetadata = new ResourceMetadata();
+ resourceMetadata.setRealm(skeletonKeyConfig.getRealm());
+ resourceMetadata.setRealmKey(realmPublicKey);
+ String truststore = skeletonKeyConfig.getTruststore();
+ if (truststore != null)
+ {
+ truststore = EnvUtil.replace(truststore);
+ String truststorePassword = skeletonKeyConfig.getTruststorePassword();
+ KeyStore trust = null;
+ try
+ {
+ trust = loadKeyStore(truststore, truststorePassword);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to load truststore", e);
+ }
+ resourceMetadata.setTruststore(trust);
+ }
+ String clientKeystore = skeletonKeyConfig.getClientKeystore();
+ String clientKeyPassword = null;
+ if (clientKeystore != null)
+ {
+ clientKeystore = EnvUtil.replace(clientKeystore);
+ String clientKeystorePassword = skeletonKeyConfig.getClientKeystorePassword();
+ KeyStore serverKS = null;
+ try
+ {
+ serverKS = loadKeyStore(clientKeystore, clientKeystorePassword);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed to load keystore", e);
+ }
+ resourceMetadata.setClientKeystore(serverKS);
+ clientKeyPassword = skeletonKeyConfig.getClientKeyPassword();
+ resourceMetadata.setClientKeyPassword(clientKeyPassword);
+ }
+ }
+
+ @Override
+ public void invoke(Request request, Response response) throws IOException, ServletException
+ {
+ try
+ {
+ String contextPath = request.getContextPath();
+ String requestURI = request.getDecodedRequestURI();
+ log.debug("--- invoke: " + requestURI);
+ if (request.getMethod().equalsIgnoreCase("GET")
+ && context.getLoginConfig().getLoginPage().equals(request.getRequestPathMB().toString()))
+ {
+ if (handleLoginPage(request, response)) return;
+ }
+ else if (request.getMethod().equalsIgnoreCase("GET")
+ && requestURI.endsWith(Actions.J_OAUTH_LOGOUT))
+ {
+ logoutCurrentUser(request, response);
+ return;
+ }
+ else if (request.getMethod().equalsIgnoreCase("POST")
+ && requestURI.endsWith(Actions.J_OAUTH_ADMIN_FORCED_LOGOUT))
+ {
+ adminLogout(request, response);
+ return;
+ }
+ else if (request.getMethod().equalsIgnoreCase("POST")
+ && requestURI.startsWith(contextPath) &&
+ requestURI.endsWith(Constants.FORM_ACTION)
+ && request.getParameter("client_id") != null)
+ {
+ handleOAuth(request, response);
+ return;
+ }
+ else if (request.getMethod().equalsIgnoreCase("POST")
+ && requestURI.endsWith(Actions.J_OAUTH_TOKEN_GRANT))
+ {
+ tokenGrant(request, response);
+ return;
+ }
+ else if (request.getMethod().equalsIgnoreCase("POST")
+ && requestURI.startsWith(contextPath) &&
+ requestURI.endsWith(Actions.J_OAUTH_RESOLVE_ACCESS_CODE))
+ {
+ resolveAccessCode(request, response);
+ return;
+ }
+ else if (request.getMethod().equalsIgnoreCase("GET")
+ && requestURI.startsWith(contextPath) &&
+ requestURI.endsWith("j_oauth_realm_info.html"))
+ {
+ publishRealmInfoHtml(request, response);
+ return;
+ }
+ // propagate the skeleton key token string?
+ if (!skeletonKeyConfig.isCancelPropagation())
+ {
+ if (request.getAttribute(SkeletonKeySession.class.getName()) == null && request.getSessionInternal() != null)
+ {
+ SkeletonKeySession skSession = (SkeletonKeySession) request.getSessionInternal().getNote(SkeletonKeySession.class.getName());
+ if (skSession != null)
+ {
+ request.setAttribute(SkeletonKeySession.class.getName(), skSession);
+ ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
+ }
+ }
+ }
+ request.setAttribute("OAUTH_FORM_ACTION", "j_security_check");
+ super.invoke(request, response);
+ }
+ finally
+ {
+ ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
+ }
+ }
+
+ protected boolean handleLoginPage(Request request, Response response) throws IOException, ServletException
+ {
+ String client_id = request.getParameter("client_id");
+ // if this is not an OAUTH redirect, just return and let the default flow happen
+ if (client_id == null) return false;
+
+ String redirect_uri = request.getParameter("redirect_uri");
+ String state = request.getParameter("state");
+
+ if (redirect_uri == null)
+ {
+ response.sendError(400, "No oauth redirect query parameter set");
+ return true;
+ }
+ // only bypass authentication if our session is authenticated,
+ // the login query parameter is on request URL,
+ // and we have configured the login-role
+ else if (!skeletonKeyConfig.isSsoDisabled()
+ && request.getSessionInternal() != null
+ && request.getSessionInternal().getPrincipal() != null
+ && request.getParameter("login") != null)
+ {
+ log.debug("We're ALREADY LOGGED IN!!!");
+ GenericPrincipal gp = (GenericPrincipal) request.getSessionInternal().getPrincipal();
+ redirectAccessCode(true, response, redirect_uri, client_id, state, gp);
+ }
+ else
+ {
+ UriBuilder builder = UriBuilder.fromUri("j_security_check")
+ .queryParam("redirect_uri", redirect_uri)
+ .queryParam("client_id", client_id);
+ if (state != null) builder.queryParam("state", state);
+ String loginAction = builder.build().toString();
+ request.setAttribute("OAUTH_FORM_ACTION", loginAction);
+ getNext().invoke(request, response);
+ }
+ return true;
+ }
+
+ protected GenericPrincipal checkLoggedIn(Request request, HttpServletResponse response)
+ {
+ if (request.getPrincipal() != null)
+ {
+ return (GenericPrincipal) request.getPrincipal();
+ }
+ else if (request.getSessionInternal() != null && request.getSessionInternal().getPrincipal() != null)
+ {
+ return (GenericPrincipal) request.getSessionInternal().getPrincipal();
+ }
+ return null;
+ }
+
+
+ protected void adminLogout(Request request, HttpServletResponse response) throws IOException
+ {
+ log.debug("<< adminLogout");
+ GenericPrincipal gp = checkLoggedIn(request, response);
+ if (gp == null)
+ {
+ if (bearer(request, response, false))
+ {
+ gp = (GenericPrincipal) request.getPrincipal();
+ }
+ else
+ {
+ response.sendError(403);
+ return;
+ }
+ }
+ if (!gp.hasRole(skeletonKeyConfig.getAdminRole()))
+ {
+ response.sendError(403);
+ return;
+ }
+ String logoutUser = request.getParameter("user");
+ if (logoutUser != null)
+ {
+ userSessionManagement.logout(logoutUser);
+ logoutResources(logoutUser, gp.getName());
+ }
+ else
+ {
+ userSessionManagement.logoutAllBut(gp.getName());
+ logoutResources(null, gp.getName());
+ }
+ String forwardTo = request.getParameter("forward");
+ if (forwardTo == null)
+ {
+ response.setStatus(204);
+ return;
+ }
+ RequestDispatcher disp =
+ context.getServletContext().getRequestDispatcher(forwardTo);
+ try
+ {
+ disp.forward(request.getRequest(), response);
+ }
+ catch (Throwable t)
+ {
+ request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t);
+ response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+ "failed to forward");
+ }
+
+
+ }
+
+
+ protected void logoutCurrentUser(Request request, HttpServletResponse response) throws IOException
+ {
+ if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null)
+ {
+ redirectToWelcomePage(request, response);
+ return;
+ }
+ GenericPrincipal principal = (GenericPrincipal) request.getSessionInternal().getPrincipal();
+ String username = principal.getName();
+ String admin = username;
+ userSessionManagement.logout(username);
+ request.setUserPrincipal(null);
+ request.setAuthType(null);
+ // logout user on all declared authenticated resources
+ logoutResources(username, admin);
+ redirectToWelcomePage(request, response);
+ }
+
+ protected void logoutResources(String username, String admin)
+ {
+ if (skeletonKeyConfig.getResources().size() != 0)
+ {
+ SkeletonKeyToken token = new SkeletonKeyToken();
+ token.id(generateId());
+ token.principal(admin);
+ token.audience(skeletonKeyConfig.getRealm());
+ SkeletonKeyToken.Access realmAccess = new SkeletonKeyToken.Access();
+ realmAccess.addRole(skeletonKeyConfig.getAdminRole());
+ token.setRealmAccess(realmAccess);
+ String tokenString = buildTokenString(realmPrivateKey, token);
+ ResteasyClient client = new ResteasyClientBuilder()
+ .providerFactory(providers)
+ .hostnameVerification(ResteasyClientBuilder.HostnameVerificationPolicy.ANY)
+ .trustStore(resourceMetadata.getTruststore())
+ .keyStore(resourceMetadata.getClientKeystore(), resourceMetadata.getClientKeyPassword())
+ .build();
+ try
+ {
+ for (String resource : skeletonKeyConfig.getResources())
+ {
+ try
+ {
+ log.debug("logging out: " + resource);
+ WebTarget target = client.target(resource).path(Actions.J_OAUTH_REMOTE_LOGOUT);
+ if (username != null) target = target.queryParam("user", username);
+ javax.ws.rs.core.Response response = target.request()
+ .header("Authorization", "Bearer " + tokenString)
+ .put(null);
+ if (response.getStatus() != 204) log.error("Failed to log out");
+ response.close();
+ }
+ catch (Exception ignored)
+ {
+ log.error("Failed to log out", ignored);
+ }
+ }
+ }
+ finally
+ {
+ client.close();
+ }
+ }
+ }
+
+ protected void redirectToWelcomePage(Request request, HttpServletResponse response) throws IOException
+ {
+ ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null);
+ String[] welcomes = context.findWelcomeFiles();
+ if (welcomes.length > 0)
+ {
+ UriBuilder welcome = uriInfo.getBaseUriBuilder().path(welcomes[0]);
+ response.sendRedirect(welcome.toTemplate());
+ }
+ else
+ {
+ response.setStatus(204);
+ }
+ }
+
+
+ protected void publishRealmInfoHtml(Request request, HttpServletResponse response) throws IOException
+ {
+ ManagedResourceConfig rep = getRealmRepresentation(request);
+ StringWriter writer;
+ String json;
+
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(JsonSerialize.Inclusion.NON_DEFAULT);
+ mapper.enable(SerializationConfig.Feature.INDENT_OUTPUT);
+
+ StringBuffer html = new StringBuffer();
+ html.append("<html><body bgcolor=\"#CED8F6\">");
+ html.append("<h1>Realm: ").append(rep.getRealm()).append("</h1>");
+
+ ManagedResourceConfig bearer = new ManagedResourceConfig();
+ bearer.setRealm(rep.getRealm());
+ bearer.setRealmKey(rep.getRealmKey());
+ writer = new StringWriter();
+ mapper.writeValue(writer, bearer);
+ json = writer.toString();
+
+ html.append("<h3>BearerTokenAuthValve Json Config</h3>");
+ html.append("<form><textarea rows=\"7\" cols=\"80\">").append(json).append("</textarea></form>");
+
+ html.append("<br>");
+
+ writer = new StringWriter();
+ rep.getClientCredentials().put("password", "REQUIRED");
+ rep.setClientId("REQUIRED");
+ rep.setTruststore("REQUIRED");
+ rep.setTruststorePassword("REQUIRED");
+ mapper.writeValue(writer, rep);
+ json = writer.toString();
+ html.append("<h3>OAuthManagedResourceValve Json Config</h3>");
+ html.append("<form><textarea rows=\"20\" cols=\"80\">").append(json).append("</textarea></form>");
+
+ html.append("</body></html>");
+
+ response.setStatus(200);
+ response.setContentType("text/html");
+ response.getOutputStream().println(html.toString());
+ response.getOutputStream().flush();
+
+ }
+
+
+ protected ManagedResourceConfig getRealmRepresentation(Request request)
+ {
+ ManagedResourceConfig rep = new ManagedResourceConfig();
+ ResteasyUriInfo uriInfo = ServletUtil.extractUriInfo(request, null);
+ UriBuilder authUrl = uriInfo.getBaseUriBuilder().path(context.getLoginConfig().getLoginPage());
+ UriBuilder codeUrl = uriInfo.getBaseUriBuilder().path(Actions.J_OAUTH_RESOLVE_ACCESS_CODE);
+ rep.setRealm(skeletonKeyConfig.getRealm());
+ rep.setRealmKey(realmPublicKeyPem);
+ rep.setAuthUrl(authUrl.toTemplate());
+ rep.setCodeUrl(codeUrl.toTemplate());
+ rep.setAdminRole(skeletonKeyConfig.getAdminRole());
+ return rep;
+ }
+
+ public boolean bearer(Request request, HttpServletResponse response, boolean propagate) throws IOException
+ {
+ if (request.getHeader("Authorization") != null)
+ {
+ CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(resourceMetadata, true, false);
+ try
+ {
+ if (bearer.login(request, response))
+ {
+ return true;
+ }
+ }
+ catch (LoginException e)
+ {
+ }
+ }
+ return false;
+ }
+
+ @Override
+ protected void register(Request request, HttpServletResponse response, Principal principal, String authType, String username, String password)
+ {
+ super.register(request, response, principal, authType, username, password);
+ log.debug("authenticate userSessionManage.login(): " + principal.getName());
+ userSessionManagement.login(request.getSessionInternal(), principal.getName());
+ if (!skeletonKeyConfig.isCancelPropagation())
+ {
+ GenericPrincipal gp = (GenericPrincipal) request.getPrincipal();
+ if (gp != null)
+ {
+ SkeletonKeyToken token = buildToken(gp);
+ String stringToken = buildTokenString(realmPrivateKey, token);
+ SkeletonKeySession skSession = new SkeletonKeySession(stringToken, resourceMetadata);
+ request.setAttribute(SkeletonKeySession.class.getName(), skSession);
+ ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
+ request.getSessionInternal(true).setNote(SkeletonKeySession.class.getName(), skSession);
+ }
+ }
+ }
+
+ @Override
+ public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException
+ {
+ if (bearer(request, response, true))
+ {
+ return true;
+ }
+ return super.authenticate(request, response, config);
+ }
+
+
+ protected void resolveAccessCode(Request request, Response response) throws IOException
+ {
+ if (!request.isSecure())
+ {
+ response.sendError(400);
+ return;
+ }
+ // always verify code and remove access code from map before authenticating user
+ // if user authentication fails, we want the code to be removed irreguardless just in case we're under attack
+ String code = request.getParameter("code");
+ JWSInput input = new JWSInput(code, providers);
+ boolean verifiedCode = false;
+ try
+ {
+ verifiedCode = RSAProvider.verify(input, realmPublicKey);
+ }
+ catch (Exception ignored)
+ {
+ log.error("Failed to verify signature", ignored);
+ }
+ if (!verifiedCode)
+ {
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Unable to verify code signature");
+ response.sendError(400);
+ response.setContentType("application/json");
+ mapWriter.writeValue(response.getOutputStream(), res);
+ response.getOutputStream().flush();
+ return;
+ }
+ String key = input.readContent(String.class);
+ AccessCode accessCode = accessCodeMap.remove(key);
+ String redirect = request.getParameter("redirect_uri");
+
+ GenericPrincipal gp = basicAuth(request, response);
+ if (gp == null)
+ {
+ log.error("Failed to authenticate client_id");
+ return;
+ }
+ if (accessCode == null)
+ {
+ log.error("No access code: " + code);
+ response.sendError(400);
+ return;
+ }
+ if (accessCode.isExpired())
+ {
+ log.debug("Access code expired");
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Code is expired");
+ response.setStatus(400);
+ response.setContentType("application/json");
+ mapWriter.writeValue(response.getOutputStream(), res);
+ response.getOutputStream().flush();
+ return;
+ }
+ if (!accessCode.getToken().isActive())
+ {
+ log.debug("token not active");
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Token expired");
+ response.setStatus(400);
+ response.setContentType("application/json");
+ mapWriter.writeValue(response.getOutputStream(), res);
+ response.getOutputStream().flush();
+ return;
+ }
+ if (!gp.getName().equals(accessCode.getClient()))
+ {
+ log.debug("not equal client");
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Auth error");
+ response.setStatus(400);
+ response.setContentType("application/json");
+ mapWriter.writeValue(response.getOutputStream(), res);
+ response.getOutputStream().flush();
+ return;
+ }
+ if (!accessCode.getRedirect().equals(redirect))
+ {
+ log.debug("not equal redirect");
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Auth error");
+ response.setStatus(400);
+ response.setContentType("application/json");
+ mapWriter.writeValue(response.getOutputStream(), res);
+ response.getOutputStream().flush();
+ return;
+ }
+ if (accessCode.isSso() && !gp.hasRole(skeletonKeyConfig.getLoginRole()))
+ {
+ // we did not authenticate user on an access code request because a session was already established
+ // but, the client_id does not have permission to bypass this on a simple grant. We want
+ // to always ask for credentials from a simple oath request
+
+ log.debug("does not have login permission");
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Auth error");
+ response.setStatus(400);
+ response.setContentType("application/json");
+ mapWriter.writeValue(response.getOutputStream(), res);
+ response.getOutputStream().flush();
+ return;
+ }
+ else if (!gp.hasRole(skeletonKeyConfig.getClientRole()) && !gp.hasRole(skeletonKeyConfig.getLoginRole()))
+ {
+ log.debug("does not have login or client role permission for access token request");
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Auth error");
+ response.setStatus(400);
+ response.setContentType("application/json");
+ mapWriter.writeValue(response.getOutputStream(), res);
+ response.getOutputStream().flush();
+ return;
+
+ }
+ String wildcard = skeletonKeyConfig.getWildcardRole() == null ? "*" : skeletonKeyConfig.getWildcardRole();
+ Set<String> codeRoles = accessCode.getToken().getRealmAccess().getRoles();
+ if (codeRoles != null &&
+ (codeRoles.contains(skeletonKeyConfig.getClientRole()) || codeRoles.contains(skeletonKeyConfig.getLoginRole())))
+ {
+ // we store roles a oauth client is granted in the user role mapping, remove those roles as we don't want those clients with those
+ // permissions if they are logging in.
+ Set<String> newRoles = new HashSet<String>();
+ if (codeRoles.contains(skeletonKeyConfig.getClientRole())) newRoles.add(skeletonKeyConfig.getClientRole());
+ if (codeRoles.contains(skeletonKeyConfig.getLoginRole())) newRoles.add(skeletonKeyConfig.getLoginRole());
+ if (codeRoles.contains(wildcard)) newRoles.add(wildcard);
+ codeRoles.clear();
+ codeRoles.addAll(newRoles);
+ }
+
+ // is we have a login role, then we don't need to filter out roles, just grant all the roles the user has
+ // Also, if the client has the "wildcard" role, then we don't need to filter out roles
+ if (codeRoles != null
+ && !gp.hasRole(wildcard)
+ && !gp.hasRole(skeletonKeyConfig.getLoginRole()))
+ {
+ Set<String> clientAllowed = new HashSet<String>();
+ for (String role : gp.getRoles())
+ {
+ clientAllowed.add(role);
+ }
+ Set<String> newRoles = new HashSet<String>();
+ newRoles.addAll(codeRoles);
+ for (String role : newRoles)
+ {
+ if (!clientAllowed.contains(role))
+ {
+ codeRoles.remove(role);
+ }
+ }
+ }
+ AccessTokenResponse res = accessTokenResponse(realmPrivateKey, accessCode.getToken());
+ response.setStatus(200);
+ response.setContentType("application/json");
+ accessTokenResponseWriter.writeValue(response.getOutputStream(), res);
+ response.getOutputStream().flush();
+ }
+
+ protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token)
+ {
+ String encodedToken = buildTokenString(privateKey, token);
+
+ AccessTokenResponse res = new AccessTokenResponse();
+ res.setToken(encodedToken);
+ res.setTokenType("bearer");
+ if (token.getExpiration() != 0)
+ {
+ long time = token.getExpiration() - (System.currentTimeMillis() / 1000);
+ res.setExpiresIn(time);
+ }
+ return res;
+ }
+
+ protected String buildTokenString(PrivateKey privateKey, SkeletonKeyToken token)
+ {
+ byte[] tokenBytes = null;
+ try
+ {
+ tokenBytes = JsonSerialization.toByteArray(token, false);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ return new JWSBuilder()
+ .content(tokenBytes)
+ .rsa256(privateKey);
+ }
+
+
+ protected void handleOAuth(Request request, Response response) throws IOException
+ {
+ log.debug("<--- Begin oauthAuthenticate");
+ String redirect_uri = request.getParameter("redirect_uri");
+ String client_id = request.getParameter("client_id");
+ String state = request.getParameter("state");
+ String username = request.getParameter(Constants.FORM_USERNAME);
+ String password = request.getParameter(Constants.FORM_PASSWORD);
+ Principal principal = context.getRealm().authenticate(username, password);
+ if (principal == null)
+ {
+ UriBuilder builder = UriBuilder.fromUri(redirect_uri).queryParam("error", "unauthorized_client");
+ if (state != null) builder.queryParam("state", state);
+ response.sendRedirect(builder.toTemplate());
+ return;
+ }
+ GenericPrincipal gp = (GenericPrincipal) principal;
+ register(request, response, principal, HttpServletRequest.FORM_AUTH, username, password);
+ userSessionManagement.login(request.getSessionInternal(), username);
+ redirectAccessCode(false, response, redirect_uri, client_id, state, gp);
+
+ return;
+ }
+
+ protected void tokenGrant(Request request, Response response) throws IOException
+ {
+ if (!request.isSecure())
+ {
+ response.sendError(400);
+ return;
+ }
+ GenericPrincipal gp = basicAuth(request, response);
+ if (gp == null) return;
+ SkeletonKeyToken token = buildToken(gp);
+ AccessTokenResponse res = accessTokenResponse(realmPrivateKey, token);
+ response.setStatus(200);
+ response.setContentType("application/json");
+ accessTokenResponseWriter.writeValue(response.getOutputStream(), res);
+ response.getOutputStream().flush();
+ }
+
+ protected GenericPrincipal basicAuth(Request request, Response response) throws IOException
+ {
+ String authHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
+ if (authHeader == null)
+ {
+ basicAuthError(response);
+ return null;
+ }
+ String[] creds = BasicAuthHelper.parseHeader(authHeader);
+ if (creds == null)
+ {
+ basicAuthError(response);
+ return null;
+ }
+ String username = creds[0];
+ String password = creds[1];
+ GenericPrincipal gp = (GenericPrincipal) context.getRealm().authenticate(username, password);
+ if (gp == null)
+ {
+ basicAuthError(response);
+ return null;
+ }
+ return gp;
+ }
+
+ protected void basicAuthError(Response response) throws IOException
+ {
+ response.setHeader(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"" + context.getLoginConfig().getRealmName() + "\"");
+ response.sendError(401);
+ }
+
+ protected void redirectAccessCode(boolean sso, Response response, String redirect_uri, String client_id, String state, GenericPrincipal gp) throws IOException
+ {
+ SkeletonKeyToken token = buildToken(gp);
+ AccessCode code = new AccessCode();
+ code.setToken(token);
+ code.setClient(client_id);
+ code.setSso(sso);
+ code.setRedirect(redirect_uri);
+ int expiration = skeletonKeyConfig.getAccessCodeLifetime() == 0 ? 300 : skeletonKeyConfig.getAccessCodeLifetime();
+ code.setExpiration((System.currentTimeMillis() / 1000) + expiration);
+ accessCodeMap.put(code.getId(), code);
+ log.debug("--- sign access code");
+ String accessCode = null;
+ try
+ {
+ accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realmPrivateKey);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new RuntimeException(e);
+ }
+ log.debug("--- build redirect");
+ UriBuilder redirectUri = UriBuilder.fromUri(redirect_uri).queryParam("code", accessCode);
+ if (state != null) redirectUri.queryParam("state", state);
+ response.sendRedirect(redirectUri.toTemplate());
+ log.debug("<--- end oauthAuthenticate");
+ }
+
+ protected SkeletonKeyToken buildToken(GenericPrincipal gp)
+ {
+ SkeletonKeyToken token = new SkeletonKeyToken();
+ token.id(generateId());
+ token.principal(gp.getName());
+ token.audience(skeletonKeyConfig.getRealm());
+ int expiration = skeletonKeyConfig.getAccessCodeLifetime() == 0 ? 3600 : skeletonKeyConfig.getAccessCodeLifetime();
+ if (skeletonKeyConfig.getTokenLifetime() > 0)
+ {
+ token.expiration((System.currentTimeMillis() / 1000) + expiration);
+ }
+ SkeletonKeyToken.Access realmAccess = new SkeletonKeyToken.Access();
+ for (String role : gp.getRoles())
+ {
+ realmAccess.addRole(role);
+ }
+ token.setRealmAccess(realmAccess);
+ return token;
+ }
+
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java
new file mode 100755
index 0000000..772607c
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/OAuthManagedResourceValve.java
@@ -0,0 +1,303 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Lifecycle;
+import org.apache.catalina.LifecycleEvent;
+import org.apache.catalina.LifecycleException;
+import org.apache.catalina.LifecycleListener;
+import org.apache.catalina.Session;
+import org.apache.catalina.authenticator.Constants;
+import org.apache.catalina.authenticator.FormAuthenticator;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.core.StandardContext;
+import org.apache.catalina.deploy.LoginConfig;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.jboss.logging.Logger;
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.plugins.providers.RegisterBuiltin;
+import org.keycloak.RealmConfiguration;
+import org.keycloak.ResourceMetadata;
+import org.keycloak.SkeletonKeyPrincipal;
+import org.keycloak.SkeletonKeySession;
+import org.keycloak.adapters.as7.config.ManagedResourceConfig;
+import org.keycloak.adapters.as7.config.ManagedResourceConfigLoader;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+
+import javax.security.auth.login.LoginException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Web deployment whose security is managed by a remote OAuth Skeleton Key authentication server
+ * <p/>
+ * Redirects browser to remote authentication server if not logged in. Also allows OAuth Bearer Token requests
+ * that contain a Skeleton Key bearer tokens.
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class OAuthManagedResourceValve extends FormAuthenticator implements LifecycleListener
+{
+ protected RealmConfiguration realmConfiguration;
+ private static final Logger log = Logger.getLogger(OAuthManagedResourceValve.class);
+ protected UserSessionManagement userSessionManagement = new UserSessionManagement();
+ protected ManagedResourceConfig remoteSkeletonKeyConfig;
+ protected ResourceMetadata resourceMetadata;
+
+
+ @Override
+ public void start() throws LifecycleException
+ {
+ super.start();
+ StandardContext standardContext = (StandardContext) context;
+ standardContext.addLifecycleListener(this);
+ }
+
+ @Override
+ public void lifecycleEvent(LifecycleEvent event)
+ {
+ if (event.getType() == Lifecycle.AFTER_START_EVENT) init();
+ }
+
+ protected void init()
+ {
+ ManagedResourceConfigLoader managedResourceConfigLoader = new ManagedResourceConfigLoader(context);
+ resourceMetadata = managedResourceConfigLoader.getResourceMetadata();
+ remoteSkeletonKeyConfig = managedResourceConfigLoader.getRemoteSkeletonKeyConfig();
+ String client_id = remoteSkeletonKeyConfig.getClientId();
+ if (client_id == null)
+ {
+ throw new IllegalArgumentException("Must set client-id to use with auth server");
+ }
+ realmConfiguration = new RealmConfiguration();
+ String authUrl = remoteSkeletonKeyConfig.getAuthUrl();
+ if (authUrl == null)
+ {
+ throw new RuntimeException("You must specify auth-url");
+ }
+ String tokenUrl = remoteSkeletonKeyConfig.getCodeUrl();
+ if (tokenUrl == null)
+ {
+ throw new RuntimeException("You mut specify code-url");
+ }
+ realmConfiguration.setMetadata(resourceMetadata);
+ realmConfiguration.setClientId(client_id);
+
+ for (Map.Entry<String, String> entry : managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getClientCredentials().entrySet())
+ {
+ realmConfiguration.getCredentials().param(entry.getKey(), entry.getValue());
+ }
+ int size = 10;
+ if (managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getConnectionPoolSize() > 0)
+ size = managedResourceConfigLoader.getRemoteSkeletonKeyConfig().getConnectionPoolSize();
+ ResteasyClientBuilder.HostnameVerificationPolicy policy = ResteasyClientBuilder.HostnameVerificationPolicy.WILDCARD;
+ if (managedResourceConfigLoader.getRemoteSkeletonKeyConfig().isAllowAnyHostname())
+ policy = ResteasyClientBuilder.HostnameVerificationPolicy.ANY;
+ ResteasyProviderFactory providerFactory = new ResteasyProviderFactory();
+ ClassLoader old = Thread.currentThread().getContextClassLoader();
+ Thread.currentThread().setContextClassLoader(OAuthManagedResourceValve.class.getClassLoader());
+ try
+ {
+ ResteasyProviderFactory.getInstance(); // initialize builtins
+ RegisterBuiltin.register(providerFactory);
+ }
+ finally
+ {
+ Thread.currentThread().setContextClassLoader(old);
+ }
+ ResteasyClient client = new ResteasyClientBuilder()
+ .providerFactory(providerFactory)
+ .connectionPoolSize(size)
+ .hostnameVerification(policy)
+ .trustStore(resourceMetadata.getTruststore())
+ .keyStore(resourceMetadata.getClientKeystore(), resourceMetadata.getClientKeyPassword())
+ .build();
+ realmConfiguration.setClient(client);
+ realmConfiguration.setAuthUrl(UriBuilder.fromUri(authUrl).queryParam("client_id", client_id));
+ realmConfiguration.setCodeUrl(client.target(tokenUrl));
+ }
+
+ @Override
+ public void invoke(Request request, Response response) throws IOException, ServletException
+ {
+ try
+ {
+ String requestURI = request.getDecodedRequestURI();
+ if (requestURI.endsWith("j_oauth_remote_logout"))
+ {
+ remoteLogout(request, response);
+ return;
+ }
+ super.invoke(request, response);
+ }
+ finally
+ {
+ ResteasyProviderFactory.clearContextData(); // to clear push of SkeletonKeySession
+ }
+ }
+
+ @Override
+ public boolean authenticate(Request request, HttpServletResponse response, LoginConfig config) throws IOException
+ {
+ try
+ {
+ if (bearer(false, request, response)) return true;
+ else if (checkLoggedIn(request, response))
+ {
+ if (request.getSessionInternal().getNote(Constants.FORM_REQUEST_NOTE) != null)
+ {
+ if (restoreRequest(request, request.getSessionInternal()))
+ {
+ log.debug("restoreRequest");
+ return (true);
+ }
+ else
+ {
+ log.debug("Restore of original request failed");
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ return (false);
+ }
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ // initiate or continue oauth2 protocol
+ oauth(request, response);
+ }
+ catch (LoginException e)
+ {
+ }
+ return false;
+ }
+
+ protected void remoteLogout(Request request, HttpServletResponse response) throws IOException
+ {
+ try
+ {
+ log.debug("->> remoteLogout: ");
+ if (!bearer(true, request, response))
+ {
+ log.debug("remoteLogout: bearer auth failed");
+ return;
+ }
+ GenericPrincipal gp = (GenericPrincipal) request.getPrincipal();
+ if (!gp.hasRole(remoteSkeletonKeyConfig.getAdminRole()))
+ {
+ log.debug("remoteLogout: role failure");
+ response.sendError(403);
+ return;
+ }
+ String user = request.getParameter("user");
+ if (user != null)
+ {
+ userSessionManagement.logout(user);
+ }
+ else
+ {
+ userSessionManagement.logoutAll();
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("failed to logout", e);
+ }
+ response.setStatus(204);
+ }
+
+ protected boolean bearer(boolean challenge, Request request, HttpServletResponse response) throws LoginException, IOException
+ {
+ CatalinaBearerTokenAuthenticator bearer = new CatalinaBearerTokenAuthenticator(realmConfiguration.getMetadata(), !remoteSkeletonKeyConfig.isCancelPropagation(), challenge);
+ if (bearer.login(request, response))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ protected boolean checkLoggedIn(Request request, HttpServletResponse response)
+ {
+ if (request.getSessionInternal() == null || request.getSessionInternal().getPrincipal() == null)
+ return false;
+ log.debug("remote logged in already");
+ GenericPrincipal principal = (GenericPrincipal) request.getSessionInternal().getPrincipal();
+ request.setUserPrincipal(principal);
+ request.setAuthType("OAUTH");
+ Session session = request.getSessionInternal();
+ if (session != null && !remoteSkeletonKeyConfig.isCancelPropagation())
+ {
+ SkeletonKeySession skSession = (SkeletonKeySession) session.getNote(SkeletonKeySession.class.getName());
+ if (skSession != null)
+ {
+ request.setAttribute(SkeletonKeySession.class.getName(), skSession);
+ ResteasyProviderFactory.pushContext(SkeletonKeySession.class, skSession);
+
+ }
+ }
+ return true;
+ }
+
+ /**
+ * This method always set the HTTP response, so do not continue after invoking
+ */
+ protected void oauth(Request request, HttpServletResponse response) throws IOException
+ {
+ ServletOAuthLogin oauth = new ServletOAuthLogin(realmConfiguration, request, response, request.getConnector().getRedirectPort());
+ String code = oauth.getCode();
+ if (code == null)
+ {
+ String error = oauth.getError();
+ if (error != null)
+ {
+ response.sendError(400, "OAuth " + error);
+ return;
+ }
+ else
+ {
+ saveRequest(request, request.getSessionInternal(true));
+ oauth.loginRedirect();
+ }
+ return;
+ }
+ else
+ {
+ if (!oauth.resolveCode(code)) return;
+
+ SkeletonKeyToken token = oauth.getToken();
+ Set<String> roles = null;
+ if (resourceMetadata.getResourceName() != null)
+ {
+ SkeletonKeyToken.Access access = token.getResourceAccess(resourceMetadata.getResourceName());
+ if (access != null) roles = access.getRoles();
+ }
+ else
+ {
+ SkeletonKeyToken.Access access = token.getRealmAccess();
+ if (access != null) roles = access.getRoles();
+ }
+ SkeletonKeyPrincipal skp = new SkeletonKeyPrincipal(token.getPrincipal(), null);
+ GenericPrincipal principal = new CatalinaSecurityContextHelper().createPrincipal(context.getRealm(), skp, roles);
+ Session session = request.getSessionInternal(true);
+ session.setPrincipal(principal);
+ session.setAuthType("OAUTH");
+ if (!remoteSkeletonKeyConfig.isCancelPropagation())
+ {
+ SkeletonKeySession skSession = new SkeletonKeySession(oauth.getTokenString(), realmConfiguration.getMetadata());
+ session.setNote(SkeletonKeySession.class.getName(), skSession);
+ }
+
+ String username = token.getPrincipal();
+ log.debug("userSessionManage.login: " + username);
+ userSessionManagement.login(session, username);
+ }
+ }
+
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
new file mode 100755
index 0000000..4a7d8c1
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/ServletOAuthLogin.java
@@ -0,0 +1,320 @@
+package org.keycloak.adapters.as7;
+
+import org.jboss.logging.Logger;
+import org.keycloak.RSATokenVerifier;
+import org.keycloak.RealmConfiguration;
+import org.keycloak.VerificationException;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.SkeletonKeyToken;
+import org.jboss.resteasy.util.BasicAuthHelper;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
+import java.io.IOException;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class ServletOAuthLogin
+{
+ private static final Logger log = Logger.getLogger(ServletOAuthLogin.class);
+ protected HttpServletRequest request;
+ protected HttpServletResponse response;
+ protected boolean codePresent;
+ protected RealmConfiguration realmInfo;
+ protected int redirectPort;
+ protected String tokenString;
+ protected SkeletonKeyToken token;
+
+ public ServletOAuthLogin(RealmConfiguration realmInfo, HttpServletRequest request, HttpServletResponse response, int redirectPort)
+ {
+ this.request = request;
+ this.response = response;
+ this.realmInfo = realmInfo;
+ this.redirectPort = redirectPort;
+ }
+
+ public String getTokenString()
+ {
+ return tokenString;
+ }
+
+ public SkeletonKeyToken getToken()
+ {
+ return token;
+ }
+
+ public RealmConfiguration getRealmInfo()
+ {
+ return realmInfo;
+ }
+
+ protected String getDefaultCookiePath()
+ {
+ String path = request.getContextPath();
+ if ("".equals(path) || path == null) path = "/";
+ return path;
+ }
+
+ protected String getRequestUrl()
+ {
+ return request.getRequestURL().toString();
+ }
+
+ protected boolean isRequestSecure()
+ {
+ return request.isSecure();
+ }
+
+ protected void sendError(int code)
+ {
+ try
+ {
+ response.sendError(code);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void sendRedirect(String url)
+ {
+ try
+ {
+ response.sendRedirect(url);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected Cookie getCookie(String cookieName)
+ {
+ if (request.getCookies() == null) return null;
+ for (Cookie cookie : request.getCookies())
+ {
+ if (cookie.getName().equals(cookieName))
+ {
+ return cookie;
+ }
+ }
+ return null;
+ }
+
+ protected String getCookieValue(String cookieName)
+ {
+ Cookie cookie = getCookie(cookieName);
+ if (cookie == null) return null;
+ return cookie.getValue();
+ }
+
+ protected String getQueryParamValue(String paramName)
+ {
+ String query = request.getQueryString();
+ if (query == null) return null;
+ String[] params = query.split("&");
+ for (String param : params)
+ {
+ int eq = param.indexOf('=');
+ if (eq == -1) continue;
+ String name = param.substring(0, eq);
+ if (!name.equals(paramName)) continue;
+ return param.substring(eq + 1);
+ }
+ return null;
+ }
+
+ public String getError()
+ {
+ return getQueryParamValue("error");
+ }
+
+ public String getCode()
+ {
+ return getQueryParamValue("code");
+ }
+
+ protected void setCookie(String name, String value, String domain, String path, boolean secure)
+ {
+ Cookie cookie = new Cookie(name, value);
+ if (domain != null) cookie.setDomain(domain);
+ if (path != null) cookie.setPath(path);
+ if (secure) cookie.setSecure(true);
+ response.addCookie(cookie);
+ }
+
+ protected String getRedirectUri(String state)
+ {
+ String url = getRequestUrl();
+ if (!isRequestSecure() && realmInfo.isSslRequired())
+ {
+ int port = redirectPort;
+ if (port < 0)
+ {
+ // disabled?
+ return null;
+ }
+ UriBuilder secureUrl = UriBuilder.fromUri(url).scheme("https").port(-1);
+ if (port != 443) secureUrl.port(port);
+ url = secureUrl.build().toString();
+ }
+ return realmInfo.getAuthUrl().clone()
+ .queryParam("client_id", realmInfo.getClientId())
+ .queryParam("redirect_uri", url)
+ .queryParam("state", state)
+ .queryParam("login", "true")
+ .build().toString();
+ }
+
+ protected static final AtomicLong counter = new AtomicLong();
+
+ protected String getStateCode()
+ {
+ return counter.getAndIncrement() + "/" + UUID.randomUUID().toString();
+ }
+
+ public void loginRedirect()
+ {
+ String state = getStateCode();
+ String redirect = getRedirectUri(state);
+ if (redirect == null)
+ {
+ sendError(Response.Status.FORBIDDEN.getStatusCode());
+ return;
+ }
+ setCookie(realmInfo.getStateCookieName(), state, null, getDefaultCookiePath(), realmInfo.isSslRequired());
+ sendRedirect(redirect);
+ }
+
+ public boolean checkStateCookie()
+ {
+ Cookie stateCookie = getCookie(realmInfo.getStateCookieName());
+
+ if (stateCookie == null)
+ {
+ sendError(400);
+ log.warn("No state cookie");
+ return false;
+ }
+ // reset the cookie
+ Cookie reset = new Cookie(stateCookie.getName(), stateCookie.getValue());
+ reset.setPath(stateCookie.getPath());
+ reset.setMaxAge(0);
+ response.addCookie(reset);
+
+ String stateCookieValue = getCookieValue(realmInfo.getStateCookieName());
+ // its ok to call request.getParameter() because this should be a redirect
+ String state = request.getParameter("state");
+ if (state == null)
+ {
+ sendError(400);
+ log.warn("state parameter was null");
+ return false;
+ }
+ if (!state.equals(stateCookieValue))
+ {
+ sendError(400);
+ log.warn("state parameter invalid");
+ log.warn("cookie: " + stateCookieValue);
+ log.warn("queryParam: " + state);
+ return false;
+ }
+ return true;
+
+ }
+
+ /**
+ * Start or continue the oauth login process.
+ *
+ * if code query parameter is not present, then browser is redirected to authUrl. The redirect URL will be
+ * the URL of the current request.
+ *
+ * If code query parameter is present, then an access token is obtained by invoking a secure request to the codeUrl.
+ * If the access token is obtained, the browser is again redirected to the current request URL, but any OAuth
+ * protocol specific query parameters are removed.
+ *
+ * @return true if an access token was obtained
+ */
+ public boolean resolveCode(String code)
+ {
+ // abort if not HTTPS
+ if (realmInfo.isSslRequired() && !isRequestSecure())
+ {
+ log.error("SSL is required");
+ sendError(Response.Status.FORBIDDEN.getStatusCode());
+ return false;
+ }
+
+ if (!checkStateCookie()) return false;
+
+ String client_id = realmInfo.getClientId();
+ String password = realmInfo.getCredentials().asMap().getFirst("password");
+ String authHeader = BasicAuthHelper.createHeader(client_id, password);
+ String redirectUri = stripOauthParametersFromRedirect();
+ Form form = new Form();
+ form.param("grant_type", "authorization_code")
+ .param("code", code)
+ .param("redirect_uri", redirectUri);
+
+ Response res = realmInfo.getCodeUrl().request().header(HttpHeaders.AUTHORIZATION, authHeader).post(Entity.form(form));
+ AccessTokenResponse tokenResponse;
+ try
+ {
+ if (res.getStatus() != 200)
+ {
+ log.error("failed to turn code into token");
+ sendError(Response.Status.FORBIDDEN.getStatusCode());
+ return false;
+ }
+ log.debug("media type: " + res.getMediaType());
+ log.debug("Content-Type header: " + res.getHeaderString("Content-Type"));
+ tokenResponse = res.readEntity(AccessTokenResponse.class);
+ }
+ finally
+ {
+ res.close();
+ }
+
+ tokenString = tokenResponse.getToken();
+ try
+ {
+ token = RSATokenVerifier.verifyToken(tokenString, realmInfo.getMetadata());
+ log.debug("Verification succeeded!");
+ }
+ catch (VerificationException e)
+ {
+ log.error("failed verification of token");
+ sendError(Response.Status.FORBIDDEN.getStatusCode());
+ return false;
+ }
+ // redirect to URL without oauth query parameters
+ sendRedirect(redirectUri);
+ return true;
+ }
+
+ /**
+ * strip out unwanted query parameters and redirect so bookmarks don't retain oauth protocol bits
+ */
+ protected String stripOauthParametersFromRedirect()
+ {
+ StringBuffer buf = request.getRequestURL().append("?").append(request.getQueryString());
+ UriBuilder builder = UriBuilder.fromUri(buf.toString())
+ .replaceQueryParam("code", null)
+ .replaceQueryParam("state", null);
+ return builder.build().toString();
+ }
+
+
+}
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/UserSessionManagement.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/UserSessionManagement.java
new file mode 100755
index 0000000..081df77
--- /dev/null
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/UserSessionManagement.java
@@ -0,0 +1,111 @@
+package org.keycloak.adapters.as7;
+
+import org.apache.catalina.Session;
+import org.apache.catalina.SessionEvent;
+import org.apache.catalina.SessionListener;
+import org.apache.catalina.realm.GenericPrincipal;
+import org.jboss.logging.Logger;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manages relationship to users and sessions so that forced admin logout can be implemented
+ *
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class UserSessionManagement implements SessionListener
+{
+ private static final Logger log = Logger.getLogger(UserSessionManagement.class);
+ protected ConcurrentHashMap<String, Map<String, Session>> userSessionMap = new ConcurrentHashMap<String, Map<String, Session>>();
+
+ protected void login(Session session, String username)
+ {
+ Map<String, Session> map = userSessionMap.get(username);
+ if (map == null)
+ {
+ final Map<String, Session> value = new HashMap<String, Session>();
+ map = userSessionMap.putIfAbsent(username, value);
+ if (map == null)
+ {
+ map = value;
+ }
+ }
+ synchronized (map)
+ {
+ map.put(session.getId(), session);
+ }
+ session.addSessionListener(this);
+ }
+
+ public void logoutAll()
+ {
+ List<String> users = new ArrayList<String>();
+ users.addAll(userSessionMap.keySet());
+ for (String user : users) logout(user);
+ }
+
+ public void logoutAllBut(String but)
+ {
+ List<String> users = new ArrayList<String>();
+ users.addAll(userSessionMap.keySet());
+ for (String user : users)
+ {
+ if (!but.equals(user)) logout(user);
+ }
+ }
+
+
+ public void logout(String user)
+ {
+ log.debug("logoutUser: " + user);
+ Map<String, Session> map = userSessionMap.remove(user);
+ if (map == null)
+ {
+ log.debug("no session for user: " + user);
+ return;
+ }
+ log.debug("found session for user");
+ synchronized (map)
+ {
+ for (Session session : map.values())
+ {
+ log.debug("invalidating session for user: " + user);
+ session.setPrincipal(null);
+ session.setAuthType(null);
+ session.getSession().invalidate();
+ }
+ }
+
+ }
+
+ public void sessionEvent(SessionEvent event)
+ {
+ // We only care about session destroyed events
+ if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType())
+ && (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType())))
+ return;
+
+ // Look up the single session id associated with this session (if any)
+ Session session = event.getSession();
+ GenericPrincipal principal = (GenericPrincipal) session.getPrincipal();
+ if (principal == null) return;
+ session.setPrincipal(null);
+ session.setAuthType(null);
+
+ String username = principal.getUserPrincipal().getName();
+ Map<String, Session> map = userSessionMap.get(username);
+ if (map == null) return;
+ synchronized (map)
+ {
+ map.remove(session.getId());
+ if (map.isEmpty()) userSessionMap.remove(username);
+ }
+
+
+ }
+}
integration/pom.xml 21(+21 -0)
diff --git a/integration/pom.xml b/integration/pom.xml
new file mode 100755
index 0000000..5028c1d
--- /dev/null
+++ b/integration/pom.xml
@@ -0,0 +1,21 @@
+<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 http://maven.apache.org/maven-v4_0_0.xsd">
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.0-alpha-1</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <name>Keycloak Integration</name>
+ <description/>
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>org.keycloak</groupId>
+ <artifactId>integration-pom</artifactId>
+ <packaging>pom</packaging>
+
+ <modules>
+ <module>as7-eap6/adapter</module>
+ <!-- <module>as7-eap6/jboss-modules</module> -->
+ </modules>
+</project>
pom.xml 12(+12 -0)
diff --git a/pom.xml b/pom.xml
index 2225e9b..bcb889c 100755
--- a/pom.xml
+++ b/pom.xml
@@ -54,6 +54,7 @@
<modules>
<module>core</module>
<module>services</module>
+ <module>integration</module>
</modules>
<dependencyManagement>
@@ -109,6 +110,12 @@
<version>${resteasy.version}</version>
</dependency>
<dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>tjws</artifactId>
+ <version>${resteasy.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>1.9.12</version>
@@ -163,6 +170,11 @@
<artifactId>junit</artifactId>
<version>4.11</version>
</dependency>
+ <dependency>
+ <groupId>org.hibernate.javax.persistence</groupId>
+ <artifactId>hibernate-jpa-2.0-api</artifactId>
+ <version>1.0.1.Final</version>
+ </dependency>
</dependencies>
</dependencyManagement>
services/pom.xml 36(+36 -0)
diff --git a/services/pom.xml b/services/pom.xml
index 8c097ae..5daecdd 100755
--- a/services/pom.xml
+++ b/services/pom.xml
@@ -43,6 +43,25 @@
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId>
<scope>provided</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>tjws</artifactId>
+ <scope>test</scope>
</dependency>
<dependency>
<groupId>org.jboss.resteasy</groupId>
@@ -94,6 +113,23 @@
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.hibernate.javax.persistence</groupId>
+ <artifactId>hibernate-jpa-2.0-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ <version>1.3.161</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.hibernate</groupId>
+ <artifactId>hibernate-entitymanager</artifactId>
+ <version>3.6.6.Final</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<plugins>
diff --git a/services/src/main/java/org/keycloak/services/filters/IdentitySessionFilter.java b/services/src/main/java/org/keycloak/services/filters/IdentitySessionFilter.java
new file mode 100755
index 0000000..dbe8461
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/filters/IdentitySessionFilter.java
@@ -0,0 +1,38 @@
+package org.keycloak.services.filters;
+
+import org.jboss.resteasy.spi.ResteasyProviderFactory;
+import org.picketlink.idm.IdentitySession;
+import org.picketlink.idm.IdentitySessionFactory;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.container.ContainerResponseContext;
+import javax.ws.rs.container.ContainerResponseFilter;
+import javax.ws.rs.container.PreMatching;
+import java.io.IOException;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+@PreMatching
+public class IdentitySessionFilter implements ContainerRequestFilter, ContainerResponseFilter {
+ protected IdentitySessionFactory factory;
+
+ public IdentitySessionFilter(IdentitySessionFactory factory) {
+ this.factory = factory;
+ }
+
+ @Override
+ public void filter(ContainerRequestContext requestContext) throws IOException {
+ IdentitySession ctx = factory.createIdentitySession();
+ requestContext.setProperty(IdentitySession.class.getName(), ctx);
+ ResteasyProviderFactory.pushContext(IdentitySession.class, ctx);
+ }
+
+ @Override
+ public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
+ IdentitySession ctx = (IdentitySession)requestContext.getProperty(IdentitySession.class.getName());
+ if (ctx != null) ctx.close();
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java b/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
new file mode 100755
index 0000000..d96b32b
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/managers/AccessCodeEntry.java
@@ -0,0 +1,49 @@
+package org.keycloak.services.managers;
+
+import org.keycloak.representations.SkeletonKeyToken;
+import org.picketlink.idm.model.User;
+
+import java.util.UUID;
+
+/**
+* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+* @version $Revision: 1 $
+*/
+public class AccessCodeEntry {
+ protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
+ protected long expiration;
+ protected SkeletonKeyToken token;
+ protected User client;
+
+ public boolean isExpired() {
+ return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public long getExpiration() {
+ return expiration;
+ }
+
+ public void setExpiration(long expiration) {
+ this.expiration = expiration;
+ }
+
+ public SkeletonKeyToken getToken() {
+ return token;
+ }
+
+ public void setToken(SkeletonKeyToken token) {
+ this.token = token;
+ }
+
+ public User getClient() {
+ return client;
+ }
+
+ public void setClient(User client) {
+ this.client = client;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
index 74fc03f..7b725da 100755
--- a/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/AuthenticationManager.java
@@ -24,107 +24,91 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class AuthenticationManager
-{
- protected Logger logger = Logger.getLogger(AuthenticationManager.class);
- public static final String FORM_USERNAME = "username";
- protected RealmManager adapter;
+public class AuthenticationManager {
+ protected Logger logger = Logger.getLogger(AuthenticationManager.class);
+ public static final String FORM_USERNAME = "username";
- public AuthenticationManager(RealmManager adapter)
- {
- this.adapter = adapter;
- }
+ /**
+ * Grabs token from headers, authenticates, authorizes
+ *
+ * @param realm
+ * @param headers
+ * @return
+ */
+ public boolean isRealmAdmin(RealmModel realm, HttpHeaders headers) {
+ User user = authenticateToken(realm, headers);
+ return realm.isRealmAdmin(user);
+ }
- public User authenticateToken(RealmModel realm, HttpHeaders headers)
- {
- String tokenString = null;
- String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
- if (authHeader == null)
- {
- throw new NotAuthorizedException("Bearer");
- }
- else
- {
- String[] split = authHeader.trim().split("\\s+");
- if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer");
- if (!split[0].equalsIgnoreCase("Bearer")) throw new NotAuthorizedException("Bearer");
- tokenString = split[1];
- }
+ public User authenticateToken(RealmModel realm, HttpHeaders headers) {
+ String tokenString = null;
+ String authHeader = headers.getHeaderString(HttpHeaders.AUTHORIZATION);
+ if (authHeader == null) {
+ throw new NotAuthorizedException("Bearer");
+ } else {
+ String[] split = authHeader.trim().split("\\s+");
+ if (split == null || split.length != 2) throw new NotAuthorizedException("Bearer");
+ if (!split[0].equalsIgnoreCase("Bearer")) throw new NotAuthorizedException("Bearer");
+ tokenString = split[1];
+ }
- try
- {
- SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId());
- if (!token.isActive())
- {
- throw new NotAuthorizedException("token_expired");
- }
- User user = realm.getIdm().getUser(token.getPrincipal());
- if (user == null || !user.isEnabled())
- {
- throw new NotAuthorizedException("invalid_user");
- }
- return user;
- }
- catch (VerificationException e)
- {
- logger.error("Failed to verify token", e);
- throw new NotAuthorizedException("invalid_token");
- }
- }
-
- public boolean authenticateForm(RealmModel realm, User user, MultivaluedMap<String, String> formData)
- {
- String username = user.getLoginName();
- Set<String> types = new HashSet<String>();
+ try {
+ SkeletonKeyToken token = RSATokenVerifier.verifyToken(tokenString, realm.getPublicKey(), realm.getId());
+ if (!token.isActive()) {
+ throw new NotAuthorizedException("token_expired");
+ }
+ User user = realm.getIdm().getUser(token.getPrincipal());
+ if (user == null || !user.isEnabled()) {
+ throw new NotAuthorizedException("invalid_user");
+ }
+ return user;
+ } catch (VerificationException e) {
+ logger.error("Failed to verify token", e);
+ throw new NotAuthorizedException("invalid_token");
+ }
+ }
- for (RequiredCredentialModel credential : realm.getRequiredCredentials())
- {
- types.add(credential.getType());
- }
+ public boolean authenticateForm(RealmModel realm, User user, MultivaluedMap<String, String> formData) {
+ String username = user.getLoginName();
+ Set<String> types = new HashSet<String>();
- if (types.contains(RequiredCredentialRepresentation.PASSWORD))
- {
- String password = formData.getFirst(RequiredCredentialRepresentation.PASSWORD);
- if (password == null)
- {
- logger.warn("Password not provided");
- return false;
- }
+ for (RequiredCredentialModel credential : realm.getRequiredCredentials()) {
+ types.add(credential.getType());
+ }
- if (types.contains(RequiredCredentialRepresentation.TOTP))
- {
- String token = formData.getFirst(RequiredCredentialRepresentation.TOTP);
- if (token == null)
- {
- logger.warn("TOTP token not provided");
- return false;
+ if (types.contains(RequiredCredentialRepresentation.PASSWORD)) {
+ String password = formData.getFirst(RequiredCredentialRepresentation.PASSWORD);
+ if (password == null) {
+ logger.warn("Password not provided");
+ return false;
}
- TOTPCredentials creds = new TOTPCredentials();
- creds.setToken(token);
- creds.setUsername(username);
- creds.setPassword(new Password(password));
- realm.getIdm().validateCredentials(creds);
- if (creds.getStatus() != Credentials.Status.VALID)
- {
- return false;
- }
- }
- else
- {
- UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, new Password(password));
- realm.getIdm().validateCredentials(creds);
- if (creds.getStatus() != Credentials.Status.VALID)
- {
- return false;
+
+ if (types.contains(RequiredCredentialRepresentation.TOTP)) {
+ String token = formData.getFirst(RequiredCredentialRepresentation.TOTP);
+ if (token == null) {
+ logger.warn("TOTP token not provided");
+ return false;
+ }
+ TOTPCredentials creds = new TOTPCredentials();
+ creds.setToken(token);
+ creds.setUsername(username);
+ creds.setPassword(new Password(password));
+ realm.getIdm().validateCredentials(creds);
+ if (creds.getStatus() != Credentials.Status.VALID) {
+ return false;
+ }
+ } else {
+ UsernamePasswordCredentials creds = new UsernamePasswordCredentials(username, new Password(password));
+ realm.getIdm().validateCredentials(creds);
+ if (creds.getStatus() != Credentials.Status.VALID) {
+ return false;
+ }
}
- }
- }
- else
- {
- logger.warn("Do not know how to authenticate user");
- return false;
- }
- return true;
- }
+ } else {
+ logger.warn("Do not know how to authenticate user");
+ return false;
+ }
+ return true;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/managers/InstallationManager.java b/services/src/main/java/org/keycloak/services/managers/InstallationManager.java
new file mode 100755
index 0000000..6154547
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/managers/InstallationManager.java
@@ -0,0 +1,33 @@
+package org.keycloak.services.managers;
+
+import org.keycloak.services.models.RealmManager;
+import org.keycloak.services.models.RealmModel;
+import org.keycloak.services.models.RequiredCredentialModel;
+import org.keycloak.services.resources.RegistrationService;
+import org.picketlink.idm.model.Realm;
+import org.picketlink.idm.model.SimpleRole;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class InstallationManager {
+ public void install(RealmManager manager) {
+ RealmModel defaultRealm = manager.createRealm(Realm.DEFAULT_REALM, Realm.DEFAULT_REALM);
+ defaultRealm.setName(Realm.DEFAULT_REALM);
+ defaultRealm.setEnabled(true);
+ defaultRealm.setTokenLifespan(300);
+ defaultRealm.setAccessCodeLifespan(60);
+ defaultRealm.setSslNotRequired(false);
+ defaultRealm.setCookieLoginAllowed(true);
+ defaultRealm.setRegistrationAllowed(true);
+ manager.generateRealmKeys(defaultRealm);
+ defaultRealm.updateRealm();
+ defaultRealm.addRequiredCredential(RequiredCredentialModel.PASSWORD);
+ defaultRealm.getIdm().add(new SimpleRole(RegistrationService.REALM_CREATOR_ROLE));
+ }
+
+ public boolean isInstalled(RealmManager manager) {
+ return manager.defaultRealm() != null;
+ }
+}
diff --git a/services/src/main/java/org/keycloak/services/managers/TokenManager.java b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
index 4d1428c..6c01504 100755
--- a/services/src/main/java/org/keycloak/services/managers/TokenManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/TokenManager.java
@@ -21,156 +21,123 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class TokenManager
-{
- protected RealmManager adapter;
-
- public TokenManager(RealmManager adapter)
- {
- this.adapter = adapter;
- }
-
- public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user)
- {
- SkeletonKeyToken token = new SkeletonKeyToken();
- token.id(adapter.generateId());
- token.principal(user.getLoginName());
- token.audience(realm.getName());
- token.issuedNow();
- token.issuedFor(client.getLoginName());
- if (realm.getTokenLifespan() > 0)
- {
- token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
- }
- Map<String, ResourceModel> resourceMap = realm.getResourceMap();
-
- for (String res : scope.keySet())
- {
- ResourceModel resource = resourceMap.get(res);
- Set<String> scopeMapping = resource.getScope(client);
- Set<String> roleMapping = resource.getRoleMappings(user);
- SkeletonKeyToken.Access access = token.addAccess(resource.getName());
- for (String role : scope.get(res))
- {
- if (!scopeMapping.contains("*") && !scopeMapping.contains(role))
- {
- throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
+public class TokenManager {
+
+ public SkeletonKeyToken createScopedToken(SkeletonKeyScope scope, RealmModel realm, User client, User user) {
+ SkeletonKeyToken token = new SkeletonKeyToken();
+ token.id(RealmManager.generateId());
+ token.principal(user.getLoginName());
+ token.audience(realm.getName());
+ token.issuedNow();
+ token.issuedFor(client.getLoginName());
+ if (realm.getTokenLifespan() > 0) {
+ token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+ }
+ Map<String, ResourceModel> resourceMap = realm.getResourceMap();
+
+ for (String res : scope.keySet()) {
+ ResourceModel resource = resourceMap.get(res);
+ Set<String> scopeMapping = resource.getScope(client);
+ Set<String> roleMapping = resource.getRoleMappings(user);
+ SkeletonKeyToken.Access access = token.addAccess(resource.getName());
+ for (String role : scope.get(res)) {
+ if (!scopeMapping.contains("*") && !scopeMapping.contains(role)) {
+ throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
+ }
+ if (!roleMapping.contains(role)) {
+ throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
+
+ }
+ access.addRole(role);
}
- if (!roleMapping.contains(role))
- {
- throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build());
-
+ }
+ return token;
+ }
+
+ public SkeletonKeyToken createScopedToken(String scopeParam, RealmModel realm, User client, User user) {
+ SkeletonKeyScope scope = decodeScope(scopeParam);
+ return createScopedToken(scope, realm, client, user);
+ }
+
+ public SkeletonKeyToken createLoginToken(RealmModel realm, User client, User user) {
+ Set<String> mapping = realm.getScope(client);
+ if (!mapping.contains("*")) {
+ throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized to request a user login.</p>").type("text/html").build());
+ }
+ SkeletonKeyToken token = createAccessToken(realm, user);
+ token.issuedFor(client.getLoginName());
+ return token;
+
+ }
+
+ public SkeletonKeyScope decodeScope(String scopeParam) {
+ SkeletonKeyScope scope = null;
+ byte[] bytes = Base64Url.decode(scopeParam);
+ try {
+ scope = JsonSerialization.fromBytes(SkeletonKeyScope.class, bytes);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return scope;
+ }
+
+
+ public SkeletonKeyToken createAccessToken(RealmModel realm, User user) {
+ List<ResourceModel> resources = realm.getResources();
+ SkeletonKeyToken token = new SkeletonKeyToken();
+ token.id(RealmManager.generateId());
+ token.issuedNow();
+ token.principal(user.getLoginName());
+ token.audience(realm.getId());
+ if (realm.getTokenLifespan() > 0) {
+ token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+ }
+
+ Set<String> realmMapping = realm.getRoleMappings(user);
+
+ if (realmMapping != null && realmMapping.size() > 0) {
+ SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
+ for (String role : realmMapping) {
+ access.addRole(role);
}
- access.addRole(role);
- }
- }
- return token;
- }
-
- public SkeletonKeyToken createScopedToken(String scopeParam, RealmModel realm, User client, User user)
- {
- SkeletonKeyScope scope = decodeScope(scopeParam);
- return createScopedToken(scope, realm, client, user);
- }
-
- public SkeletonKeyToken createLoginToken(RealmModel realm, User client, User user)
- {
- Set<String> mapping = realm.getScope(client);
- if (!mapping.contains("*"))
- {
- throw new ForbiddenException(Response.status(403).entity("<h1>Security Alert</h1><p>Known client not authorized to request a user login.</p>").type("text/html").build());
- }
- SkeletonKeyToken token = createAccessToken(realm, user);
- token.issuedFor(client.getLoginName());
- return token;
-
- }
-
- public SkeletonKeyScope decodeScope(String scopeParam)
- {
- SkeletonKeyScope scope = null;
- byte[] bytes = Base64Url.decode(scopeParam);
- try
- {
- scope = JsonSerialization.fromBytes(SkeletonKeyScope.class, bytes);
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- return scope;
- }
-
-
- public SkeletonKeyToken createAccessToken(RealmModel realm, User user)
- {
- List<ResourceModel> resources = realm.getResources();
- SkeletonKeyToken token = new SkeletonKeyToken();
- token.id(adapter.generateId());
- token.issuedNow();
- token.principal(user.getLoginName());
- token.audience(realm.getId());
- if (realm.getTokenLifespan() > 0)
- {
- token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
- }
-
- Set<String> realmMapping = realm.getRoleMappings(user);
-
- if (realmMapping != null && realmMapping.size() > 0)
- {
- SkeletonKeyToken.Access access = new SkeletonKeyToken.Access();
- for (String role : realmMapping)
- {
- access.addRole(role);
- }
- token.setRealmAccess(access);
- }
- if (resources != null)
- {
- for (ResourceModel resource : resources)
- {
- Set<String> mapping = resource.getRoleMappings(user);
- if (mapping == null) continue;
- SkeletonKeyToken.Access access = token.addAccess(resource.getName())
- .verifyCaller(resource.isSurrogateAuthRequired());
- for (String role : mapping)
- {
- access.addRole(role);
+ token.setRealmAccess(access);
+ }
+ if (resources != null) {
+ for (ResourceModel resource : resources) {
+ Set<String> mapping = resource.getRoleMappings(user);
+ if (mapping == null) continue;
+ SkeletonKeyToken.Access access = token.addAccess(resource.getName())
+ .verifyCaller(resource.isSurrogateAuthRequired());
+ for (String role : mapping) {
+ access.addRole(role);
+ }
}
- }
- }
- return token;
- }
-
- public SkeletonKeyToken createIdentityToken(RealmModel realm, String username)
- {
- SkeletonKeyToken token = new SkeletonKeyToken();
- token.id(adapter.generateId());
- token.issuedNow();
- token.principal(username);
- token.audience(realm.getId());
- if (realm.getTokenLifespan() > 0)
- {
- token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
- }
- return token;
- }
-
- public String encodeToken(RealmModel realm, SkeletonKeyToken token)
- {
- byte[] tokenBytes = null;
- try
- {
- tokenBytes = JsonSerialization.toByteArray(token, false);
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- String encodedToken = new JWSBuilder()
- .content(tokenBytes)
- .rsa256(realm.getPrivateKey());
- return encodedToken;
- }
+ }
+ return token;
+ }
+
+ public SkeletonKeyToken createIdentityToken(RealmModel realm, String username) {
+ SkeletonKeyToken token = new SkeletonKeyToken();
+ token.id(RealmManager.generateId());
+ token.issuedNow();
+ token.principal(username);
+ token.audience(realm.getId());
+ if (realm.getTokenLifespan() > 0) {
+ token.expiration((System.currentTimeMillis() / 1000) + realm.getTokenLifespan());
+ }
+ return token;
+ }
+
+ public String encodeToken(RealmModel realm, SkeletonKeyToken token) {
+ byte[] tokenBytes = null;
+ try {
+ tokenBytes = JsonSerialization.toByteArray(token, false);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ String encodedToken = new JWSBuilder()
+ .content(tokenBytes)
+ .rsa256(realm.getPrivateKey());
+ return encodedToken;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/models/RealmManager.java b/services/src/main/java/org/keycloak/services/models/RealmManager.java
index 02485bf..6ee87ce 100755
--- a/services/src/main/java/org/keycloak/services/models/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/models/RealmManager.java
@@ -1,49 +1,71 @@
package org.keycloak.services.models;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.IdentityManager;
-import org.picketlink.idm.internal.IdentityManagerFactory;
import org.picketlink.idm.model.Realm;
+import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.SimpleAgent;
+import org.picketlink.idm.model.SimpleUser;
+import org.picketlink.idm.model.User;
+import javax.ws.rs.core.Response;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
import java.util.concurrent.atomic.AtomicLong;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class RealmManager
-{
- private static AtomicLong counter = new AtomicLong(1);
-
- public static String generateId()
- {
- return counter.getAndIncrement() + "-" + System.currentTimeMillis();
- }
-
- protected IdentityManagerFactory factory;
-
- public RealmManager(IdentityManagerFactory factory)
- {
- this.factory = factory;
- }
-
- public RealmModel getRealm(String id)
- {
- Realm existing = factory.findRealm(id);
- if (existing == null)
- {
- return null;
- }
- return new RealmModel(existing, factory);
- }
-
- public RealmModel create(String name)
- {
- Realm newRealm = factory.createRealm(generateId());
- IdentityManager idm = factory.createIdentityManager(newRealm);
- SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID);
- idm.add(agent);
- return new RealmModel(newRealm, factory);
- }
-
-}
+public class RealmManager {
+ private static AtomicLong counter = new AtomicLong(1);
+
+ public static String generateId() {
+ return counter.getAndIncrement() + "-" + System.currentTimeMillis();
+ }
+
+ protected IdentitySession IdentitySession;
+
+ public RealmManager(IdentitySession IdentitySession) {
+ this.IdentitySession = IdentitySession;
+ }
+
+ public RealmModel defaultRealm() {
+ return getRealm(Realm.DEFAULT_REALM);
+ }
+
+ public RealmModel getRealm(String id) {
+ Realm existing = IdentitySession.findRealm(id);
+ if (existing == null) {
+ return null;
+ }
+ return new RealmModel(existing, IdentitySession);
+ }
+
+ public RealmModel createRealm(String name) {
+ return createRealm(generateId(), name);
+ }
+
+ public RealmModel createRealm(String id, String name) {
+ Realm newRealm = IdentitySession.createRealm(id);
+ IdentityManager idm = IdentitySession.createIdentityManager(newRealm);
+ SimpleAgent agent = new SimpleAgent(RealmModel.REALM_AGENT_ID);
+ idm.add(agent);
+ RealmModel realm = new RealmModel(newRealm, IdentitySession);
+ return realm;
+ }
+
+ public void generateRealmKeys(RealmModel realm) {
+ KeyPair keyPair = null;
+ try {
+ keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ realm.setPrivateKey(keyPair.getPrivate());
+ realm.setPublicKey(keyPair.getPublic());
+ realm.updateRealm();
+ }
+ }
diff --git a/services/src/main/java/org/keycloak/services/models/RealmModel.java b/services/src/main/java/org/keycloak/services/models/RealmModel.java
index 6028bbf..0cdf45c 100755
--- a/services/src/main/java/org/keycloak/services/models/RealmModel.java
+++ b/services/src/main/java/org/keycloak/services/models/RealmModel.java
@@ -4,20 +4,19 @@ import org.bouncycastle.openssl.PEMWriter;
import org.jboss.resteasy.security.PemUtils;
import org.keycloak.representations.idm.RequiredCredentialRepresentation;
import org.keycloak.services.models.relationships.RealmAdminRelationship;
-import org.keycloak.services.models.relationships.RealmResourceRelationship;
+import org.keycloak.services.models.relationships.ResourceRelationship;
import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
import org.keycloak.services.models.relationships.ScopeRelationship;
+import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.IdentityManager;
import org.picketlink.idm.credential.Password;
import org.picketlink.idm.credential.TOTPCredential;
import org.picketlink.idm.credential.X509CertificateCredentials;
-import org.picketlink.idm.internal.IdentityManagerFactory;
import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Grant;
import org.picketlink.idm.model.Realm;
import org.picketlink.idm.model.Role;
-import org.picketlink.idm.model.SimpleAgent;
import org.picketlink.idm.model.Tier;
import org.picketlink.idm.model.User;
import org.picketlink.idm.query.IdentityQuery;
@@ -39,374 +38,311 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class RealmModel
-{
- public static final String REALM_AGENT_ID = "_realm_";
- public static final String REALM_NAME = "name";
- public static final String REALM_ACCESS_CODE_LIFESPAN = "accessCodeLifespan";
- public static final String REALM_TOKEN_LIFESPAN = "tokenLifespan";
- public static final String REALM_PRIVATE_KEY = "privateKey";
- public static final String REALM_PUBLIC_KEY = "publicKey";
- public static final String REALM_IS_SSL_NOT_REQUIRED = "isSSLNotRequired";
- public static final String REALM_IS_COOKIE_LOGIN_ALLOWED = "isCookieLoginAllowed";
-
- protected Realm realm;
- protected Agent realmAgent;
- protected IdentityManagerFactory factory;
- protected volatile transient PublicKey publicKey;
- protected volatile transient PrivateKey privateKey;
-
- public RealmModel(Realm realm, IdentityManagerFactory factory)
- {
- this.realm = realm;
- this.factory = factory;
- realmAgent = getIdm().getAgent(REALM_AGENT_ID);
- }
-
- public IdentityManager getIdm()
- {
- return factory.createIdentityManager(realm);
- }
-
- public void updateRealm()
- {
- getIdm().update(realmAgent);
- }
-
- public String getId()
- {
- return realm.getId();
- }
-
- public String getName()
- {
- return (String)realmAgent.getAttribute(REALM_NAME).getValue();
- }
-
- public void setName(String name)
- {
- realmAgent.setAttribute(new Attribute<String>(REALM_NAME, name));
- }
-
- public boolean isEnabled()
- {
- return realmAgent.isEnabled();
- }
-
- public void setEnabled(boolean enabled)
- {
- realmAgent.setEnabled(enabled);
- }
-
- public boolean isSslNotRequired()
- {
- return (Boolean)realmAgent.getAttribute(REALM_IS_SSL_NOT_REQUIRED).getValue();
- }
-
- public void setSslNotRequired(boolean sslNotRequired)
- {
- realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_SSL_NOT_REQUIRED, sslNotRequired));
- }
-
- public boolean isCookieLoginAllowed()
- {
- return (Boolean)realmAgent.getAttribute(REALM_IS_COOKIE_LOGIN_ALLOWED).getValue();
- }
-
- public void setCookieLoginAllowed(boolean cookieLoginAllowed)
- {
- realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_COOKIE_LOGIN_ALLOWED, cookieLoginAllowed));
- }
-
- public long getTokenLifespan()
- {
- return (Long) realmAgent.getAttribute(REALM_TOKEN_LIFESPAN).getValue();
- }
-
- public void setTokenLifespan(long tokenLifespan)
- {
- realmAgent.setAttribute(new Attribute<Long>(REALM_TOKEN_LIFESPAN,tokenLifespan));
- }
-
- public long getAccessCodeLifespan()
- {
- return (Long) realmAgent.getAttribute(REALM_ACCESS_CODE_LIFESPAN).getValue();
- }
-
- public void setAccessCodeLifespan(long accessCodeLifespan)
- {
- realmAgent.setAttribute(new Attribute<Long>(REALM_ACCESS_CODE_LIFESPAN, accessCodeLifespan));
- }
-
- public String getPublicKeyPem()
- {
- return (String) realmAgent.getAttribute(REALM_PUBLIC_KEY).getValue();
- }
-
- public void setPublicKeyPem(String publicKeyPem)
- {
- realmAgent.setAttribute(new Attribute<String>(REALM_PUBLIC_KEY, publicKeyPem));
- this.publicKey = null;
- }
-
- public String getPrivateKeyPem()
- {
- return (String) realmAgent.getAttribute(REALM_PRIVATE_KEY).getValue();
- }
-
- public void setPrivateKeyPem(String privateKeyPem)
- {
- realmAgent.setAttribute(new Attribute<String>(REALM_PRIVATE_KEY, privateKeyPem));
- this.privateKey = null;
- }
-
- public PublicKey getPublicKey()
- {
- if (publicKey != null) return publicKey;
- String pem = getPublicKeyPem();
- if (pem != null)
- {
- try
- {
- publicKey = PemUtils.decodePublicKey(pem);
- }
- catch (Exception e)
- {
+public class RealmModel {
+ public static final String REALM_AGENT_ID = "_realm_";
+ public static final String REALM_NAME = "name";
+ public static final String REALM_ACCESS_CODE_LIFESPAN = "accessCodeLifespan";
+ public static final String REALM_TOKEN_LIFESPAN = "tokenLifespan";
+ public static final String REALM_PRIVATE_KEY = "privateKey";
+ public static final String REALM_PUBLIC_KEY = "publicKey";
+ public static final String REALM_IS_SSL_NOT_REQUIRED = "isSSLNotRequired";
+ public static final String REALM_IS_COOKIE_LOGIN_ALLOWED = "isCookieLoginAllowed";
+ public static final String REALM_IS_REGISTRATION_ALLOWED = "isRegistrationAllowed";
+
+ protected Realm realm;
+ protected Agent realmAgent;
+ protected IdentitySession identitySession;
+ protected volatile transient PublicKey publicKey;
+ protected volatile transient PrivateKey privateKey;
+
+ public RealmModel(Realm realm, IdentitySession session) {
+ this.realm = realm;
+ this.identitySession = session;
+ realmAgent = getIdm().getAgent(REALM_AGENT_ID);
+ }
+
+ public IdentityManager getIdm() {
+ return identitySession.createIdentityManager(realm);
+ }
+
+ public void updateRealm() {
+ getIdm().update(realmAgent);
+ }
+
+ public String getId() {
+ return realm.getId();
+ }
+
+ public String getName() {
+ return (String) realmAgent.getAttribute(REALM_NAME).getValue();
+ }
+
+ public void setName(String name) {
+ realmAgent.setAttribute(new Attribute<String>(REALM_NAME, name));
+ }
+
+ public boolean isEnabled() {
+ return realmAgent.isEnabled();
+ }
+
+ public void setEnabled(boolean enabled) {
+ realmAgent.setEnabled(enabled);
+ }
+
+ public boolean isSslNotRequired() {
+ return (Boolean) realmAgent.getAttribute(REALM_IS_SSL_NOT_REQUIRED).getValue();
+ }
+
+ public void setSslNotRequired(boolean sslNotRequired) {
+ realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_SSL_NOT_REQUIRED, sslNotRequired));
+ }
+
+ public boolean isCookieLoginAllowed() {
+ return (Boolean) realmAgent.getAttribute(REALM_IS_COOKIE_LOGIN_ALLOWED).getValue();
+ }
+
+ public void setCookieLoginAllowed(boolean cookieLoginAllowed) {
+ realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_COOKIE_LOGIN_ALLOWED, cookieLoginAllowed));
+ }
+
+ public boolean isRegistrationAllowed() {
+ return (Boolean) realmAgent.getAttribute(REALM_IS_REGISTRATION_ALLOWED).getValue();
+ }
+
+ public void setRegistrationAllowed(boolean registrationAllowed) {
+ realmAgent.setAttribute(new Attribute<Boolean>(REALM_IS_REGISTRATION_ALLOWED, registrationAllowed));
+ }
+
+ public long getTokenLifespan() {
+ return (Long) realmAgent.getAttribute(REALM_TOKEN_LIFESPAN).getValue();
+ }
+
+ public void setTokenLifespan(long tokenLifespan) {
+ realmAgent.setAttribute(new Attribute<Long>(REALM_TOKEN_LIFESPAN, tokenLifespan));
+ }
+
+ public long getAccessCodeLifespan() {
+ return (Long) realmAgent.getAttribute(REALM_ACCESS_CODE_LIFESPAN).getValue();
+ }
+
+ public void setAccessCodeLifespan(long accessCodeLifespan) {
+ realmAgent.setAttribute(new Attribute<Long>(REALM_ACCESS_CODE_LIFESPAN, accessCodeLifespan));
+ }
+
+ public String getPublicKeyPem() {
+ return (String) realmAgent.getAttribute(REALM_PUBLIC_KEY).getValue();
+ }
+
+ public void setPublicKeyPem(String publicKeyPem) {
+ realmAgent.setAttribute(new Attribute<String>(REALM_PUBLIC_KEY, publicKeyPem));
+ this.publicKey = null;
+ }
+
+ public String getPrivateKeyPem() {
+ return (String) realmAgent.getAttribute(REALM_PRIVATE_KEY).getValue();
+ }
+
+ public void setPrivateKeyPem(String privateKeyPem) {
+ realmAgent.setAttribute(new Attribute<String>(REALM_PRIVATE_KEY, privateKeyPem));
+ this.privateKey = null;
+ }
+
+ public PublicKey getPublicKey() {
+ if (publicKey != null) return publicKey;
+ String pem = getPublicKeyPem();
+ if (pem != null) {
+ try {
+ publicKey = PemUtils.decodePublicKey(pem);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return publicKey;
+ }
+
+ public void setPublicKey(PublicKey publicKey) {
+ this.publicKey = publicKey;
+ StringWriter writer = new StringWriter();
+ PEMWriter pemWriter = new PEMWriter(writer);
+ try {
+ pemWriter.writeObject(publicKey);
+ pemWriter.flush();
+ } catch (IOException e) {
throw new RuntimeException(e);
- }
- }
- return publicKey;
- }
-
- public void setPublicKey(PublicKey publicKey)
- {
- this.publicKey = publicKey;
- StringWriter writer = new StringWriter();
- PEMWriter pemWriter = new PEMWriter(writer);
- try
- {
- pemWriter.writeObject(publicKey);
- pemWriter.flush();
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- String s = writer.toString();
- setPublicKeyPem(PemUtils.removeBeginEnd(s));
- }
-
- public PrivateKey getPrivateKey()
- {
- if (privateKey != null) return privateKey;
- String pem = getPrivateKeyPem();
- if (pem != null)
- {
- try
- {
- privateKey = PemUtils.decodePrivateKey(pem);
- }
- catch (Exception e)
- {
+ }
+ String s = writer.toString();
+ setPublicKeyPem(PemUtils.removeBeginEnd(s));
+ }
+
+ public PrivateKey getPrivateKey() {
+ if (privateKey != null) return privateKey;
+ String pem = getPrivateKeyPem();
+ if (pem != null) {
+ try {
+ privateKey = PemUtils.decodePrivateKey(pem);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+ return privateKey;
+ }
+
+ public void setPrivateKey(PrivateKey privateKey) {
+ this.privateKey = privateKey;
+ StringWriter writer = new StringWriter();
+ PEMWriter pemWriter = new PEMWriter(writer);
+ try {
+ pemWriter.writeObject(privateKey);
+ pemWriter.flush();
+ } catch (IOException e) {
throw new RuntimeException(e);
- }
- }
- return privateKey;
- }
-
- public void setPrivateKey(PrivateKey privateKey)
- {
- this.privateKey = privateKey;
- StringWriter writer = new StringWriter();
- PEMWriter pemWriter = new PEMWriter(writer);
- try
- {
- pemWriter.writeObject(privateKey);
- pemWriter.flush();
- }
- catch (IOException e)
- {
- throw new RuntimeException(e);
- }
- String s = writer.toString();
- setPrivateKeyPem(PemUtils.removeBeginEnd(s));
- }
-
- public List<RequiredCredentialModel> getRequiredCredentials()
- {
- IdentityManager idm = getIdm();
- Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
- RelationshipQuery<RequiredCredentialRelationship> query = idm.createRelationshipQuery(RequiredCredentialRelationship.class);
- query.setParameter(RequiredCredentialRelationship.REALM_AGENT, realmAgent);
- List<RequiredCredentialRelationship> results = query.getResultList();
- List<RequiredCredentialModel> rtn = new ArrayList<RequiredCredentialModel>();
- for (RequiredCredentialRelationship relationship : results)
- {
- RequiredCredentialModel model = new RequiredCredentialModel();
- model.setInput(relationship.isInput());
- model.setSecret(relationship.isSecret());
- model.setType(relationship.getCredentialType());
- rtn.add(model);
- }
- return rtn;
- }
-
- public void addRequiredCredential(RequiredCredentialModel cred)
- {
- IdentityManager idm = getIdm();
- Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
- RequiredCredentialRelationship relationship = new RequiredCredentialRelationship();
- relationship.setCredentialType(cred.getType());
- relationship.setInput(cred.isInput());
- relationship.setSecret(cred.isSecret());
- relationship.setRealmAgent(realmAgent);
- idm.add(relationship);
- }
-
- public void updateCredential(User user, UserCredentialModel cred)
- {
- IdentityManager idm = getIdm();
- if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD))
- {
- Password password = new Password(cred.getValue());
- idm.updateCredential(user, password);
- }
- else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP))
- {
- TOTPCredential totp = new TOTPCredential(cred.getValue());
- idm.updateCredential(user, totp);
- }
- else if (cred.getType().equals(RequiredCredentialRepresentation.CLIENT_CERT))
- {
- X509Certificate cert = null;
- try
- {
- cert = org.keycloak.PemUtils.decodeCertificate(cred.getValue());
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- X509CertificateCredentials creds = new X509CertificateCredentials(cert);
- idm.updateCredential(user, creds);
- }
- }
-
- public List<Role> getRoles()
- {
- IdentityManager idm = getIdm();
- IdentityQuery<Role> query = idm.createIdentityQuery(Role.class);
- query.setParameter(Role.PARTITION, realm);
- return query.getResultList();
- }
-
-
- protected ResourceModel loadResource(Agent resource)
- {
- Tier tier = factory.findTier(resource.getPartition().getId());
- return new ResourceModel(tier, resource, this, factory);
- }
-
- /**
- * Key name, value resource
- *
- * @return
- */
- public Map<String, ResourceModel> getResourceMap()
- {
- Map<String, ResourceModel> resourceMap = new HashMap<String, ResourceModel>();
- for (ResourceModel resource : getResources())
- {
- resourceMap.put(resource.getName(), resource);
- }
- return resourceMap;
- }
-
- public List<ResourceModel> getResources()
- {
- IdentityManager idm = getIdm();
- RelationshipQuery<RealmResourceRelationship> query = idm.createRelationshipQuery(RealmResourceRelationship.class);
- query.setParameter(RealmResourceRelationship.REALM_AGENT, realmAgent);
- List<RealmResourceRelationship> results = query.getResultList();
- List<ResourceModel> resources = new ArrayList<ResourceModel>();
- for (RealmResourceRelationship relationship : results)
- {
- ResourceModel model = loadResource(relationship.getResourceAgent());
- resources.add(model);
- }
-
- return resources;
- }
-
- public ResourceModel addResource(String name)
- {
- Tier newTier = factory.createTier(RealmManager.generateId());
- IdentityManager idm = factory.createIdentityManager(newTier);
- SimpleAgent resourceAgent = new SimpleAgent(ResourceModel.RESOURCE_AGENT_ID);
- resourceAgent.setAttribute(new Attribute<String>(ResourceModel.RESOURCE_NAME, name));
- idm.add(resourceAgent);
- idm = getIdm();
- RealmResourceRelationship relationship = new RealmResourceRelationship();
- relationship.setRealmAgent(realmAgent);
- relationship.setResourceAgent(resourceAgent);
- idm.add(relationship);
- return new ResourceModel(newTier, resourceAgent, this, factory);
- }
-
- public Set<String> getRoleMappings(User user)
- {
- RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
- query.setParameter(Grant.ASSIGNEE, user);
- List<Grant> grants = query.getResultList();
- HashSet<String> set = new HashSet<String>();
- for (Grant grant : grants)
- {
- if (grant.getRole().getPartition().getId().equals(realm.getId()))set.add(grant.getRole().getName());
- }
- return set;
- }
-
- public void addScope(Agent agent, String roleName)
- {
- IdentityManager idm = getIdm();
- Role role = idm.getRole(roleName);
- if (role == null) throw new RuntimeException("role not found");
- ScopeRelationship scope = new ScopeRelationship();
- scope.setClient(agent);
- scope.setScope(role);
-
- }
-
-
- public Set<String> getScope(Agent agent)
- {
- RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
- query.setParameter(ScopeRelationship.CLIENT, agent);
- List<ScopeRelationship> scope = query.getResultList();
- HashSet<String> set = new HashSet<String>();
- for (ScopeRelationship rel : scope)
- {
- if (rel.getScope().getPartition().getId().equals(realm.getId())) set.add(rel.getScope().getName());
- }
- return set;
- }
-
- public boolean isRealmAdmin(Agent agent)
- {
- IdentityManager idm = getIdm();
- RelationshipQuery<RealmAdminRelationship> query = idm.createRelationshipQuery(RealmAdminRelationship.class);
- query.setParameter(RealmAdminRelationship.REALM, realm);
- query.setParameter(RealmAdminRelationship.ADMIN, agent);
- List<RealmAdminRelationship> results = query.getResultList();
- return results.size() > 0;
- }
-
- public void addRealmAdmin(Agent agent)
- {
- IdentityManager idm = getIdm();
- RealmAdminRelationship relationship = new RealmAdminRelationship();
- relationship.setAdmin(agent);
- relationship.setRealm(realm);
- idm.add(relationship);
- }
+ }
+ String s = writer.toString();
+ setPrivateKeyPem(PemUtils.removeBeginEnd(s));
+ }
+
+ public List<RequiredCredentialModel> getRequiredCredentials() {
+ IdentityManager idm = getIdm();
+ Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
+ RelationshipQuery<RequiredCredentialRelationship> query = idm.createRelationshipQuery(RequiredCredentialRelationship.class);
+ query.setParameter(RequiredCredentialRelationship.REALM_AGENT, realmAgent);
+ List<RequiredCredentialRelationship> results = query.getResultList();
+ List<RequiredCredentialModel> rtn = new ArrayList<RequiredCredentialModel>();
+ for (RequiredCredentialRelationship relationship : results) {
+ RequiredCredentialModel model = new RequiredCredentialModel();
+ model.setInput(relationship.isInput());
+ model.setSecret(relationship.isSecret());
+ model.setType(relationship.getCredentialType());
+ rtn.add(model);
+ }
+ return rtn;
+ }
+
+ public void addRequiredCredential(RequiredCredentialModel cred) {
+ IdentityManager idm = getIdm();
+ Agent realmAgent = idm.getAgent(REALM_AGENT_ID);
+ RequiredCredentialRelationship relationship = new RequiredCredentialRelationship();
+ relationship.setCredentialType(cred.getType());
+ relationship.setInput(cred.isInput());
+ relationship.setSecret(cred.isSecret());
+ relationship.setRealmAgent(realmAgent);
+ idm.add(relationship);
+ }
+
+ public void updateCredential(User user, UserCredentialModel cred) {
+ IdentityManager idm = getIdm();
+ if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) {
+ Password password = new Password(cred.getValue());
+ idm.updateCredential(user, password);
+ } else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) {
+ TOTPCredential totp = new TOTPCredential(cred.getValue());
+ idm.updateCredential(user, totp);
+ } else if (cred.getType().equals(RequiredCredentialRepresentation.CLIENT_CERT)) {
+ X509Certificate cert = null;
+ try {
+ cert = org.keycloak.PemUtils.decodeCertificate(cred.getValue());
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ X509CertificateCredentials creds = new X509CertificateCredentials(cert);
+ idm.updateCredential(user, creds);
+ }
+ }
+
+ public List<Role> getRoles() {
+ IdentityManager idm = getIdm();
+ IdentityQuery<Role> query = idm.createIdentityQuery(Role.class);
+ query.setParameter(Role.PARTITION, realm);
+ return query.getResultList();
+ }
+
+
+ /**
+ * Key name, value resource
+ *
+ * @return
+ */
+ public Map<String, ResourceModel> getResourceMap() {
+ Map<String, ResourceModel> resourceMap = new HashMap<String, ResourceModel>();
+ for (ResourceModel resource : getResources()) {
+ resourceMap.put(resource.getName(), resource);
+ }
+ return resourceMap;
+ }
+
+ public List<ResourceModel> getResources() {
+ IdentityManager idm = getIdm();
+ RelationshipQuery<ResourceRelationship> query = idm.createRelationshipQuery(ResourceRelationship.class);
+ query.setParameter(ResourceRelationship.REALM_AGENT, realmAgent);
+ List<ResourceRelationship> results = query.getResultList();
+ List<ResourceModel> resources = new ArrayList<ResourceModel>();
+ for (ResourceRelationship relationship : results) {
+ Tier resourceTier = identitySession.findTier(relationship.getResourceId());
+ ResourceModel model = new ResourceModel(resourceTier,relationship, this, identitySession);
+ resources.add(model);
+ }
+
+ return resources;
+ }
+
+ public ResourceModel addResource(String name) {
+ Tier newTier = identitySession.createTier(RealmManager.generateId());
+ IdentityManager idm = getIdm();
+ ResourceRelationship relationship = new ResourceRelationship();
+ relationship.setResourceName(name);
+ relationship.setRealmAgent(realmAgent);
+ relationship.setResourceId(newTier.getId());
+ idm.add(relationship);
+ return new ResourceModel(newTier, relationship, this, identitySession);
+ }
+
+ public Set<String> getRoleMappings(User user) {
+ RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
+ query.setParameter(Grant.ASSIGNEE, user);
+ List<Grant> grants = query.getResultList();
+ HashSet<String> set = new HashSet<String>();
+ for (Grant grant : grants) {
+ if (grant.getRole().getPartition().getId().equals(realm.getId())) set.add(grant.getRole().getName());
+ }
+ return set;
+ }
+
+ public void addScope(Agent agent, String roleName) {
+ IdentityManager idm = getIdm();
+ Role role = idm.getRole(roleName);
+ if (role == null) throw new RuntimeException("role not found");
+ ScopeRelationship scope = new ScopeRelationship();
+ scope.setClient(agent);
+ scope.setScope(role);
+
+ }
+
+
+ public Set<String> getScope(Agent agent) {
+ RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
+ query.setParameter(ScopeRelationship.CLIENT, agent);
+ List<ScopeRelationship> scope = query.getResultList();
+ HashSet<String> set = new HashSet<String>();
+ for (ScopeRelationship rel : scope) {
+ if (rel.getScope().getPartition().getId().equals(realm.getId())) set.add(rel.getScope().getName());
+ }
+ return set;
+ }
+
+ public boolean isRealmAdmin(Agent agent) {
+ IdentityManager idm = new RealmManager(identitySession).defaultRealm().getIdm();
+ RelationshipQuery<RealmAdminRelationship> query = idm.createRelationshipQuery(RealmAdminRelationship.class);
+ query.setParameter(RealmAdminRelationship.REALM, realm.getId());
+ query.setParameter(RealmAdminRelationship.ADMIN, agent);
+ List<RealmAdminRelationship> results = query.getResultList();
+ return results.size() > 0;
+ }
+
+ public void addRealmAdmin(Agent agent) {
+ IdentityManager idm = new RealmManager(identitySession).defaultRealm().getIdm();
+ RealmAdminRelationship relationship = new RealmAdminRelationship();
+ relationship.setAdmin(agent);
+ relationship.setRealm(realm.getId());
+ idm.add(relationship);
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java
index cb24a98..cf68d46 100755
--- a/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java
+++ b/services/src/main/java/org/keycloak/services/models/relationships/RealmAdminRelationship.java
@@ -4,6 +4,7 @@ import org.picketlink.idm.model.AbstractAttributedType;
import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Realm;
import org.picketlink.idm.model.Relationship;
+import org.picketlink.idm.model.annotation.AttributeProperty;
import org.picketlink.idm.model.annotation.IdentityProperty;
import org.picketlink.idm.query.RelationshipQueryParameter;
@@ -11,48 +12,43 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class RealmAdminRelationship extends AbstractAttributedType implements Relationship
-{
- private static final long serialVersionUID = 1L;
-
- public static final RelationshipQueryParameter REALM = new RelationshipQueryParameter() {
-
- @Override
- public String getName() {
- return "realm";
- }
- };
-
- public static final RelationshipQueryParameter ADMIN = new RelationshipQueryParameter() {
-
- @Override
- public String getName() {
- return "admin";
- }
- };
-
- protected Realm realm;
- protected Agent admin;
-
- @IdentityProperty
- public Realm getRealm()
- {
- return realm;
- }
-
- public void setRealm(Realm realm)
- {
- this.realm = realm;
- }
-
- @IdentityProperty
- public Agent getAdmin()
- {
- return admin;
- }
-
- public void setAdmin(Agent admin)
- {
- this.admin = admin;
- }
+public class RealmAdminRelationship extends AbstractAttributedType implements Relationship {
+ private static final long serialVersionUID = 1L;
+
+ public static final RelationshipQueryParameter REALM = new RelationshipQueryParameter() {
+
+ @Override
+ public String getName() {
+ return "realm";
+ }
+ };
+
+ public static final RelationshipQueryParameter ADMIN = new RelationshipQueryParameter() {
+
+ @Override
+ public String getName() {
+ return "admin";
+ }
+ };
+
+ protected String realm;
+ protected Agent admin;
+
+ @AttributeProperty
+ public String getRealm() {
+ return realm;
+ }
+
+ public void setRealm(String realm) {
+ this.realm = realm;
+ }
+
+ @IdentityProperty
+ public Agent getAdmin() {
+ return admin;
+ }
+
+ public void setAdmin(Agent admin) {
+ this.admin = admin;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java
index 48a1c90..59ce02d 100755
--- a/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java
+++ b/services/src/main/java/org/keycloak/services/models/relationships/RequiredCredentialRelationship.java
@@ -11,69 +11,59 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class RequiredCredentialRelationship extends AbstractAttributedType implements Relationship
-{
- private static final long serialVersionUID = 1L;
+public class RequiredCredentialRelationship extends AbstractAttributedType implements Relationship {
+ private static final long serialVersionUID = 1L;
- public static final RelationshipQueryParameter REALM_AGENT = new RelationshipQueryParameter() {
+ public static final RelationshipQueryParameter REALM_AGENT = new RelationshipQueryParameter() {
- @Override
- public String getName() {
- return "realmAgent";
- }
- };
+ @Override
+ public String getName() {
+ return "realmAgent";
+ }
+ };
- protected Agent realmAgent;
- protected String credentialType;
- protected boolean input;
- protected boolean secret;
+ protected Agent realmAgent;
+ protected String credentialType;
+ protected boolean input;
+ protected boolean secret;
- public RequiredCredentialRelationship()
- {
- }
+ public RequiredCredentialRelationship() {
+ }
- @IdentityProperty
- public Agent getRealmAgent()
- {
- return realmAgent;
- }
+ @IdentityProperty
+ public Agent getRealmAgent() {
+ return realmAgent;
+ }
- public void setRealmAgent(Agent realmAgent)
- {
- this.realmAgent = realmAgent;
- }
+ public void setRealmAgent(Agent realmAgent) {
+ this.realmAgent = realmAgent;
+ }
- @AttributeProperty
- public String getCredentialType()
- {
- return credentialType;
- }
+ @AttributeProperty
+ public String getCredentialType() {
+ return credentialType;
+ }
- public void setCredentialType(String credentialType)
- {
- this.credentialType = credentialType;
- }
+ public void setCredentialType(String credentialType) {
+ this.credentialType = credentialType;
+ }
- @AttributeProperty
- public boolean isInput()
- {
- return input;
- }
+ @AttributeProperty
+ public boolean isInput() {
+ return input;
+ }
- public void setInput(boolean input)
- {
- this.input = input;
- }
+ public void setInput(boolean input) {
+ this.input = input;
+ }
- @AttributeProperty
- public boolean isSecret()
- {
- return secret;
- }
+ @AttributeProperty
+ public boolean isSecret() {
+ return secret;
+ }
- public void setSecret(boolean secret)
- {
- this.secret = secret;
- }
+ public void setSecret(boolean secret) {
+ this.secret = secret;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java b/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java
index b8bea48..7221c72 100755
--- a/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java
+++ b/services/src/main/java/org/keycloak/services/models/relationships/ScopeRelationship.java
@@ -11,40 +11,35 @@ import org.picketlink.idm.query.RelationshipQueryParameter;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class ScopeRelationship extends AbstractAttributedType implements Relationship
-{
- private static final long serialVersionUID = 1L;
-
- public static final RelationshipQueryParameter CLIENT = new RelationshipQueryParameter() {
-
- @Override
- public String getName() {
- return "client";
- }
- };
-
- protected Agent client;
- protected Role scope;
-
- @IdentityProperty
- public Agent getClient()
- {
- return client;
- }
-
- public void setClient(Agent client)
- {
- this.client = client;
- }
-
- @IdentityProperty
- public Role getScope()
- {
- return scope;
- }
-
- public void setScope(Role scope)
- {
- this.scope = scope;
- }
+public class ScopeRelationship extends AbstractAttributedType implements Relationship {
+ private static final long serialVersionUID = 1L;
+
+ public static final RelationshipQueryParameter CLIENT = new RelationshipQueryParameter() {
+
+ @Override
+ public String getName() {
+ return "client";
+ }
+ };
+
+ protected Agent client;
+ protected Role scope;
+
+ @IdentityProperty
+ public Agent getClient() {
+ return client;
+ }
+
+ public void setClient(Agent client) {
+ this.client = client;
+ }
+
+ @IdentityProperty
+ public Role getScope() {
+ return scope;
+ }
+
+ public void setScope(Role scope) {
+ this.scope = scope;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java b/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java
index 6476ef7..c8ca584 100755
--- a/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java
+++ b/services/src/main/java/org/keycloak/services/models/RequiredCredentialModel.java
@@ -1,42 +1,48 @@
package org.keycloak.services.models;
+import org.keycloak.representations.idm.RequiredCredentialRepresentation;
+
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class RequiredCredentialModel
-{
- protected String type;
- protected boolean input;
- protected boolean secret;
-
- public String getType()
- {
- return type;
- }
-
- public void setType(String type)
- {
- this.type = type;
- }
-
- public boolean isInput()
- {
- return input;
- }
-
- public void setInput(boolean input)
- {
- this.input = input;
- }
-
- public boolean isSecret()
- {
- return secret;
- }
-
- public void setSecret(boolean secret)
- {
- this.secret = secret;
- }
+public class RequiredCredentialModel {
+ protected String type;
+ protected boolean input;
+ protected boolean secret;
+
+ public RequiredCredentialModel() {
+ }
+
+ public RequiredCredentialModel(String type, boolean input, boolean secret) {
+ this.type = type;
+ this.input = input;
+ this.secret = secret;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public boolean isInput() {
+ return input;
+ }
+
+ public void setInput(boolean input) {
+ this.input = input;
+ }
+
+ public boolean isSecret() {
+ return secret;
+ }
+
+ public void setSecret(boolean secret) {
+ this.secret = secret;
+ }
+
+ public static final RequiredCredentialModel PASSWORD = new RequiredCredentialModel(RequiredCredentialRepresentation.PASSWORD, true, true);
}
diff --git a/services/src/main/java/org/keycloak/services/models/ResourceModel.java b/services/src/main/java/org/keycloak/services/models/ResourceModel.java
index b41edd6..cb343b0 100755
--- a/services/src/main/java/org/keycloak/services/models/ResourceModel.java
+++ b/services/src/main/java/org/keycloak/services/models/ResourceModel.java
@@ -1,8 +1,9 @@
package org.keycloak.services.models;
+import org.keycloak.services.models.relationships.ResourceRelationship;
import org.keycloak.services.models.relationships.ScopeRelationship;
+import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.IdentityManager;
-import org.picketlink.idm.internal.IdentityManagerFactory;
import org.picketlink.idm.model.Agent;
import org.picketlink.idm.model.Attribute;
import org.picketlink.idm.model.Grant;
@@ -20,112 +21,94 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class ResourceModel
-{
- public static final String RESOURCE_AGENT_ID = "_resource_";
- public static final String RESOURCE_NAME = "name";
- public static final String RESOURCE_SURROGATE_AUTH = "surrogate_auth";
-
- protected Tier tier;
- protected Agent agent;
- protected RealmModel realm;
- protected IdentityManagerFactory factory;
-
- public ResourceModel(Tier tier, Agent agent, RealmModel realm, IdentityManagerFactory factory)
- {
- this.tier = tier;
- this.agent = agent;
- this.realm = realm;
- this.factory = factory;
- }
-
- public IdentityManager getIdm()
- {
- return factory.createIdentityManager(tier);
- }
-
- public void updateResource()
- {
- getIdm().update(agent);
- }
-
- public String getId()
- {
- return tier.getId();
- }
-
- public String getName()
- {
- return (String)agent.getAttribute(RESOURCE_NAME).getValue();
- }
-
- public void setName(String name)
- {
- agent.setAttribute(new Attribute<String>(RESOURCE_NAME, name));
- getIdm().update(agent);
- }
-
- public boolean isEnabled()
- {
- return agent.isEnabled();
- }
-
- public void setEnabled(boolean enabled)
- {
- agent.setEnabled(enabled);
- }
-
- public boolean isSurrogateAuthRequired()
- {
- return (Boolean)agent.getAttribute(RESOURCE_SURROGATE_AUTH).getValue();
- }
-
- public void setSurrogateAuthRequired(boolean surrogateAuthRequired)
- {
- agent.setAttribute(new Attribute<Boolean>(RESOURCE_SURROGATE_AUTH, surrogateAuthRequired));
- }
-
- public List<Role> getRoles()
- {
- IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
- query.setParameter(Role.PARTITION, tier);
- return query.getResultList();
- }
-
- public Set<String> getRoleMappings(User user)
- {
- RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
- query.setParameter(Grant.ASSIGNEE, user);
- List<Grant> grants = query.getResultList();
- HashSet<String> set = new HashSet<String>();
- for (Grant grant : grants)
- {
- if (grant.getRole().getPartition().getId().equals(tier.getId()))set.add(grant.getRole().getName());
- }
- return set;
- }
-
- public void addScope(Agent agent, String roleName)
- {
- IdentityManager idm = getIdm();
- Role role = idm.getRole(roleName);
- if (role == null) throw new RuntimeException("role not found");
- ScopeRelationship scope = new ScopeRelationship();
- scope.setClient(agent);
- scope.setScope(role);
-
- }
-
- public Set<String> getScope(Agent agent)
- {
- RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
- query.setParameter(ScopeRelationship.CLIENT, agent);
- List<ScopeRelationship> scope = query.getResultList();
- HashSet<String> set = new HashSet<String>();
- for (ScopeRelationship rel : scope)
- {
- if (rel.getScope().getPartition().getId().equals(tier.getId())) set.add(rel.getScope().getName());
- }
- return set;
- }
+public class ResourceModel {
+ public static final String RESOURCE_AGENT_ID = "_resource_";
+ public static final String RESOURCE_NAME = "name";
+ public static final String RESOURCE_SURROGATE_AUTH = "surrogate_auth";
+
+ protected Tier tier;
+ protected ResourceRelationship agent;
+ protected RealmModel realm;
+ protected IdentitySession IdentitySession;
+
+ public ResourceModel(Tier tier, ResourceRelationship agent, RealmModel realm, IdentitySession factory) {
+ this.tier = tier;
+ this.agent = agent;
+ this.realm = realm;
+ this.IdentitySession = factory;
+ }
+
+ public IdentityManager getIdm() {
+ return IdentitySession.createIdentityManager(tier);
+ }
+
+ public void updateResource() {
+ getIdm().update(agent);
+ }
+
+ public String getId() {
+ return tier.getId();
+ }
+
+ public String getName() {
+ return agent.getResourceName();
+ }
+
+ public void setName(String name) {
+ agent.setResourceName(name);
+ }
+
+ public boolean isEnabled() {
+ return agent.getEnabled();
+ }
+
+ public void setEnabled(boolean enabled) {
+ agent.setEnabled(enabled);
+ }
+
+ public boolean isSurrogateAuthRequired() {
+ return agent.getSurrogateAuthRequired();
+ }
+
+ public void setSurrogateAuthRequired(boolean surrogateAuthRequired) {
+ agent.setSurrogateAuthRequired(surrogateAuthRequired);
+ }
+
+ public List<Role> getRoles() {
+ IdentityQuery<Role> query = getIdm().createIdentityQuery(Role.class);
+ query.setParameter(Role.PARTITION, tier);
+ return query.getResultList();
+ }
+
+ public Set<String> getRoleMappings(User user) {
+ RelationshipQuery<Grant> query = getIdm().createRelationshipQuery(Grant.class);
+ query.setParameter(Grant.ASSIGNEE, user);
+ List<Grant> grants = query.getResultList();
+ HashSet<String> set = new HashSet<String>();
+ for (Grant grant : grants) {
+ if (grant.getRole().getPartition().getId().equals(tier.getId())) set.add(grant.getRole().getName());
+ }
+ return set;
+ }
+
+ public void addScope(Agent agent, String roleName) {
+ IdentityManager idm = getIdm();
+ Role role = idm.getRole(roleName);
+ if (role == null) throw new RuntimeException("role not found");
+ ScopeRelationship scope = new ScopeRelationship();
+ scope.setClient(agent);
+ scope.setScope(role);
+
+ }
+
+ public Set<String> getScope(Agent agent) {
+ RelationshipQuery<ScopeRelationship> query = getIdm().createRelationshipQuery(ScopeRelationship.class);
+ query.setParameter(ScopeRelationship.CLIENT, agent);
+ List<ScopeRelationship> scope = query.getResultList();
+ HashSet<String> set = new HashSet<String>();
+ for (ScopeRelationship rel : scope) {
+ if (rel.getScope().getPartition().getId().equals(tier.getId())) set.add(rel.getScope().getName());
+ }
+ return set;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java b/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java
index e2a3603..5807319 100755
--- a/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java
+++ b/services/src/main/java/org/keycloak/services/models/UserCredentialModel.java
@@ -4,29 +4,24 @@ package org.keycloak.services.models;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class UserCredentialModel
-{
+public class UserCredentialModel {
- protected String type;
- protected String value;
+ protected String type;
+ protected String value;
- public String getType()
- {
- return type;
- }
+ public String getType() {
+ return type;
+ }
- public void setType(String type)
- {
- this.type = type;
- }
+ public void setType(String type) {
+ this.type = type;
+ }
- public String getValue()
- {
- return value;
- }
+ public String getValue() {
+ return value;
+ }
- public void setValue(String value)
- {
- this.value = value;
- }
+ public void setValue(String value) {
+ this.value = value;
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
new file mode 100755
index 0000000..3af3e9c
--- /dev/null
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -0,0 +1,90 @@
+package org.keycloak.services.resources;
+
+import org.keycloak.SkeletonKeyContextResolver;
+import org.keycloak.services.filters.IdentitySessionFilter;
+import org.keycloak.services.models.relationships.RealmAdminRelationship;
+import org.keycloak.services.models.relationships.ResourceRelationship;
+import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
+import org.keycloak.services.models.relationships.ScopeRelationship;
+import org.picketlink.idm.IdentitySessionFactory;
+import org.picketlink.idm.config.IdentityConfiguration;
+import org.picketlink.idm.config.IdentityConfigurationBuilder;
+import org.picketlink.idm.internal.DefaultIdentitySessionFactory;
+import org.picketlink.idm.jpa.internal.ResourceLocalJpaIdentitySessionHandler;
+import org.picketlink.idm.jpa.schema.CredentialObject;
+import org.picketlink.idm.jpa.schema.CredentialObjectAttribute;
+import org.picketlink.idm.jpa.schema.IdentityObject;
+import org.picketlink.idm.jpa.schema.IdentityObjectAttribute;
+import org.picketlink.idm.jpa.schema.PartitionObject;
+import org.picketlink.idm.jpa.schema.RelationshipIdentityObject;
+import org.picketlink.idm.jpa.schema.RelationshipObject;
+import org.picketlink.idm.jpa.schema.RelationshipObjectAttribute;
+
+import javax.annotation.PreDestroy;
+import javax.ws.rs.core.Application;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakApplication extends Application {
+ protected Set<Object> singletons = new HashSet<Object>();
+ protected Set<Class<?>> classes = new HashSet<Class<?>>();
+
+ protected IdentitySessionFactory factory;
+
+ public KeycloakApplication() {
+ this.factory = createFactory();
+ IdentitySessionFilter filter = new IdentitySessionFilter(factory);
+ singletons.add(new RealmsResource());
+ singletons.add(filter);
+ classes.add(SkeletonKeyContextResolver.class);
+ classes.add(RegistrationService.class);
+ }
+
+ public IdentitySessionFactory getFactory() {
+ return factory;
+ }
+
+ @PreDestroy
+ public void destroy() {
+ factory.close();
+ }
+
+ public static IdentitySessionFactory createFactory() {
+ ResourceLocalJpaIdentitySessionHandler handler = new ResourceLocalJpaIdentitySessionHandler("keycloak-identity-store");
+ IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
+
+ builder
+ .stores()
+ .jpa()
+ .identityClass(IdentityObject.class)
+ .attributeClass(IdentityObjectAttribute.class)
+ .relationshipClass(RelationshipObject.class)
+ .relationshipIdentityClass(RelationshipIdentityObject.class)
+ .relationshipAttributeClass(RelationshipObjectAttribute.class)
+ .credentialClass(CredentialObject.class)
+ .credentialAttributeClass(CredentialObjectAttribute.class)
+ .partitionClass(PartitionObject.class)
+ .supportAllFeatures()
+ .supportRelationshipType(RealmAdminRelationship.class, ResourceRelationship.class, RequiredCredentialRelationship.class, ScopeRelationship.class)
+ .setIdentitySessionHandler(handler);
+
+ IdentityConfiguration build = builder.build();
+ return new DefaultIdentitySessionFactory(build);
+ }
+
+
+ @Override
+ public Set<Class<?>> getClasses() {
+ return classes;
+ }
+
+ @Override
+ public Set<Object> getSingletons() {
+ return singletons;
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/services/resources/RegistrationService.java b/services/src/main/java/org/keycloak/services/resources/RegistrationService.java
index c4c9b05..55c576c 100755
--- a/services/src/main/java/org/keycloak/services/resources/RegistrationService.java
+++ b/services/src/main/java/org/keycloak/services/resources/RegistrationService.java
@@ -1,15 +1,17 @@
package org.keycloak.services.resources;
+import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.idm.UserRepresentation;
import org.keycloak.services.models.RealmManager;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.UserCredentialModel;
-import org.picketlink.idm.model.Realm;
+import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.SimpleUser;
import org.picketlink.idm.model.User;
import javax.ws.rs.Consumes;
+import javax.ws.rs.ForbiddenException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
@@ -23,47 +25,53 @@ import java.net.URI;
* @version $Revision: 1 $
*/
@Path("/registrations")
-public class RegistrationService
-{
- public static final String REALM_CREATOR_ROLE = "realm-creator";
- protected RealmManager adapter;
- protected RealmModel defaultRealm;
+public class RegistrationService {
+ protected static final Logger logger = Logger.getLogger(RegistrationService.class);
+ public static final String REALM_CREATOR_ROLE = "realm-creator";
- @Context
- protected UriInfo uriInfo;
+ @Context
+ protected UriInfo uriInfo;
- public RegistrationService(RealmManager adapter)
- {
- this.adapter = adapter;
- defaultRealm = adapter.getRealm(Realm.DEFAULT_REALM);
- }
+ @Context
+ protected IdentitySession identitySession;
+ @POST
+ @Consumes(MediaType.APPLICATION_JSON)
+ public Response register(UserRepresentation newUser) {
+ identitySession.getTransaction().begin();
+ try {
+ RealmManager realmManager = new RealmManager(identitySession);
+ RealmModel defaultRealm = realmManager.defaultRealm();
+ if (!defaultRealm.isEnabled()) {
+ throw new ForbiddenException();
+ }
+ if (!defaultRealm.isRegistrationAllowed()) {
+ throw new ForbiddenException();
+ }
+ User user = defaultRealm.getIdm().getUser(newUser.getUsername());
+ if (user != null) {
+ return Response.status(400).type("text/plain").entity("user exists").build();
+ }
-
- @POST
- @Consumes(MediaType.APPLICATION_JSON)
- public Response register(UserRepresentation newUser)
- {
- User user = defaultRealm.getIdm().getUser(newUser.getUsername());
- if (user != null)
- {
- return Response.status(400).type("text/plain").entity("user exists").build();
- }
-
- user = new SimpleUser(newUser.getUsername());
- defaultRealm.getIdm().add(user);
- for (UserRepresentation.Credential cred : newUser.getCredentials())
- {
- UserCredentialModel credModel = new UserCredentialModel();
- credModel.setType(cred.getType());
- credModel.setValue(cred.getValue());
- defaultRealm.updateCredential(user, credModel);
- }
- Role realmCreator = defaultRealm.getIdm().getRole(REALM_CREATOR_ROLE);
- defaultRealm.getIdm().grantRole(user, realmCreator);
- URI uri = uriInfo.getBaseUriBuilder().path(RealmFactory.class).path(user.getLoginName()).build();
- return Response.created(uri).build();
- }
+ user = new SimpleUser(newUser.getUsername());
+ defaultRealm.getIdm().add(user);
+ for (UserRepresentation.Credential cred : newUser.getCredentials()) {
+ UserCredentialModel credModel = new UserCredentialModel();
+ credModel.setType(cred.getType());
+ credModel.setValue(cred.getValue());
+ defaultRealm.updateCredential(user, credModel);
+ }
+ Role realmCreator = defaultRealm.getIdm().getRole(REALM_CREATOR_ROLE);
+ defaultRealm.getIdm().grantRole(user, realmCreator);
+ identitySession.getTransaction().commit();
+ URI uri = uriInfo.getBaseUriBuilder().path(RealmsResource.class).path(user.getLoginName()).build();
+ return Response.created(uri).build();
+ } catch (RuntimeException e) {
+ logger.error("Failed to register", e);
+ identitySession.getTransaction().rollback();
+ throw e;
+ }
+ }
}
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index ebdf2a9..d77339d 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -9,21 +9,21 @@ import org.jboss.resteasy.logging.Logger;
import org.keycloak.representations.AccessTokenResponse;
import org.keycloak.representations.SkeletonKeyScope;
import org.keycloak.representations.SkeletonKeyToken;
+import org.keycloak.services.managers.AccessCodeEntry;
import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.managers.TokenManager;
import org.keycloak.services.models.RealmManager;
import org.keycloak.services.models.RealmModel;
import org.keycloak.services.models.RequiredCredentialModel;
import org.keycloak.services.models.ResourceModel;
+import org.picketlink.idm.IdentitySession;
import org.picketlink.idm.model.User;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.NotAuthorizedException;
-import javax.ws.rs.NotFoundException;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
-import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
@@ -41,555 +41,400 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.atomic.AtomicLong;
/**
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-@Path("/realms")
-public class TokenService
-{
- public static class AccessCode
- {
- protected String id = UUID.randomUUID().toString() + System.currentTimeMillis();
- protected long expiration;
- protected SkeletonKeyToken token;
- protected User client;
-
- public boolean isExpired()
- {
- return expiration != 0 && (System.currentTimeMillis() / 1000) > expiration;
- }
-
- public String getId()
- {
- return id;
- }
-
- public long getExpiration()
- {
- return expiration;
- }
-
- public void setExpiration(long expiration)
- {
- this.expiration = expiration;
- }
-
- public SkeletonKeyToken getToken()
- {
- return token;
- }
-
- public void setToken(SkeletonKeyToken token)
- {
- this.token = token;
- }
-
- public User getClient()
- {
- return client;
- }
-
- public void setClient(User client)
- {
- this.client = client;
- }
- }
-
- protected RealmManager adapter;
- protected TokenManager tokenManager;
- protected AuthenticationManager authManager;
- protected Logger logger = Logger.getLogger(TokenService.class);
- protected Map<String, AccessCode> accessCodeMap = new HashMap<String, AccessCode>();
- @Context
- protected UriInfo uriInfo;
- @Context
- protected Providers providers;
- @Context
- protected SecurityContext securityContext;
- @Context
- protected HttpHeaders headers;
-
- private static AtomicLong counter = new AtomicLong(1);
- private static String generateId()
- {
- return counter.getAndIncrement() + "." + UUID.randomUUID().toString();
- }
-
- public TokenService(RealmManager adapter)
- {
- this.adapter = adapter;
- this.tokenManager = new TokenManager(adapter);
- this.authManager = new AuthenticationManager(adapter);
- }
-
- @Path("{realm}/grants/identity-token")
- @POST
- @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- @Produces(MediaType.APPLICATION_JSON)
- public Response identityTokenGrant(@PathParam("realm") String realmId, MultivaluedMap<String, String> form)
- {
- String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
- if (username == null)
- {
- throw new NotAuthorizedException("No user");
- }
- RealmModel realm = adapter.getRealm(realmId);
- if (realm == null)
- {
- throw new NotFoundException("Realm not found");
- }
- if (!realm.isEnabled())
- {
- throw new NotAuthorizedException("Disabled realm");
- }
- User user = realm.getIdm().getUser(username);
- if (user == null)
- {
- throw new NotAuthorizedException("No user");
- }
- if (!user.isEnabled())
- {
- throw new NotAuthorizedException("Disabled user.");
- }
- SkeletonKeyToken token = tokenManager.createIdentityToken(realm, username);
- String encoded = tokenManager.encodeToken(realm, token);
- AccessTokenResponse res = accessTokenResponse(token, encoded);
- return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
- }
-
- @Path("{realm}/grants/access")
- @POST
- @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- @Produces(MediaType.APPLICATION_JSON)
- public Response accessTokenGrant(@PathParam("realm") String realmId, MultivaluedMap<String, String> form)
- {
- String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
- if (username == null)
- {
- throw new NotAuthorizedException("No user");
- }
- RealmModel realm = adapter.getRealm(realmId);
- if (realm == null)
- {
- throw new NotFoundException("Realm not found");
- }
- if (!realm.isEnabled())
- {
- throw new NotAuthorizedException("Disabled realm");
- }
- User user = realm.getIdm().getUser(username);
- if (user == null)
- {
- throw new NotAuthorizedException("No user");
- }
- if (!user.isEnabled())
- {
- throw new NotAuthorizedException("Disabled user.");
- }
- if (authManager.authenticateForm(realm, user, form))
- {
- throw new NotAuthorizedException("Auth failed");
- }
- SkeletonKeyToken token = tokenManager.createAccessToken(realm, user);
- String encoded = tokenManager.encodeToken(realm, token);
- AccessTokenResponse res = accessTokenResponse(token, encoded);
- return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
- }
-
- @Path("{realm}/auth/request/login")
- @POST
- @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
- public Response login(@PathParam("realm") String realmId,
- MultivaluedMap<String, String> formData)
- {
- String clientId = formData.getFirst("client_id");
- String scopeParam = formData.getFirst("scope");
- String state = formData.getFirst("state");
- String redirect = formData.getFirst("redirect_uri");
-
- RealmModel realm = adapter.getRealm(realmId);
- if (realm == null)
- {
- throw new NotFoundException("Realm not found");
- }
- if (!realm.isEnabled())
- {
- return Response.ok("Realm not enabled").type("text/html").build();
- }
- User client = realm.getIdm().getUser(clientId);
- if (client == null)
- {
- throw new NotAuthorizedException("No client");
- }
- if (!client.isEnabled())
- {
- return Response.ok("Requester not enabled").type("text/html").build();
- }
- String username = formData.getFirst("username");
- User user = realm.getIdm().getUser(username);
- if (user == null)
- {
- logger.debug("user not found");
- return loginForm("Not valid user", redirect, clientId, scopeParam, state, realm, client);
- }
- if (!user.isEnabled())
- {
- return Response.ok("Your account is not enabled").type("text/html").build();
-
- }
- boolean authenticated = authManager.authenticateForm(realm, user, formData);
- if (!authenticated) return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client);
-
- SkeletonKeyToken token = null;
- if (scopeParam != null) token = tokenManager.createScopedToken(scopeParam, realm, client, user);
- else token = tokenManager.createLoginToken(realm, client, user);
-
- AccessCode code = new AccessCode();
- code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
- code.setToken(token);
- code.setClient(client);
- synchronized (accessCodeMap)
- {
- accessCodeMap.put(code.getId(), code);
- }
- String accessCode = null;
- try
- {
- accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey());
- }
- catch (UnsupportedEncodingException e)
- {
- throw new RuntimeException(e);
- }
- UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode);
- if (state != null) redirectUri.queryParam("state", state);
- return Response.status(302).location(redirectUri.build()).build();
- }
-
- @Path("{realm}/access/codes")
- @POST
- @Produces("application/json")
- public Response accessRequest(@PathParam("realm") String realmId,
- MultivaluedMap<String, String> formData)
- {
- RealmModel realm = adapter.getRealm(realmId);
- if (realm == null)
- {
- throw new NotFoundException("Realm not found");
- }
- if (!realm.isEnabled())
- {
- throw new NotAuthorizedException("Realm not enabled");
- }
-
- String code = formData.getFirst("code");
- if (code == null)
- {
- logger.debug("code not specified");
- Map<String, String> error = new HashMap<String, String>();
- error.put("error", "invalid_request");
- error.put("error_description", "code not specified");
- return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
-
- }
- String client_id = formData.getFirst("client_id");
- if (client_id == null)
- {
- logger.debug("client_id not specified");
- Map<String, String> error = new HashMap<String, String>();
- error.put("error", "invalid_request");
- error.put("error_description", "client_id not specified");
- return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
- }
- User client = realm.getIdm().getUser(client_id);
- if (client == null)
- {
- logger.debug("Could not find user");
- Map<String, String> error = new HashMap<String, String>();
- error.put("error", "invalid_client");
- error.put("error_description", "Could not find user");
- return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
- }
-
- if (!client.isEnabled())
- {
- logger.debug("user is not enabled");
- Map<String, String> error = new HashMap<String, String>();
- error.put("error", "invalid_client");
- error.put("error_description", "User is not enabled");
- return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
- }
-
- boolean authenticated = authManager.authenticateForm(realm, client, formData);
- if (!authenticated)
- {
- Map<String, String> error = new HashMap<String, String>();
- error.put("error", "unauthorized_client");
- return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
- }
-
-
-
- JWSInput input = new JWSInput(code, providers);
- boolean verifiedCode = false;
- try
- {
- verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
- }
- catch (Exception ignored)
- {
- logger.debug("Failed to verify signature", ignored);
- }
- if (!verifiedCode)
- {
- Map<String, String> res = new HashMap<String, String>();
- res.put("error", "invalid_grant");
- res.put("error_description", "Unable to verify code signature");
- return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
- }
- String key = input.readContent(String.class);
- AccessCode accessCode = null;
- synchronized (accessCodeMap)
- {
- accessCode = accessCodeMap.remove(key);
- }
- if (accessCode == null)
- {
- Map<String, String> res = new HashMap<String, String>();
- res.put("error", "invalid_grant");
- res.put("error_description", "Code not found");
- return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
- }
- if (accessCode.isExpired())
- {
- Map<String, String> res = new HashMap<String, String>();
- res.put("error", "invalid_grant");
- res.put("error_description", "Code is expired");
- return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
- }
- if (!accessCode.getToken().isActive())
- {
- Map<String, String> res = new HashMap<String, String>();
- res.put("error", "invalid_grant");
- res.put("error_description", "Token expired");
- return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
- }
- if (!client.getId().equals(accessCode.getClient().getId()))
- {
- Map<String, String> res = new HashMap<String, String>();
- res.put("error", "invalid_grant");
- res.put("error_description", "Auth error");
- return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
- }
- AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
- return Response.ok(res).build();
-
- }
-
- protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token)
- {
- byte[] tokenBytes = null;
- try
- {
- tokenBytes = JsonSerialization.toByteArray(token, false);
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- String encodedToken = new JWSBuilder()
- .content(tokenBytes)
- .rsa256(privateKey);
-
- return accessTokenResponse(token, encodedToken);
- }
-
- protected AccessTokenResponse accessTokenResponse(SkeletonKeyToken token, String encodedToken)
- {
- AccessTokenResponse res = new AccessTokenResponse();
- res.setToken(encodedToken);
- res.setTokenType("bearer");
- if (token.getExpiration() != 0)
- {
- long time = token.getExpiration() - (System.currentTimeMillis() / 1000);
- res.setExpiresIn(time);
- }
- return res;
- }
-
- @Path("{realm}/auth/request")
- @GET
- public Response requestAccessCode(@PathParam("realm") String realmId,
- @QueryParam("response_type") String responseType,
- @QueryParam("redirect_uri") String redirect,
- @QueryParam("client_id") String clientId,
- @QueryParam("scope") String scopeParam,
- @QueryParam("state") String state)
- {
- RealmModel realm = adapter.getRealm(realmId);
- if (realm == null)
- {
- throw new NotFoundException("Realm not found");
- }
- if (!realm.isEnabled())
- {
- throw new NotAuthorizedException("Realm not enabled");
- }
- User client = realm.getIdm().getUser(clientId);
- if (client == null)
- return Response.ok("<h1>Security Alert</h1><p>Unknown client trying to get access to your account.</p>").type("text/html").build();
-
- return loginForm(null, redirect, clientId, scopeParam, state, realm, client);
- }
-
- private Response loginForm(String validationError, String redirect, String clientId, String scopeParam, String state, RealmModel realm, User client)
- {
- StringBuffer html = new StringBuffer();
- if (scopeParam != null)
- {
- html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
- if (validationError != null)
- {
- try
- {
- Thread.sleep(1000); // put in a delay
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
- html.append("<p/><p><b>").append(validationError).append("</b></p>");
- }
- html.append("<p>A Third Party is requesting access to the following resources</p>");
- html.append("<table>");
- SkeletonKeyScope scope = tokenManager.decodeScope(scopeParam);
- Map<String, ResourceModel> resourceMap = realm.getResourceMap();
-
- for (String res : scope.keySet())
- {
- ResourceModel resource = resourceMap.get(res);
- html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
- Set<String> scopeMapping = resource.getScope(client);
- for (String role : scope.get(res))
- {
- html.append(" ").append(role);
- if (!scopeMapping.contains("*") && !scopeMapping.contains(role))
- {
- return Response.ok("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build();
- }
- }
- html.append("</td></tr>");
- }
- html.append("</table><p>To Authorize, please login below</p>");
- }
- else
- {
- Set<String> scopeMapping = realm.getScope(client);
- if (scopeMapping.contains("*"))
- {
- html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>");
- if (validationError != null)
- {
- try
- {
- Thread.sleep(1000); // put in a delay
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
- html.append("<p/><p><b>").append(validationError).append("</b></p>");
- }
- }
- else
- {
+public class TokenService {
+
+
+ protected static final Logger logger = Logger.getLogger(TokenService.class);
+ protected Map<String, AccessCodeEntry> accessCodeMap;
+
+ @Context
+ protected UriInfo uriInfo;
+ @Context
+ protected Providers providers;
+ @Context
+ protected SecurityContext securityContext;
+ @Context
+ protected HttpHeaders headers;
+ @Context
+ protected
+ IdentitySession IdentitySession;
+
+ protected RealmModel realm;
+ protected TokenManager tokenManager = new TokenManager();
+ protected AuthenticationManager authManager = new AuthenticationManager();
+
+ public TokenService(RealmModel realm, Map<String, AccessCodeEntry> accessCodeMap) {
+ this.realm = realm;
+ this.accessCodeMap = accessCodeMap;
+ }
+
+ @Path("grants/identity-token")
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response identityTokenGrant(MultivaluedMap<String, String> form) {
+ String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
+ if (username == null) {
+ throw new NotAuthorizedException("No user");
+ }
+ if (!realm.isEnabled()) {
+ throw new NotAuthorizedException("Disabled realm");
+ }
+ User user = realm.getIdm().getUser(username);
+ if (user == null) {
+ throw new NotAuthorizedException("No user");
+ }
+ if (!user.isEnabled()) {
+ throw new NotAuthorizedException("Disabled user.");
+ }
+ if (!authManager.authenticateForm(realm, user, form)) {
+ throw new NotAuthorizedException("FORM");
+ }
+ tokenManager = new TokenManager();
+ SkeletonKeyToken token = tokenManager.createIdentityToken(realm, username);
+ String encoded = tokenManager.encodeToken(realm, token);
+ AccessTokenResponse res = accessTokenResponse(token, encoded);
+ return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
+ }
+
+ @Path("grants/access")
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ @Produces(MediaType.APPLICATION_JSON)
+ public Response accessTokenGrant(MultivaluedMap<String, String> form) {
+ String username = form.getFirst(AuthenticationManager.FORM_USERNAME);
+ if (username == null) {
+ throw new NotAuthorizedException("No user");
+ }
+ if (!realm.isEnabled()) {
+ throw new NotAuthorizedException("Disabled realm");
+ }
+ User user = realm.getIdm().getUser(username);
+ if (user == null) {
+ throw new NotAuthorizedException("No user");
+ }
+ if (!user.isEnabled()) {
+ throw new NotAuthorizedException("Disabled user.");
+ }
+ if (authManager.authenticateForm(realm, user, form)) {
+ throw new NotAuthorizedException("Auth failed");
+ }
+ SkeletonKeyToken token = tokenManager.createAccessToken(realm, user);
+ String encoded = tokenManager.encodeToken(realm, token);
+ AccessTokenResponse res = accessTokenResponse(token, encoded);
+ return Response.ok(res, MediaType.APPLICATION_JSON_TYPE).build();
+ }
+
+ @Path("auth/request/login")
+ @POST
+ @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
+ public Response login(MultivaluedMap<String, String> formData) {
+ String clientId = formData.getFirst("client_id");
+ String scopeParam = formData.getFirst("scope");
+ String state = formData.getFirst("state");
+ String redirect = formData.getFirst("redirect_uri");
+
+ if (!realm.isEnabled()) {
+ return Response.ok("Realm not enabled").type("text/html").build();
+ }
+ User client = realm.getIdm().getUser(clientId);
+ if (client == null) {
+ throw new NotAuthorizedException("No client");
+ }
+ if (!client.isEnabled()) {
+ return Response.ok("Requester not enabled").type("text/html").build();
+ }
+ String username = formData.getFirst("username");
+ User user = realm.getIdm().getUser(username);
+ if (user == null) {
+ logger.debug("user not found");
+ return loginForm("Not valid user", redirect, clientId, scopeParam, state, realm, client);
+ }
+ if (!user.isEnabled()) {
+ return Response.ok("Your account is not enabled").type("text/html").build();
+
+ }
+ boolean authenticated = authManager.authenticateForm(realm, user, formData);
+ if (!authenticated)
+ return loginForm("Unable to authenticate, try again", redirect, clientId, scopeParam, state, realm, client);
+
+ SkeletonKeyToken token = null;
+ if (scopeParam != null) token = tokenManager.createScopedToken(scopeParam, realm, client, user);
+ else token = tokenManager.createLoginToken(realm, client, user);
+
+ AccessCodeEntry code = new AccessCodeEntry();
+ code.setExpiration((System.currentTimeMillis() / 1000) + realm.getAccessCodeLifespan());
+ code.setToken(token);
+ code.setClient(client);
+ synchronized (accessCodeMap) {
+ accessCodeMap.put(code.getId(), code);
+ }
+ String accessCode = null;
+ try {
+ accessCode = new JWSBuilder().content(code.getId().getBytes("UTF-8")).rsa256(realm.getPrivateKey());
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ UriBuilder redirectUri = UriBuilder.fromUri(redirect).queryParam("code", accessCode);
+ if (state != null) redirectUri.queryParam("state", state);
+ return Response.status(302).location(redirectUri.build()).build();
+ }
+
+ @Path("access/codes")
+ @POST
+ @Produces("application/json")
+ public Response accessRequest(MultivaluedMap<String, String> formData) {
+ if (!realm.isEnabled()) {
+ throw new NotAuthorizedException("Realm not enabled");
+ }
+
+ String code = formData.getFirst("code");
+ if (code == null) {
+ logger.debug("code not specified");
+ Map<String, String> error = new HashMap<String, String>();
+ error.put("error", "invalid_request");
+ error.put("error_description", "code not specified");
+ return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+
+ }
+ String client_id = formData.getFirst("client_id");
+ if (client_id == null) {
+ logger.debug("client_id not specified");
+ Map<String, String> error = new HashMap<String, String>();
+ error.put("error", "invalid_request");
+ error.put("error_description", "client_id not specified");
+ return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+ }
+ User client = realm.getIdm().getUser(client_id);
+ if (client == null) {
+ logger.debug("Could not find user");
+ Map<String, String> error = new HashMap<String, String>();
+ error.put("error", "invalid_client");
+ error.put("error_description", "Could not find user");
+ return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+ }
+
+ if (!client.isEnabled()) {
+ logger.debug("user is not enabled");
+ Map<String, String> error = new HashMap<String, String>();
+ error.put("error", "invalid_client");
+ error.put("error_description", "User is not enabled");
+ return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+ }
+
+ boolean authenticated = authManager.authenticateForm(realm, client, formData);
+ if (!authenticated) {
+ Map<String, String> error = new HashMap<String, String>();
+ error.put("error", "unauthorized_client");
+ return Response.status(Response.Status.BAD_REQUEST).entity(error).type("application/json").build();
+ }
+
+
+ JWSInput input = new JWSInput(code, providers);
+ boolean verifiedCode = false;
+ try {
+ verifiedCode = RSAProvider.verify(input, realm.getPublicKey());
+ } catch (Exception ignored) {
+ logger.debug("Failed to verify signature", ignored);
+ }
+ if (!verifiedCode) {
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Unable to verify code signature");
+ return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+ }
+ String key = input.readContent(String.class);
+ AccessCodeEntry accessCode = null;
+ synchronized (accessCodeMap) {
+ accessCode = accessCodeMap.remove(key);
+ }
+ if (accessCode == null) {
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Code not found");
+ return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+ }
+ if (accessCode.isExpired()) {
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Code is expired");
+ return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+ }
+ if (!accessCode.getToken().isActive()) {
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Token expired");
+ return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+ }
+ if (!client.getId().equals(accessCode.getClient().getId())) {
+ Map<String, String> res = new HashMap<String, String>();
+ res.put("error", "invalid_grant");
+ res.put("error_description", "Auth error");
+ return Response.status(Response.Status.BAD_REQUEST).type(MediaType.APPLICATION_JSON_TYPE).entity(res).build();
+ }
+ AccessTokenResponse res = accessTokenResponse(realm.getPrivateKey(), accessCode.getToken());
+ return Response.ok(res).build();
+
+ }
+
+ protected AccessTokenResponse accessTokenResponse(PrivateKey privateKey, SkeletonKeyToken token) {
+ byte[] tokenBytes = null;
+ try {
+ tokenBytes = JsonSerialization.toByteArray(token, false);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ String encodedToken = new JWSBuilder()
+ .content(tokenBytes)
+ .rsa256(privateKey);
+
+ return accessTokenResponse(token, encodedToken);
+ }
+
+ protected AccessTokenResponse accessTokenResponse(SkeletonKeyToken token, String encodedToken) {
+ AccessTokenResponse res = new AccessTokenResponse();
+ res.setToken(encodedToken);
+ res.setTokenType("bearer");
+ if (token.getExpiration() != 0) {
+ long time = token.getExpiration() - (System.currentTimeMillis() / 1000);
+ res.setExpiresIn(time);
+ }
+ return res;
+ }
+
+ @Path("auth/request")
+ @GET
+ public Response requestAccessCode(@QueryParam("response_type") String responseType,
+ @QueryParam("redirect_uri") String redirect,
+ @QueryParam("client_id") String clientId,
+ @QueryParam("scope") String scopeParam,
+ @QueryParam("state") String state) {
+ if (!realm.isEnabled()) {
+ throw new NotAuthorizedException("Realm not enabled");
+ }
+ User client = realm.getIdm().getUser(clientId);
+ if (client == null)
+ return Response.ok("<h1>Security Alert</h1><p>Unknown client trying to get access to your account.</p>").type("text/html").build();
+
+ return loginForm(null, redirect, clientId, scopeParam, state, realm, client);
+ }
+
+ private Response loginForm(String validationError, String redirect, String clientId, String scopeParam, String state, RealmModel realm, User client) {
+ StringBuffer html = new StringBuffer();
+ if (scopeParam != null) {
html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
- if (validationError != null)
- {
- try
- {
- Thread.sleep(1000); // put in a delay
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
- html.append("<p/><p><b>").append(validationError).append("</b></p>");
- }
- SkeletonKeyScope scope = new SkeletonKeyScope();
- List<ResourceModel> resources = realm.getResources();
- boolean found = false;
- for (ResourceModel resource : resources)
- {
- Set<String> resourceScope = resource.getScope(client);
- if (resourceScope == null) continue;
- if (resourceScope.size() == 0) continue;
- if (!found)
- {
- found = true;
- html.append("<p>A Third Party is requesting access to the following resources</p>");
- html.append("<table>");
- }
- html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
- // todo add description of role
- for (String role : resourceScope)
- {
- html.append(" ").append(role);
- scope.add(resource.getName(), role);
- }
+ if (validationError != null) {
+ try {
+ Thread.sleep(1000); // put in a delay
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ html.append("<p/><p><b>").append(validationError).append("</b></p>");
}
- if (!found)
- {
- return Response.ok("<h1>Security Alert</h1><p>Known client not authorized to access this realm.</p>").type("text/html").build();
+ html.append("<p>A Third Party is requesting access to the following resources</p>");
+ html.append("<table>");
+ SkeletonKeyScope scope = tokenManager.decodeScope(scopeParam);
+ Map<String, ResourceModel> resourceMap = realm.getResourceMap();
+
+ for (String res : scope.keySet()) {
+ ResourceModel resource = resourceMap.get(res);
+ html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
+ Set<String> scopeMapping = resource.getScope(client);
+ for (String role : scope.get(res)) {
+ html.append(" ").append(role);
+ if (!scopeMapping.contains("*") && !scopeMapping.contains(role)) {
+ return Response.ok("<h1>Security Alert</h1><p>Known client not authorized for the requested scope.</p>").type("text/html").build();
+ }
+ }
+ html.append("</td></tr>");
}
- html.append("</table>");
- try
- {
- String json = JsonSerialization.toString(scope, false);
- scopeParam = Base64Url.encode(json.getBytes("UTF-8"));
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
+ html.append("</table><p>To Authorize, please login below</p>");
+ } else {
+ Set<String> scopeMapping = realm.getScope(client);
+ if (scopeMapping.contains("*")) {
+ html.append("<h1>Login For ").append(realm.getName()).append(" Realm</h1>");
+ if (validationError != null) {
+ try {
+ Thread.sleep(1000); // put in a delay
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ html.append("<p/><p><b>").append(validationError).append("</b></p>");
+ }
+ } else {
+ html.append("<h1>Grant Request For ").append(realm.getName()).append(" Realm</h1>");
+ if (validationError != null) {
+ try {
+ Thread.sleep(1000); // put in a delay
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ html.append("<p/><p><b>").append(validationError).append("</b></p>");
+ }
+ SkeletonKeyScope scope = new SkeletonKeyScope();
+ List<ResourceModel> resources = realm.getResources();
+ boolean found = false;
+ for (ResourceModel resource : resources) {
+ Set<String> resourceScope = resource.getScope(client);
+ if (resourceScope == null) continue;
+ if (resourceScope.size() == 0) continue;
+ if (!found) {
+ found = true;
+ html.append("<p>A Third Party is requesting access to the following resources</p>");
+ html.append("<table>");
+ }
+ html.append("<tr><td><b>Resource: </b>").append(resource.getName()).append("</td><td><b>Roles:</b>");
+ // todo add description of role
+ for (String role : resourceScope) {
+ html.append(" ").append(role);
+ scope.add(resource.getName(), role);
+ }
+ }
+ if (!found) {
+ return Response.ok("<h1>Security Alert</h1><p>Known client not authorized to access this realm.</p>").type("text/html").build();
+ }
+ html.append("</table>");
+ try {
+ String json = JsonSerialization.toString(scope, false);
+ scopeParam = Base64Url.encode(json.getBytes("UTF-8"));
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
}
+ }
+
+ UriBuilder formActionUri = uriInfo.getBaseUriBuilder().path(TokenService.class).path(TokenService.class, "login");
+ String action = formActionUri.build(realm.getId()).toString();
+ html.append("<form action=\"").append(action).append("\" method=\"POST\">");
+ html.append("Username: <input type=\"text\" name=\"username\" size=\"20\"><br>");
- }
- }
-
- UriBuilder formActionUri = uriInfo.getBaseUriBuilder().path(TokenService.class).path(TokenService.class, "login");
- String action = formActionUri.build(realm.getId()).toString();
- html.append("<form action=\"").append(action).append("\" method=\"POST\">");
- html.append("Username: <input type=\"text\" name=\"username\" size=\"20\"><br>");
-
- for (RequiredCredentialModel credential : realm.getRequiredCredentials())
- {
- if (!credential.isInput()) continue;
- html.append(credential.getType()).append(": ");
- if (credential.isSecret())
- {
- html.append("<input type=\"password\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>");
-
- } else
- {
- html.append("<input type=\"text\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>");
- }
- }
- html.append("<input type=\"hidden\" name=\"client_id\" value=\"").append(clientId).append("\">");
- if (scopeParam != null)
- {
- html.append("<input type=\"hidden\" name=\"scope\" value=\"").append(scopeParam).append("\">");
- }
- if (state != null) html.append("<input type=\"hidden\" name=\"state\" value=\"").append(state).append("\">");
- html.append("<input type=\"hidden\" name=\"redirect_uri\" value=\"").append(redirect).append("\">");
- html.append("<input type=\"submit\" value=\"");
- if (scopeParam == null) html.append("Login");
- else html.append("Grant Access");
- html.append("\">");
- html.append("</form>");
- return Response.ok(html.toString()).type("text/html").build();
- }
+ for (RequiredCredentialModel credential : realm.getRequiredCredentials()) {
+ if (!credential.isInput()) continue;
+ html.append(credential.getType()).append(": ");
+ if (credential.isSecret()) {
+ html.append("<input type=\"password\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>");
+
+ } else {
+ html.append("<input type=\"text\" name=\"").append(credential.getType()).append("\" size=\"20\"><br>");
+ }
+ }
+ html.append("<input type=\"hidden\" name=\"client_id\" value=\"").append(clientId).append("\">");
+ if (scopeParam != null) {
+ html.append("<input type=\"hidden\" name=\"scope\" value=\"").append(scopeParam).append("\">");
+ }
+ if (state != null) html.append("<input type=\"hidden\" name=\"state\" value=\"").append(state).append("\">");
+ html.append("<input type=\"hidden\" name=\"redirect_uri\" value=\"").append(redirect).append("\">");
+ html.append("<input type=\"submit\" value=\"");
+ if (scopeParam == null) html.append("Login");
+ else html.append("Grant Access");
+ html.append("\">");
+ html.append("</form>");
+ return Response.ok(html.toString()).type("text/html").build();
+ }
}
diff --git a/services/src/test/java/org/keycloak/test/AdapterTest.java b/services/src/test/java/org/keycloak/test/AdapterTest.java
index 6605780..98fa18b 100755
--- a/services/src/test/java/org/keycloak/test/AdapterTest.java
+++ b/services/src/test/java/org/keycloak/test/AdapterTest.java
@@ -7,27 +7,23 @@ import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runners.MethodSorters;
import org.keycloak.representations.idm.RequiredCredentialRepresentation;
+import org.keycloak.services.managers.InstallationManager;
import org.keycloak.services.models.RealmManager;
import org.keycloak.services.models.RealmModel;
-import org.keycloak.services.models.relationships.RealmResourceRelationship;
import org.keycloak.services.models.RequiredCredentialModel;
-import org.keycloak.services.models.relationships.RequiredCredentialRelationship;
-import org.keycloak.services.models.relationships.ScopeRelationship;
import org.keycloak.services.models.UserCredentialModel;
+import org.keycloak.services.resources.KeycloakApplication;
+import org.picketlink.idm.IdentitySession;
+import org.picketlink.idm.IdentitySessionFactory;
import org.picketlink.idm.IdentityManager;
-import org.picketlink.idm.config.IdentityConfigurationBuilder;
import org.picketlink.idm.credential.Credentials;
import org.picketlink.idm.credential.Password;
import org.picketlink.idm.credential.UsernamePasswordCredentials;
-import org.picketlink.idm.file.internal.FileUtils;
-import org.picketlink.idm.internal.IdentityManagerFactory;
-import org.picketlink.idm.model.Realm;
import org.picketlink.idm.model.Role;
import org.picketlink.idm.model.SimpleRole;
import org.picketlink.idm.model.SimpleUser;
import org.picketlink.idm.model.User;
-import java.io.File;
import java.util.List;
/**
@@ -35,125 +31,108 @@ import java.util.List;
* @version $Revision: 1 $
*/
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-public class AdapterTest
-{
- private static IdentityManagerFactory factory;
- public static final String WORKING_DIRECTORY = "/tmp/keycloak";
- public RealmManager adapter;
- public RealmModel realmModel;
- @Before
- public void before() throws Exception
- {
- after();
- factory = createFactory();
- adapter = new RealmManager(factory);
- }
+public class AdapterTest {
+ private IdentitySessionFactory factory;
+ private IdentitySession IdentitySession;
+ private RealmManager adapter;
+ private RealmModel realmModel;
- private static IdentityManagerFactory createFactory() {
- IdentityConfigurationBuilder builder = new IdentityConfigurationBuilder();
+ @Before
+ public void before() throws Exception {
+ factory = KeycloakApplication.createFactory();
+ IdentitySession = factory.createIdentitySession();
+ adapter = new RealmManager(IdentitySession);
+ }
- builder
- .stores()
- .file()
- .addRealm(Realm.DEFAULT_REALM)
- .workingDirectory(WORKING_DIRECTORY)
- .preserveState(true)
- .supportAllFeatures()
- .supportRelationshipType(RealmResourceRelationship.class, RequiredCredentialRelationship.class, ScopeRelationship.class);
+ @After
+ public void after() throws Exception {
+ IdentitySession.close();
+ factory.close();
+ }
- return new IdentityManagerFactory(builder.build());
- }
+ @Test
+ public void installTest() throws Exception {
+ new InstallationManager().install(adapter);
- @After
- public void after() throws Exception
- {
- File file = new File(WORKING_DIRECTORY);
- FileUtils.delete(file);
- Thread.sleep(10); // my windows machine seems to have delays on deleting files sometimes
- }
+ }
- @Test
- public void test1CreateRealm() throws Exception
- {
- realmModel = adapter.create("JUGGLER");
- realmModel.setAccessCodeLifespan(100);
- realmModel.setCookieLoginAllowed(true);
- realmModel.setEnabled(true);
- realmModel.setName("JUGGLER");
- realmModel.setPrivateKeyPem("0234234");
- realmModel.setPublicKeyPem("0234234");
- realmModel.setTokenLifespan(1000);
- realmModel.updateRealm();
+ @Test
+ public void test1CreateRealm() throws Exception {
+ realmModel = adapter.createRealm("JUGGLER");
+ realmModel.setAccessCodeLifespan(100);
+ realmModel.setCookieLoginAllowed(true);
+ realmModel.setEnabled(true);
+ realmModel.setName("JUGGLER");
+ realmModel.setPrivateKeyPem("0234234");
+ realmModel.setPublicKeyPem("0234234");
+ realmModel.setTokenLifespan(1000);
+ realmModel.updateRealm();
- System.out.println(realmModel.getId());
- realmModel = adapter.getRealm(realmModel.getId());
- Assert.assertNotNull(realmModel);
- Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
- Assert.assertEquals(realmModel.getTokenLifespan(), 1000);
- Assert.assertEquals(realmModel.isEnabled(), true);
- Assert.assertEquals(realmModel.getName(), "JUGGLER");
- Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
- Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
- }
+ System.out.println(realmModel.getId());
+ realmModel = adapter.getRealm(realmModel.getId());
+ Assert.assertNotNull(realmModel);
+ Assert.assertEquals(realmModel.getAccessCodeLifespan(), 100);
+ Assert.assertEquals(realmModel.getTokenLifespan(), 1000);
+ Assert.assertEquals(realmModel.isEnabled(), true);
+ Assert.assertEquals(realmModel.getName(), "JUGGLER");
+ Assert.assertEquals(realmModel.getPrivateKeyPem(), "0234234");
+ Assert.assertEquals(realmModel.getPublicKeyPem(), "0234234");
+ }
- @Test
- public void test2RequiredCredential() throws Exception
- {
- test1CreateRealm();
- RequiredCredentialModel creds = new RequiredCredentialModel();
- creds.setSecret(true);
- creds.setType(RequiredCredentialRepresentation.PASSWORD);
- creds.setInput(true);
- realmModel.addRequiredCredential(creds);
- creds = new RequiredCredentialModel();
- creds.setSecret(true);
- creds.setType(RequiredCredentialRepresentation.TOTP);
- creds.setInput(true);
- realmModel.addRequiredCredential(creds);
- List<RequiredCredentialModel> storedCreds = realmModel.getRequiredCredentials();
- Assert.assertEquals(2, storedCreds.size());
- boolean totp = false;
- boolean password = false;
- for (RequiredCredentialModel cred : storedCreds)
- {
- if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) password = true;
- else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) totp = true;
- }
- Assert.assertTrue(totp);
- Assert.assertTrue(password);
- }
+ @Test
+ public void test2RequiredCredential() throws Exception {
+ test1CreateRealm();
+ RequiredCredentialModel creds = new RequiredCredentialModel();
+ creds.setSecret(true);
+ creds.setType(RequiredCredentialRepresentation.PASSWORD);
+ creds.setInput(true);
+ realmModel.addRequiredCredential(creds);
+ creds = new RequiredCredentialModel();
+ creds.setSecret(true);
+ creds.setType(RequiredCredentialRepresentation.TOTP);
+ creds.setInput(true);
+ realmModel.addRequiredCredential(creds);
+ List<RequiredCredentialModel> storedCreds = realmModel.getRequiredCredentials();
+ Assert.assertEquals(2, storedCreds.size());
+ boolean totp = false;
+ boolean password = false;
+ for (RequiredCredentialModel cred : storedCreds) {
+ if (cred.getType().equals(RequiredCredentialRepresentation.PASSWORD)) password = true;
+ else if (cred.getType().equals(RequiredCredentialRepresentation.TOTP)) totp = true;
+ }
+ Assert.assertTrue(totp);
+ Assert.assertTrue(password);
+ }
- @Test
- public void testCredentialValidation() throws Exception
- {
- test1CreateRealm();
- User user = new SimpleUser("bburke");
- realmModel.getIdm().add(user);
- UserCredentialModel cred = new UserCredentialModel();
- cred.setType(RequiredCredentialRepresentation.PASSWORD);
- cred.setValue("geheim");
- realmModel.updateCredential(user, cred);
- IdentityManager idm = realmModel.getIdm();
- UsernamePasswordCredentials creds = new UsernamePasswordCredentials(user.getLoginName(), new Password("geheim"));
- idm.validateCredentials(creds);
- Assert.assertEquals(creds.getStatus(), Credentials.Status.VALID);
- }
+ @Test
+ public void testCredentialValidation() throws Exception {
+ test1CreateRealm();
+ User user = new SimpleUser("bburke");
+ realmModel.getIdm().add(user);
+ UserCredentialModel cred = new UserCredentialModel();
+ cred.setType(RequiredCredentialRepresentation.PASSWORD);
+ cred.setValue("geheim");
+ realmModel.updateCredential(user, cred);
+ IdentityManager idm = realmModel.getIdm();
+ UsernamePasswordCredentials creds = new UsernamePasswordCredentials(user.getLoginName(), new Password("geheim"));
+ idm.validateCredentials(creds);
+ Assert.assertEquals(creds.getStatus(), Credentials.Status.VALID);
+ }
- @Test
- public void testRoles() throws Exception
- {
- test1CreateRealm();
- IdentityManager idm = realmModel.getIdm();
- idm.add(new SimpleRole("admin"));
- idm.add(new SimpleRole("user"));
- List<Role> roles = realmModel.getRoles();
- Assert.assertEquals(2, roles.size());
- SimpleUser user = new SimpleUser("bburke");
- idm.add(user);
- Role role = idm.getRole("user");
- idm.grantRole(user, role);
- Assert.assertTrue(idm.hasRole(user, role));
- }
+ @Test
+ public void testRoles() throws Exception {
+ test1CreateRealm();
+ IdentityManager idm = realmModel.getIdm();
+ idm.add(new SimpleRole("admin"));
+ idm.add(new SimpleRole("user"));
+ List<Role> roles = realmModel.getRoles();
+ Assert.assertEquals(2, roles.size());
+ SimpleUser user = new SimpleUser("bburke");
+ idm.add(user);
+ Role role = idm.getRole("user");
+ idm.grantRole(user, role);
+ Assert.assertTrue(idm.hasRole(user, role));
+ }
}
diff --git a/services/src/test/java/org/keycloak/test/KeycloakTestBase.java b/services/src/test/java/org/keycloak/test/KeycloakTestBase.java
new file mode 100755
index 0000000..5bd0b6d
--- /dev/null
+++ b/services/src/test/java/org/keycloak/test/KeycloakTestBase.java
@@ -0,0 +1,31 @@
+package org.keycloak.test;
+
+import org.jboss.resteasy.jwt.JsonSerialization;
+import org.jboss.resteasy.test.BaseResourceTest;
+import org.keycloak.representations.idm.RealmRepresentation;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakTestBase extends BaseResourceTest
+{
+ public static RealmRepresentation loadJson(String path) throws IOException
+ {
+ InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ int c;
+ while ( (c = is.read()) != -1)
+ {
+ os.write(c);
+ }
+ byte[] bytes = os.toByteArray();
+ System.out.println(new String(bytes));
+
+ return JsonSerialization.fromBytes(RealmRepresentation.class, bytes);
+ }
+}
diff --git a/services/src/test/java/org/keycloak/test/RealmCreationTest.java b/services/src/test/java/org/keycloak/test/RealmCreationTest.java
new file mode 100755
index 0000000..57d378f
--- /dev/null
+++ b/services/src/test/java/org/keycloak/test/RealmCreationTest.java
@@ -0,0 +1,94 @@
+package org.keycloak.test;
+
+import org.jboss.resteasy.client.jaxrs.ResteasyClient;
+import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder;
+import org.jboss.resteasy.spi.ResteasyDeployment;
+import org.jboss.resteasy.test.EmbeddedContainer;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.keycloak.SkeletonKeyContextResolver;
+import org.keycloak.representations.AccessTokenResponse;
+import org.keycloak.representations.idm.RealmRepresentation;
+import org.keycloak.representations.idm.RequiredCredentialRepresentation;
+import org.keycloak.representations.idm.UserRepresentation;
+import org.keycloak.services.managers.AuthenticationManager;
+import org.keycloak.services.managers.InstallationManager;
+import org.keycloak.services.models.RealmManager;
+import org.keycloak.services.resources.KeycloakApplication;
+import org.picketlink.idm.IdentitySession;
+import org.picketlink.idm.model.Realm;
+
+import javax.ws.rs.NotAuthorizedException;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.Entity;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.HttpHeaders;
+import javax.ws.rs.core.Response;
+
+import static org.jboss.resteasy.test.TestPortProvider.generateURL;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class RealmCreationTest {
+
+ private static ResteasyDeployment deployment;
+ private static Client client;
+
+ @BeforeClass
+ public static void before() throws Exception {
+ deployment = new ResteasyDeployment();
+ deployment.setApplicationClass(KeycloakApplication.class.getName());
+ EmbeddedContainer.start(deployment);
+ KeycloakApplication application = (KeycloakApplication) deployment.getApplication();
+ IdentitySession IdentitySession = application.getFactory().createIdentitySession();
+ RealmManager manager = new RealmManager(IdentitySession);
+ new InstallationManager().install(manager);
+ client = new ResteasyClientBuilder().build();
+ client.register(SkeletonKeyContextResolver.class);
+ }
+
+ public static void after() throws Exception {
+ client.close();
+ EmbeddedContainer.stop();
+ }
+
+ @Test
+ public void testRegisterLoginAndCreate() throws Exception {
+ UserRepresentation user = new UserRepresentation();
+ user.setUsername("bburke");
+ user.credential(RequiredCredentialRepresentation.PASSWORD, "geheim", false);
+
+ WebTarget target = client.target(generateURL("/"));
+ Response response = target.path("registrations").request().post(Entity.json(user));
+ Assert.assertEquals(201, response.getStatus());
+ response.close();
+
+
+ AccessTokenResponse tokenResponse = null;
+ try {
+ Form form = new Form();
+ form.param(AuthenticationManager.FORM_USERNAME, "bburke");
+ form.param(RequiredCredentialRepresentation.PASSWORD, "badpassword");
+ tokenResponse = target.path("realms").path(Realm.DEFAULT_REALM).path("tokens/grants/identity-token").request().post(Entity.form(form), AccessTokenResponse.class);
+ Assert.fail();
+ } catch (NotAuthorizedException e) {
+ }
+ Form form = new Form();
+ form.param(AuthenticationManager.FORM_USERNAME, "bburke");
+ form.param(RequiredCredentialRepresentation.PASSWORD, "geheim");
+ tokenResponse = target.path("realms").path(Realm.DEFAULT_REALM).path("tokens/grants/identity-token").request().post(Entity.form(form), AccessTokenResponse.class);
+ Assert.assertNotNull(tokenResponse);
+ System.out.println(tokenResponse.getToken());
+ //
+
+ RealmRepresentation realm = KeycloakTestBase.loadJson("testrealm.json");
+ response = target.path("realms").request().header(HttpHeaders.AUTHORIZATION, "Bearer " + tokenResponse.getToken()).post(Entity.json(realm));
+ Assert.assertEquals(201, response.getStatus());
+ response.close();
+ }
+}
diff --git a/services/src/test/resources/META-INF/persistence.xml b/services/src/test/resources/META-INF/persistence.xml
index 1e5524f..7b7e664 100755
--- a/services/src/test/resources/META-INF/persistence.xml
+++ b/services/src/test/resources/META-INF/persistence.xml
@@ -2,7 +2,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0">
- <persistence-unit name="identitydb" transaction-type="RESOURCE_LOCAL">
+ <persistence-unit name="keycloak-identity-store" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>org.picketlink.idm.jpa.schema.IdentityObject</class>