Handle ClientData parsing errors in SessionCodeChecks gracefully
- Move ClientData parsing out of SessionCodeChecks ctor - Respond with a bad request if invalid client data is presented Closes #32515 Signed-off-by: Thomas Darimont <thomas.darimont@googlemail.com> Signed-off-by: Alexander Schwartz <aschwart@redhat.com> Co-authored-by: Alexander Schwartz <aschwart@redhat.com>
This commit is contained in:
parent
83a57892ea
commit
693a63b532
3 changed files with 24 additions and 17 deletions
|
@ -96,17 +96,12 @@ public class ClientData {
|
||||||
return String.format("ClientData [ redirectUri=%s, responseType=%s, responseMode=%s, state=%s ]", redirectUri, responseType, responseMode, state);
|
return String.format("ClientData [ redirectUri=%s, responseType=%s, responseMode=%s, state=%s ]", redirectUri, responseType, responseMode, state);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ClientData decodeClientDataFromParameter(String clientDataParam) {
|
public static ClientData decodeClientDataFromParameter(String clientDataParam) throws IOException {
|
||||||
try {
|
if (ObjectUtil.isBlank(clientDataParam)) {
|
||||||
if (ObjectUtil.isBlank(clientDataParam)) {
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
byte[] cdataJson = Base64Url.decode(clientDataParam);
|
|
||||||
return JsonSerialization.readValue(cdataJson, ClientData.class);
|
|
||||||
}
|
|
||||||
} catch (IOException ioe) {
|
|
||||||
logger.warnf("ClientData parameter in invalid format. ClientData parameter was %s", clientDataParam);
|
|
||||||
return null;
|
return null;
|
||||||
|
} else {
|
||||||
|
byte[] cdataJson = Base64Url.decode(clientDataParam);
|
||||||
|
return JsonSerialization.readValue(cdataJson, ClientData.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,8 @@ import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.protocol.ClientData;
|
import org.keycloak.protocol.ClientData;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
public class IdentityBrokerStateTest {
|
public class IdentityBrokerStateTest {
|
||||||
|
|
||||||
|
@ -48,7 +50,7 @@ public class IdentityBrokerStateTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDecodedWithClientIdAnActualUuidBASE64UriFriendly() {
|
public void testDecodedWithClientIdAnActualUuidBASE64UriFriendly() throws IOException {
|
||||||
|
|
||||||
// Given
|
// Given
|
||||||
String state = "gNrGamIDGKpKSI9yOrcFzYTKoFGH779_WNCacAelkhk";
|
String state = "gNrGamIDGKpKSI9yOrcFzYTKoFGH779_WNCacAelkhk";
|
||||||
|
@ -90,7 +92,7 @@ public class IdentityBrokerStateTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodedWithClientIdNotUUid() {
|
public void testEncodedWithClientIdNotUUid() throws IOException {
|
||||||
// Given
|
// Given
|
||||||
String encoded = "gNrGamIDGKpKSI9yOrcFzYTKoFGH779_WNCacAelkhk.vpISZLVDAc0.aHR0cDovL2kuYW0uYW4udXJs";
|
String encoded = "gNrGamIDGKpKSI9yOrcFzYTKoFGH779_WNCacAelkhk.vpISZLVDAc0.aHR0cDovL2kuYW0uYW4udXJs";
|
||||||
String clientId = "http://i.am.an.url";
|
String clientId = "http://i.am.an.url";
|
||||||
|
@ -107,7 +109,7 @@ public class IdentityBrokerStateTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodedWithClientData() {
|
public void testEncodedWithClientData() throws IOException {
|
||||||
// Given
|
// Given
|
||||||
String encoded = "gNrGamIDGKpKSI9yOrcFzYTKoFGH779_WNCacAelkhk.vpISZLVDAc0.aHR0cDovL2kuYW0uYW4udXJs.eyJydSI6Imh0dHBzOi8vbXktcmVkaXJlY3QtdXJpIiwicnQiOiJjb2RlIiwicm0iOiJxdWVyeSIsInN0Ijoic29tZS1zdGF0ZSJ9";
|
String encoded = "gNrGamIDGKpKSI9yOrcFzYTKoFGH779_WNCacAelkhk.vpISZLVDAc0.aHR0cDovL2kuYW0uYW4udXJs.eyJydSI6Imh0dHBzOi8vbXktcmVkaXJlY3QtdXJpIiwicnQiOiJjb2RlIiwicm0iOiJxdWVyeSIsInN0Ijoic29tZS1zdGF0ZSJ9";
|
||||||
String clientId = "http://i.am.an.url";
|
String clientId = "http://i.am.an.url";
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.services.resources;
|
||||||
|
|
||||||
import static org.keycloak.services.managers.AuthenticationManager.authenticateIdentityCookie;
|
import static org.keycloak.services.managers.AuthenticationManager.authenticateIdentityCookie;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
|
@ -42,8 +43,6 @@ import org.keycloak.protocol.AuthorizationEndpointBase;
|
||||||
import org.keycloak.protocol.ClientData;
|
import org.keycloak.protocol.ClientData;
|
||||||
import org.keycloak.protocol.LoginProtocol;
|
import org.keycloak.protocol.LoginProtocol;
|
||||||
import org.keycloak.protocol.RestartLoginCookie;
|
import org.keycloak.protocol.RestartLoginCookie;
|
||||||
import org.keycloak.protocol.oidc.endpoints.AuthorizationEndpointChecker;
|
|
||||||
import org.keycloak.protocol.oidc.endpoints.request.AuthorizationEndpointRequest;
|
|
||||||
import org.keycloak.services.ErrorPage;
|
import org.keycloak.services.ErrorPage;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
import org.keycloak.services.managers.AuthenticationManager;
|
import org.keycloak.services.managers.AuthenticationManager;
|
||||||
|
@ -76,7 +75,7 @@ public class SessionCodeChecks {
|
||||||
private final String code;
|
private final String code;
|
||||||
private final String execution;
|
private final String execution;
|
||||||
private final String clientId;
|
private final String clientId;
|
||||||
private final ClientData clientData;
|
private final String clientDataString;
|
||||||
private final String tabId;
|
private final String tabId;
|
||||||
private final String flowPath;
|
private final String flowPath;
|
||||||
private final String authSessionId;
|
private final String authSessionId;
|
||||||
|
@ -97,7 +96,7 @@ public class SessionCodeChecks {
|
||||||
this.tabId = tabId;
|
this.tabId = tabId;
|
||||||
this.flowPath = flowPath;
|
this.flowPath = flowPath;
|
||||||
this.authSessionId = authSessionId;
|
this.authSessionId = authSessionId;
|
||||||
this.clientData = ClientData.decodeClientDataFromParameter(clientData);
|
this.clientDataString = clientData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -174,6 +173,17 @@ public class SessionCodeChecks {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClientData clientData;
|
||||||
|
try {
|
||||||
|
clientData = ClientData.decodeClientDataFromParameter(clientDataString);
|
||||||
|
} catch (RuntimeException | IOException e) {
|
||||||
|
logger.debugf(e, "ClientData parameter in invalid format. ClientData parameter was %s", clientDataString);
|
||||||
|
event.detail(Details.REASON, "Invalid client data: " + e.getMessage());
|
||||||
|
event.error(Errors.INVALID_REQUEST);
|
||||||
|
response = ErrorPage.error(session, null, Response.Status.BAD_REQUEST, Messages.INVALID_REQUEST);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (authSession != null) {
|
if (authSession != null) {
|
||||||
session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSession);
|
session.getProvider(LoginFormsProvider.class).setAuthenticationSession(authSession);
|
||||||
return authSession;
|
return authSession;
|
||||||
|
|
Loading…
Reference in a new issue