Add support for passing acr_values in auth requests in keycloak.js (#9383) (#24259)

Fixes #9383
This commit is contained in:
Thomas Darimont 2023-10-25 15:33:39 +02:00 committed by GitHub
parent c036980c37
commit d56baa80b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 70 additions and 0 deletions

View file

@ -370,6 +370,7 @@ to {project_name} will contain the scope parameter `scope=openid address phone`.
* enableLogging - Enables logging messages from Keycloak to the console (default is `false`).
* pkceMethod - The method for Proof Key Code Exchange (https://datatracker.ietf.org/doc/html/rfc7636[PKCE]) to use. Configuring this value enables the PKCE mechanism. Available options:
- "S256" - The SHA256 based PKCE method
* acrValues - Generates the `acr_values` parameter which refers to authentication context class reference and allows clients to declare the required assurance level requirements, e.g. authentication mechanisms. See https://openid.net/specs/openid-connect-modrna-authentication-1_0.html#acr_values[Section 4. acr_values request values and level of assurance in OpenID Connect MODRNA Authentication Profile 1.0].
* messageReceiveTimeout - Set a timeout in milliseconds for waiting for message responses from the Keycloak server. This is used, for example, when waiting for a message during 3rd party cookies check. The default value is 10000.
* locale - When onLoad is 'login-required', sets the 'ui_locales' query param in compliance with https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest[section 3.1.2.1 of the OIDC 1.0 specification].
@ -393,6 +394,7 @@ provider instead. More info in the link:{adminguide_link}#_client_suggested_idp[
* acr - Contains the information about `acr` claim, which will be sent inside `claims` parameter to the {project_name} server. Typical usage
is for step-up authentication. Example of use `{ values: ["silver", "gold"], essential: true }`. See OpenID Connect specification
and link:{adminguide_link}#_step-up-flow[Step-up authentication documentation] for more details.
* acrValues - Generates the `acr_values` parameter which refers to authentication context class reference and allows clients to declare the required assurance level requirements, e.g. authentication mechanisms. See https://openid.net/specs/openid-connect-modrna-authentication-1_0.html#acr_values[Section 4. acr_values request values and level of assurance in OpenID Connect MODRNA Authentication Profile 1.0].
* action - If value is `register` then user is redirected to registration page, if the value is `UPDATE_PASSWORD` then the user will be redirected to the reset password page (if not authenticated will send user to login page first and redirect after authenticated), otherwise to login page.
* locale - Sets the 'ui_locales' query param in compliance with https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest[section 3.1.2.1 of the OIDC 1.0 specification].
* cordovaOptions - Specifies the arguments that are passed to the Cordova in-app-browser (if applicable). Options `hidden` and `location` are not affected by these arguments. All available options are defined at https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-inappbrowser/. Example of use: `{ zoom: "no", hardwareback: "yes" }`;

View file

@ -175,6 +175,13 @@ export interface KeycloakInitOptions {
*/
pkceMethod?: KeycloakPkceMethod;
/**
* Configures the 'acr_values' query param in compliance with section 3.1.2.1
* of the OIDC 1.0 specification.
* Used to tell Keycloak what level of authentication the user needs.
*/
acrValues?: string;
/**
* Enables logging messages from Keycloak to the console.
* @default false
@ -250,6 +257,13 @@ export interface KeycloakLoginOptions {
*/
acr?: Acr;
/**
* Configures the 'acr_values' query param in compliance with section 3.1.2.1
* of the OIDC 1.0 specification.
* Used to tell Keycloak what level of authentication the user needs.
*/
acrValues?: string;
/**
* Used to tell Keycloak which IDP the user wants to authenticate with.
*/

View file

@ -150,6 +150,10 @@ function Keycloak (config) {
kc.scope = initOptions.scope;
}
if (typeof initOptions.acrValues === 'string') {
kc.acrValues = initOptions.acrValues;
}
if (typeof initOptions.messageReceiveTimeout === 'number' && initOptions.messageReceiveTimeout > 0) {
kc.messageReceiveTimeout = initOptions.messageReceiveTimeout;
} else {
@ -461,6 +465,10 @@ function Keycloak (config) {
url += '&claims=' + encodeURIComponent(claimsParameter);
}
if ((options && options.acrValues) || kc.acrValues) {
url += '&acr_values=' + encodeURIComponent(options.acrValues || kc.acrValues);
}
if (kc.pkceMethod) {
var codeVerifier = generateCodeVerifier(96);
callbackState.pkceCodeVerifier = codeVerifier;

View file

@ -4,6 +4,7 @@ import java.io.IOException;
import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.keycloak.util.JsonSerialization;
@ -103,6 +104,12 @@ public class JSObjectBuilder {
return this;
}
public JSObjectBuilder acrValues(String value) {
Objects.requireNonNull(value, "value");
arguments.put("acrValues", value);
return this;
}
private boolean skipQuotes(Object o) {
return (o instanceof Integer || o instanceof Boolean || o instanceof JSObjectBuilder);
}

View file

@ -541,6 +541,45 @@ public class JavascriptAdapterTest extends AbstractJavascriptTest {
});
}
/**
* Test for {@code acr_values} handling via {@code loginOptions}: <pre>{@code
* Keycloak keycloak = new Keycloak(); keycloak.login({...., acrValues: "1"})
* }</pre>
*/
@Test
public void testAcrValuesInLoginOptionsShouldBeConsideredByLoginUrl() {
testExecutor.configure().init(defaultArguments());
JSObjectBuilder loginOptions = JSObjectBuilder.create();
testExecutor.login(loginOptions, (JavascriptStateValidator) (driver, output, events) -> {
try {
String queryString = new URL(driver.getCurrentUrl()).getQuery();
String acrValues = UriUtils.decodeQueryString(queryString).getFirst(OIDCLoginProtocol.ACR_PARAM);
Assert.assertNull(acrValues);
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
});
// Test given "acrValues" option will be translated into the "acr_values" parameter passed to Keycloak server
jsDriver.navigate().to(testAppUrl);
testExecutor.configure().init(defaultArguments());
loginOptions = JSObjectBuilder.create().acrValues("2fa");
testExecutor.login(loginOptions, (JavascriptStateValidator) (driver, output, events) -> {
try {
String queryString = new URL(driver.getCurrentUrl()).getQuery();
String acrValuesParam = UriUtils.decodeQueryString(queryString).getFirst(OIDCLoginProtocol.ACR_PARAM);
Assert.assertNotNull(acrValuesParam);
assertThat(acrValuesParam, is("2fa"));
} catch (IOException ioe) {
throw new AssertionError(ioe);
}
});
}
@Test
public void testUpdateToken() {
XMLHttpRequest request = XMLHttpRequest.create()