Skip to content

Commit

Permalink
Add support for Initiating User Registration via prompt=create (keycl…
Browse files Browse the repository at this point in the history
…oak#10701) (keycloak#35903)

Fixes keycloak#10701

Signed-off-by: Thomas Darimont <[email protected]>
  • Loading branch information
thomasdarimont authored Dec 16, 2024
1 parent cfdfd82 commit 3cdbbc5
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ public class OIDCConfigurationRepresentation {
@JsonProperty("subject_types_supported")
private List<String> subjectTypesSupported;

@JsonProperty("prompt_values_supported")
private List<String> promptValuesSupported;

@JsonProperty("id_token_signing_alg_values_supported")
private List<String> idTokenSigningAlgValuesSupported;

Expand Down Expand Up @@ -655,4 +658,11 @@ public void setAuthorizationResponseIssParameterSupported(Boolean authorizationR
this.authorizationResponseIssParameterSupported = authorizationResponseIssParameterSupported;
}

public List<String> getPromptValuesSupported() {
return promptValuesSupported;
}

public void setPromptValuesSupported(List<String> promptValuesSupported) {
this.promptValuesSupported = promptValuesSupported;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -419,7 +419,8 @@ Sometimes it can be useful for the client application to directly redirect the u
user clicks *Register* or *Forget password* on the normal login screen. Automatic redirect to the registration or reset-credentials screen can be done as follows:

* When the client wants the user to be redirected directly to the registration, the OIDC client should replace the very last snippet from the OIDC login URL path (`/auth`) with `/registrations` . So the full URL
might be similar to the following: `https://keycloak.example.com/realms/your_realm/protocol/openid-connect/registrations`.
might be similar to the following: `https://keycloak.example.com/realms/your_realm/protocol/openid-connect/registrations`. As an alternative to using the `/registrations` endpoint, clients can use the OIDC
`prompt` parameter with `prompt=create` to redirect the user to the registration.

* When the client wants a user to be redirected directly to the `Reset credentials` flow, the OIDC client should replace the very last snippet from the OIDC login URL path (`/auth`) with `/forgot-credentials` .

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ public class OIDCLoginProtocol implements LoginProtocol {
public static final String PROMPT_VALUE_NONE = "none";
public static final String PROMPT_VALUE_LOGIN = "login";
public static final String PROMPT_VALUE_CONSENT = "consent";
public static final String PROMPT_VALUE_CREATE = "create";
public static final String PROMPT_VALUE_SELECT_ACCOUNT = "select_account";

// Client authentication methods
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,9 @@ public class OIDCWellKnownProvider implements WellKnownProvider {
// KEYCLOAK-7451 OAuth Authorization Server Metadata for Proof Key for Code Exchange
public static final List<String> DEFAULT_CODE_CHALLENGE_METHODS_SUPPORTED = list(OAuth2Constants.PKCE_METHOD_PLAIN, OAuth2Constants.PKCE_METHOD_S256);

// See: GH-10701, note that the supported prompt value "create" is only added if the realm supports registrations.
public static final List<String> DEFAULT_PROMPT_VALUES_SUPPORTED = list(OIDCLoginProtocol.PROMPT_VALUE_NONE /*, OIDCLoginProtocol.PROMPT_VALUE_CREATE*/, OIDCLoginProtocol.PROMPT_VALUE_LOGIN, OIDCLoginProtocol.PROMPT_VALUE_CONSENT);

private final KeycloakSession session;
private final Map<String, Object> openidConfigOverride;
private final boolean includeClientScopes;
Expand Down Expand Up @@ -167,6 +170,8 @@ public Object getConfig() {
config.setGrantTypesSupported(DEFAULT_GRANT_TYPES_SUPPORTED);
config.setAcrValuesSupported(getAcrValuesSupported(realm));

config.setPromptValuesSupported(getPromptValuesSupported(realm));

config.setTokenEndpointAuthMethodsSupported(getClientAuthMethodsSupported());
config.setTokenEndpointAuthSigningAlgValuesSupported(getSupportedClientSigningAlgorithms(false));
config.setIntrospectionEndpointAuthMethodsSupported(getClientAuthMethodsSupported());
Expand Down Expand Up @@ -235,6 +240,14 @@ public Object getConfig() {
return config;
}

protected List<String> getPromptValuesSupported(RealmModel realm) {
List<String> prompts = new ArrayList<>(DEFAULT_PROMPT_VALUES_SUPPORTED);
if (realm.isRegistrationAllowed()) {
prompts.add(OIDCLoginProtocol.PROMPT_VALUE_CREATE);
}
return prompts;
}

@Override
public void close() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,16 @@ private Response process(final MultivaluedMap<String, String> params) {

// So back button doesn't work
CacheControlUtil.noBackButtonCacheControlHeader(session);

// Add support for Initiating User Registration via OpenID Connect 1.0 via prompt=create
// see: https://openid.net/specs/openid-connect-prompt-create-1_0.html#section-4.1
if (OIDCLoginProtocol.PROMPT_VALUE_CREATE.equals(params.getFirst(OAuth2Constants.PROMPT))) {
if (!Organizations.isRegistrationAllowed(session, realm)) {
throw new ErrorPageException(session, authenticationSession, Response.Status.BAD_REQUEST, Messages.REGISTRATION_NOT_ALLOWED);
}
return buildRegister();
}

switch (action) {
case REGISTER:
return buildRegister();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@
import org.keycloak.testsuite.pages.ErrorPage;
import org.keycloak.testsuite.pages.LoginPage;
import org.keycloak.testsuite.pages.OAuthGrantPage;
import org.keycloak.testsuite.pages.RegisterPage;
import org.keycloak.testsuite.rest.resource.TestingOIDCEndpointsApplicationResource;
import org.keycloak.testsuite.util.RealmManager;
import org.keycloak.util.JWKSUtils;
import org.keycloak.util.JsonSerialization;
import org.keycloak.testsuite.util.OAuthClient;
Expand Down Expand Up @@ -124,6 +126,9 @@ public class OIDCAdvancedRequestParamsTest extends AbstractTestRealmKeycloakTest
@Page
protected AppPage appPage;

@Page
protected RegisterPage registerPage;

@Page
protected LoginPage loginPage;

Expand Down Expand Up @@ -406,6 +411,35 @@ public void promptLogin() {
Assert.assertEquals(oldIdToken.getSessionState(), newIdToken.getSessionState());
}

// prompt=create
@Test
public void promptCreate() {

// Assert registration page with prompt=login
driver.navigate().to(oauth.getLoginFormUrl() + "&prompt=create");
registerPage.assertCurrent();
}

// prompt=create
@Test
public void promptCreateShouldFailWhenRegistrationsAreDisabled() {

RealmRepresentation realmRep = adminClient.realm("test").toRepresentation();
Boolean registrationAllowed = realmRep.isRegistrationAllowed();
realmRep.setRegistrationAllowed(false);
adminClient.realm("test").update(realmRep);

// Assert registration page with prompt=login
try {
driver.navigate().to(oauth.getLoginFormUrl() + "&prompt=create");
errorPage.assertCurrent();
assertTrue(errorPage.getError().contains("Registration not allowed"));
} finally {
realmRep.setRegistrationAllowed(registrationAllowed);
adminClient.realm("test").update(realmRep);
}
}

// prompt=consent
@Test
public void promptConsent() {
Expand Down

0 comments on commit 3cdbbc5

Please sign in to comment.