Check frontendUrl in the hostname providers

Closes https://github.com/keycloak/keycloak/issues/17686
This commit is contained in:
rmartinc 2023-03-15 17:39:03 +01:00 committed by Pedro Igor
parent e26203467f
commit bef0a4a6f1
4 changed files with 40 additions and 12 deletions

View file

@ -17,6 +17,7 @@
package org.keycloak.quarkus.runtime.hostname; package org.keycloak.quarkus.runtime.hostname;
import static org.keycloak.common.util.UriUtils.checkUrl;
import static org.keycloak.urls.UrlType.ADMIN; import static org.keycloak.urls.UrlType.ADMIN;
import static org.keycloak.urls.UrlType.BACKEND; import static org.keycloak.urls.UrlType.BACKEND;
import static org.keycloak.urls.UrlType.FRONTEND; import static org.keycloak.urls.UrlType.FRONTEND;
@ -31,6 +32,7 @@ import java.util.function.Function;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.common.util.Resteasy; import org.keycloak.common.util.Resteasy;
import org.keycloak.config.HostnameOptions; import org.keycloak.config.HostnameOptions;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
@ -185,9 +187,14 @@ public final class DefaultHostnameProvider implements HostnameProvider, Hostname
String frontendUrl = realm.getAttribute("frontendUrl"); String frontendUrl = realm.getAttribute("frontendUrl");
if (isNotBlank(frontendUrl)) { if (isNotBlank(frontendUrl)) {
realmUrl = URI.create(frontendUrl); try {
session.setAttribute(realmUriKey, realmUrl); checkUrl(SslRequired.NONE, frontendUrl, "frontendUrl");
return realmUrl; realmUrl = URI.create(frontendUrl);
session.setAttribute(realmUriKey, realmUrl);
return realmUrl;
} catch (IllegalArgumentException e) {
LOGGER.errorf(e, "Failed to parse realm frontendUrl '%s'. Falling back to global value.", frontendUrl);
}
} }
} }

View file

@ -272,7 +272,7 @@ public class RealmsResource {
} }
private void checkSsl(RealmModel realm) { private void checkSsl(RealmModel realm) {
if (!session.getContext().getUri().getBaseUri().getScheme().equals("https") if (!"https".equals(session.getContext().getUri().getBaseUri().getScheme())
&& realm.getSslRequired().isRequired(session.getContext().getConnection())) { && realm.getSslRequired().isRequired(session.getContext().getConnection())) {
HttpRequest request = session.getContext().getHttpRequest(); HttpRequest request = session.getContext().getHttpRequest();
Cors cors = Cors.add(request).auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS); Cors cors = Cors.add(request).auth().allowedMethods(request.getHttpMethod()).auth().exposedHeaders(Cors.ACCESS_CONTROL_ALLOW_METHODS);

View file

@ -1,6 +1,10 @@
package org.keycloak.url; package org.keycloak.url;
import static org.keycloak.common.util.UriUtils.checkUrl;
import static org.keycloak.utils.StringUtil.isNotBlank;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.common.enums.SslRequired;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.urls.HostnameProvider; import org.keycloak.urls.HostnameProvider;
@ -8,7 +12,6 @@ import org.keycloak.urls.UrlType;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException;
public class DefaultHostnameProvider implements HostnameProvider { public class DefaultHostnameProvider implements HostnameProvider {
@ -97,11 +100,12 @@ public class DefaultHostnameProvider implements HostnameProvider {
realmUri = null; realmUri = null;
String realmFrontendUrl = session.getContext().getRealm().getAttribute("frontendUrl"); String realmFrontendUrl = session.getContext().getRealm().getAttribute("frontendUrl");
if (realmFrontendUrl != null && !realmFrontendUrl.isEmpty()) { if (isNotBlank(realmFrontendUrl)) {
try { try {
realmUri = new URI(realmFrontendUrl); checkUrl(SslRequired.NONE, realmFrontendUrl, "frontendUrl");
} catch (URISyntaxException e) { realmUri = URI.create(realmFrontendUrl);
LOGGER.error("Failed to parse realm frontendUrl. Falling back to global value.", e); } catch (IllegalArgumentException e) {
LOGGER.errorf(e, "Failed to parse realm frontendUrl '%s'. Falling back to global value.", realmFrontendUrl);
} }
} }

View file

@ -13,7 +13,6 @@ import org.keycloak.broker.provider.util.SimpleHttp;
import org.keycloak.client.registration.Auth; import org.keycloak.client.registration.Auth;
import org.keycloak.client.registration.ClientRegistration; import org.keycloak.client.registration.ClientRegistration;
import org.keycloak.client.registration.ClientRegistrationException; import org.keycloak.client.registration.ClientRegistrationException;
import org.keycloak.common.Profile;
import org.keycloak.common.util.UriUtils; import org.keycloak.common.util.UriUtils;
import org.keycloak.jose.jws.JWSInput; import org.keycloak.jose.jws.JWSInput;
import org.keycloak.jose.jws.JWSInputException; import org.keycloak.jose.jws.JWSInputException;
@ -26,8 +25,6 @@ import org.keycloak.representations.idm.ClientInitialAccessPresentation;
import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientRepresentation;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude; import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
import org.keycloak.testsuite.util.AdminClientUtil; import org.keycloak.testsuite.util.AdminClientUtil;
import org.keycloak.testsuite.util.ClientBuilder; import org.keycloak.testsuite.util.ClientBuilder;
import org.keycloak.testsuite.util.OAuthClient; import org.keycloak.testsuite.util.OAuthClient;
@ -126,6 +123,26 @@ public class DefaultHostnameTest extends AbstractHostnameTest {
} }
} }
@Test
public void wrongProtocolRealmFrontendUrl() throws Exception {
expectedBackendUrl = transformUrlIfQuarkusServer(AUTH_SERVER_ROOT);
oauth.clientId("direct-grant");
RealmResource realmResource = realmsResouce().realm("frontendUrl");
RealmRepresentation rep = realmResource.toRepresentation();
try {
rep.getAttributes().put("frontendUrl", "wrong://example.com");
realmResource.update(rep);
assertWellKnown("frontendUrl", transformUrlIfQuarkusServer(AUTH_SERVER_ROOT));
} finally {
rep.getAttributes().put("frontendUrl", realmFrontEndUrl);
realmResource.update(rep);
reset();
}
}
@Test @Test
public void fixedAdminUrl() throws Exception { public void fixedAdminUrl() throws Exception {
expectedBackendUrl = transformUrlIfQuarkusServer(AUTH_SERVER_ROOT); expectedBackendUrl = transformUrlIfQuarkusServer(AUTH_SERVER_ROOT);