keycloak-aplcache

KEYCLOAK-720 Support for relative URI resolved by hostname

9/30/2014 10:43:00 AM

Details

diff --git a/examples/demo-template/customer-app/src/main/java/org/keycloak/example/AdminClient.java b/examples/demo-template/customer-app/src/main/java/org/keycloak/example/AdminClient.java
index 0e14f29..8bf9d59 100755
--- a/examples/demo-template/customer-app/src/main/java/org/keycloak/example/AdminClient.java
+++ b/examples/demo-template/customer-app/src/main/java/org/keycloak/example/AdminClient.java
@@ -42,7 +42,7 @@ public class AdminClient {
         HttpClient client = new HttpClientBuilder()
                 .disableTrustManager().build();
         try {
-            HttpGet get = new HttpGet(getBaseUrl(req) + "/auth/admin/realms/demo/roles");
+            HttpGet get = new HttpGet(CustomerDatabaseClient.getBaseUrl(req, session) + "/auth/admin/realms/demo/roles");
             get.addHeader("Authorization", "Bearer " + session.getTokenString());
             try {
                 HttpResponse response = client.execute(get);
@@ -64,9 +64,4 @@ public class AdminClient {
         }
     }
 
-    public static String getBaseUrl(HttpServletRequest request) {
-        String url = request.getRequestURL().toString();
-        return url.substring(0, url.indexOf('/', 8));
-    }
-
 }
diff --git a/examples/demo-template/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java b/examples/demo-template/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
index 83e6c7e..8468a48 100755
--- a/examples/demo-template/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
+++ b/examples/demo-template/customer-app/src/main/java/org/keycloak/example/CustomerDatabaseClient.java
@@ -6,8 +6,12 @@ import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
 import org.keycloak.KeycloakSecurityContext;
 import org.keycloak.adapters.HttpClientBuilder;
+import org.keycloak.adapters.KeycloakDeployment;
+import org.keycloak.adapters.RefreshableKeycloakSecurityContext;
+import org.keycloak.enums.RelativeUrlsUsed;
 import org.keycloak.representations.IDToken;
 import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.UriUtils;
 
 import javax.servlet.http.HttpServletRequest;
 import java.io.IOException;
@@ -48,7 +52,7 @@ public class CustomerDatabaseClient {
         HttpClient client = new HttpClientBuilder()
                 .disableTrustManager().build();
         try {
-            HttpGet get = new HttpGet(getBaseUrl(req) + "/database/customers");
+            HttpGet get = new HttpGet(getBaseUrl(req, session) + "/database/customers");
             get.addHeader("Authorization", "Bearer " + session.getTokenString());
             try {
                 HttpResponse response = client.execute(get);
@@ -70,8 +74,23 @@ public class CustomerDatabaseClient {
         }
     }
 
-    public static String getBaseUrl(HttpServletRequest request) {
-        String url = request.getRequestURL().toString();
-        return url.substring(0, url.indexOf('/', 8));
+    public static String getBaseUrl(HttpServletRequest request, KeycloakSecurityContext session) {
+        if (session instanceof RefreshableKeycloakSecurityContext) {
+            KeycloakDeployment deployment = ((RefreshableKeycloakSecurityContext)session).getDeployment();
+            switch (deployment.getRelativeUrls()) {
+                case ALL_REQUESTS:
+                    // Resolve baseURI from the request
+                    return UriUtils.getOrigin(request.getRequestURL().toString());
+                case BROWSER_ONLY:
+                    // Resolve baseURI from the codeURL (This is already non-relative and based on our hostname)
+                    return UriUtils.getOrigin(deployment.getCodeUrl());
+                case NEVER:
+                    return "";
+                default:
+                    return "";
+            }
+        } else {
+            return UriUtils.getOrigin(request.getRequestURL().toString());
+        }
     }
 }
diff --git a/examples/demo-template/customer-app/src/main/webapp/WEB-INF/keycloak.json b/examples/demo-template/customer-app/src/main/webapp/WEB-INF/keycloak.json
index c2241b3..ca0707e 100755
--- a/examples/demo-template/customer-app/src/main/webapp/WEB-INF/keycloak.json
+++ b/examples/demo-template/customer-app/src/main/webapp/WEB-INF/keycloak.json
@@ -7,5 +7,6 @@
     "expose-token": true,
     "credentials": {
         "secret": "password"
-    }
+    },
+    "use-hostname-for-local-requests": false
 }
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
index 676fcae..f1e5292 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterDeploymentContext.java
@@ -5,6 +5,7 @@ import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
 import org.jboss.logging.Logger;
+import org.keycloak.enums.RelativeUrlsUsed;
 import org.keycloak.enums.SslRequired;
 import org.keycloak.representations.adapters.config.AdapterConfig;
 import org.keycloak.representations.idm.PublishedRealmRepresentation;
@@ -48,14 +49,23 @@ public class AdapterDeploymentContext {
         KeycloakDeployment deployment = this.deployment;
         if (deployment == null) return null;
         if (deployment.getAuthServerBaseUrl() == null) return deployment;
-        if (deployment.relativeUrls) {
-            deployment = new DeploymentDelegate(this.deployment);
-            deployment.setAuthServerBaseUrl(getBaseBuilder(facade, this.deployment.getAuthServerBaseUrl()).build().toString());
-        }
+
+        deployment = resolveUrls(deployment, facade);
         if (deployment.getRealmKey() == null) resolveRealmKey(deployment);
         return deployment;
     }
 
+    protected KeycloakDeployment resolveUrls(KeycloakDeployment deployment, HttpFacade facade) {
+        if (deployment.relativeUrls == RelativeUrlsUsed.NEVER) {
+            // Absolute URI are already set to everything
+            return deployment;
+        } else {
+            DeploymentDelegate delegate = new DeploymentDelegate(this.deployment);
+            delegate.setAuthServerBaseUrl(getBaseBuilder(facade, this.deployment.getAuthServerBaseUrl()).build().toString());
+            return delegate;
+        }
+    }
+
     protected void resolveRealmKey(KeycloakDeployment deployment) {
         if (deployment.getClient() == null) {
             throw new RuntimeException("KeycloakDeployment was never initialized through appropriate SPIs");
@@ -107,6 +117,46 @@ public class AdapterDeploymentContext {
             this.delegate = delegate;
         }
 
+        public void setAuthServerBaseUrl(String authServerBaseUrl) {
+            this.authServerBaseUrl = authServerBaseUrl;
+            KeycloakUriBuilder serverBuilder = KeycloakUriBuilder.fromUri(authServerBaseUrl);
+            resolveBrowserUrls(serverBuilder);
+
+            if (delegate.getRelativeUrls() == RelativeUrlsUsed.ALL_REQUESTS) {
+                resolveNonBrowserUrls(serverBuilder);
+            }
+        }
+
+        @Override
+        public RelativeUrlsUsed getRelativeUrls() {
+            return delegate.getRelativeUrls();
+        }
+
+        @Override
+        public String getRealmInfoUrl() {
+            return (this.realmInfoUrl != null) ? this.realmInfoUrl : delegate.getRealmInfoUrl();
+        }
+
+        @Override
+        public String getCodeUrl() {
+            return (this.codeUrl != null) ? this.codeUrl : delegate.getCodeUrl();
+        }
+
+        @Override
+        public String getRefreshUrl() {
+            return (this.refreshUrl != null) ? this.refreshUrl : delegate.getRefreshUrl();
+        }
+
+        @Override
+        public KeycloakUriBuilder getLogoutUrl() {
+            return (this.logoutUrl != null) ? this.logoutUrl : delegate.getLogoutUrl();
+        }
+
+        @Override
+        public String getAccountUrl() {
+            return (this.accountUrl != null) ? this.accountUrl : delegate.getAccountUrl();
+        }
+
         @Override
         public String getResourceName() {
             return delegate.getResourceName();
diff --git a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
index 053dddf..9709294 100755
--- a/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/KeycloakDeployment.java
@@ -1,9 +1,13 @@
 package org.keycloak.adapters;
 
 import org.apache.http.client.HttpClient;
+import org.jboss.logging.Logger;
 import org.keycloak.ServiceUrlConstants;
+import org.keycloak.enums.RelativeUrlsUsed;
 import org.keycloak.enums.SslRequired;
+import org.keycloak.representations.adapters.config.AdapterConfig;
 import org.keycloak.util.KeycloakUriBuilder;
+import org.keycloak.util.UriUtils;
 
 import java.net.URI;
 import java.security.PublicKey;
@@ -16,10 +20,11 @@ import java.util.Map;
  */
 public class KeycloakDeployment {
 
-    protected boolean relativeUrls;
+    private static final Logger log = Logger.getLogger(KeycloakDeployment.class);
+
+    protected RelativeUrlsUsed relativeUrls;
     protected String realm;
     protected PublicKey realmKey;
-    protected KeycloakUriBuilder serverBuilder;
     protected String authServerBaseUrl;
     protected String realmInfoUrl;
     protected KeycloakUriBuilder authUrl;
@@ -76,26 +81,62 @@ public class KeycloakDeployment {
         return authServerBaseUrl;
     }
 
-    public void setAuthServerBaseUrl(String authServerBaseUrl) {
+    public void setAuthServerBaseUrl(String authServerBaseUrl, AdapterConfig config) {
         this.authServerBaseUrl = authServerBaseUrl;
         if (authServerBaseUrl == null) return;
 
         URI uri = URI.create(authServerBaseUrl);
         if (uri.getHost() == null) {
-            relativeUrls = true;
-            return;
+            if (config.isUseHostnameForLocalRequests()) {
+                relativeUrls = RelativeUrlsUsed.BROWSER_ONLY;
+
+                KeycloakUriBuilder serverBuilder = KeycloakUriBuilder.fromUri(authServerBaseUrl);
+                serverBuilder.host(UriUtils.getHostName()).port(config.getLocalRequestsPort()).scheme(config.getLocalRequestsScheme());
+                resolveNonBrowserUrls(serverBuilder);
+            } else {
+                relativeUrls = RelativeUrlsUsed.ALL_REQUESTS;
+                return;
+            }
+        } else {
+            // We have absolute URI in config
+            relativeUrls = RelativeUrlsUsed.NEVER;
+            KeycloakUriBuilder serverBuilder = KeycloakUriBuilder.fromUri(authServerBaseUrl);
+            resolveBrowserUrls(serverBuilder);
+            resolveNonBrowserUrls(serverBuilder);
         }
+    }
+
 
-        relativeUrls = false;
 
-        serverBuilder = KeycloakUriBuilder.fromUri(authServerBaseUrl);
-        String login = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(getRealm()).toString();
+    /**
+     * @param authUrlBuilder absolute URI
+     */
+    protected void resolveBrowserUrls(KeycloakUriBuilder authUrlBuilder) {
+        if (log.isDebugEnabled()) {
+            log.debug("resolveBrowserUrls");
+        }
+
+        String login = authUrlBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(getRealm()).toString();
         authUrl = KeycloakUriBuilder.fromUri(login);
-        refreshUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(getRealm()).toString();
-        logoutUrl = KeycloakUriBuilder.fromUri(serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH).build(getRealm()).toString());
-        accountUrl = serverBuilder.clone().path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH).build(getRealm()).toString();
-        realmInfoUrl = serverBuilder.clone().path(ServiceUrlConstants.REALM_INFO_PATH).build(getRealm()).toString();
-        codeUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(getRealm()).toString();
+    }
+
+    /**
+     * @param authUrlBuilder absolute URI
+     */
+    protected void resolveNonBrowserUrls(KeycloakUriBuilder authUrlBuilder) {
+        if (log.isDebugEnabled()) {
+            log.debug("resolveNonBrowserUrls");
+        }
+
+        refreshUrl = authUrlBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(getRealm()).toString();
+        logoutUrl = KeycloakUriBuilder.fromUri(authUrlBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGOUT_PATH).build(getRealm()).toString());
+        accountUrl = authUrlBuilder.clone().path(ServiceUrlConstants.ACCOUNT_SERVICE_PATH).build(getRealm()).toString();
+        realmInfoUrl = authUrlBuilder.clone().path(ServiceUrlConstants.REALM_INFO_PATH).build(getRealm()).toString();
+        codeUrl = authUrlBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(getRealm()).toString();
+    }
+
+    public RelativeUrlsUsed getRelativeUrls() {
+        return relativeUrls;
     }
 
     public String getRealmInfoUrl() {
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 963519b..0a3ab33 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
@@ -2,6 +2,7 @@ package org.keycloak.adapters;
 
 import org.codehaus.jackson.map.ObjectMapper;
 import org.codehaus.jackson.map.annotate.JsonSerialize;
+import org.jboss.logging.Logger;
 import org.keycloak.enums.SslRequired;
 import org.keycloak.representations.adapters.config.AdapterConfig;
 import org.keycloak.util.PemUtils;
@@ -15,6 +16,9 @@ import java.security.PublicKey;
  * @version $Revision: 1 $
  */
 public class KeycloakDeploymentBuilder {
+
+    private static final Logger log = Logger.getLogger(KeycloakDeploymentBuilder.class);
+
     protected KeycloakDeployment deployment = new KeycloakDeployment();
 
     protected KeycloakDeploymentBuilder() {
@@ -68,7 +72,9 @@ public class KeycloakDeploymentBuilder {
         if (adapterConfig.getAuthServerUrl() == null && (!deployment.isBearerOnly() || realmKeyPem == null)) {
             throw new RuntimeException("You must specify auth-url");
         }
-        deployment.setAuthServerBaseUrl(adapterConfig.getAuthServerUrl());
+        deployment.setAuthServerBaseUrl(adapterConfig.getAuthServerUrl(), adapterConfig);
+
+        log.debug("Use authServerUrl: " + deployment.getAuthServerBaseUrl() + ", codeUrl: " + deployment.getCodeUrl() + ", relativeUrls: " + deployment.getRelativeUrls());
         return deployment;
     }