keycloak-uncached
Changes
distribution/modules/build.xml 8(+8 -0)
distribution/modules/pom.xml 10(+10 -0)
distribution/modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml 37(+37 -0)
distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-adapter/main/module.xml 46(+46 -0)
integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java 1(+1 -0)
integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java 4(+4 -0)
integration/as7-eap6/adapter/pom.xml 5(+5 -0)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaRequestAuthenticator.java 9(+7 -2)
integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaSecurityContextHelper.java 25(+21 -4)
integration/as7-eap-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java 2(+2 -0)
integration/jboss-adapter-core/pom.xml 83(+83 -0)
integration/jboss-adapter-core/src/main/java/org/keycloak/adapters/jboss/KeycloakLoginModule.java 100(+100 -0)
integration/pom.xml 2(+2 -0)
integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java 7(+6 -1)
integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java 38(+21 -17)
integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthMech.java 8(+6 -2)
integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java 6(+4 -2)
integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowRequestAuthenticator.java 3(+2 -1)
integration/wildfly-adapter/pom.xml 108(+108 -0)
integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/SecurityInfoHelper.java 116(+116 -0)
integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyAuthenticationMechanism.java 29(+29 -0)
integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyKeycloakServletExtension.java 24(+24 -0)
integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyRequestAuthenticator.java 136(+136 -0)
integration/wildfly-adapter/src/main/resources/META-INF/services/io.undertow.servlet.ServletExtension 1(+1 -0)
integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessor.java 24(+23 -1)
Details
diff --git a/distribution/appliance-dist/src/main/xslt/standalone.xsl b/distribution/appliance-dist/src/main/xslt/standalone.xsl
index 8f8011b..64fda33 100755
--- a/distribution/appliance-dist/src/main/xslt/standalone.xsl
+++ b/distribution/appliance-dist/src/main/xslt/standalone.xsl
@@ -38,6 +38,18 @@
</xsl:copy>
</xsl:template>
+ <xsl:template match="node()[name(.)='security-domains']">
+ <xsl:copy>
+ <xsl:apply-templates select="node()[name(.)='security-domain']"/>
+ <security-domain name="keycloak">
+ <authentication>
+ <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule" flag="required"/>
+ </authentication>
+ </security-domain>
+ </xsl:copy>
+ </xsl:template>
+
+
<!-- for some reason, Wildfly 8 final decided to turn off management-native which means jboss-as-maven-plugin no
longer works -->
<xsl:template match="node()[name(.)='management-interfaces']">
diff --git a/distribution/as7-adapter-zip/assembly.xml b/distribution/as7-adapter-zip/assembly.xml
index f4b56a1..6a507fd 100755
--- a/distribution/as7-adapter-zip/assembly.xml
+++ b/distribution/as7-adapter-zip/assembly.xml
@@ -12,6 +12,7 @@
<excludes>
<exclude>org/keycloak/keycloak-undertow-adapter/**</exclude>
<exclude>org/keycloak/keycloak-wildfly-subsystem/**</exclude>
+ <exclude>org/keycloak/keycloak-wildfly-adapter/**</exclude>
</excludes>
<outputDirectory>modules</outputDirectory>
</fileSet>
distribution/modules/build.xml 8(+8 -0)
diff --git a/distribution/modules/build.xml b/distribution/modules/build.xml
index 16694d4..8503475 100755
--- a/distribution/modules/build.xml
+++ b/distribution/modules/build.xml
@@ -59,6 +59,10 @@
<maven-resource group="org.keycloak" artifact="keycloak-adapter-core"/>
</module-def>
+ <module-def name="org.keycloak.keycloak-jboss-adapter-core">
+ <maven-resource group="org.keycloak" artifact="keycloak-jboss-adapter-core"/>
+ </module-def>
+
<module-def name="org.keycloak.keycloak-as7-adapter">
<maven-resource group="org.keycloak" artifact="keycloak-as7-adapter"/>
</module-def>
@@ -67,6 +71,10 @@
<maven-resource group="org.keycloak" artifact="keycloak-undertow-adapter"/>
</module-def>
+ <module-def name="org.keycloak.keycloak-wildfly-adapter">
+ <maven-resource group="org.keycloak" artifact="keycloak-wildfly-adapter"/>
+ </module-def>
+
<module-def name="org.keycloak.keycloak-wildfly-subsystem">
<maven-resource group="org.keycloak" artifact="keycloak-wildfly-subsystem"/>
</module-def>
distribution/modules/pom.xml 10(+10 -0)
diff --git a/distribution/modules/pom.xml b/distribution/modules/pom.xml
index ee3c31f..107a06d 100755
--- a/distribution/modules/pom.xml
+++ b/distribution/modules/pom.xml
@@ -51,6 +51,11 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
+ <artifactId>keycloak-jboss-adapter-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
<artifactId>keycloak-as7-adapter</artifactId>
<version>${project.version}</version>
</dependency>
@@ -61,6 +66,11 @@
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
+ <artifactId>keycloak-wildfly-adapter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
<artifactId>keycloak-wildfly-subsystem</artifactId>
<version>${project.version}</version>
</dependency>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml
new file mode 100755
index 0000000..5ecc097
--- /dev/null
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-jboss-adapter-core/main/module.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-jboss-adapter-core">
+ <resources>
+ <!-- Insert resources here -->
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="org.picketbox"/>
+ <module name="org.keycloak.keycloak-adapter-core"/>
+ <module name="org.keycloak.keycloak-core"/>
+ </dependencies>
+
+</module>
diff --git a/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-adapter/main/module.xml b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-adapter/main/module.xml
new file mode 100755
index 0000000..a89bac4
--- /dev/null
+++ b/distribution/modules/src/main/resources/modules/org/keycloak/keycloak-wildfly-adapter/main/module.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ ~ JBoss, Home of Professional Open Source.
+ ~ Copyright 2010, Red Hat, Inc., and individual contributors
+ ~ as indicated by the @author tags. See the copyright.txt file in the
+ ~ distribution for a full listing of individual contributors.
+ ~
+ ~ This is free software; you can redistribute it and/or modify it
+ ~ under the terms of the GNU Lesser General Public License as
+ ~ published by the Free Software Foundation; either version 2.1 of
+ ~ the License, or (at your option) any later version.
+ ~
+ ~ This software is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ ~ Lesser General Public License for more details.
+ ~
+ ~ You should have received a copy of the GNU Lesser General Public
+ ~ License along with this software; if not, write to the Free
+ ~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ ~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ -->
+
+<module xmlns="urn:jboss:module:1.1" name="org.keycloak.keycloak-wildfly-adapter">
+ <resources>
+ <!-- Insert resources here -->
+ </resources>
+ <dependencies>
+ <module name="javax.api"/>
+ <module name="org.bouncycastle"/>
+ <module name="org.codehaus.jackson.jackson-core-asl"/>
+ <module name="org.codehaus.jackson.jackson-mapper-asl"/>
+ <module name="org.codehaus.jackson.jackson-xc"/>
+ <module name="org.apache.httpcomponents" />
+ <module name="javax.servlet.api"/>
+ <module name="org.jboss.logging"/>
+ <module name="io.undertow.core"/>
+ <module name="io.undertow.servlet"/>
+ <module name="org.picketbox"/>
+ <module name="org.keycloak.keycloak-undertow-adapter"/>
+ <module name="org.keycloak.keycloak-adapter-core"/>
+ <module name="org.keycloak.keycloak-core"/>
+ </dependencies>
+
+</module>
diff --git a/docbook/reference/en/en-US/modules/jboss-adapter.xml b/docbook/reference/en/en-US/modules/jboss-adapter.xml
index c6e6597..90dc1cd 100755
--- a/docbook/reference/en/en-US/modules/jboss-adapter.xml
+++ b/docbook/reference/en/en-US/modules/jboss-adapter.xml
@@ -73,6 +73,66 @@ $ unzip keycloak-as7-adapter-dist.zip
]]>
</programlisting>
</para>
+ <para>
+ Finally, for both AS7, EAP 6.x, and Wildfly installations you must specify a shared keycloak security domain.
+ This security domain should be used with EJBs and other components when you need the security context created
+ in the secured web tier to be propagated to the EJBs (other EE component) you are invoking. Otherwise
+ this configuration is optional.
+ </para>
+<programlisting><![CDATA[
+<server xmlns="urn:jboss:domain:1.4">
+ <subsystem xmlns="urn:jboss:domain:security:1.2">
+ <security-domains>
+...
+ <security-domain name="keycloak">
+ <authentication>
+ <login-module code="org.keycloak.adapters.jboss.KeycloakLoginModule"
+ flag="required"/>
+ </authentication>
+ </security-domain>
+ </security-domains>
+]]>
+</programlisting>
+ <para>
+ For example, if you have a JAX-RS service that is an EJB within your WEB-INF/classes directory, you'll want
+ to annotate it with the @SecurityDomain annotation as follows:
+ </para>
+<programlisting><![CDATA[
+import org.jboss.ejb3.annotation.SecurityDomain;
+import org.jboss.resteasy.annotations.cache.NoCache;
+
+import javax.annotation.security.RolesAllowed;
+import javax.ejb.EJB;
+import javax.ejb.Stateless;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import java.util.ArrayList;
+import java.util.List;
+
+@Path("customers")
+@Stateless
+@SecurityDomain("keycloak")
+public class CustomerService {
+
+ @EJB
+ CustomerDB db;
+
+ @GET
+ @Produces("application/json")
+ @NoCache
+ @RolesAllowed("db_user")
+ public List<String> getCustomers() {
+ return db.getCustomers();
+ }
+}
+]]>
+</programlisting>
+ <para>
+ We hope to improve our integration in the future so that you don't have to specify the @SecurityDomain
+ annotation when you want to propagate a keycloak security context to the EJB tier.
+ </para>
+
</section>
<section>
<title>Per WAR Configuration</title>
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakAccount.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakAccount.java
new file mode 100755
index 0000000..4bc9dd4
--- /dev/null
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakAccount.java
@@ -0,0 +1,19 @@
+package org.keycloak.adapters;
+
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
+import org.keycloak.representations.AccessToken;
+
+import java.security.Principal;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public interface KeycloakAccount {
+ Principal getPrincipal();
+ Set<String> getRoles();
+ KeycloakSecurityContext getKeycloakSecurityContext();
+}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
index 5a326b8..d497c0d 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeploymentBuilder.java
@@ -48,6 +48,7 @@ public class KeycloakDeploymentBuilder {
deployment.setSslRequired(!adapterConfig.isSslNotRequired());
deployment.setResourceCredentials(adapterConfig.getCredentials());
deployment.setPublicClient(adapterConfig.isPublicClient());
+ deployment.setUseResourceRoleMappings(adapterConfig.isUseResourceRoleMappings());
if (adapterConfig.isBearerOnly()) {
deployment.setBearerOnly(true);
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
index 5ddbc58..6442499 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/RefreshableKeycloakSecurityContext.java
@@ -46,6 +46,10 @@ public class RefreshableKeycloakSecurityContext extends KeycloakSecurityContext
return this.token.isActive() && this.token.getIssuedAt() > deployment.getNotBefore();
}
+ public KeycloakDeployment getDeployment() {
+ return deployment;
+ }
+
public void setDeployment(KeycloakDeployment deployment) {
this.deployment = deployment;
}
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
index f0d697c..103098a 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/RequestAuthenticator.java
@@ -8,7 +8,7 @@ import org.keycloak.KeycloakPrincipal;
* @version $Revision: 1 $
*/
public abstract class RequestAuthenticator {
- protected Logger log = Logger.getLogger(RequestAuthenticator.class);
+ protected static Logger log = Logger.getLogger(RequestAuthenticator.class);
protected HttpFacade facade;
protected KeycloakDeployment deployment;
@@ -33,19 +33,25 @@ public abstract class RequestAuthenticator {
public AuthOutcome authenticate() {
log.info("--> authenticate()");
BearerTokenRequestAuthenticator bearer = createBearerTokenAuthenticator();
+ log.info("try bearer");
AuthOutcome outcome = bearer.authenticate(facade);
if (outcome == AuthOutcome.FAILED) {
challenge = bearer.getChallenge();
+ log.info("Bearer FAILED");
return AuthOutcome.FAILED;
} else if (outcome == AuthOutcome.AUTHENTICATED) {
completeAuthentication(bearer);
+ log.info("Bearer AUTHENTICATED");
return AuthOutcome.AUTHENTICATED;
} else if (deployment.isBearerOnly()) {
challenge = bearer.getChallenge();
+ log.info("NOT_ATTEMPTED: bearer only");
return AuthOutcome.NOT_ATTEMPTED;
}
+ log.info("try oauth");
if (isCached()) {
+ log.info("AUTHENTICATED: was cached");
return AuthOutcome.AUTHENTICATED;
}
integration/as7-eap6/adapter/pom.xml 5(+5 -0)
diff --git a/integration/as7-eap6/adapter/pom.xml b/integration/as7-eap6/adapter/pom.xml
index ea2c35e..07dc6e3 100755
--- a/integration/as7-eap6/adapter/pom.xml
+++ b/integration/as7-eap6/adapter/pom.xml
@@ -24,6 +24,11 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-jboss-adapter-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${keycloak.apache.httpcomponents.version}</version>
diff --git a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaRequestAuthenticator.java b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaRequestAuthenticator.java
index 1188e6d..9e211b2 100755
--- a/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaRequestAuthenticator.java
+++ b/integration/as7-eap6/adapter/src/main/java/org/keycloak/adapters/as7/CatalinaRequestAuthenticator.java
@@ -4,6 +4,7 @@ import org.apache.catalina.Session;
import org.apache.catalina.authenticator.Constants;
import org.apache.catalina.connector.Request;
import org.apache.catalina.realm.GenericPrincipal;
+import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.KeycloakDeployment;
@@ -22,6 +23,7 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class CatalinaRequestAuthenticator extends RequestAuthenticator {
+ private static final Logger log = Logger.getLogger(CatalinaRequestAuthenticator.class);
protected KeycloakAuthenticatorValve valve;
protected CatalinaUserSessionManagement userSessionManagement;
protected Request request;
@@ -53,7 +55,7 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
@Override
protected void completeOAuthAuthentication(KeycloakPrincipal skp, RefreshableKeycloakSecurityContext securityContext) {
Set<String> roles = getRolesFromToken(securityContext);
- GenericPrincipal principal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), skp, roles);
+ GenericPrincipal principal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), skp, roles, securityContext);
Session session = request.getSessionInternal(true);
session.setPrincipal(principal);
session.setAuthType("OAUTH");
@@ -66,7 +68,10 @@ public class CatalinaRequestAuthenticator extends RequestAuthenticator {
@Override
protected void completeBearerAuthentication(KeycloakPrincipal principal, RefreshableKeycloakSecurityContext securityContext) {
Set<String> roles = getRolesFromToken(securityContext);
- Principal generalPrincipal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), principal, roles);
+ for (String role : roles) {
+ log.info("Bearer role: " + role);
+ }
+ Principal generalPrincipal = new CatalinaSecurityContextHelper().createPrincipal(request.getContext().getRealm(), principal, roles, securityContext);
request.setUserPrincipal(generalPrincipal);
request.setAuthType("KEYCLOAK");
request.setAttribute(KeycloakSecurityContext.class.getName(), securityContext);
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
index 8cfbcb5..f33c463 100755
--- 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
@@ -9,6 +9,8 @@ import org.jboss.security.SecurityContext;
import org.jboss.security.SecurityContextAssociation;
import org.jboss.security.SimpleGroup;
import org.jboss.security.SimplePrincipal;
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.KeycloakAccount;
import javax.security.auth.Subject;
import java.security.Principal;
@@ -25,9 +27,24 @@ import java.util.Set;
* @version $Revision: 1 $
*/
public class CatalinaSecurityContextHelper {
- public GenericPrincipal createPrincipal(Realm realm, Principal identity, Collection<String> roleSet) {
+ public GenericPrincipal createPrincipal(Realm realm, final Principal identity, final Set<String> roleSet, final KeycloakSecurityContext securityContext) {
+ KeycloakAccount account = new KeycloakAccount() {
+ @Override
+ public Principal getPrincipal() {
+ return identity;
+ }
+
+ @Override
+ public Set<String> getRoles() {
+ return roleSet;
+ }
+
+ @Override
+ public KeycloakSecurityContext getKeycloakSecurityContext() {
+ return securityContext;
+ }
+ };
Subject subject = new Subject();
- String credentials = "";
Set<Principal> principals = subject.getPrincipals();
principals.add(identity);
Group[] roleSets = getRoleSets(roleSet);
@@ -56,11 +73,11 @@ public class CatalinaSecurityContextHelper {
principals.add(callerGroup);
SecurityContext sc = SecurityContextAssociation.getSecurityContext();
Principal userPrincipal = getPrincipal(subject);
- sc.getUtil().createSubjectInfo(userPrincipal, credentials, subject);
+ sc.getUtil().createSubjectInfo(userPrincipal, account, subject);
List<String> rolesAsStringList = new ArrayList<String>();
rolesAsStringList.addAll(roleSet);
return new JBossGenericPrincipal(realm, userPrincipal.getName(), null, rolesAsStringList,
- userPrincipal, null, credentials, null, subject);
+ userPrincipal, null, account, null, subject);
}
diff --git a/integration/as7-eap-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java b/integration/as7-eap-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java
index 2ac2ccf..c9a32d6 100755
--- a/integration/as7-eap-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java
+++ b/integration/as7-eap-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java
@@ -36,6 +36,7 @@ public class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
private static final ModuleIdentifier KEYCLOAK_AS7_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-as7-adapter");
private static final ModuleIdentifier KEYCLOAK_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-adapter-core");
+ private static final ModuleIdentifier KEYCLOAK_JBOSS_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-jboss-adapter-core");
private static final ModuleIdentifier KEYCLOAK_CORE = ModuleIdentifier.create("org.keycloak.keycloak-core");
//private static final ModuleIdentifier APACHE_HTTPCOMPONENTS = ModuleIdentifier.create("org.apache.httpcomponents");
@@ -51,6 +52,7 @@ public class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
final ModuleLoader moduleLoader = Module.getBootModuleLoader();
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_AS7_ADAPTER, false, false, true, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_JBOSS_CORE_ADAPTER, false, false, false, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE_ADAPTER, false, false, false, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE, false, false, false, false));
//moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, APACHE_HTTPCOMPONENTS, false, false, true, false));
integration/jboss-adapter-core/pom.xml 83(+83 -0)
diff --git a/integration/jboss-adapter-core/pom.xml b/integration/jboss-adapter-core/pom.xml
new file mode 100755
index 0000000..0d599a5
--- /dev/null
+++ b/integration/jboss-adapter-core/pom.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0"?>
+<project>
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.0-alpha-3-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-jboss-adapter-core</artifactId>
+ <name>Common JBoss/Wildfly Core Classes</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>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>${keycloak.apache.httpcomponents.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.iharder</groupId>
+ <artifactId>base64</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk16</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-xc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.picketbox</groupId>
+ <artifactId>picketbox</artifactId>
+ <version>4.0.20.Final</version>
+ <scope>provided</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/jboss-adapter-core/src/main/java/org/keycloak/adapters/jboss/KeycloakLoginModule.java b/integration/jboss-adapter-core/src/main/java/org/keycloak/adapters/jboss/KeycloakLoginModule.java
new file mode 100755
index 0000000..e3db8c5
--- /dev/null
+++ b/integration/jboss-adapter-core/src/main/java/org/keycloak/adapters/jboss/KeycloakLoginModule.java
@@ -0,0 +1,100 @@
+package org.keycloak.adapters.jboss;
+
+import org.jboss.logging.Logger;
+import org.jboss.security.SimpleGroup;
+import org.jboss.security.SimplePrincipal;
+import org.jboss.security.auth.callback.ObjectCallback;
+import org.jboss.security.auth.spi.AbstractServerLoginModule;
+import org.keycloak.adapters.KeycloakAccount;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import javax.security.auth.login.LoginException;
+import java.io.IOException;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class KeycloakLoginModule extends AbstractServerLoginModule {
+ protected static Logger log = Logger.getLogger(KeycloakLoginModule.class);
+ protected Set<String> roleSet;
+ protected Principal identity;
+
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public boolean login() throws LoginException {
+ log.info("KeycloakLoginModule.login()");
+ if (super.login() == true) {
+ log.info("super.login()==true");
+ return true;
+ }
+
+ Object credential = getCredential();
+ if (credential != null && (credential instanceof KeycloakAccount)) {
+ log.info("Found Account");
+ KeycloakAccount account = (KeycloakAccount)credential;
+ roleSet = account.getRoles();
+ identity = account.getPrincipal();
+ sharedState.put("javax.security.auth.login.name", identity);
+ sharedState.put("javax.security.auth.login.password", credential);
+ loginOk = true;
+ return true;
+ }
+
+ // We return false to allow the next module to attempt authentication, maybe a
+ // username and password has been supplied to a web auth.
+ return false;
+ }
+
+
+ @Override
+ protected Principal getIdentity() {
+ return identity;
+ }
+
+ /*
+ @Override
+ protected Group[] getRoleSets() throws LoginException {
+ return new Group[0];
+ }
+ */
+
+ @Override
+ protected Group[] getRoleSets() throws LoginException {
+ //log.info("getRoleSets");
+ SimpleGroup roles = new SimpleGroup("Roles");
+ Group[] roleSets = {roles};
+ for (String role : roleSet) {
+ //log.info(" adding role: " + role);
+ roles.addMember(new SimplePrincipal(role));
+ }
+ return roleSets;
+ }
+
+ protected Object getCredential() throws LoginException {
+ NameCallback nc = new NameCallback("Alias: ");
+ ObjectCallback oc = new ObjectCallback("Credential: ");
+ Callback[] callbacks = { nc, oc };
+
+ try {
+ callbackHandler.handle(callbacks);
+
+ return oc.getCredential();
+ } catch (IOException ioe) {
+ LoginException le = new LoginException();
+ le.initCause(ioe);
+ throw le;
+ } catch (UnsupportedCallbackException uce) {
+ LoginException le = new LoginException();
+ le.initCause(uce);
+ throw le;
+ }
+ }
+
+}
integration/pom.xml 2(+2 -0)
diff --git a/integration/pom.xml b/integration/pom.xml
index f52c6e6..d07f29b 100755
--- a/integration/pom.xml
+++ b/integration/pom.xml
@@ -18,8 +18,10 @@
<module>adapter-core</module>
<module>jaxrs-oauth-client</module>
<module>servlet-oauth-client</module>
+ <module>jboss-adapter-core</module>
<module>as7-eap6/adapter</module>
<module>undertow</module>
+ <module>wildfly-adapter</module>
<module>wildfly-subsystem</module>
<module>as7-eap-subsystem</module>
<module>js</module>
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
index 50895c6..4c07480 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakServletExtension.java
@@ -65,7 +65,7 @@ public class KeycloakServletExtension implements ServletExtension {
if (is == null) throw new RuntimeException("Unable to find realm config in /WEB-INF/keycloak.json or in keycloak subsystem.");
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(is);
UndertowUserSessionManagement userSessionManagement = new UndertowUserSessionManagement(deployment);
- final ServletKeycloakAuthMech mech = new ServletKeycloakAuthMech(deployment, userSessionManagement, deploymentInfo.getConfidentialPortManager());
+ final ServletKeycloakAuthMech mech = createAuthenticationMechanism(deploymentInfo, deployment, userSessionManagement);
UndertowAuthenticatedActionsHandler.Wrapper actions = new UndertowAuthenticatedActionsHandler.Wrapper(deployment);
@@ -102,4 +102,9 @@ public class KeycloakServletExtension implements ServletExtension {
cookieConfig.setPath(deploymentInfo.getContextPath());
deploymentInfo.setServletSessionConfig(cookieConfig);
}
+
+ protected ServletKeycloakAuthMech createAuthenticationMechanism(DeploymentInfo deploymentInfo, KeycloakDeployment deployment, UndertowUserSessionManagement userSessionManagement) {
+ log.info("creating ServletKeycloakAuthMech");
+ return new ServletKeycloakAuthMech(deployment, userSessionManagement, deploymentInfo.getConfidentialPortManager());
+ }
}
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java
index 310958a..be72184 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/KeycloakUndertowAccount.java
@@ -3,6 +3,7 @@ package org.keycloak.adapters.undertow;
import io.undertow.security.idm.Account;
import org.jboss.logging.Logger;
import org.keycloak.KeycloakPrincipal;
+import org.keycloak.adapters.KeycloakAccount;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
import org.keycloak.representations.AccessToken;
@@ -16,7 +17,7 @@ import java.util.Set;
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $
*/
-public class KeycloakUndertowAccount implements Account, Serializable {
+public class KeycloakUndertowAccount implements Account, Serializable, KeycloakAccount {
protected static Logger log = Logger.getLogger(KeycloakUndertowAccount.class);
protected RefreshableKeycloakSecurityContext session;
protected KeycloakPrincipal principal;
@@ -25,19 +26,27 @@ public class KeycloakUndertowAccount implements Account, Serializable {
public KeycloakUndertowAccount(KeycloakPrincipal principal, RefreshableKeycloakSecurityContext session, KeycloakDeployment deployment) {
this.principal = principal;
this.session = session;
- setRoles(session.getToken(), deployment);
+ setRoles(session.getToken());
}
- protected void setRoles(AccessToken accessToken, KeycloakDeployment deployment) {
+ protected void setRoles(AccessToken accessToken) {
Set<String> roles = null;
- if (deployment.isUseResourceRoleMappings()) {
- AccessToken.Access access = accessToken.getResourceAccess(deployment.getResourceName());
+ if (session.getDeployment().isUseResourceRoleMappings()) {
+ log.info("useResourceRoleMappings");
+ AccessToken.Access access = accessToken.getResourceAccess(session.getDeployment().getResourceName());
if (access != null) roles = access.getRoles();
} else {
+ log.info("use realm role mappings");
AccessToken.Access access = accessToken.getRealmAccess();
if (access != null) roles = access.getRoles();
}
if (roles == null) roles = Collections.emptySet();
+ /*
+ log.info("Setting roles: ");
+ for (String role : roles) {
+ log.info(" role: " + role);
+ }
+ */
this.accountRoles = roles;
}
@@ -51,22 +60,17 @@ public class KeycloakUndertowAccount implements Account, Serializable {
return accountRoles;
}
- public AccessToken getAccessToken() {
- return session.getToken();
- }
-
- public String getEncodedAccessToken() {
- return session.getTokenString();
- }
-
+ @Override
public RefreshableKeycloakSecurityContext getKeycloakSecurityContext() {
return session;
}
- public boolean isActive(KeycloakDeployment deployment) {
- // this object may have been serialized, so we need to reset realm config/metadata
+ public void setDeployment(KeycloakDeployment deployment) {
session.setDeployment(deployment);
- log.info("realmConfig notBefore: " + deployment.getNotBefore());
+ }
+
+ public boolean isActive() {
+ // this object may have been serialized, so we need to reset realm config/metadata
if (session.isActive()) {
log.info("session is active");
return true;
@@ -81,7 +85,7 @@ public class KeycloakUndertowAccount implements Account, Serializable {
}
log.info("refresh succeeded");
- setRoles(session.getToken(), deployment);
+ setRoles(session.getToken());
return true;
}
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthMech.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthMech.java
index 2ce8f06..42b9237 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthMech.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletKeycloakAuthMech.java
@@ -29,8 +29,7 @@ public class ServletKeycloakAuthMech implements AuthenticationMechanism {
@Override
public AuthenticationMechanismOutcome authenticate(HttpServerExchange exchange, SecurityContext securityContext) {
UndertowHttpFacade facade = new UndertowHttpFacade(exchange);
- ServletRequestAuthenticator authenticator = new ServletRequestAuthenticator(facade, deployment,
- portManager.getConfidentialPort(exchange), securityContext, exchange, userSessionManagement);
+ ServletRequestAuthenticator authenticator = createRequestAuthenticator(exchange, securityContext, facade);
AuthOutcome outcome = authenticator.authenticate();
if (outcome == AuthOutcome.AUTHENTICATED) {
return AuthenticationMechanismOutcome.AUTHENTICATED;
@@ -46,6 +45,11 @@ public class ServletKeycloakAuthMech implements AuthenticationMechanism {
return AuthenticationMechanismOutcome.NOT_ATTEMPTED;
}
+ protected ServletRequestAuthenticator createRequestAuthenticator(HttpServerExchange exchange, SecurityContext securityContext, UndertowHttpFacade facade) {
+ return new ServletRequestAuthenticator(facade, deployment,
+ portManager.getConfidentialPort(exchange), securityContext, exchange, userSessionManagement);
+ }
+
@Override
public ChallengeResult sendChallenge(HttpServerExchange exchange, SecurityContext securityContext) {
AuthChallenge challenge = exchange.getAttachment(KEYCLOAK_CHALLENGE_ATTACHMENT_KEY);
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java
index f294eb7..f9c2edf 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/ServletRequestAuthenticator.java
@@ -5,6 +5,7 @@ import io.undertow.server.HttpServerExchange;
import io.undertow.servlet.handlers.ServletRequestContext;
import org.keycloak.KeycloakSecurityContext;
import org.keycloak.adapters.HttpFacade;
+import org.keycloak.adapters.KeycloakAccount;
import org.keycloak.adapters.KeycloakDeployment;
import javax.servlet.http.HttpServletRequest;
@@ -39,7 +40,8 @@ public class ServletRequestAuthenticator extends UndertowRequestAuthenticator {
log.info("Account was not in session, returning null");
return false;
}
- if (account.isActive(deployment)) {
+ account.setDeployment(deployment);
+ if (account.isActive()) {
log.info("Cached account found");
securityContext.authenticationComplete(account, "KEYCLOAK", false);
propagateKeycloakContext( account);
@@ -59,7 +61,7 @@ public class ServletRequestAuthenticator extends UndertowRequestAuthenticator {
}
@Override
- protected void login(KeycloakUndertowAccount account) {
+ protected void login(KeycloakAccount account) {
final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
HttpServletRequest req = (HttpServletRequest) servletRequestContext.getServletRequest();
HttpSession session = req.getSession(true);
diff --git a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowRequestAuthenticator.java b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowRequestAuthenticator.java
index 89b2e11..cd5fdaa 100755
--- a/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowRequestAuthenticator.java
+++ b/integration/undertow/src/main/java/org/keycloak/adapters/undertow/UndertowRequestAuthenticator.java
@@ -4,6 +4,7 @@ import io.undertow.security.api.SecurityContext;
import io.undertow.server.HttpServerExchange;
import org.keycloak.KeycloakPrincipal;
import org.keycloak.adapters.HttpFacade;
+import org.keycloak.adapters.KeycloakAccount;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.OAuthRequestAuthenticator;
import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
@@ -46,7 +47,7 @@ public class UndertowRequestAuthenticator extends RequestAuthenticator {
login(account);
}
- protected void login(KeycloakUndertowAccount account) {
+ protected void login(KeycloakAccount account) {
}
integration/wildfly-adapter/pom.xml 108(+108 -0)
diff --git a/integration/wildfly-adapter/pom.xml b/integration/wildfly-adapter/pom.xml
new file mode 100755
index 0000000..7ed0602
--- /dev/null
+++ b/integration/wildfly-adapter/pom.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0"?>
+<project>
+ <parent>
+ <artifactId>keycloak-parent</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>1.0-alpha-3-SNAPSHOT</version>
+ <relativePath>../../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-wildfly-adapter</artifactId>
+ <name>Keycloak Wildfly 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>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-adapter-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-undertow-adapter</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-jboss-adapter-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>${keycloak.apache.httpcomponents.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>net.iharder</groupId>
+ <artifactId>base64</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk16</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-core-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-mapper-asl</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.jackson</groupId>
+ <artifactId>jackson-xc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.picketbox</groupId>
+ <artifactId>picketbox</artifactId>
+ <version>4.0.20.Final</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.jboss.spec.javax.servlet</groupId>
+ <artifactId>jboss-servlet-api_3.0_spec</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>io.undertow</groupId>
+ <artifactId>undertow-servlet</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>io.undertow</groupId>
+ <artifactId>undertow-core</artifactId>
+ <scope>provided</scope>
+ </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/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/SecurityInfoHelper.java b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/SecurityInfoHelper.java
new file mode 100755
index 0000000..9838772
--- /dev/null
+++ b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/SecurityInfoHelper.java
@@ -0,0 +1,116 @@
+package org.keycloak.adapters.wildfly;
+
+import org.jboss.security.NestableGroup;
+import org.jboss.security.SecurityConstants;
+import org.jboss.security.SecurityContextAssociation;
+import org.jboss.security.SimpleGroup;
+import org.jboss.security.SimplePrincipal;
+import org.keycloak.adapters.KeycloakAccount;
+
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class SecurityInfoHelper {
+ public static void propagateSessionInfo(KeycloakAccount account) {
+ Subject subject = new Subject();
+ Set<Principal> principals = subject.getPrincipals();
+ principals.add(account.getPrincipal());
+ Group[] roleSets = getRoleSets(account.getRoles());
+ 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(account.getPrincipal());
+ principals.add(callerGroup);
+ org.jboss.security.SecurityContext sc = SecurityContextAssociation.getSecurityContext();
+ Principal userPrincipal = getPrincipal(subject);
+ sc.getUtil().createSubjectInfo(userPrincipal, account, subject);
+ }
+
+ /**
+ * Get the Principal given the authenticated Subject. Currently the first subject that is not of type {@code Group} is
+ * considered or the single subject inside the CallerPrincipal group.
+ *
+ * @param subject
+ * @return the authenticated subject
+ */
+ protected static 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 static 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 static 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/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyAuthenticationMechanism.java b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyAuthenticationMechanism.java
new file mode 100755
index 0000000..99c411c
--- /dev/null
+++ b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyAuthenticationMechanism.java
@@ -0,0 +1,29 @@
+package org.keycloak.adapters.wildfly;
+
+import io.undertow.security.api.SecurityContext;
+import io.undertow.server.HttpServerExchange;
+import io.undertow.servlet.api.ConfidentialPortManager;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.undertow.ServletKeycloakAuthMech;
+import org.keycloak.adapters.undertow.ServletRequestAuthenticator;
+import org.keycloak.adapters.undertow.UndertowHttpFacade;
+import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class WildflyAuthenticationMechanism extends ServletKeycloakAuthMech {
+
+ public WildflyAuthenticationMechanism(KeycloakDeployment deployment,
+ UndertowUserSessionManagement userSessionManagement,
+ ConfidentialPortManager portManager) {
+ super(deployment, userSessionManagement, portManager);
+ }
+
+ @Override
+ protected ServletRequestAuthenticator createRequestAuthenticator(HttpServerExchange exchange, SecurityContext securityContext, UndertowHttpFacade facade) {
+ return new WildflyRequestAuthenticator(facade, deployment,
+ portManager.getConfidentialPort(exchange), securityContext, exchange, userSessionManagement);
+ }
+}
diff --git a/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyKeycloakServletExtension.java b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyKeycloakServletExtension.java
new file mode 100755
index 0000000..e0623ad
--- /dev/null
+++ b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyKeycloakServletExtension.java
@@ -0,0 +1,24 @@
+package org.keycloak.adapters.wildfly;
+
+import io.undertow.servlet.api.DeploymentInfo;
+import org.jboss.logging.Logger;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.undertow.KeycloakServletExtension;
+import org.keycloak.adapters.undertow.ServletKeycloakAuthMech;
+import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class WildflyKeycloakServletExtension extends KeycloakServletExtension {
+ protected static Logger log = Logger.getLogger(WildflyKeycloakServletExtension.class);
+
+ @Override
+ protected ServletKeycloakAuthMech createAuthenticationMechanism(DeploymentInfo deploymentInfo, KeycloakDeployment deployment,
+ UndertowUserSessionManagement userSessionManagement) {
+ log.info("creating WildflyAuthenticationMechanism");
+ return new WildflyAuthenticationMechanism(deployment, userSessionManagement, deploymentInfo.getConfidentialPortManager());
+
+ }
+}
diff --git a/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyRequestAuthenticator.java b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyRequestAuthenticator.java
new file mode 100755
index 0000000..0b3563a
--- /dev/null
+++ b/integration/wildfly-adapter/src/main/java/org/keycloak/adapters/wildfly/WildflyRequestAuthenticator.java
@@ -0,0 +1,136 @@
+package org.keycloak.adapters.wildfly;
+
+import io.undertow.security.api.SecurityContext;
+import io.undertow.server.HttpServerExchange;
+import org.jboss.logging.Logger;
+import org.jboss.security.NestableGroup;
+import org.jboss.security.SecurityConstants;
+import org.jboss.security.SecurityContextAssociation;
+import org.jboss.security.SimpleGroup;
+import org.jboss.security.SimplePrincipal;
+import org.keycloak.adapters.HttpFacade;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.undertow.KeycloakUndertowAccount;
+import org.keycloak.adapters.undertow.ServletRequestAuthenticator;
+import org.keycloak.adapters.undertow.UndertowUserSessionManagement;
+
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.security.acl.Group;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
+ * @version $Revision: 1 $
+ */
+public class WildflyRequestAuthenticator extends ServletRequestAuthenticator {
+ protected static Logger log = Logger.getLogger(WildflyRequestAuthenticator.class);
+
+ public WildflyRequestAuthenticator(HttpFacade facade, KeycloakDeployment deployment, int sslRedirectPort,
+ SecurityContext securityContext, HttpServerExchange exchange,
+ UndertowUserSessionManagement userSessionManagement) {
+ super(facade, deployment, sslRedirectPort, securityContext, exchange, userSessionManagement);
+ }
+
+ @Override
+ protected void propagateKeycloakContext(KeycloakUndertowAccount account) {
+ super.propagateKeycloakContext(account);
+ SecurityInfoHelper.propagateSessionInfo(account);
+ log.info("propagate security context to wildfly");
+ Subject subject = new Subject();
+ Set<Principal> principals = subject.getPrincipals();
+ principals.add(account.getPrincipal());
+ Group[] roleSets = getRoleSets(account.getRoles());
+ 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(account.getPrincipal());
+ principals.add(callerGroup);
+ org.jboss.security.SecurityContext sc = SecurityContextAssociation.getSecurityContext();
+ Principal userPrincipal = getPrincipal(subject);
+ sc.getUtil().createSubjectInfo(userPrincipal, account, subject);
+ }
+
+ /**
+ * Get the Principal given the authenticated Subject. Currently the first subject that is not of type {@code Group} is
+ * considered or the single subject inside the CallerPrincipal group.
+ *
+ * @param subject
+ * @return the authenticated subject
+ */
+ 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/wildfly-adapter/src/main/resources/META-INF/services/io.undertow.servlet.ServletExtension b/integration/wildfly-adapter/src/main/resources/META-INF/services/io.undertow.servlet.ServletExtension
new file mode 100755
index 0000000..a46a78e
--- /dev/null
+++ b/integration/wildfly-adapter/src/main/resources/META-INF/services/io.undertow.servlet.ServletExtension
@@ -0,0 +1 @@
+org.keycloak.adapters.wildfly.WildflyKeycloakServletExtension
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessor.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessor.java
index 59fd9aa..16872c8 100755
--- a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessor.java
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakAdapterConfigDeploymentProcessor.java
@@ -48,11 +48,30 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
// Seems wise to have this run after INSTALL_WAR_DEPLOYMENT
public static final int PRIORITY = Phase.INSTALL_WAR_DEPLOYMENT - 1;
+ // not sure if we need this yet, keeping here just in case
+ protected void addSecurityDomain(DeploymentUnit deploymentUnit, KeycloakAdapterConfigService service) {
+ String deploymentName = deploymentUnit.getName();
+ if (!service.isKeycloakDeployment(deploymentName)) {
+ return;
+ }
+ WarMetaData warMetaData = deploymentUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);
+ if (warMetaData == null) return;
+ JBossWebMetaData webMetaData = warMetaData.getMergedJBossWebMetaData();
+ if (webMetaData == null) return;
+
+ LoginConfigMetaData loginConfig = webMetaData.getLoginConfig();
+ if (loginConfig == null || !loginConfig.getAuthMethod().equalsIgnoreCase("KEYCLOAK")) {
+ return;
+ }
+
+ webMetaData.setSecurityDomain("keycloak");
+ }
+
@Override
public void deploy(DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
DeploymentUnit deploymentUnit = phaseContext.getDeploymentUnit();
- String deploymentName = deploymentUnit.getName();
+ String deploymentName = deploymentUnit.getName();
KeycloakAdapterConfigService service = KeycloakAdapterConfigService.find(phaseContext.getServiceRegistry());
//log.info("********* CHECK KEYCLOAK DEPLOYMENT: " + deploymentName);
if (service.isKeycloakDeployment(deploymentName)) {
@@ -61,6 +80,9 @@ public class KeycloakAdapterConfigDeploymentProcessor implements DeploymentUnitP
}
// FYI, Undertow Extension will find deployments that have auth-method set to KEYCLOAK
+
+ // todo notsure if we need this
+ // addSecurityDomain(deploymentUnit, service);
}
private void addKeycloakAuthData(DeploymentPhaseContext phaseContext, String deploymentName, KeycloakAdapterConfigService service) {
diff --git a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java
index d16645d..5dd1e52 100755
--- a/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java
+++ b/integration/wildfly-subsystem/src/main/java/org/keycloak/subsystem/extension/KeycloakDependencyProcessor.java
@@ -36,7 +36,9 @@ import org.keycloak.subsystem.logging.KeycloakLogger;
*/
public class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
+ private static final ModuleIdentifier KEYCLOAK_WILDFLY_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-wildfly-adapter");
private static final ModuleIdentifier KEYCLOAK_UNDERTOW_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-undertow-adapter");
+ private static final ModuleIdentifier KEYCLOAK_JBOSS_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-jboss-adapter-core");
private static final ModuleIdentifier KEYCLOAK_CORE_ADAPTER = ModuleIdentifier.create("org.keycloak.keycloak-adapter-core");
private static final ModuleIdentifier KEYCLOAK_CORE = ModuleIdentifier.create("org.keycloak.keycloak-core");
//private static final ModuleIdentifier APACHE_HTTPCOMPONENTS = ModuleIdentifier.create("org.apache.httpcomponents");
@@ -51,7 +53,9 @@ public class KeycloakDependencyProcessor implements DeploymentUnitProcessor {
final ModuleSpecification moduleSpecification = deploymentUnit.getAttachment(Attachments.MODULE_SPECIFICATION);
final ModuleLoader moduleLoader = Module.getBootModuleLoader();
- moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_UNDERTOW_ADAPTER, false, false, true, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_WILDFLY_ADAPTER, false, false, true, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_UNDERTOW_ADAPTER, false, false, false, false));
+ moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_JBOSS_CORE_ADAPTER, false, false, false, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE_ADAPTER, false, false, false, false));
moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, KEYCLOAK_CORE, false, false, false, false));
//moduleSpecification.addSystemDependency(new ModuleDependency(moduleLoader, APACHE_HTTPCOMPONENTS, false, false, true, false));
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java b/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java
index c5cc177..50ed5ea 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/AdminService.java
@@ -218,7 +218,7 @@ public class AdminService {
}
}
- @Path("isLoggedIn.js")
+ @Path("isLoggedIn.js")
@GET
@Produces("application/javascript")
@NoCache