diff --git a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
index 6b93561..0122657 100755
--- a/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
+++ b/services/src/main/java/org/keycloak/protocol/oidc/endpoints/AuthorizationEndpoint.java
@@ -17,6 +17,11 @@
package org.keycloak.protocol.oidc.endpoints;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
import javax.ws.rs.GET;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
@@ -33,7 +38,6 @@ import org.keycloak.models.ClientModel;
import org.keycloak.models.ClientSessionModel;
import org.keycloak.models.IdentityProviderModel;
import org.keycloak.models.RealmModel;
-import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.protocol.AuthorizationEndpointBase;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
import org.keycloak.protocol.oidc.utils.OIDCResponseMode;
@@ -56,6 +60,43 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
public static final String CODE_AUTH_TYPE = "code";
+ /**
+ * Prefix used to store additional HTTP GET params from original client request into {@link ClientSessionModel} note to be available later in Authenticators, RequiredActions etc. Prefix is used to
+ * prevent collisions with internally used notes.
+ *
+ * @see ClientSessionModel#getNote(String)
+ * @see #KNOWN_REQ_PARAMS
+ * @see #additionalReqParams
+ */
+ public static final String CLIENT_SESSION_NOTE_ADDITIONAL_REQ_PARAMS_PREFIX = "client_request_param_";
+ /**
+ * Max number of additional req params copied into client session note to prevent DoS attacks
+ *
+ * @see #additionalReqParams
+ */
+ public static final int ADDITIONAL_REQ_PARAMS_MAX_MUMBER = 5;
+ /**
+ * Max size of additional req param value copied into client session note to prevent DoS attacks - params with longer value are ignored
+ *
+ * @see #additionalReqParams
+ */
+ public static final int ADDITIONAL_REQ_PARAMS_MAX_SIZE = 200;
+
+ /** Set of known protocol GET params not to be stored into {@link #additionalReqParams} */
+ private static final Set<String> KNOWN_REQ_PARAMS = new HashSet<>();
+ static {
+ KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.CLIENT_ID_PARAM);
+ KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.RESPONSE_TYPE_PARAM);
+ KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.RESPONSE_MODE_PARAM);
+ KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.REDIRECT_URI_PARAM);
+ KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.STATE_PARAM);
+ KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.SCOPE_PARAM);
+ KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.LOGIN_HINT_PARAM);
+ KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.PROMPT_PARAM);
+ KNOWN_REQ_PARAMS.add(AdapterConstants.KC_IDP_HINT);
+ KNOWN_REQ_PARAMS.add(OIDCLoginProtocol.NONCE_PARAM);
+ }
+
private enum Action {
REGISTER, CODE, FORGOT_CREDENTIALS
}
@@ -77,6 +118,7 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
private String prompt;
private String nonce;
private String idpHint;
+ protected Map<String, String> additionalReqParams = new HashMap<>();
public AuthorizationEndpoint(RealmModel realm, EventBuilder event) {
super(realm, event);
@@ -98,6 +140,8 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
idpHint = params.getFirst(AdapterConstants.KC_IDP_HINT);
nonce = params.getFirst(OIDCLoginProtocol.NONCE_PARAM);
+ extractAdditionalReqParams(params);
+
checkSsl();
checkRealm();
checkResponseType();
@@ -119,6 +163,27 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
throw new RuntimeException("Unknown action " + action);
}
+ protected void extractAdditionalReqParams(MultivaluedMap<String, String> params) {
+ for (String paramName : params.keySet()) {
+ if (!KNOWN_REQ_PARAMS.contains(paramName)) {
+ String value = params.getFirst(paramName);
+ if (value != null && value.trim().isEmpty()) {
+ value = null;
+ }
+ if (value != null && value.length() <= ADDITIONAL_REQ_PARAMS_MAX_SIZE) {
+ if (additionalReqParams.size() >= ADDITIONAL_REQ_PARAMS_MAX_MUMBER) {
+ logger.debug("Maximal number of additional OIDC params (" + ADDITIONAL_REQ_PARAMS_MAX_MUMBER + ") exceeded, ignoring rest of them!");
+ break;
+ }
+ additionalReqParams.put(paramName, value);
+ } else {
+ logger.debug("OIDC Additional param " + paramName + " ignored because value is empty or longer than " + ADDITIONAL_REQ_PARAMS_MAX_SIZE);
+ }
+ }
+
+ }
+ }
+
public AuthorizationEndpoint register() {
event.event(EventType.REGISTER);
action = Action.REGISTER;
@@ -249,6 +314,12 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
if (prompt != null) clientSession.setNote(OIDCLoginProtocol.PROMPT_PARAM, prompt);
if (idpHint != null) clientSession.setNote(AdapterConstants.KC_IDP_HINT, idpHint);
if (responseMode != null) clientSession.setNote(OIDCLoginProtocol.RESPONSE_MODE_PARAM, responseMode);
+
+ if (additionalReqParams != null) {
+ for (String paramName : additionalReqParams.keySet()) {
+ clientSession.setNote(CLIENT_SESSION_NOTE_ADDITIONAL_REQ_PARAMS_PREFIX + paramName, additionalReqParams.get(paramName));
+ }
+ }
}
private Response buildAuthorizationCodeAuthorizationResponse() {
@@ -292,7 +363,4 @@ public class AuthorizationEndpoint extends AuthorizationEndpointBase {
return processor.authenticate();
}
-
-
-
}