Details
diff --git a/core/src/main/java/org/keycloak/util/UriUtils.java b/core/src/main/java/org/keycloak/util/UriUtils.java
index 873283f..8532c5b 100644
--- a/core/src/main/java/org/keycloak/util/UriUtils.java
+++ b/core/src/main/java/org/keycloak/util/UriUtils.java
@@ -1,12 +1,15 @@
package org.keycloak.util;
import java.net.URI;
+import java.util.regex.Pattern;
/**
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
*/
public class UriUtils {
+ private static final Pattern originPattern = Pattern.compile("(http://|https://)[\\w]+(\\.[\\w]+)*(:[\\d]{2,5})?");
+
public static String getOrigin(URI uri) {
return getOrigin(uri.toString());
}
@@ -16,4 +19,8 @@ public class UriUtils {
return u.substring(0, u.indexOf('/', 8));
}
+ public static boolean isOrigin(String url) {
+ return originPattern.matcher(url).matches();
+ }
+
}
diff --git a/core/src/test/java/org/keycloak/util/UriUtilsTest.java b/core/src/test/java/org/keycloak/util/UriUtilsTest.java
new file mode 100644
index 0000000..52d484d
--- /dev/null
+++ b/core/src/test/java/org/keycloak/util/UriUtilsTest.java
@@ -0,0 +1,44 @@
+package org.keycloak.util;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
+ */
+public class UriUtilsTest {
+
+ @Test
+ public void testOrigins() {
+ assertValid("http://test");
+ assertValid("http://test:8080");
+ assertValid("https://test");
+ assertValid("http://test.com");
+ assertValid("https://test.com");
+ assertValid("https://test.com:8080");
+ assertValid("http://sub.test.com");
+ assertValid("https://sub.test.com");
+ assertValid("https://sub.test.com:8080");
+ assertValid("http://192.168.123.123");
+ assertValid("https://192.168.123.123");
+ assertValid("https://192.168.123.123:8080");
+
+ assertInvalid("https://test/");
+ assertInvalid("{");
+ assertInvalid("https://{}");
+ assertInvalid("https://)");
+ assertInvalid("http://test:test");
+ assertInvalid("http://test:8080:8080");
+ }
+
+ public void assertValid(String origin) {
+ assertTrue(UriUtils.isOrigin(origin));
+ }
+
+ public void assertInvalid(String origin) {
+ assertFalse(UriUtils.isOrigin(origin));
+ }
+
+}
diff --git a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
index d713450..ef190d9 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/OpenIDConnectService.java
@@ -44,6 +44,7 @@ import org.keycloak.services.resources.flows.Urls;
import org.keycloak.util.Base64Url;
import org.keycloak.util.BasicAuthHelper;
import org.keycloak.util.StreamUtil;
+import org.keycloak.util.UriUtils;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
@@ -188,6 +189,10 @@ public class OpenIDConnectService {
@Produces(MediaType.TEXT_HTML)
public Response getLoginStatusIframe(@QueryParam("client_id") String client_id,
@QueryParam("origin") String origin) {
+ if (!UriUtils.isOrigin(origin)) {
+ throw new BadRequestException("Invalid origin");
+ }
+
ClientModel client = realm.findClient(client_id);
if (client == null) {
throw new NotFoundException("could not find client: " + client_id);
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 5ba6cae..ff22dc2 100755
--- a/services/src/main/java/org/keycloak/services/resources/AccountService.java
+++ b/services/src/main/java/org/keycloak/services/resources/AccountService.java
@@ -84,6 +84,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.core.Variant;
+import java.lang.reflect.Method;
import java.net.URI;
import java.util.HashSet;
import java.util.Iterator;
@@ -99,6 +100,16 @@ public class AccountService {
private static final Logger logger = Logger.getLogger(AccountService.class);
+ private static Set<String> VALID_PATHS = new HashSet<String>();
+ static {
+ for (Method m : AccountService.class.getMethods()) {
+ Path p = m.getAnnotation(Path.class);
+ if (p != null) {
+ VALID_PATHS.add(p.value());
+ }
+ }
+ }
+
private static final EventType[] LOG_EVENTS = {EventType.LOGIN, EventType.LOGOUT, EventType.REGISTER, EventType.REMOVE_SOCIAL_LINK, EventType.REMOVE_TOTP, EventType.SEND_RESET_PASSWORD,
EventType.SEND_VERIFY_EMAIL, EventType.SOCIAL_LINK, EventType.UPDATE_EMAIL, EventType.UPDATE_PASSWORD, EventType.UPDATE_PROFILE, EventType.UPDATE_TOTP, EventType.VERIFY_EMAIL};
@@ -715,6 +726,9 @@ public class AccountService {
logger.debug("error from oauth");
throw new ForbiddenException("error");
}
+ if (path != null && !VALID_PATHS.contains(path)) {
+ throw new BadRequestException("Invalid path");
+ }
if (!realm.isEnabled()) {
logger.debug("realm not enabled");
throw new ForbiddenException();
diff --git a/services/src/main/java/org/keycloak/services/resources/QRCodeResource.java b/services/src/main/java/org/keycloak/services/resources/QRCodeResource.java
index 6cc66ee..c846df2 100755
--- a/services/src/main/java/org/keycloak/services/resources/QRCodeResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/QRCodeResource.java
@@ -43,14 +43,22 @@ public class QRCodeResource {
if (size != null) {
String[] s = size.split("x");
- width = Integer.parseInt(s[0]);
- height = Integer.parseInt(s[1]);
+ try {
+ width = Integer.parseInt(s[0]);
+ height = Integer.parseInt(s[1]);
+ } catch (Throwable t) {
+ return Response.status(Response.Status.BAD_REQUEST).build();
+ }
}
if (contents == null) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
+ if (width > 1000 || height > 1000 || contents.length() > 1000) {
+ return Response.status(Response.Status.BAD_REQUEST).build();
+ }
+
QRCodeWriter writer = new QRCodeWriter();
final BitMatrix bitMatrix = writer.encode(contents, BarcodeFormat.QR_CODE, width, height);