keycloak-memoizeit

relative redirect uris

5/2/2014 11:58:29 AM

Details

diff --git a/services/src/main/java/org/keycloak/services/resources/AccountService.java b/services/src/main/java/org/keycloak/services/resources/AccountService.java
index e72eec5..30c7e55 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -512,7 +512,7 @@ public class AccountService {
         ApplicationModel application = realm.getApplicationByName(referrer);
         if (application != null) {
             if (referrerUri != null) {
-                referrerUri = TokenService.verifyRedirectUri(referrerUri, application);
+                referrerUri = TokenService.verifyRedirectUri(uriInfo, referrerUri, application);
             } else {
                 referrerUri = application.getBaseUrl();
             }
@@ -523,7 +523,7 @@ public class AccountService {
         } else if (referrerUri != null) {
             ClientModel client = realm.getOAuthClient(referrer);
             if (client != null) {
-                referrerUri = TokenService.verifyRedirectUri(referrerUri, application);
+                referrerUri = TokenService.verifyRedirectUri(uriInfo, referrerUri, application);
 
                 if (referrerUri != null) {
                     return new String[]{referrer, referrerUri};
diff --git a/services/src/main/java/org/keycloak/services/resources/SocialResource.java b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
index 98f8837..aacaa60 100755
--- a/services/src/main/java/org/keycloak/services/resources/SocialResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/SocialResource.java
@@ -290,7 +290,7 @@ public class SocialResource {
             logger.warn("Login requester not enabled.");
             return Flows.forms(realm, uriInfo).setError("Login requester not enabled.").createErrorPage();
         }
-        redirectUri = TokenService.verifyRedirectUri(redirectUri, client);
+        redirectUri = TokenService.verifyRedirectUri(uriInfo, redirectUri, client);
         if (redirectUri == null) {
             audit.error(Errors.INVALID_REDIRECT_URI);
             return Flows.forms(realm, uriInfo).setError("Invalid redirect_uri.").createErrorPage();
diff --git a/services/src/main/java/org/keycloak/services/resources/TokenService.java b/services/src/main/java/org/keycloak/services/resources/TokenService.java
index dbfaa3e..743af42 100755
--- a/services/src/main/java/org/keycloak/services/resources/TokenService.java
+++ b/services/src/main/java/org/keycloak/services/resources/TokenService.java
@@ -63,7 +63,9 @@ import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 import javax.ws.rs.ext.Providers;
+import java.net.URI;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -288,7 +290,7 @@ public class TokenService {
             return oauth.forwardToSecurityFailure("Login requester not enabled.");
         }
 
-        redirect = verifyRedirectUri(redirect, client);
+        redirect = verifyRedirectUri(uriInfo, redirect, client);
         if (redirect == null) {
             audit.error(Errors.INVALID_REDIRECT_URI);
             return oauth.forwardToSecurityFailure("Invalid redirect_uri.");
@@ -377,7 +379,7 @@ public class TokenService {
             return oauth.forwardToSecurityFailure("Login requester not enabled.");
         }
 
-        redirect = verifyRedirectUri(redirect, client);
+        redirect = verifyRedirectUri(uriInfo, redirect, client);
         if (redirect == null) {
             audit.error(Errors.INVALID_REDIRECT_URI);
             return oauth.forwardToSecurityFailure("Invalid redirect_uri.");
@@ -636,7 +638,7 @@ public class TokenService {
             audit.error(Errors.CLIENT_DISABLED);
             return oauth.forwardToSecurityFailure("Login requester not enabled.");
         }
-        redirect = verifyRedirectUri(redirect, client);
+        redirect = verifyRedirectUri(uriInfo, redirect, client);
         if (redirect == null) {
             audit.error(Errors.INVALID_REDIRECT_URI);
             return oauth.forwardToSecurityFailure("Invalid redirect_uri.");
@@ -690,7 +692,7 @@ public class TokenService {
             return oauth.forwardToSecurityFailure("Login requester not enabled.");
         }
 
-        redirect = verifyRedirectUri(redirect, client);
+        redirect = verifyRedirectUri(uriInfo, redirect, client);
         if (redirect == null) {
             audit.error(Errors.INVALID_REDIRECT_URI);
             return oauth.forwardToSecurityFailure("Invalid redirect_uri.");
@@ -813,10 +815,11 @@ public class TokenService {
         return false;
     }
 
-    public static String verifyRedirectUri(String redirectUri, ClientModel client) {
+    public static String verifyRedirectUri(UriInfo uriInfo, String redirectUri, ClientModel client) {
+        Set<String> validRedirects = client.getRedirectUris();
         if (redirectUri == null) {
-            return client.getRedirectUris().size() == 1 ? client.getRedirectUris().iterator().next() : null;
-        } else if (client.getRedirectUris().isEmpty()) {
+            return validRedirects.size() == 1 ? validRedirects.iterator().next() : null;
+        } else if (validRedirects.isEmpty()) {
             if (client.isPublicClient()) {
                 logger.error("Client redirect uri must be registered for public client");
                 return null;
@@ -825,7 +828,22 @@ public class TokenService {
         } else {
             String r = redirectUri.indexOf('?') != -1 ? redirectUri.substring(0, redirectUri.indexOf('?')) : redirectUri;
 
-            boolean valid = matchesRedirects(client.getRedirectUris(), r);
+            // If the valid redirect URI is relative (no scheme, host, port) then use the request's scheme, host, and port
+            Set<String> resolveValidRedirects = new HashSet<String>();
+            for (String validRedirect : validRedirects) {
+                if (validRedirect.startsWith("/")) {
+                    URI baseUri = uriInfo.getBaseUri();
+                    String uri = baseUri.getScheme() + "://" + baseUri.getHost();
+                    if (baseUri.getPort() != -1) {
+                        uri += ":" + baseUri.getPort();
+                    }
+                    validRedirect = uri + validRedirect;
+                    logger.debugv("replacing relative valid redirect with: {0}", validRedirect);
+                }
+                resolveValidRedirects.add(validRedirect);
+            }
+
+            boolean valid = matchesRedirects(resolveValidRedirects, r);
 
             if (!valid && r.startsWith(Constants.INSTALLED_APP_URL) && r.indexOf(':', Constants.INSTALLED_APP_URL.length()) >= 0) {
                 int i = r.indexOf(':', Constants.INSTALLED_APP_URL.length());
@@ -840,9 +858,8 @@ public class TokenService {
 
                 r = sb.toString();
 
-                valid = matchesRedirects(client.getRedirectUris(), r);
+                valid = matchesRedirects(resolveValidRedirects, r);
             }
-
             return valid ? redirectUri : null;
         }
     }