Account console backend should redirect to login on missing auth (#31469)

Adapted the login redirect logic from the old account console.

Fixes #31469

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
This commit is contained in:
Thomas Darimont 2024-09-05 11:06:54 +02:00 committed by Pedro Igor
parent 4d5c692e3e
commit c400eff9b0
3 changed files with 72 additions and 3 deletions

View file

@ -161,7 +161,7 @@ public abstract class AbstractSecuredLocalService {
return oauth.redirect(session.getContext().getUri(), accountUri.toString()); return oauth.redirect(session.getContext().getUri(), accountUri.toString());
} }
static class OAuthRedirect extends AbstractOAuthClient { public static class OAuthRedirect extends AbstractOAuthClient {
/** /**
* closes client * closes client

View file

@ -2,7 +2,9 @@ package org.keycloak.services.resources.account;
import jakarta.ws.rs.GET; import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path; import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriBuilder;
import org.jboss.resteasy.reactive.NoCache; import org.jboss.resteasy.reactive.NoCache;
import org.keycloak.authentication.requiredactions.DeleteAccount; import org.keycloak.authentication.requiredactions.DeleteAccount;
import org.keycloak.common.Profile; import org.keycloak.common.Profile;
@ -17,12 +19,14 @@ import org.keycloak.models.RealmModel;
import org.keycloak.models.RequiredActionProviderModel; import org.keycloak.models.RequiredActionProviderModel;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.UserModel; import org.keycloak.models.UserModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.protocol.oidc.utils.RedirectUtils; import org.keycloak.protocol.oidc.utils.RedirectUtils;
import org.keycloak.services.Urls; import org.keycloak.services.Urls;
import org.keycloak.services.managers.AppAuthManager; import org.keycloak.services.managers.AppAuthManager;
import org.keycloak.services.managers.Auth; import org.keycloak.services.managers.Auth;
import org.keycloak.services.managers.AuthenticationManager; import org.keycloak.services.managers.AuthenticationManager;
import org.keycloak.services.resource.AccountResourceProvider; import org.keycloak.services.resource.AccountResourceProvider;
import org.keycloak.services.resources.AbstractSecuredLocalService;
import org.keycloak.services.resources.RealmsResource; import org.keycloak.services.resources.RealmsResource;
import org.keycloak.services.util.ResolveRelative; import org.keycloak.services.util.ResolveRelative;
import org.keycloak.services.util.ViteManifest; import org.keycloak.services.util.ViteManifest;
@ -34,9 +38,11 @@ import org.keycloak.theme.freemarker.FreeMarkerProvider;
import org.keycloak.urls.UrlType; import org.keycloak.urls.UrlType;
import org.keycloak.util.JsonSerialization; import org.keycloak.util.JsonSerialization;
import org.keycloak.utils.MediaType; import org.keycloak.utils.MediaType;
import org.keycloak.utils.StringUtil;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URI;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
@ -93,8 +99,13 @@ public class AccountConsole implements AccountResourceProvider {
@GET @GET
@NoCache @NoCache
@Path("{any:.*}") @Path("{path:.*}")
public Response getMainPage() throws IOException, FreeMarkerException { public Response getMainPage(@PathParam("path") String path) throws IOException, FreeMarkerException {
if (auth == null) {
return redirectToLogin(path);
}
final var serverUriInfo = session.getContext().getUri(UrlType.FRONTEND); final var serverUriInfo = session.getContext().getUri(UrlType.FRONTEND);
final var serverBaseUri = serverUriInfo.getBaseUri(); final var serverBaseUri = serverUriInfo.getBaseUri();
// Strip any trailing slashes from the URL. // Strip any trailing slashes from the URL.
@ -195,6 +206,20 @@ public class AccountConsole implements AccountResourceProvider {
return builder.build(); return builder.build();
} }
private Response redirectToLogin(String path) {
UriBuilder consoleUriBuilder = Urls.accountBase(session.getContext().getUri().getBaseUri());
if (!StringUtil.isNullOrEmpty(path)) {
consoleUriBuilder.path(path);
}
URI targetUri = consoleUriBuilder.build(realm.getName());
var oauthRedirect = new AbstractSecuredLocalService.OAuthRedirect();
oauthRedirect.setAuthUrl(OIDCLoginProtocolService.authUrl(session.getContext().getUri()).build(realm.getName()).toString());
oauthRedirect.setClientId(client.getClientId());
oauthRedirect.setSecure(realm.getSslRequired().isRequired(session.getContext().getConnection()));
return oauthRedirect.redirect(session.getContext().getUri(), targetUri.toString());
}
private Map<String, String> supportedLocales(Properties messages) { private Map<String, String> supportedLocales(Properties messages) {
return realm.getSupportedLocalesStream() return realm.getSupportedLocalesStream()
.collect(Collectors.toMap(Function.identity(), l -> messages.getProperty("locale_" + l, l))); .collect(Collectors.toMap(Function.identity(), l -> messages.getProperty("locale_" + l, l)));

View file

@ -0,0 +1,44 @@
package org.keycloak.testsuite.account;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.HttpClientBuilder;
import org.jboss.arquillian.graphene.page.Page;
import org.junit.Test;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
import org.keycloak.testsuite.Assert;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.util.OAuthClient;
public class AccountConsoleTest extends AbstractTestRealmKeycloakTest {
@Page
protected LoginPage loginPage;
@Override
public void configureTestRealm(RealmRepresentation testRealm) {
}
@Test
public void redirectToLoginIfNotAuthenticated() throws Exception {
String accountUrl = oauth.getCurrentUri().toString().replace("/admin/master/console", "/realms/" + oauth.getRealm() + "/account");
HttpGet getAccount = new HttpGet(accountUrl);
int statusCode;
String redirectLocation;
try (var client = HttpClientBuilder.create().disableRedirectHandling().build()) {
try (var response = client.execute(getAccount)) {
statusCode = response.getStatusLine().getStatusCode();
redirectLocation = response.getFirstHeader("Location").getValue();
}
}
Assert.assertEquals(302, statusCode);
String expectedLoginUrlPart = "/realms/" + oauth.getRealm() + "/protocol/openid-connect/auth?client_id=account";
Assert.assertTrue(redirectLocation.contains(expectedLoginUrlPart));
}
}