keycloak-uncached

Details

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
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>