commit
ea6d7e1fac
5 changed files with 80 additions and 2 deletions
|
@ -1,12 +1,15 @@
|
||||||
package org.keycloak.util;
|
package org.keycloak.util;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
*/
|
*/
|
||||||
public class UriUtils {
|
public class UriUtils {
|
||||||
|
|
||||||
|
private static final Pattern originPattern = Pattern.compile("(http://|https://)[\\w]+(\\.[\\w]+)*(:[\\d]{2,5})?");
|
||||||
|
|
||||||
public static String getOrigin(URI uri) {
|
public static String getOrigin(URI uri) {
|
||||||
return getOrigin(uri.toString());
|
return getOrigin(uri.toString());
|
||||||
}
|
}
|
||||||
|
@ -16,4 +19,8 @@ public class UriUtils {
|
||||||
return u.substring(0, u.indexOf('/', 8));
|
return u.substring(0, u.indexOf('/', 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isOrigin(String url) {
|
||||||
|
return originPattern.matcher(url).matches();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
44
core/src/test/java/org/keycloak/util/UriUtilsTest.java
Normal file
44
core/src/test/java/org/keycloak/util/UriUtilsTest.java
Normal file
|
@ -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));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -44,6 +44,7 @@ import org.keycloak.services.resources.flows.Urls;
|
||||||
import org.keycloak.util.Base64Url;
|
import org.keycloak.util.Base64Url;
|
||||||
import org.keycloak.util.BasicAuthHelper;
|
import org.keycloak.util.BasicAuthHelper;
|
||||||
import org.keycloak.util.StreamUtil;
|
import org.keycloak.util.StreamUtil;
|
||||||
|
import org.keycloak.util.UriUtils;
|
||||||
|
|
||||||
import javax.ws.rs.Consumes;
|
import javax.ws.rs.Consumes;
|
||||||
import javax.ws.rs.GET;
|
import javax.ws.rs.GET;
|
||||||
|
@ -188,6 +189,10 @@ public class OpenIDConnectService {
|
||||||
@Produces(MediaType.TEXT_HTML)
|
@Produces(MediaType.TEXT_HTML)
|
||||||
public Response getLoginStatusIframe(@QueryParam("client_id") String client_id,
|
public Response getLoginStatusIframe(@QueryParam("client_id") String client_id,
|
||||||
@QueryParam("origin") String origin) {
|
@QueryParam("origin") String origin) {
|
||||||
|
if (!UriUtils.isOrigin(origin)) {
|
||||||
|
throw new BadRequestException("Invalid origin");
|
||||||
|
}
|
||||||
|
|
||||||
ClientModel client = realm.findClient(client_id);
|
ClientModel client = realm.findClient(client_id);
|
||||||
if (client == null) {
|
if (client == null) {
|
||||||
throw new NotFoundException("could not find client: " + client_id);
|
throw new NotFoundException("could not find client: " + client_id);
|
||||||
|
|
|
@ -84,6 +84,7 @@ import javax.ws.rs.core.Response;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import javax.ws.rs.core.UriInfo;
|
import javax.ws.rs.core.UriInfo;
|
||||||
import javax.ws.rs.core.Variant;
|
import javax.ws.rs.core.Variant;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
@ -99,6 +100,16 @@ public class AccountService {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AccountService.class);
|
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,
|
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};
|
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");
|
logger.debug("error from oauth");
|
||||||
throw new ForbiddenException("error");
|
throw new ForbiddenException("error");
|
||||||
}
|
}
|
||||||
|
if (path != null && !VALID_PATHS.contains(path)) {
|
||||||
|
throw new BadRequestException("Invalid path");
|
||||||
|
}
|
||||||
if (!realm.isEnabled()) {
|
if (!realm.isEnabled()) {
|
||||||
logger.debug("realm not enabled");
|
logger.debug("realm not enabled");
|
||||||
throw new ForbiddenException();
|
throw new ForbiddenException();
|
||||||
|
|
|
@ -43,14 +43,22 @@ public class QRCodeResource {
|
||||||
|
|
||||||
if (size != null) {
|
if (size != null) {
|
||||||
String[] s = size.split("x");
|
String[] s = size.split("x");
|
||||||
width = Integer.parseInt(s[0]);
|
try {
|
||||||
height = Integer.parseInt(s[1]);
|
width = Integer.parseInt(s[0]);
|
||||||
|
height = Integer.parseInt(s[1]);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
return Response.status(Response.Status.BAD_REQUEST).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contents == null) {
|
if (contents == null) {
|
||||||
return Response.status(Response.Status.BAD_REQUEST).build();
|
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();
|
QRCodeWriter writer = new QRCodeWriter();
|
||||||
final BitMatrix bitMatrix = writer.encode(contents, BarcodeFormat.QR_CODE, width, height);
|
final BitMatrix bitMatrix = writer.encode(contents, BarcodeFormat.QR_CODE, width, height);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue