Skip to content

Commit 5a05d21

Browse files
committed
Unbounded login_hint parameter Can Corrupt KC_RESTART Cookie
closes #40857 Signed-off-by: mposolda <[email protected]>
1 parent 0ebb702 commit 5a05d21

File tree

9 files changed

+351
-74
lines changed

9 files changed

+351
-74
lines changed

docs/documentation/topics/templates/document-attributes.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@
5858
:apidocs_link: https://www.keycloak.org/docs/{project_version}/api_documentation/
5959
:adminguide_email_name: Configuring email for a realm
6060
:adminguide_email_link: {adminguide_link}#_email
61+
:allproviderconfigguide_name: All provider configuration Guide
62+
:allproviderconfigguide_link: https://www.keycloak.org/server/all-provider-config
6163
:bootstrapadminrecovery_name: Admin Bootstrap and Recovery
6264
:bootstrapadminrecovery_link: https://www.keycloak.org/server/bootstrap-admin-recovery
6365
:client_certificate_lookup_link: https://www.keycloak.org/server/reverseproxy#_enabling_client_certificate_lookup

docs/documentation/upgrading/topics/changes/changes-26_4_0.adoc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,16 @@ The input fields in the login theme for OTP and recovery codes and have been op
176176
* The input mode is now `numeric`, which will ease the input on mobile devices.
177177
* The auto-complete is set to `one-time-code` to avoid interference with password managers.
178178

179+
=== Maximum length of the parameters in the OIDC authentication request
180+
181+
When the OIDC authentication request (or OAuth2 authorization request) is sent, there is now limit for the maximum length of every standard OIDC/OAuth2 parameter. The maximum length of each standard parameter is 4000 characters,
182+
which is very big number and can be lowered in the future releases. For now, it is kept big for the backwards compatibility. The only exception is the `login_hint` parameter, which is limited
183+
to the maximum length of 255 characters. This is aligned with the maximum length for the `username` and `email` attributes configured in the default user profile configuration.
184+
185+
If you want to make those number higher or lower, you can start the server with the option `req-params-default-max-size` for the default maximum length of the standard
186+
OIDC/OAuth2 parameters or you can use something like `req-params-max-size` for one specific parameter. See the `login-protocol` provider configuration
187+
of the link:{allproviderconfigguide_link}[{allproviderconfigguide_name}] for more details.
188+
179189
=== UTF-8 management in the email sender
180190

181191
Since this release, {project_name} adds a new option `allowutf8` for the realm SMTP configuration (*Allow UTF-8* field inside the *Email* tab in the *Realm settings* section of the Admin Console).

services/src/main/java/org/keycloak/protocol/oidc/OIDCLoginProtocolFactory.java

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.keycloak.common.constants.KerberosConstants;
2424
import org.keycloak.common.constants.ServiceAccountConstants;
2525
import org.keycloak.common.util.UriUtils;
26+
import org.keycloak.connections.httpclient.HttpClientProvider;
2627
import org.keycloak.events.EventBuilder;
2728
import org.keycloak.models.ClientModel;
2829
import org.keycloak.models.ClientScopeModel;
@@ -47,18 +48,26 @@
4748
import org.keycloak.protocol.oidc.mappers.UserRealmRoleMappingMapper;
4849
import org.keycloak.protocol.oidc.mappers.UserSessionNoteMapper;
4950
import org.keycloak.protocol.oidc.mappers.SubMapper;
51+
import org.keycloak.provider.ProviderConfigProperty;
52+
import org.keycloak.provider.ProviderConfigurationBuilder;
5053
import org.keycloak.representations.IDToken;
5154
import org.keycloak.representations.idm.ClientRepresentation;
5255
import org.keycloak.services.ServicesLogger;
5356
import org.keycloak.services.managers.AuthenticationManager;
5457

5558
import java.util.HashMap;
5659
import java.util.HashSet;
60+
import java.util.List;
5761
import java.util.Map;
5862
import java.util.Set;
5963

6064
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_ID;
6165
import static org.keycloak.models.ImpersonationSessionNote.IMPERSONATOR_USERNAME;
66+
import static org.keycloak.protocol.oidc.OIDCProviderConfig.DEFAULT_ADDITIONAL_REQ_PARAMS_FAIL_FAST;
67+
import static org.keycloak.protocol.oidc.OIDCProviderConfig.DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_NUMBER;
68+
import static org.keycloak.protocol.oidc.OIDCProviderConfig.DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_OVERALL_SIZE;
69+
import static org.keycloak.protocol.oidc.OIDCProviderConfig.DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_SIZE;
70+
import static org.keycloak.protocol.oidc.OIDCProviderConfig.DEFAULT_REQ_PARAMS_DEFAULT_MAX_SIZE;
6271

6372
/**
6473
* @author <a href="mailto:[email protected]">Bill Burke</a>
@@ -115,10 +124,12 @@ public class OIDCLoginProtocolFactory extends AbstractLoginProtocolFactory {
115124
public static final String ROLES_SCOPE_CONSENT_TEXT = "${rolesScopeConsentText}";
116125
public static final String ORGANIZATION_SCOPE_CONSENT_TEXT = "${organizationScopeConsentText}";
117126

118-
public static final String CONFIG_OIDC_REQ_PARAMS_MAX_NUMBER = "add-req-params-max-number";
119-
public static final String CONFIG_OIDC_REQ_PARAMS_MAX_SIZE = "add-req-params-max-size";
120-
public static final String CONFIG_OIDC_REQ_PARAMS_MAX_OVERALL_SIZE = "add-req-params-max-overall-size";
121-
public static final String CONFIG_OIDC_REQ_PARAMS_FAIL_FAST = "add-req-params-fail-fast";
127+
public static final String CONFIG_OIDC_REQ_PARAMS_DEFAULT_MAX_SIZE = "req-params-default-max-size";
128+
public static final String CONFIG_OIDC_REQ_PARAMS_MAX_SIZE_PREFIX = "req-params-max-size";
129+
public static final String CONFIG_OIDC_ADD_REQ_PARAMS_MAX_NUMBER = "add-req-params-max-number";
130+
public static final String CONFIG_OIDC_ADD_REQ_PARAMS_MAX_SIZE = "add-req-params-max-size";
131+
public static final String CONFIG_OIDC_ADD_REQ_PARAMS_MAX_OVERALL_SIZE = "add-req-params-max-overall-size";
132+
public static final String CONFIG_OIDC_ADD_REQ_PARAMS_FAIL_FAST = "add-req-params-fail-fast";
122133

123134
/**
124135
* @deprecated To be removed in Keycloak 27
@@ -554,4 +565,48 @@ public void setupClientDefaults(ClientRepresentation rep, ClientModel newClient)
554565
public int order() {
555566
return UI_ORDER;
556567
}
568+
569+
@Override
570+
public List<ProviderConfigProperty> getConfigMetadata() {
571+
return ProviderConfigurationBuilder.create()
572+
.property()
573+
.name(CONFIG_OIDC_REQ_PARAMS_DEFAULT_MAX_SIZE)
574+
.type("int")
575+
.helpText("Maximum default length of the standard OIDC parameter sent to the OIDC authentication request. This applies to most of the standard parameters like for example 'state', 'nonce' etc." +
576+
" The exception is 'login_hint' parameter, which has maximum length of 255 characters.")
577+
.defaultValue(DEFAULT_REQ_PARAMS_DEFAULT_MAX_SIZE)
578+
.add()
579+
.property()
580+
.name(CONFIG_OIDC_REQ_PARAMS_MAX_SIZE_PREFIX + "--" + OIDCLoginProtocol.LOGIN_HINT_PARAM)
581+
.type("int")
582+
.helpText("Maximum length of the standard OIDC authentication request parameter overriden for the specified parameter. Useful if some standard OIDC parameter should have different limit than '" + CONFIG_OIDC_REQ_PARAMS_DEFAULT_MAX_SIZE +
583+
"'. It is needed to add the name of the parameter after this prefix into the configuration. In this example, the '" + OIDCLoginProtocol.LOGIN_HINT_PARAM + "' parameter is used, but this format is supported for any known standard OIDC/OAuth2 parameter.")
584+
.add()
585+
.property()
586+
.name(CONFIG_OIDC_ADD_REQ_PARAMS_MAX_NUMBER)
587+
.type("int")
588+
.helpText("Maximum number of additional request parameters sent to the OIDC authentication request. As 'additional request parameter' is meant some custom parameter not directly treated as standard OIDC/OAuth2 protocol parameter. Additional parameters might be useful for example to add custom claims to the OIDC token (in case that also particular protocol mappers are configured).")
589+
.defaultValue(DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_NUMBER)
590+
.add()
591+
.property()
592+
.name(CONFIG_OIDC_ADD_REQ_PARAMS_MAX_SIZE)
593+
.type("int")
594+
.helpText("Maximum size of single additional request parameter value See '" + CONFIG_OIDC_ADD_REQ_PARAMS_MAX_NUMBER + "' for more details about additional request parameters")
595+
.defaultValue(DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_SIZE)
596+
.add()
597+
.property()
598+
.name(CONFIG_OIDC_ADD_REQ_PARAMS_MAX_OVERALL_SIZE)
599+
.type("int")
600+
.helpText("Maximum size of all additional request parameters values together. See '" + CONFIG_OIDC_ADD_REQ_PARAMS_MAX_NUMBER + "' for more details about additional request parameters")
601+
.defaultValue(DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_OVERALL_SIZE)
602+
.add()
603+
.property()
604+
.name(CONFIG_OIDC_ADD_REQ_PARAMS_FAIL_FAST)
605+
.type("boolean")
606+
.helpText("Whether the fail-fast strategy should be enforced in case if the limit for some standard OIDC parameter or additional OIDC parameter is not met for the parameters sent to the OIDC authentication request." +
607+
" If false, then all additional request parameters to not meet the configuration are silently ignored. If true, an exception will be raised and OIDC authentication request will not be allowed.")
608+
.defaultValue(DEFAULT_ADDITIONAL_REQ_PARAMS_FAIL_FAST)
609+
.add()
610+
.build();
611+
}
557612
}

services/src/main/java/org/keycloak/protocol/oidc/OIDCProviderConfig.java

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,32 @@
11
package org.keycloak.protocol.oidc;
22

3+
import java.util.Map;
4+
35
import org.keycloak.Config;
46

57
/**
68
* @author <a href="mailto:[email protected]">Patrick Weiner</a>
79
*/
810
public class OIDCProviderConfig {
911

12+
private final Config.Scope config;
13+
14+
/**
15+
* Maximum default length of the standard OIDC parameter sent to the OIDC authentication request.
16+
*/
17+
public static final int DEFAULT_REQ_PARAMS_DEFAULT_MAX_SIZE = 4000;
18+
19+
private final int reqParamsDefaultMaxSize;
20+
21+
/**
22+
* Overriden values for maximum sizes of specified standard OIDC parameters. The value for the specified parameter can be still overriden
23+
* by administrator in the configuration of the {@link OIDCLoginProtocolFactory}. In case that value is not overriden in the configuration or in this map,
24+
* then the value specified by the {@link OIDCLoginProtocolFactory#CONFIG_OIDC_REQ_PARAMS_DEFAULT_MAX_SIZE} is used
25+
*/
26+
private Map<String, Integer> DEFAULT_MAX_PARAMS_SIZES = Map.of(
27+
OIDCLoginProtocol.LOGIN_HINT_PARAM, 255 // Aligned with user-profile configuration for username and email
28+
);
29+
1030
/**
1131
* Default value for {@link #additionalReqParamsMaxNumber} if case no configuration property is set.
1232
*/
@@ -62,10 +82,13 @@ public class OIDCProviderConfig {
6282

6383

6484
public OIDCProviderConfig(Config.Scope config) {
65-
this.additionalReqParamsMaxNumber = config.getInt(OIDCLoginProtocolFactory.CONFIG_OIDC_REQ_PARAMS_MAX_NUMBER, DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_NUMBER);
66-
this.additionalReqParamsMaxSize = config.getInt(OIDCLoginProtocolFactory.CONFIG_OIDC_REQ_PARAMS_MAX_SIZE, DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_SIZE);
67-
this.additionalReqParamsMaxOverallSize = config.getInt(OIDCLoginProtocolFactory.CONFIG_OIDC_REQ_PARAMS_MAX_OVERALL_SIZE, DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_OVERALL_SIZE);
68-
this.additionalReqParamsFailFast = config.getBoolean(OIDCLoginProtocolFactory.CONFIG_OIDC_REQ_PARAMS_FAIL_FAST, DEFAULT_ADDITIONAL_REQ_PARAMS_FAIL_FAST);
85+
this.config = config;
86+
87+
this.reqParamsDefaultMaxSize = config.getInt(OIDCLoginProtocolFactory.CONFIG_OIDC_REQ_PARAMS_DEFAULT_MAX_SIZE, DEFAULT_REQ_PARAMS_DEFAULT_MAX_SIZE);
88+
this.additionalReqParamsMaxNumber = config.getInt(OIDCLoginProtocolFactory.CONFIG_OIDC_ADD_REQ_PARAMS_MAX_NUMBER, DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_NUMBER);
89+
this.additionalReqParamsMaxSize = config.getInt(OIDCLoginProtocolFactory.CONFIG_OIDC_ADD_REQ_PARAMS_MAX_SIZE, DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_SIZE);
90+
this.additionalReqParamsMaxOverallSize = config.getInt(OIDCLoginProtocolFactory.CONFIG_OIDC_ADD_REQ_PARAMS_MAX_OVERALL_SIZE, DEFAULT_ADDITIONAL_REQ_PARAMS_MAX_OVERALL_SIZE);
91+
this.additionalReqParamsFailFast = config.getBoolean(OIDCLoginProtocolFactory.CONFIG_OIDC_ADD_REQ_PARAMS_FAIL_FAST, DEFAULT_ADDITIONAL_REQ_PARAMS_FAIL_FAST);
6992

7093
this.allowMultipleAudiencesForJwtClientAuthentication = config.getBoolean(OIDCLoginProtocolFactory.CONFIG_OIDC_ALLOW_MULTIPLE_AUDIENCES_FOR_JWT_CLIENT_AUTHENTICATION, DEFAULT_ALLOW_MULTIPLE_AUDIENCES_FOR_JWT_CLIENT_AUTHENTICATION);
7194
}
@@ -89,4 +112,26 @@ public int getAdditionalReqParamsMaxOverallSize() {
89112
public boolean isAllowMultipleAudiencesForJwtClientAuthentication() {
90113
return allowMultipleAudiencesForJwtClientAuthentication;
91114
}
115+
116+
/**
117+
* @param paramName Parameter name. Expected to be one of the known OIDC parameters
118+
*
119+
* @return maximum length for the specified OIDC parameter
120+
*/
121+
public int getMaxLengthForTheParameter(String paramName) {
122+
// Configured value for the particular OIDC parameter
123+
Integer paramMaxSize = config.getInt(OIDCLoginProtocolFactory.CONFIG_OIDC_REQ_PARAMS_MAX_SIZE_PREFIX + "--" + paramName);
124+
125+
// Stick to default. See if we have default value overriden
126+
if (paramMaxSize == null) {
127+
paramMaxSize = DEFAULT_MAX_PARAMS_SIZES.get(paramName);
128+
}
129+
130+
// Fallback to default for all standard OIDC parameters
131+
if (paramMaxSize == null) {
132+
paramMaxSize = reqParamsDefaultMaxSize;
133+
}
134+
135+
return paramMaxSize;
136+
}
92137
}

0 commit comments

Comments
 (0)