Use account-console client for server-side auth check

- Also generate PKCE verifier and use challenge parameters

Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com>
This commit is contained in:
Thomas Darimont 2024-10-14 23:29:00 +02:00 committed by Pedro Igor
parent 6a4ec24015
commit 729417b20a
3 changed files with 27 additions and 1 deletions

View file

@ -42,6 +42,7 @@ public class AbstractOAuthClient {
protected String stateCookiePath; protected String stateCookiePath;
protected boolean isSecure; protected boolean isSecure;
protected boolean publicClient; protected boolean publicClient;
protected boolean pkceEnabled;
protected String getStateCode() { protected String getStateCode() {
return counter.getAndIncrement() + "/" + UUID.randomUUID().toString(); return counter.getAndIncrement() + "/" + UUID.randomUUID().toString();
} }
@ -126,6 +127,14 @@ public class AbstractOAuthClient {
this.relativeUrlsUsed = relativeUrlsUsed; this.relativeUrlsUsed = relativeUrlsUsed;
} }
public boolean isPkceEnabled() {
return pkceEnabled;
}
public void setPkceEnabled(boolean pkceEnabled) {
this.pkceEnabled = pkceEnabled;
}
protected String stripOauthParametersFromRedirect(String uri) { protected String stripOauthParametersFromRedirect(String uri) {
KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri) KeycloakUriBuilder builder = KeycloakUriBuilder.fromUri(uri)
.replaceQueryParam(OAuth2Constants.CODE, null) .replaceQueryParam(OAuth2Constants.CODE, null)

View file

@ -28,6 +28,7 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.protocol.oidc.OIDCLoginProtocolService; import org.keycloak.protocol.oidc.OIDCLoginProtocolService;
import org.keycloak.protocol.oidc.utils.PkceUtils;
import org.keycloak.services.managers.Auth; import org.keycloak.services.managers.Auth;
import org.keycloak.services.messages.Messages; import org.keycloak.services.messages.Messages;
import org.keycloak.util.TokenUtil; import org.keycloak.util.TokenUtil;
@ -44,6 +45,7 @@ import jakarta.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.UriInfo; import jakarta.ws.rs.core.UriInfo;
import java.net.URI; import java.net.URI;
import java.util.Set; import java.util.Set;
import java.util.UUID;
/** /**
* Helper class for securing local services. Provides login basics as well as CSRF check basics * Helper class for securing local services. Provides login basics as well as CSRF check basics
@ -180,6 +182,20 @@ public abstract class AbstractSecuredLocalService {
.queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE) .queryParam(OAuth2Constants.RESPONSE_TYPE, OAuth2Constants.CODE)
.queryParam(OAuth2Constants.SCOPE, scopeParam); .queryParam(OAuth2Constants.SCOPE, scopeParam);
if (isPkceEnabled()) {
String pkceChallenge;
try {
// TODO generate PKCE challenge based on server value
String codeVerifier = UUID.randomUUID().toString();
pkceChallenge = PkceUtils.generateS256CodeChallenge(codeVerifier);
} catch (Exception e) {
throw new RuntimeException(e);
}
uriBuilder
.queryParam(OAuth2Constants.CODE_CHALLENGE, pkceChallenge)
.queryParam(OAuth2Constants.CODE_CHALLENGE_METHOD, OAuth2Constants.PKCE_METHOD_S256);
}
URI url = uriBuilder.build(); URI url = uriBuilder.build();
NewCookie cookie = new NewCookie(getStateCookieName(), state, getStateCookiePath(uriInfo), null, null, -1, isSecure, true); NewCookie cookie = new NewCookie(getStateCookieName(), state, getStateCookiePath(uriInfo), null, null, -1, isSecure, true);

View file

@ -215,7 +215,8 @@ public class AccountConsole implements AccountResourceProvider {
var oauthRedirect = new AbstractSecuredLocalService.OAuthRedirect(); var oauthRedirect = new AbstractSecuredLocalService.OAuthRedirect();
oauthRedirect.setAuthUrl(OIDCLoginProtocolService.authUrl(session.getContext().getUri()).build(realm.getName()).toString()); oauthRedirect.setAuthUrl(OIDCLoginProtocolService.authUrl(session.getContext().getUri()).build(realm.getName()).toString());
oauthRedirect.setClientId(client.getClientId()); oauthRedirect.setClientId(Constants.ACCOUNT_CONSOLE_CLIENT_ID);
oauthRedirect.setPkceEnabled(true);
oauthRedirect.setSecure(realm.getSslRequired().isRequired(session.getContext().getConnection())); oauthRedirect.setSecure(realm.getSslRequired().isRequired(session.getContext().getConnection()));
return oauthRedirect.redirect(session.getContext().getUri(), targetUri.toString()); return oauthRedirect.redirect(session.getContext().getUri(), targetUri.toString());
} }