Automatically fill username when authenticating to through a broker
Closes #28848 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
parent
1e3837421e
commit
f0f8a88489
5 changed files with 68 additions and 11 deletions
|
@ -75,6 +75,10 @@ public class IdentityProviderAuthenticator implements Authenticator {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void redirect(AuthenticationFlowContext context, String providerId) {
|
protected void redirect(AuthenticationFlowContext context, String providerId) {
|
||||||
|
redirect(context, providerId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void redirect(AuthenticationFlowContext context, String providerId, String loginHint) {
|
||||||
Optional<IdentityProviderModel> idp = context.getRealm().getIdentityProvidersStream()
|
Optional<IdentityProviderModel> idp = context.getRealm().getIdentityProvidersStream()
|
||||||
.filter(IdentityProviderModel::isEnabled)
|
.filter(IdentityProviderModel::isEnabled)
|
||||||
.filter(identityProvider -> Objects.equals(providerId, identityProvider.getAlias()))
|
.filter(identityProvider -> Objects.equals(providerId, identityProvider.getAlias()))
|
||||||
|
@ -84,7 +88,7 @@ public class IdentityProviderAuthenticator implements Authenticator {
|
||||||
String clientId = context.getAuthenticationSession().getClient().getClientId();
|
String clientId = context.getAuthenticationSession().getClient().getClientId();
|
||||||
String tabId = context.getAuthenticationSession().getTabId();
|
String tabId = context.getAuthenticationSession().getTabId();
|
||||||
String clientData = AuthenticationProcessor.getClientData(context.getSession(), context.getAuthenticationSession());
|
String clientData = AuthenticationProcessor.getClientData(context.getSession(), context.getAuthenticationSession());
|
||||||
URI location = Urls.identityProviderAuthnRequest(context.getUriInfo().getBaseUri(), providerId, context.getRealm().getName(), accessCode, clientId, tabId, clientData);
|
URI location = Urls.identityProviderAuthnRequest(context.getUriInfo().getBaseUri(), providerId, context.getRealm().getName(), accessCode, clientId, tabId, clientData, loginHint);
|
||||||
Response response = Response.seeOther(location)
|
Response response = Response.seeOther(location)
|
||||||
.build();
|
.build();
|
||||||
// will forward the request to the IDP with prompt=none if the IDP accepts forwards with prompt=none.
|
// will forward the request to the IDP with prompt=none if the IDP accepts forwards with prompt=none.
|
||||||
|
|
|
@ -59,6 +59,12 @@ public class OrganizationAuthenticator extends IdentityProviderAuthenticator {
|
||||||
}
|
}
|
||||||
|
|
||||||
String domain = getEmailDomain(username);
|
String domain = getEmailDomain(username);
|
||||||
|
|
||||||
|
if (domain == null) {
|
||||||
|
context.attempted();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
OrganizationProvider provider = getOrganizationProvider();
|
OrganizationProvider provider = getOrganizationProvider();
|
||||||
OrganizationModel organization = provider.getByDomainName(domain);
|
OrganizationModel organization = provider.getByDomainName(domain);
|
||||||
|
|
||||||
|
@ -74,7 +80,7 @@ public class OrganizationAuthenticator extends IdentityProviderAuthenticator {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
redirect(context, identityProvider.getAlias());
|
redirect(context, identityProvider.getAlias(), username);
|
||||||
}
|
}
|
||||||
|
|
||||||
private OrganizationProvider getOrganizationProvider() {
|
private OrganizationProvider getOrganizationProvider() {
|
||||||
|
|
|
@ -52,7 +52,7 @@ public class Urls {
|
||||||
.build(realmName, providerAlias);
|
.build(realmName, providerAlias);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static URI identityProviderAuthnRequest(URI baseUri, String providerAlias, String realmName, String accessCode, String clientId, String tabId, String clientData) {
|
public static URI identityProviderAuthnRequest(URI baseUri, String providerAlias, String realmName, String accessCode, String clientId, String tabId, String clientData, String loginHint) {
|
||||||
UriBuilder uriBuilder = realmBase(baseUri).path(RealmsResource.class, "getBrokerService")
|
UriBuilder uriBuilder = realmBase(baseUri).path(RealmsResource.class, "getBrokerService")
|
||||||
.path(IdentityBrokerService.class, "performLogin");
|
.path(IdentityBrokerService.class, "performLogin");
|
||||||
|
|
||||||
|
@ -68,6 +68,9 @@ public class Urls {
|
||||||
if (clientData != null) {
|
if (clientData != null) {
|
||||||
uriBuilder.replaceQueryParam(Constants.CLIENT_DATA, clientData);
|
uriBuilder.replaceQueryParam(Constants.CLIENT_DATA, clientData);
|
||||||
}
|
}
|
||||||
|
if (loginHint != null) {
|
||||||
|
uriBuilder.replaceQueryParam(OIDCLoginProtocol.LOGIN_HINT_PARAM, loginHint);
|
||||||
|
}
|
||||||
|
|
||||||
return uriBuilder.build(realmName, providerAlias);
|
return uriBuilder.build(realmName, providerAlias);
|
||||||
}
|
}
|
||||||
|
@ -87,7 +90,7 @@ public class Urls {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static URI identityProviderAuthnRequest(URI baseURI, String providerAlias, String realmName) {
|
public static URI identityProviderAuthnRequest(URI baseURI, String providerAlias, String realmName) {
|
||||||
return identityProviderAuthnRequest(baseURI, providerAlias, realmName, null, null, null, null);
|
return identityProviderAuthnRequest(baseURI, providerAlias, realmName, null, null, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static URI identityProviderAfterFirstBrokerLogin(URI baseUri, String realmName, String accessCode, String clientId, String tabId, String clientData) {
|
public static URI identityProviderAfterFirstBrokerLogin(URI baseUri, String realmName, String accessCode, String clientId, String tabId, String clientData) {
|
||||||
|
|
|
@ -26,6 +26,8 @@ import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.OrganizationResource;
|
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||||
import org.keycloak.admin.client.resource.UsersResource;
|
import org.keycloak.admin.client.resource.UsersResource;
|
||||||
import org.keycloak.common.Profile.Feature;
|
import org.keycloak.common.Profile.Feature;
|
||||||
|
import org.keycloak.models.IdentityProviderModel;
|
||||||
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.testsuite.Assert;
|
import org.keycloak.testsuite.Assert;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||||
|
@ -56,6 +58,29 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
assertBrokerRegistration(organization);
|
assertBrokerRegistration(organization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoginHint() {
|
||||||
|
OrganizationResource organization = testRealm().organizations().get(createOrganization().getId());
|
||||||
|
IdentityProviderRepresentation idp = organization.identityProvider().toRepresentation();
|
||||||
|
idp.getConfig().put(IdentityProviderModel.LOGIN_HINT, "true");
|
||||||
|
organization.identityProvider().update(idp).close();
|
||||||
|
|
||||||
|
oauth.clientId("broker-app");
|
||||||
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
log.debug("Logging in");
|
||||||
|
Assert.assertFalse(loginPage.isPasswordInputPresent());
|
||||||
|
Assert.assertFalse(loginPage.isSocialButtonPresent(bc.getIDPAlias()));
|
||||||
|
loginPage.loginUsername(bc.getUserEmail());
|
||||||
|
|
||||||
|
// user automatically redirected to the organization identity provider
|
||||||
|
waitForPage(driver, "sign in to", true);
|
||||||
|
Assert.assertTrue("Driver should be on the provider realm page right now",
|
||||||
|
driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/"));
|
||||||
|
// check if the username is automatically filled
|
||||||
|
Assert.assertEquals(bc.getUserEmail(), loginPage.getUsername());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultAuthenticationMechanismIfNotOrganizationMember() {
|
public void testDefaultAuthenticationMechanismIfNotOrganizationMember() {
|
||||||
testRealm().organizations().get(createOrganization().getId());
|
testRealm().organizations().get(createOrganization().getId());
|
||||||
|
@ -72,6 +97,22 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
Assert.assertTrue(loginPage.isPasswordInputPresent());
|
Assert.assertTrue(loginPage.isPasswordInputPresent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTryLoginWithUsernameNotAnEmail() {
|
||||||
|
testRealm().organizations().get(createOrganization().getId());
|
||||||
|
oauth.clientId("broker-app");
|
||||||
|
|
||||||
|
// login with email only
|
||||||
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
log.debug("Logging in");
|
||||||
|
Assert.assertFalse(loginPage.isPasswordInputPresent());
|
||||||
|
loginPage.loginUsername("user");
|
||||||
|
|
||||||
|
// check if the login page is shown
|
||||||
|
Assert.assertTrue(loginPage.isUsernameInputPresent());
|
||||||
|
Assert.assertTrue(loginPage.isPasswordInputPresent());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLinkExistingAccount() {
|
public void testLinkExistingAccount() {
|
||||||
// create a realm user in the consumer realm
|
// create a realm user in the consumer realm
|
||||||
|
@ -154,7 +195,6 @@ public class OrganizationBrokerSelfRegistrationTest extends AbstractOrganization
|
||||||
waitForPage(driver, "sign in to", true);
|
waitForPage(driver, "sign in to", true);
|
||||||
Assert.assertTrue("Driver should be on the provider realm page right now",
|
Assert.assertTrue("Driver should be on the provider realm page right now",
|
||||||
driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/"));
|
driver.getCurrentUrl().contains("/auth/realms/" + bc.providerRealmName() + "/"));
|
||||||
|
|
||||||
// login to the organization identity provider and run the configured first broker login flow
|
// login to the organization identity provider and run the configured first broker login flow
|
||||||
loginPage.login(bc.getUserEmail(), bc.getUserPassword());
|
loginPage.login(bc.getUserEmail(), bc.getUserPassword());
|
||||||
waitForPage(driver, "update account information", false);
|
waitForPage(driver, "update account information", false);
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
||||||
import jakarta.ws.rs.core.Response;
|
import jakarta.ws.rs.core.Response;
|
||||||
import jakarta.ws.rs.core.Response.Status;
|
import jakarta.ws.rs.core.Response.Status;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.OrganizationIdentityProviderResource;
|
import org.keycloak.admin.client.resource.OrganizationIdentityProviderResource;
|
||||||
import org.keycloak.admin.client.resource.OrganizationResource;
|
import org.keycloak.admin.client.resource.OrganizationResource;
|
||||||
|
@ -38,16 +39,19 @@ public class OrganizationIdentityProviderTest extends AbstractOrganizationTest {
|
||||||
public void testUpdate() {
|
public void testUpdate() {
|
||||||
OrganizationRepresentation organization = createOrganization();
|
OrganizationRepresentation organization = createOrganization();
|
||||||
OrganizationIdentityProviderResource orgIdPResource = testRealm().organizations().get(organization.getId()).identityProvider();
|
OrganizationIdentityProviderResource orgIdPResource = testRealm().organizations().get(organization.getId()).identityProvider();
|
||||||
IdentityProviderRepresentation idpRepresentation = orgIdPResource.toRepresentation();
|
IdentityProviderRepresentation actual = orgIdPResource.toRepresentation();
|
||||||
assertThat(idpRepresentation.getAlias(), equalTo(bc.getIDPAlias()));
|
IdentityProviderRepresentation expected = actual;
|
||||||
|
assertThat(expected.getAlias(), equalTo(bc.getIDPAlias()));
|
||||||
|
|
||||||
String displayName = "My Org Broker";
|
|
||||||
//update
|
//update
|
||||||
idpRepresentation.setDisplayName(displayName);
|
expected.setDisplayName("My Org Broker");
|
||||||
try (Response response = orgIdPResource.update(idpRepresentation)) {
|
expected.getConfig().put("test", "value");
|
||||||
|
try (Response response = orgIdPResource.update(expected)) {
|
||||||
assertThat(response.getStatus(), equalTo(Response.Status.NO_CONTENT.getStatusCode()));
|
assertThat(response.getStatus(), equalTo(Response.Status.NO_CONTENT.getStatusCode()));
|
||||||
}
|
}
|
||||||
assertThat(orgIdPResource.toRepresentation().getDisplayName(), equalTo(displayName));
|
actual = orgIdPResource.toRepresentation();
|
||||||
|
assertThat(expected.getDisplayName(), equalTo(actual.getDisplayName()));
|
||||||
|
Assert.assertEquals(expected.getConfig().get("test"), actual.getConfig().get("test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in a new issue