keycloak-uncached
Changes
adapters/oidc/fuse7/jetty94/pom.xml 130(+130 -0)
adapters/oidc/fuse7/jetty94/src/main/java/org/keycloak/adapters/osgi/jetty94/KeycloakAuthenticatorService.java 41(+41 -0)
adapters/oidc/fuse7/jetty94/src/main/java/org/keycloak/adapters/osgi/jetty94/PaxWebIntegrationService.java 275(+275 -0)
adapters/oidc/fuse7/jetty94/src/main/resources/META-INF/services/org.ops4j.pax.web.service.AuthenticatorService 1(+1 -0)
adapters/oidc/fuse7/pom.xml 1(+1 -0)
Details
adapters/oidc/fuse7/jetty94/pom.xml 130(+130 -0)
diff --git a/adapters/oidc/fuse7/jetty94/pom.xml b/adapters/oidc/fuse7/jetty94/pom.xml
new file mode 100644
index 0000000..b1a2913
--- /dev/null
+++ b/adapters/oidc/fuse7/jetty94/pom.xml
@@ -0,0 +1,130 @@
+<?xml version="1.0"?>
+<!--
+ ~ Copyright 2016 Red Hat, Inc. and/or its affiliates
+ ~ and other contributors as indicated by the @author tags.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<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-fuse7-integration-pom</artifactId>
+ <groupId>org.keycloak</groupId>
+ <version>4.0.0.Beta3-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>keycloak-pax-web-jetty94</artifactId>
+ <name>Keycloak Fuse 7.0 Adapter - Jetty 9.4</name>
+ <packaging>bundle</packaging>
+
+ <properties>
+ <keycloak.osgi.export>
+ org.keycloak.adapters.osgi.jetty94.*;version="${project.version}"
+ </keycloak.osgi.export>
+ <keycloak.osgi.import>
+ !org.keycloak.adapters.osgi.jetty94,
+ org.keycloak.*;version="${project.version}",
+ *;resolution:=optional
+ </keycloak.osgi.import>
+ <keycloak.osgi.fragment>org.ops4j.pax.web.pax-web-jetty</keycloak.osgi.fragment>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.jboss.logging</groupId>
+ <artifactId>jboss-logging</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.web</groupId>
+ <artifactId>pax-web-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.ops4j.pax.web</groupId>
+ <artifactId>pax-web-spi</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.enterprise</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>org.keycloak</groupId>
+ <artifactId>keycloak-jetty94-adapter</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-security</artifactId>
+ <version>${jetty9.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>${maven.compiler.source}</source>
+ <target>${maven.compiler.target}</target>
+ </configuration>
+ </plugin>
+
+ <!-- Adding OSGI metadata to the JAR without changing the packaging type. -->
+ <plugin>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <instructions>
+ <Bundle-Name>${project.name}</Bundle-Name>
+ <Bundle-SymbolicName>${project.groupId}.${project.artifactId}</Bundle-SymbolicName>
+ <Import-Package>${keycloak.osgi.import}</Import-Package>
+ <Export-Package>${keycloak.osgi.export}</Export-Package>
+ <Fragment-Host>${keycloak.osgi.fragment}</Fragment-Host>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/adapters/oidc/fuse7/jetty94/src/main/java/org/keycloak/adapters/osgi/jetty94/KeycloakAuthenticatorService.java b/adapters/oidc/fuse7/jetty94/src/main/java/org/keycloak/adapters/osgi/jetty94/KeycloakAuthenticatorService.java
new file mode 100644
index 0000000..30f7679
--- /dev/null
+++ b/adapters/oidc/fuse7/jetty94/src/main/java/org/keycloak/adapters/osgi/jetty94/KeycloakAuthenticatorService.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2018 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.osgi.jetty94;
+
+import org.ops4j.pax.web.service.AuthenticatorService;
+
+/**
+ *
+ * @author hmlnarik
+ */
+public class KeycloakAuthenticatorService implements AuthenticatorService {
+
+ @Override
+ public <T> T getAuthenticatorService(String method, Class<T> iface) {
+ if (method == null || iface != org.eclipse.jetty.security.Authenticator.class) {
+ return null;
+ }
+
+ if ("KEYCLOAK".equalsIgnoreCase(method)) {
+ return iface.cast(new org.keycloak.adapters.jetty.KeycloakJettyAuthenticator());
+ }
+
+ return null;
+ }
+
+}
diff --git a/adapters/oidc/fuse7/jetty94/src/main/java/org/keycloak/adapters/osgi/jetty94/PaxWebIntegrationService.java b/adapters/oidc/fuse7/jetty94/src/main/java/org/keycloak/adapters/osgi/jetty94/PaxWebIntegrationService.java
new file mode 100644
index 0000000..35f5d9f
--- /dev/null
+++ b/adapters/oidc/fuse7/jetty94/src/main/java/org/keycloak/adapters/osgi/jetty94/PaxWebIntegrationService.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright 2016 Red Hat, Inc. and/or its affiliates
+ * and other contributors as indicated by the @author tags.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.keycloak.adapters.osgi.jetty94;
+
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.util.security.Constraint;
+import org.jboss.logging.Logger;
+import org.ops4j.pax.web.service.WebContainer;
+import org.ops4j.pax.web.service.spi.model.SecurityConstraintMappingModel;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.http.HttpContext;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+import java.net.URL;
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Integration with pax-web, which allows to inject custom jetty-web.xml configuration from current bundle classpath into {@link WebContainer}
+ * and allows to inject custom security constraint for securing resources by Keycloak.
+ *
+ * <p>It assumes that pax-web {@link WebContainer} is used as implementation of OSGI {@link org.osgi.service.http.HttpService}, which
+ * is true in karaf/fuse environment</p>
+ *
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class PaxWebIntegrationService {
+
+ protected static final Logger log = Logger.getLogger(PaxWebIntegrationService.class);
+
+ private BundleContext bundleContext;
+ private String jettyWebXmlLocation;
+ private List<Object> constraintMappings;
+
+ private ServiceTracker webContainerTracker;
+ private HttpContext httpContext;
+
+ public BundleContext getBundleContext() {
+ return bundleContext;
+ }
+
+ public void setBundleContext(BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ }
+
+ public String getJettyWebXmlLocation() {
+ return jettyWebXmlLocation;
+ }
+
+ public void setJettyWebXmlLocation(String jettyWebXmlLocation) {
+ this.jettyWebXmlLocation = jettyWebXmlLocation;
+ }
+
+ public List<Object> getConstraintMappings() {
+ return constraintMappings;
+ }
+
+ public void setConstraintMappings(List<Object> constraintMappings) {
+ this.constraintMappings = constraintMappings;
+ }
+
+ protected ServiceTracker getWebContainerTracker() {
+ return webContainerTracker;
+ }
+
+ protected HttpContext getHttpContext() {
+ return httpContext;
+ }
+
+
+ public void start() {
+ ServiceTrackerCustomizer trackerCustomizer = new ServiceTrackerCustomizer() {
+
+ @Override
+ public Object addingService(ServiceReference reference) {
+ return addingWebContainerCallback(reference);
+ }
+
+ @Override
+ public void modifiedService(ServiceReference reference, Object service) {
+ }
+
+ @Override
+ public void removedService(ServiceReference reference, Object service) {
+ removingWebContainerCallback(reference);
+ }
+ };
+
+ webContainerTracker = new ServiceTracker(bundleContext, WebContainer.class.getName(), trackerCustomizer);
+ webContainerTracker.open();
+ }
+
+ public void stop() {
+ webContainerTracker.remove(webContainerTracker.getServiceReference());
+ }
+
+ protected WebContainer addingWebContainerCallback(ServiceReference webContainerServiceReference) {
+ WebContainer service = (WebContainer) bundleContext.getService(webContainerServiceReference);
+ httpContext = service.createDefaultHttpContext();
+
+ addJettyWebXml(service);
+
+ if (constraintMappings == null) {
+ throw new IllegalStateException("constraintMappings was null!");
+ }
+ List<ConstraintHandler> handlers = new ArrayList<>();
+ try {
+ handlers.add(new JettyConstraintHandler());
+ } catch (Throwable t) {
+ // Ignore
+ }
+ try {
+ handlers.add(new PaxWebConstraintHandler());
+ } catch (Throwable t) {
+ // Ignore
+ }
+ for (Object constraintMapping : constraintMappings) {
+ boolean handled = false;
+ for (ConstraintHandler handler : handlers) {
+ handled |= handler.addConstraintMapping(httpContext, service, constraintMapping);
+ }
+ if (!handled) {
+ log.warnv("Unable to add constraint mapping for constraint of type " + constraintMapping.getClass().toString());
+ }
+ }
+
+ service.registerLoginConfig("BASIC", "does-not-matter", null, null, httpContext);
+
+ return service;
+ }
+
+ protected void addJettyWebXml(WebContainer service) {
+ String jettyWebXmlLoc;
+ if (this.jettyWebXmlLocation == null) {
+ jettyWebXmlLoc = "/WEB-INF/jetty-web.xml";
+ } else {
+ jettyWebXmlLoc = this.jettyWebXmlLocation;
+ }
+
+ URL jettyWebXml = bundleContext.getBundle().getResource(jettyWebXmlLoc);
+ if (jettyWebXml != null) {
+ log.debug("Found jetty-web XML configuration on bundle classpath on " + jettyWebXmlLoc);
+ service.registerJettyWebXml(jettyWebXml, httpContext);
+ } else {
+ log.debug("Not found jetty-web XML configuration on bundle classpath on " + jettyWebXmlLoc);
+ }
+ }
+
+ protected void addConstraintMapping(WebContainer service, SecurityConstraintMappingModel constraintMapping) {
+ String name = constraintMapping.getConstraintName();
+ if (name == null) {
+ name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
+ }
+ log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getUrl() + ", dataConstraint=" + constraintMapping.getDataConstraint() + ", canAuthenticate="
+ + constraintMapping.isAuthentication() + ", roles=" + constraintMapping.getRoles());
+ service.registerConstraintMapping(name, constraintMapping.getUrl(), constraintMapping.getMapping(), constraintMapping.getDataConstraint(), constraintMapping.isAuthentication(), constraintMapping.getRoles(), httpContext);
+ }
+
+ protected void addConstraintMapping(WebContainer service, ConstraintMapping constraintMapping) {
+ Constraint constraint = constraintMapping.getConstraint();
+ String[] roles = constraint.getRoles();
+ // name property is unavailable on constraint object :/
+
+ String name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
+
+ int dataConstraint = constraint.getDataConstraint();
+ String dataConstraintStr;
+ switch (dataConstraint) {
+ case Constraint.DC_UNSET: dataConstraintStr = null; break;
+ case Constraint.DC_NONE: dataConstraintStr = "NONE"; break;
+ case Constraint.DC_CONFIDENTIAL: dataConstraintStr = "CONFIDENTIAL"; break;
+ case Constraint.DC_INTEGRAL: dataConstraintStr = "INTEGRAL"; break;
+ default:
+ log.warnv("Unknown data constraint: " + dataConstraint);
+ dataConstraintStr = "CONFIDENTIAL";
+ }
+ List<String> rolesList = Arrays.asList(roles);
+
+ log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getPathSpec() + ", dataConstraint=" + dataConstraintStr + ", canAuthenticate="
+ + constraint.getAuthenticate() + ", roles=" + rolesList);
+ service.registerConstraintMapping(name, constraintMapping.getPathSpec(), null, dataConstraintStr, constraint.getAuthenticate(), rolesList, httpContext);
+ }
+
+ protected void removingWebContainerCallback(ServiceReference serviceReference) {
+ WebContainer service = (WebContainer)bundleContext.getService(serviceReference);
+ if (service != null) {
+ service.unregisterLoginConfig(httpContext);
+ service.unregisterConstraintMapping(httpContext);
+ }
+ }
+
+ private interface ConstraintHandler {
+ boolean addConstraintMapping(HttpContext httpContext, WebContainer service, Object cm);
+ }
+
+ private static class PaxWebConstraintHandler implements ConstraintHandler {
+
+ public boolean addConstraintMapping(HttpContext httpContext, WebContainer service, Object cm) {
+ if (cm instanceof SecurityConstraintMappingModel) {
+ SecurityConstraintMappingModel constraintMapping = (SecurityConstraintMappingModel) cm;
+ String name = constraintMapping.getConstraintName();
+ if (name == null) {
+ name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
+ }
+ log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getUrl() + ", dataConstraint=" + constraintMapping.getDataConstraint() + ", canAuthenticate="
+ + constraintMapping.isAuthentication() + ", roles=" + constraintMapping.getRoles());
+ service.registerConstraintMapping(name, constraintMapping.getUrl(), constraintMapping.getMapping(), constraintMapping.getDataConstraint(), constraintMapping.isAuthentication(), constraintMapping.getRoles(), httpContext);
+ return true;
+ }
+ return false;
+ }
+
+ }
+
+ private static class JettyConstraintHandler implements ConstraintHandler {
+
+ public boolean addConstraintMapping(HttpContext httpContext, WebContainer service, Object cm) {
+ if (cm instanceof ConstraintMapping) {
+ ConstraintMapping constraintMapping = (ConstraintMapping) cm;
+ Constraint constraint = constraintMapping.getConstraint();
+ String[] roles = constraint.getRoles();
+ // name property is unavailable on constraint object :/
+
+ String name = "Constraint-" + new SecureRandom().nextInt(Integer.MAX_VALUE);
+
+ int dataConstraint = constraint.getDataConstraint();
+ String dataConstraintStr;
+ switch (dataConstraint) {
+ case Constraint.DC_UNSET:
+ dataConstraintStr = null;
+ break;
+ case Constraint.DC_NONE:
+ dataConstraintStr = "NONE";
+ break;
+ case Constraint.DC_CONFIDENTIAL:
+ dataConstraintStr = "CONFIDENTIAL";
+ break;
+ case Constraint.DC_INTEGRAL:
+ dataConstraintStr = "INTEGRAL";
+ break;
+ default:
+ log.warnv("Unknown data constraint: " + dataConstraint);
+ dataConstraintStr = "CONFIDENTIAL";
+ }
+ List<String> rolesList = Arrays.asList(roles);
+
+ log.debug("Adding security constraint name=" + name + ", url=" + constraintMapping.getPathSpec() + ", dataConstraint=" + dataConstraintStr + ", canAuthenticate="
+ + constraint.getAuthenticate() + ", roles=" + rolesList);
+ service.registerConstraintMapping(name, constraintMapping.getPathSpec(), null, dataConstraintStr, constraint.getAuthenticate(), rolesList, httpContext);
+ return true;
+ }
+ return false;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/adapters/oidc/fuse7/jetty94/src/main/resources/META-INF/services/org.ops4j.pax.web.service.AuthenticatorService b/adapters/oidc/fuse7/jetty94/src/main/resources/META-INF/services/org.ops4j.pax.web.service.AuthenticatorService
new file mode 100644
index 0000000..cce9788
--- /dev/null
+++ b/adapters/oidc/fuse7/jetty94/src/main/resources/META-INF/services/org.ops4j.pax.web.service.AuthenticatorService
@@ -0,0 +1 @@
+org.keycloak.adapters.osgi.jetty94.KeycloakAuthenticatorService
\ No newline at end of file
adapters/oidc/fuse7/pom.xml 1(+1 -0)
diff --git a/adapters/oidc/fuse7/pom.xml b/adapters/oidc/fuse7/pom.xml
index fad9726..6d90b84 100644
--- a/adapters/oidc/fuse7/pom.xml
+++ b/adapters/oidc/fuse7/pom.xml
@@ -38,6 +38,7 @@
<modules>
<module>camel-undertow</module>
+ <module>jetty94</module>
<module>undertow</module>
</modules>
</project>
diff --git a/adapters/oidc/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PaxWebIntegrationService.java b/adapters/oidc/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PaxWebIntegrationService.java
index 76cd62f..2cfb4c8 100644
--- a/adapters/oidc/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PaxWebIntegrationService.java
+++ b/adapters/oidc/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PaxWebIntegrationService.java
@@ -34,7 +34,7 @@ import java.util.Arrays;
import java.util.List;
/**
- * Integration with pax-web, which allows to inject custom jetty-web.xml configuration from current bundle classpath into {@link WebContainer}
+ * Integration with pax-web in Fuse 6.3, which allows to inject custom jetty-web.xml configuration from current bundle classpath into {@link WebContainer}
* and allows to inject custom security constraint for securing resources by Keycloak.
*
* <p>It assumes that pax-web {@link WebContainer} is used as implementation of OSGI {@link org.osgi.service.http.HttpService}, which
diff --git a/distribution/adapters/osgi/features/src/main/resources/features.xml b/distribution/adapters/osgi/features/src/main/resources/features.xml
index c510990..8899b34 100755
--- a/distribution/adapters/osgi/features/src/main/resources/features.xml
+++ b/distribution/adapters/osgi/features/src/main/resources/features.xml
@@ -62,6 +62,19 @@
<bundle>mvn:org.keycloak/keycloak-jetty92-adapter/${project.version}</bundle>
</feature>
+ <!-- Keycloak adapter for PaxWeb jetty provider -->
+<!--
+ <feature name="keycloak-pax-http-jetty" version="${project.version}">
+ <details>Keycloak Pax-Web adapter for Jetty 9.4</details>
+ <feature>keycloak-adapter-core</feature>
+ <feature>keycloak-osgi-adapter</feature>
+ <bundle>mvn:org.keycloak/keycloak-jetty-adapter-spi/${project.version}</bundle>
+ <bundle>mvn:org.keycloak/keycloak-jetty-core/${project.version}</bundle>
+ <bundle>mvn:org.keycloak/keycloak-jetty94-adapter/${project.version}</bundle>
+ <bundle>mvn:org.keycloak/keycloak-pax-web-jetty94/${project.version}</bundle>
+ </feature>
+ -->
+
<!-- Keycloak adapter for PaxWeb undertow provider -->
<feature name="keycloak-pax-http-undertow" version="${project.version}">
<details>Keycloak Pax-Web adapter for Undertow</details>