keycloak-aplcache

Merge pull request #719 from mposolda/master KEYCLOAK-721

9/30/2014 3:17:25 PM

Changes

Details

diff --git a/core/src/main/java/org/keycloak/AbstractOAuthClient.java b/core/src/main/java/org/keycloak/AbstractOAuthClient.java
index 600dab0..00fa0ed 100755
--- a/core/src/main/java/org/keycloak/AbstractOAuthClient.java
+++ b/core/src/main/java/org/keycloak/AbstractOAuthClient.java
@@ -1,5 +1,6 @@
 package org.keycloak;
 
+import org.keycloak.enums.RelativeUrlsUsed;
 import org.keycloak.util.KeycloakUriBuilder;
 
 import java.util.Map;
@@ -19,7 +20,7 @@ public class AbstractOAuthClient {
     protected String authUrl;
     protected String codeUrl;
     protected String refreshUrl;
-    protected boolean relativeUrls;
+    protected RelativeUrlsUsed relativeUrlsUsed;
     protected String scope;
     protected String stateCookieName = OAUTH_TOKEN_REQUEST_STATE;
     protected String stateCookiePath;
@@ -101,12 +102,12 @@ public class AbstractOAuthClient {
         this.publicClient = publicClient;
     }
 
-    public boolean isRelativeUrls() {
-        return relativeUrls;
+    public RelativeUrlsUsed getRelativeUrlsUsed() {
+        return relativeUrlsUsed;
     }
 
-    public void setRelativeUrls(boolean relativeUrls) {
-        this.relativeUrls = relativeUrls;
+    public void setRelativeUrlsUsed(RelativeUrlsUsed relativeUrlsUsed) {
+        this.relativeUrlsUsed = relativeUrlsUsed;
     }
 
     protected String stripOauthParametersFromRedirect(String uri) {
diff --git a/core/src/main/java/org/keycloak/enums/RelativeUrlsUsed.java b/core/src/main/java/org/keycloak/enums/RelativeUrlsUsed.java
new file mode 100644
index 0000000..cadeb14
--- /dev/null
+++ b/core/src/main/java/org/keycloak/enums/RelativeUrlsUsed.java
@@ -0,0 +1,36 @@
+package org.keycloak.enums;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public enum RelativeUrlsUsed {
+
+    /**
+     * Always use relative URI and resolve them later based on browser HTTP request
+     */
+    ALL_REQUESTS,
+
+    /**
+     * Use relative Uris just for browser requests and resolve those based on browser HTTP requests.
+     * Backend request (like refresh token request, codeToToken request etc) will use the URI based on current hostname
+     */
+    BROWSER_ONLY,
+
+    /**
+     * Relative Uri not used. Configuration contains absolute URI
+     */
+    NEVER;
+
+    public boolean useRelative(boolean isBrowserReq) {
+        switch (this) {
+            case ALL_REQUESTS:
+                return true;
+            case NEVER:
+                return false;
+            case BROWSER_ONLY:
+                return isBrowserReq;
+            default:
+                return true;
+        }
+    }
+}
diff --git a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
index 39552b2..acb4243 100755
--- a/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
+++ b/core/src/main/java/org/keycloak/representations/adapters/config/AdapterConfig.java
@@ -16,7 +16,8 @@ import org.codehaus.jackson.annotate.JsonPropertyOrder;
         "expose-token", "bearer-only",
         "connection-pool-size",
         "allow-any-hostname", "disable-trust-manager", "truststore", "truststore-password",
-        "client-keystore", "client-keystore-password", "client-key-password"
+        "client-keystore", "client-keystore-password", "client-key-password",
+        "use-hostname-for-local-requests", "local-requests-scheme", "local-requests-port"
 })
 public class AdapterConfig extends BaseAdapterConfig {
 
@@ -36,6 +37,12 @@ public class AdapterConfig extends BaseAdapterConfig {
     protected String clientKeyPassword;
     @JsonProperty("connection-pool-size")
     protected int connectionPoolSize = 20;
+    @JsonProperty("use-hostname-for-local-requests")
+    protected boolean useHostnameForLocalRequests;
+    @JsonProperty("local-requests-scheme")
+    protected String localRequestsScheme = "http";
+    @JsonProperty("local-requests-port")
+    protected int localRequestsPort = 8080;
 
     public boolean isAllowAnyHostname() {
         return allowAnyHostname;
@@ -101,4 +108,27 @@ public class AdapterConfig extends BaseAdapterConfig {
         this.connectionPoolSize = connectionPoolSize;
     }
 
+    public boolean isUseHostnameForLocalRequests() {
+        return useHostnameForLocalRequests;
+    }
+
+    public void setUseHostnameForLocalRequests(boolean useHostnameForLocalRequests) {
+        this.useHostnameForLocalRequests = useHostnameForLocalRequests;
+    }
+
+    public String getLocalRequestsScheme() {
+        return localRequestsScheme;
+    }
+
+    public void setLocalRequestsScheme(String localRequestsScheme) {
+        this.localRequestsScheme = localRequestsScheme;
+    }
+
+    public int getLocalRequestsPort() {
+        return localRequestsPort;
+    }
+
+    public void setLocalRequestsPort(int localRequestsPort) {
+        this.localRequestsPort = localRequestsPort;
+    }
 }
diff --git a/core/src/main/java/org/keycloak/util/UriUtils.java b/core/src/main/java/org/keycloak/util/UriUtils.java
index 873283f..60418ea 100644
--- a/core/src/main/java/org/keycloak/util/UriUtils.java
+++ b/core/src/main/java/org/keycloak/util/UriUtils.java
@@ -1,6 +1,8 @@
 package org.keycloak.util;
 
+import java.net.InetAddress;
 import java.net.URI;
+import java.net.UnknownHostException;
 
 /**
  * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
@@ -16,4 +18,12 @@ public class UriUtils {
         return u.substring(0, u.indexOf('/', 8));
     }
 
+    public static String getHostName() {
+        try {
+            return InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException uhe) {
+            throw new IllegalStateException(uhe);
+        }
+    }
+
 }
diff --git a/examples/demo-template/admin-access-app/src/main/java/org/keycloak/example/AdminClient.java b/examples/demo-template/admin-access-app/src/main/java/org/keycloak/example/AdminClient.java
index d97e285..2a83775 100755
--- a/examples/demo-template/admin-access-app/src/main/java/org/keycloak/example/AdminClient.java
+++ b/examples/demo-template/admin-access-app/src/main/java/org/keycloak/example/AdminClient.java
@@ -15,6 +15,7 @@ import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.util.JsonSerialization;
 import org.keycloak.util.KeycloakUriBuilder;
+import org.keycloak.util.UriUtils;
 
 import javax.servlet.http.HttpServletRequest;
 import java.io.ByteArrayOutputStream;
@@ -158,8 +159,12 @@ public class AdminClient {
     }
 
     public static String getBaseUrl(HttpServletRequest request) {
-        String url = request.getRequestURL().toString();
-        return url.substring(0, url.indexOf('/', 8));
+        String useHostname = request.getServletContext().getInitParameter("useHostname");
+        if (useHostname != null && "true".equalsIgnoreCase(useHostname)) {
+            return "http://" + UriUtils.getHostName() + ":8080";
+        } else {
+            return UriUtils.getOrigin(request.getRequestURL().toString());
+        }
     }
 
 }
diff --git a/examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/web.xml b/examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/web.xml
index 1c496ce..89fe10e 100755
--- a/examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/web.xml
+++ b/examples/demo-template/admin-access-app/src/main/webapp/WEB-INF/web.xml
@@ -6,4 +6,9 @@
 
     <module-name>admin-access</module-name>
 
+    <context-param>
+        <param-name>useHostname</param-name>
+        <param-value>false</param-value>
+    </context-param>
+
 </web-app>
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..611292b 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
@@ -5,6 +5,7 @@ import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
 import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.AdapterUtils;
 import org.keycloak.adapters.HttpClientBuilder;
 import org.keycloak.representations.idm.RoleRepresentation;
 import org.keycloak.util.JsonSerialization;
@@ -42,7 +43,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(AdapterUtils.getBaseUrl(req.getRequestURL().toString(), session) + "/auth/admin/realms/demo/roles");
             get.addHeader("Authorization", "Bearer " + session.getTokenString());
             try {
                 HttpResponse response = client.execute(get);
@@ -64,9 +65,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..7e3d74c 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
@@ -5,11 +5,18 @@ import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
 import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.AdapterUtils;
 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 javax.servlet.http.HttpSession;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.ArrayList;
@@ -48,7 +55,7 @@ public class CustomerDatabaseClient {
         HttpClient client = new HttpClientBuilder()
                 .disableTrustManager().build();
         try {
-            HttpGet get = new HttpGet(getBaseUrl(req) + "/database/customers");
+            HttpGet get = new HttpGet(AdapterUtils.getBaseUrl(req.getRequestURL().toString(), session) + "/database/customers");
             get.addHeader("Authorization", "Bearer " + session.getTokenString());
             try {
                 HttpResponse response = client.execute(get);
@@ -70,8 +77,11 @@ public class CustomerDatabaseClient {
         }
     }
 
-    public static String getBaseUrl(HttpServletRequest request) {
-        String url = request.getRequestURL().toString();
-        return url.substring(0, url.indexOf('/', 8));
+    public static String increaseAndGetCounter(HttpServletRequest req) {
+        HttpSession session = req.getSession();
+        Integer counter = (Integer)session.getAttribute("counter");
+        counter = (counter == null) ? 1 : counter + 1;
+        session.setAttribute("counter", counter);
+        return String.valueOf(counter);
     }
 }
diff --git a/examples/demo-template/customer-app/src/main/webapp/customers/session.jsp b/examples/demo-template/customer-app/src/main/webapp/customers/session.jsp
new file mode 100644
index 0000000..07f99a1
--- /dev/null
+++ b/examples/demo-template/customer-app/src/main/webapp/customers/session.jsp
@@ -0,0 +1,17 @@
+<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
+         pageEncoding="ISO-8859-1" %>
+<%@ page import="org.keycloak.ServiceUrlConstants" %>
+<%@ page import="org.keycloak.example.CustomerDatabaseClient" %>
+<%@ page import="org.keycloak.representations.IDToken" %>
+<%@ page import="org.keycloak.util.UriUtils" %>
+<html>
+  <head>
+    <title>Customer Session Page</title>
+  </head>
+  <body bgcolor="#E3F6CE">
+    <p>Your hostname: <%= UriUtils.getHostName() %></p>
+    <p>Your session ID: <%= request.getSession().getId() %></p>
+    <p>You visited this page <b><%= CustomerDatabaseClient.increaseAndGetCounter(request) %></b> times.</p>
+    <br><br>
+  </body>
+</html>
\ No newline at end of file
diff --git a/examples/demo-template/customer-app/src/main/webapp/index.html b/examples/demo-template/customer-app/src/main/webapp/index.html
index 1da03e4..8eb0c32 100755
--- a/examples/demo-template/customer-app/src/main/webapp/index.html
+++ b/examples/demo-template/customer-app/src/main/webapp/index.html
@@ -11,5 +11,8 @@
 
 <p><a href="admin/admin.jsp">Customer Admin Interface</a></p>
 
+<p><a href="customers/session.jsp">Customer Session</a></p>
+
+
 </body>
 </html>
\ No newline at end of file
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/examples/demo-template/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java b/examples/demo-template/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
index 79827b3..9557f28 100755
--- a/examples/demo-template/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
+++ b/examples/demo-template/product-app/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.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.keycloak.KeycloakSecurityContext;
+import org.keycloak.adapters.AdapterUtils;
 import org.keycloak.adapters.HttpClientBuilder;
 import org.keycloak.util.JsonSerialization;
 
@@ -39,7 +40,7 @@ public class ProductDatabaseClient
         HttpClient client = new HttpClientBuilder()
                 .disableTrustManager().build();
         try {
-            HttpGet get = new HttpGet(getBaseUrl(req) + "/database/products");
+            HttpGet get = new HttpGet(AdapterUtils.getBaseUrl(req.getRequestURL().toString(), session) + "/database/products");
             get.addHeader("Authorization", "Bearer " + session.getTokenString());
             try {
                 HttpResponse response = client.execute(get);
@@ -61,9 +62,4 @@ public class ProductDatabaseClient
         }
     }
 
-    public static String getBaseUrl(HttpServletRequest request) {
-        String url = request.getRequestURL().toString();
-        return url.substring(0, url.indexOf('/', 8));
-    }
-
 }
diff --git a/examples/demo-template/product-app/src/main/webapp/WEB-INF/keycloak.json b/examples/demo-template/product-app/src/main/webapp/WEB-INF/keycloak.json
index fb07e7f..c1ae517 100755
--- a/examples/demo-template/product-app/src/main/webapp/WEB-INF/keycloak.json
+++ b/examples/demo-template/product-app/src/main/webapp/WEB-INF/keycloak.json
@@ -6,5 +6,6 @@
   "ssl-required" : "external",
   "credentials" : {
       "secret": "password"
-   }
+  },
+  "use-hostname-for-local-requests": false
 }
diff --git a/examples/demo-template/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java b/examples/demo-template/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
index d9377c9..a12bcee 100755
--- a/examples/demo-template/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
+++ b/examples/demo-template/third-party/src/main/java/org/keycloak/example/oauth/ProductDatabaseClient.java
@@ -5,9 +5,11 @@ import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
 import org.keycloak.adapters.ServerRequest;
+import org.keycloak.enums.RelativeUrlsUsed;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.servlet.ServletOAuthClient;
 import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.UriUtils;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -58,7 +60,6 @@ public class ProductDatabaseClient {
         // and obtain the ServletOAuthClient.  I actually suggest downloading the ServletOAuthClient code
         // and take a look how it works. You can also take a look at third-party-cdi example
         ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
-        String token = null;
         try {
             return oAuthClient.getBearerToken(request);
         } catch (IOException e) {
@@ -78,7 +79,7 @@ public class ProductDatabaseClient {
         ServletOAuthClient oAuthClient = (ServletOAuthClient) request.getServletContext().getAttribute(ServletOAuthClient.class.getName());
         HttpClient client = oAuthClient.getClient();
 
-        HttpGet get = new HttpGet(getBaseUrl(request) + "/database/products");
+        HttpGet get = new HttpGet(getBaseUrl(oAuthClient, request) + "/database/products");
         get.addHeader("Authorization", "Bearer " + accessToken);
         try {
             HttpResponse response = client.execute(get);
@@ -97,9 +98,19 @@ public class ProductDatabaseClient {
         }
     }
 
-    public static String getBaseUrl(HttpServletRequest request) {
-        String url = request.getRequestURL().toString();
-        return url.substring(0, url.indexOf('/', 8));
+    public static String getBaseUrl(ServletOAuthClient oAuthClient, HttpServletRequest request) {
+        switch (oAuthClient.getRelativeUrlsUsed()) {
+            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(oAuthClient.getCodeUrl());
+            case NEVER:
+                return "";
+            default:
+                return "";
+        }
     }
 
 }
diff --git a/examples/demo-template/third-party/src/main/webapp/WEB-INF/keycloak.json b/examples/demo-template/third-party/src/main/webapp/WEB-INF/keycloak.json
index 559df05..14bbd79 100755
--- a/examples/demo-template/third-party/src/main/webapp/WEB-INF/keycloak.json
+++ b/examples/demo-template/third-party/src/main/webapp/WEB-INF/keycloak.json
@@ -5,5 +5,6 @@
   "ssl-required" : "external",
    "credentials" : {
        "secret": "password"
-   }
+   },
+   "use-hostname-for-local-requests": false
 }
\ No newline at end of file
diff --git a/examples/demo-template/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java b/examples/demo-template/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java
index d76c55c..e642605 100755
--- a/examples/demo-template/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java
+++ b/examples/demo-template/third-party-cdi/src/main/java/org/keycloak/example/oauth/DatabaseClient.java
@@ -7,6 +7,7 @@ import org.apache.http.client.methods.HttpGet;
 import org.jboss.logging.Logger;
 import org.keycloak.servlet.ServletOAuthClient;
 import org.keycloak.util.JsonSerialization;
+import org.keycloak.util.UriUtils;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.faces.application.FacesMessage;
@@ -102,9 +103,18 @@ public class DatabaseClient {
     }
 
     public String getBaseUrl() {
-        String url = request.getRequestURL().toString();
-        return url.substring(0, url.indexOf('/', 8));
+        switch (oauthClient.getRelativeUrlsUsed()) {
+            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(oauthClient.getCodeUrl());
+            case NEVER:
+                return "";
+            default:
+                return "";
+        }
     }
 
-
 }
diff --git a/examples/demo-template/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json b/examples/demo-template/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json
index 559df05..14bbd79 100755
--- a/examples/demo-template/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json
+++ b/examples/demo-template/third-party-cdi/src/main/webapp/WEB-INF/keycloak.json
@@ -5,5 +5,6 @@
   "ssl-required" : "external",
    "credentials" : {
        "secret": "password"
-   }
+   },
+   "use-hostname-for-local-requests": false
 }
\ No newline at end of file
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/AdapterUtils.java b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java
new file mode 100644
index 0000000..0048d6a
--- /dev/null
+++ b/integration/adapter-core/src/main/java/org/keycloak/adapters/AdapterUtils.java
@@ -0,0 +1,30 @@
+package org.keycloak.adapters;
+
+import org.keycloak.KeycloakSecurityContext;
+import org.keycloak.util.UriUtils;
+
+/**
+ * @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
+ */
+public class AdapterUtils {
+
+    public static String getBaseUrl(String browserRequestURL, 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(browserRequestURL);
+                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(browserRequestURL);
+        }
+    }
+}
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;
     }
 
diff --git a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
index 34e8035..0e414ec 100755
--- a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
+++ b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClient.java
@@ -8,6 +8,7 @@ import org.keycloak.jose.jws.JWSInput;
 import org.keycloak.representations.AccessTokenResponse;
 import org.keycloak.representations.IDToken;
 import org.keycloak.util.KeycloakUriBuilder;
+import org.keycloak.util.UriUtils;
 
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
@@ -40,7 +41,7 @@ public class ServletOAuthClient extends AbstractOAuthClient {
     }
 
     private AccessTokenResponse resolveBearerToken(HttpServletRequest request, String redirectUri, String code) throws IOException, ServerRequest.HttpFailure {
-        return ServerRequest.invokeAccessCodeToToken(client, publicClient, code, getUrl(request, codeUrl), redirectUri, clientId, credentials);
+        return ServerRequest.invokeAccessCodeToToken(client, publicClient, code, getUrl(request, codeUrl, false), redirectUri, clientId, credentials);
     }
 
     /**
@@ -74,7 +75,7 @@ public class ServletOAuthClient extends AbstractOAuthClient {
     public void redirect(String redirectUri, HttpServletRequest request, HttpServletResponse response) throws IOException {
         String state = getStateCode();
 
-        KeycloakUriBuilder uriBuilder =  KeycloakUriBuilder.fromUri(getUrl(request, authUrl))
+        KeycloakUriBuilder uriBuilder =  KeycloakUriBuilder.fromUri(getUrl(request, authUrl, true))
                 .queryParam(OAuth2Constants.CLIENT_ID, clientId)
                 .queryParam(OAuth2Constants.REDIRECT_URI, redirectUri)
                 .queryParam(OAuth2Constants.STATE, state);
@@ -146,7 +147,7 @@ public class ServletOAuthClient extends AbstractOAuthClient {
     }
 
     public AccessTokenResponse refreshToken(HttpServletRequest request, String refreshToken) throws IOException, ServerRequest.HttpFailure {
-        return ServerRequest.invokeRefresh(client, publicClient, refreshToken, getUrl(request, refreshUrl), clientId, credentials);
+        return ServerRequest.invokeRefresh(client, publicClient, refreshToken, getUrl(request, refreshUrl, false), clientId, credentials);
     }
 
     public static IDToken extractIdToken(String idToken) {
@@ -159,10 +160,9 @@ public class ServletOAuthClient extends AbstractOAuthClient {
         }
     }
 
-    private String getUrl(HttpServletRequest request, String url) {
-        if (relativeUrls) {
-            String baseUrl = request.getRequestURL().toString();
-            baseUrl = baseUrl.substring(0, baseUrl.indexOf('/', 8));
+    private String getUrl(HttpServletRequest request, String url, boolean isBrowserRequest) {
+        if (relativeUrlsUsed.useRelative(isBrowserRequest)) {
+            String baseUrl = UriUtils.getOrigin(request.getRequestURL().toString());
             return baseUrl + url;
         } else {
             return url;
diff --git a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java
index 52d9710..e1ccd5d 100755
--- a/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java
+++ b/integration/servlet-oauth-client/src/main/java/org/keycloak/servlet/ServletOAuthClientBuilder.java
@@ -3,9 +3,11 @@ package org.keycloak.servlet;
 import org.apache.http.client.HttpClient;
 import org.keycloak.ServiceUrlConstants;
 import org.keycloak.adapters.HttpClientBuilder;
+import org.keycloak.enums.RelativeUrlsUsed;
 import org.keycloak.representations.adapters.config.AdapterConfig;
 import org.keycloak.util.JsonSerialization;
 import org.keycloak.util.KeycloakUriBuilder;
+import org.keycloak.util.UriUtils;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -21,7 +23,7 @@ public class ServletOAuthClientBuilder {
         return build(adapterConfig);
     }
 
-    private static AdapterConfig getAdapterConfig(InputStream is) {
+    public static AdapterConfig getAdapterConfig(InputStream is) {
         try {
             return JsonSerialization.readValue(is, AdapterConfig.class);
         } catch (IOException e) {
@@ -50,13 +52,31 @@ public class ServletOAuthClientBuilder {
             throw new RuntimeException("You must specify auth-url");
         }
         KeycloakUriBuilder serverBuilder = KeycloakUriBuilder.fromUri(adapterConfig.getAuthServerUrl());
-        oauthClient.setRelativeUrls(serverBuilder.clone().getHost() == null);
+        RelativeUrlsUsed useRelative = relativeUrls(serverBuilder, adapterConfig);
+        oauthClient.setRelativeUrlsUsed(useRelative);
 
         String authUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_LOGIN_PATH).build(adapterConfig.getRealm()).toString();
-        String tokenUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(adapterConfig.getRealm()).toString();
-        String refreshUrl = serverBuilder.clone().path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(adapterConfig.getRealm()).toString();
+
+        KeycloakUriBuilder tokenUrlBuilder = serverBuilder.clone();
+        KeycloakUriBuilder refreshUrlBuilder = serverBuilder.clone();
+
+        if (useRelative == RelativeUrlsUsed.BROWSER_ONLY) {
+            // Use absolute URI for refreshToken and codeToToken requests
+            tokenUrlBuilder.scheme(adapterConfig.getLocalRequestsScheme()).host(UriUtils.getHostName()).port(adapterConfig.getLocalRequestsPort());
+            refreshUrlBuilder.scheme(adapterConfig.getLocalRequestsScheme()).host(UriUtils.getHostName()).port(adapterConfig.getLocalRequestsPort());
+        }
+        String tokenUrl = tokenUrlBuilder.path(ServiceUrlConstants.TOKEN_SERVICE_ACCESS_CODE_PATH).build(adapterConfig.getRealm()).toString();
+        String refreshUrl = refreshUrlBuilder.path(ServiceUrlConstants.TOKEN_SERVICE_REFRESH_PATH).build(adapterConfig.getRealm()).toString();
         oauthClient.setAuthUrl(authUrl);
         oauthClient.setCodeUrl(tokenUrl);
         oauthClient.setRefreshUrl(refreshUrl);
     }
+
+    private static RelativeUrlsUsed relativeUrls(KeycloakUriBuilder serverBuilder, AdapterConfig adapterConfig) {
+        if (serverBuilder.clone().getHost() == null) {
+            return (adapterConfig.isUseHostnameForLocalRequests()) ? RelativeUrlsUsed.BROWSER_ONLY : RelativeUrlsUsed.ALL_REQUESTS;
+        } else {
+            return RelativeUrlsUsed.NEVER;
+        }
+    }
 }
diff --git a/testsuite/docker-cluster/wildfly/deploy-examples.sh b/testsuite/docker-cluster/wildfly/deploy-examples.sh
new file mode 100644
index 0000000..d102dc2
--- /dev/null
+++ b/testsuite/docker-cluster/wildfly/deploy-examples.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+# Deploy and configure all examples
+
+# Deploy examples
+cd /keycloak-docker-cluster/examples
+for I in $(find . | grep .war$); do cp $I /opt/wildfly/standalone/deployments/; done;
+
+# Explode wars
+cd /opt/wildfly/standalone/deployments/
+for I in $(ls -d *.war | grep -v auth-server.war); do
+  echo "Explode dir $I";
+  mkdir $I.tmp;
+  cd $I.tmp;
+  unzip -q ../$I;
+  cd ..
+  rm $I;
+  mv $I.tmp $I;
+  touch $I.dodeploy;
+done;
+
+
+# Configure admin-access.war
+sed -i -e 's/false/true/' admin-access.war/WEB-INF/web.xml
+
+# Configure other examples
+for I in *.war/WEB-INF/keycloak.json; do
+  echo "Configuring $I";
+  sed -i -e 's/\"use-hostname-for-local-requests\": false/\"use-hostname-for-local-requests\": true/' $I;
+done;
+
+
diff --git a/testsuite/docker-cluster/wildfly/Dockerfile b/testsuite/docker-cluster/wildfly/Dockerfile
index 3727d5b..3fde5bc 100644
--- a/testsuite/docker-cluster/wildfly/Dockerfile
+++ b/testsuite/docker-cluster/wildfly/Dockerfile
@@ -29,6 +29,8 @@ RUN sed -i "s|#JAVA_OPTS=\"\$JAVA_OPTS -agentlib:jdwp=transport=dt_socket|JAVA_O
 ADD mysql-keycloak-ds.xml /opt/wildfly/standalone/deployments/
 ADD keycloak-run-node.sh /keycloak-run-node.sh
 RUN chmod u+x /keycloak-run-node.sh
+ADD deploy-examples.sh /deploy-examples.sh
+RUN chmod u+x /deploy-examples.sh
 
 EXPOSE 8787
 
diff --git a/testsuite/docker-cluster/wildfly/keycloak-run-node.sh b/testsuite/docker-cluster/wildfly/keycloak-run-node.sh
index b9af405..40603f9 100644
--- a/testsuite/docker-cluster/wildfly/keycloak-run-node.sh
+++ b/testsuite/docker-cluster/wildfly/keycloak-run-node.sh
@@ -50,9 +50,8 @@ cp -r /keycloak-docker-cluster/modules ./
 # Deploy keycloak
 cp -r /keycloak-docker-cluster/deployments/* /opt/wildfly/standalone/deployments/
 
-# Deploy examples
-cd /keycloak-docker-cluster/examples
-for I in $(find . | grep .war$); do cp $I /opt/wildfly/standalone/deployments/; done;
+# Deploy and configure examples
+/deploy-examples.sh
 
 # Deploy to volume
 rm -rf /keycloak-docker-shared/keycloak-wildfly-$MYHOST