keycloak-uncached

Details

diff --git a/adapters/oidc/osgi-adapter/pom.xml b/adapters/oidc/osgi-adapter/pom.xml
index 086660d..cb75926 100755
--- a/adapters/oidc/osgi-adapter/pom.xml
+++ b/adapters/oidc/osgi-adapter/pom.xml
@@ -99,6 +99,12 @@
             <version>${cxf.version}</version>
             <scope>provided</scope>
         </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/adapters/oidc/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PathBasedKeycloakConfigResolver.java b/adapters/oidc/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PathBasedKeycloakConfigResolver.java
index 77e19df..e280f41 100644
--- a/adapters/oidc/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PathBasedKeycloakConfigResolver.java
+++ b/adapters/oidc/osgi-adapter/src/main/java/org/keycloak/adapters/osgi/PathBasedKeycloakConfigResolver.java
@@ -25,6 +25,7 @@ import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.InputStream;
+import java.net.URI;
 import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -34,13 +35,35 @@ public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
 
     @Override
     public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
-        String path = request.getURI();
-        String[] urlTokens = path.split("/");
-        if (urlTokens.length <  4) {
-            throw new IllegalStateException("Not able to determine the web-context to load the correspondent keycloak.json file");
-        }
+        String uri = request.getURI();
+        String relativePath = request.getRelativePath();
+        String webContext = null;
+        if (relativePath == null || !uri.contains(relativePath)) {
+            String[] urlTokens = uri.split("/");
+            if (urlTokens.length <  4) {
+                throw new IllegalStateException("Not able to determine the web-context to load the correspondent keycloak.json file");
+            }
 
-        String webContext = urlTokens[3];
+            webContext = urlTokens[3];
+        } else {
+            URI parsedURI = URI.create(uri);
+            String path = parsedURI.getPath();
+            path = path.substring(0, path.indexOf(relativePath));
+            while (path.startsWith("/")) {
+                path = path.substring(1);
+            }
+            webContext = path;
+            if ("".equals(webContext)) {
+                path = relativePath;
+                while (path.startsWith("/")) {
+                    path = path.substring(1);
+                }
+                if (path.contains("/")) {
+                    path = path.substring(0, path.indexOf("/"));
+                }
+                webContext = path;
+            }
+        }
 
         KeycloakDeployment deployment = cache.get(webContext);
         if (null == deployment) {
@@ -54,7 +77,8 @@ public class PathBasedKeycloakConfigResolver implements KeycloakConfigResolver {
                 keycloakConfig = karafEtc;
             }
 
-            String absolutePath = keycloakConfig + File.separator + webContext + "-keycloak.json";
+            String absolutePath = keycloakConfig + File.separator + webContext + ("".equals(webContext) ? "" : "-")
+                    + "keycloak.json";
             InputStream is = null;
             try {
                 is = new FileInputStream(absolutePath);
diff --git a/adapters/oidc/osgi-adapter/src/test/java/org/keycloak/adapters/osgi/PathBasedKeycloakConfigResolverTest.java b/adapters/oidc/osgi-adapter/src/test/java/org/keycloak/adapters/osgi/PathBasedKeycloakConfigResolverTest.java
new file mode 100644
index 0000000..f679e55
--- /dev/null
+++ b/adapters/oidc/osgi-adapter/src/test/java/org/keycloak/adapters/osgi/PathBasedKeycloakConfigResolverTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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;
+
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.OIDCHttpFacade;
+import org.keycloak.adapters.spi.AuthenticationError;
+import org.keycloak.adapters.spi.HttpFacade;
+import org.keycloak.adapters.spi.LogoutError;
+
+import static org.junit.Assert.assertNotNull;
+
+public class PathBasedKeycloakConfigResolverTest {
+
+    @Test
+    public void relativeURIsAndContexts() throws Exception {
+        PathBasedKeycloakConfigResolver resolver = new PathBasedKeycloakConfigResolver();
+
+        assertNotNull(populate(resolver, "test")
+                .resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/a/b/c")));
+
+        assertNotNull(populate(resolver, "test")
+                .resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/a/b")));
+
+        // means default context and actually we use first segment
+        assertNotNull(populate(resolver, "test")
+                .resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/test/a/b/c")));
+
+        assertNotNull(populate(resolver, "test/a")
+                .resolve(new MockRequest("http://localhost/test/a/b/c?d=e", "/b/c")));
+
+        assertNotNull(populate(resolver, "")
+                .resolve(new MockRequest("http://localhost/", "/")));
+    }
+
+    @SuppressWarnings("unchecked")
+    private PathBasedKeycloakConfigResolver populate(PathBasedKeycloakConfigResolver resolver, String context)
+            throws Exception {
+        Field f = PathBasedKeycloakConfigResolver.class.getDeclaredField("cache");
+        f.setAccessible(true);
+        Map<String, KeycloakDeployment> cache = (Map<String, KeycloakDeployment>) f.get(resolver);
+        cache.clear();
+        cache.put(context, new KeycloakDeployment());
+
+        return resolver;
+    }
+
+    private class MockRequest implements OIDCHttpFacade.Request {
+
+        private String uri;
+        private String relativePath;
+
+        public MockRequest(String uri, String relativePath) {
+            this.uri = uri;
+            this.relativePath = relativePath;
+        }
+
+        @Override
+        public String getMethod() {
+            return null;
+        }
+
+        @Override
+        public String getURI() {
+            return this.uri;
+        }
+
+        @Override
+        public String getRelativePath() {
+            return this.relativePath;
+        }
+
+        @Override
+        public boolean isSecure() {
+            return false;
+        }
+
+        @Override
+        public String getFirstParam(String param) {
+            return null;
+        }
+
+        @Override
+        public String getQueryParamValue(String param) {
+            return null;
+        }
+
+        @Override
+        public HttpFacade.Cookie getCookie(String cookieName) {
+            return null;
+        }
+
+        @Override
+        public String getHeader(String name) {
+            return null;
+        }
+
+        @Override
+        public List<String> getHeaders(String name) {
+            return null;
+        }
+
+        @Override
+        public InputStream getInputStream() {
+            return null;
+        }
+
+        @Override
+        public InputStream getInputStream(boolean buffered) {
+            return null;
+        }
+
+        @Override
+        public String getRemoteAddr() {
+            return null;
+        }
+
+        @Override
+        public void setError(AuthenticationError error) {
+
+        }
+
+        @Override
+        public void setError(LogoutError error) {
+
+        }
+    }
+
+}