Check frontendUrl in the hostname providers
Closes https://github.com/keycloak/keycloak/issues/17686
This commit is contained in:
parent
e26203467f
commit
bef0a4a6f1
4 changed files with 40 additions and 12 deletions
|
@ -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)) {
|
||||||
|
try {
|
||||||
|
checkUrl(SslRequired.NONE, frontendUrl, "frontendUrl");
|
||||||
realmUrl = URI.create(frontendUrl);
|
realmUrl = URI.create(frontendUrl);
|
||||||
session.setAttribute(realmUriKey, realmUrl);
|
session.setAttribute(realmUriKey, realmUrl);
|
||||||
return realmUrl;
|
return realmUrl;
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
LOGGER.errorf(e, "Failed to parse realm frontendUrl '%s'. Falling back to global value.", frontendUrl);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue