trigger IDENTITY_PROVIDER_FIRST_LOGIN (and UPDATE_PROFILE ) event when identity provider flow succeeds (#15100)
closes #15098
This commit is contained in:
parent
6d2e57f93a
commit
fb5a7f654b
4 changed files with 53 additions and 5 deletions
|
@ -107,7 +107,6 @@ public class IdpReviewProfileAuthenticator extends AbstractIdpAuthenticator {
|
||||||
@Override
|
@Override
|
||||||
protected void actionImpl(AuthenticationFlowContext context, SerializedBrokeredIdentityContext userCtx, BrokeredIdentityContext brokerContext) {
|
protected void actionImpl(AuthenticationFlowContext context, SerializedBrokeredIdentityContext userCtx, BrokeredIdentityContext brokerContext) {
|
||||||
EventBuilder event = context.getEvent();
|
EventBuilder event = context.getEvent();
|
||||||
//velias: looks like UPDATE_PROFILE event is not fired. IMHO it should not be fired here as user record in keycloak is not changed, user doesn't exist yet
|
|
||||||
event.event(EventType.UPDATE_PROFILE).detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name());
|
event.event(EventType.UPDATE_PROFILE).detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name());
|
||||||
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
|
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
|
||||||
UserModelDelegate updatedProfile = new UserModelDelegate(null) {
|
UserModelDelegate updatedProfile = new UserModelDelegate(null) {
|
||||||
|
|
|
@ -773,6 +773,7 @@ public class LoginActionsService {
|
||||||
|
|
||||||
SessionCodeChecks checks = checksForCode(authSessionId, code, execution, clientId, tabId, flowPath);
|
SessionCodeChecks checks = checksForCode(authSessionId, code, execution, clientId, tabId, flowPath);
|
||||||
if (!checks.verifyActiveAndValidAction(AuthenticationSessionModel.Action.AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
|
if (!checks.verifyActiveAndValidAction(AuthenticationSessionModel.Action.AUTHENTICATE.name(), ClientSessionCode.ActionType.LOGIN)) {
|
||||||
|
event.error("Failed to verify login action");
|
||||||
return checks.getResponse();
|
return checks.getResponse();
|
||||||
}
|
}
|
||||||
event.detail(Details.CODE_ID, code);
|
event.detail(Details.CODE_ID, code);
|
||||||
|
@ -784,7 +785,9 @@ public class LoginActionsService {
|
||||||
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authSession, noteKey);
|
SerializedBrokeredIdentityContext serializedCtx = SerializedBrokeredIdentityContext.readFromAuthenticationSession(authSession, noteKey);
|
||||||
if (serializedCtx == null) {
|
if (serializedCtx == null) {
|
||||||
ServicesLogger.LOGGER.notFoundSerializedCtxInClientSession(noteKey);
|
ServicesLogger.LOGGER.notFoundSerializedCtxInClientSession(noteKey);
|
||||||
throw new WebApplicationException(ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, "Not found serialized context in authenticationSession."));
|
String message = "Not found serialized context in authenticationSession.";
|
||||||
|
event.error(message);
|
||||||
|
throw new WebApplicationException(ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, message));
|
||||||
}
|
}
|
||||||
BrokeredIdentityContext brokerContext = serializedCtx.deserialize(session, authSession);
|
BrokeredIdentityContext brokerContext = serializedCtx.deserialize(session, authSession);
|
||||||
final String identityProviderAlias = brokerContext.getIdpConfig().getAlias();
|
final String identityProviderAlias = brokerContext.getIdpConfig().getAlias();
|
||||||
|
@ -792,17 +795,23 @@ public class LoginActionsService {
|
||||||
String flowId = firstBrokerLogin ? brokerContext.getIdpConfig().getFirstBrokerLoginFlowId() : brokerContext.getIdpConfig().getPostBrokerLoginFlowId();
|
String flowId = firstBrokerLogin ? brokerContext.getIdpConfig().getFirstBrokerLoginFlowId() : brokerContext.getIdpConfig().getPostBrokerLoginFlowId();
|
||||||
if (flowId == null) {
|
if (flowId == null) {
|
||||||
ServicesLogger.LOGGER.flowNotConfigForIDP(identityProviderAlias);
|
ServicesLogger.LOGGER.flowNotConfigForIDP(identityProviderAlias);
|
||||||
throw new WebApplicationException(ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, "Flow not configured for identity provider"));
|
String message = "Flow not configured for identity provider";
|
||||||
|
event.error(message);
|
||||||
|
throw new WebApplicationException(ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, message));
|
||||||
}
|
}
|
||||||
AuthenticationFlowModel brokerLoginFlow = realm.getAuthenticationFlowById(flowId);
|
AuthenticationFlowModel brokerLoginFlow = realm.getAuthenticationFlowById(flowId);
|
||||||
if (brokerLoginFlow == null) {
|
if (brokerLoginFlow == null) {
|
||||||
ServicesLogger.LOGGER.flowNotFoundForIDP(flowId, identityProviderAlias);
|
ServicesLogger.LOGGER.flowNotFoundForIDP(flowId, identityProviderAlias);
|
||||||
throw new WebApplicationException(ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, "Flow not found for identity provider"));
|
String message = "Flow not found for identity provider";
|
||||||
|
event.error(message);
|
||||||
|
throw new WebApplicationException(ErrorPage.error(session, authSession, Response.Status.BAD_REQUEST, message));
|
||||||
}
|
}
|
||||||
|
|
||||||
event.detail(Details.IDENTITY_PROVIDER, identityProviderAlias)
|
event.detail(Details.IDENTITY_PROVIDER, identityProviderAlias)
|
||||||
.detail(Details.IDENTITY_PROVIDER_USERNAME, brokerContext.getUsername());
|
.detail(Details.IDENTITY_PROVIDER_USERNAME, brokerContext.getUsername());
|
||||||
|
|
||||||
|
event.success();
|
||||||
|
|
||||||
AuthenticationProcessor processor = new AuthenticationProcessor() {
|
AuthenticationProcessor processor = new AuthenticationProcessor() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -45,6 +45,7 @@ import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.assertHardCodedSessionNote;
|
import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.assertHardCodedSessionNote;
|
||||||
import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.configureAutoLinkFlow;
|
import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.configureAutoLinkFlow;
|
||||||
|
import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_ALIAS;
|
||||||
import static org.keycloak.testsuite.broker.BrokerTestConstants.USER_EMAIL;
|
import static org.keycloak.testsuite.broker.BrokerTestConstants.USER_EMAIL;
|
||||||
import static org.keycloak.testsuite.broker.BrokerTestTools.getConsumerRoot;
|
import static org.keycloak.testsuite.broker.BrokerTestTools.getConsumerRoot;
|
||||||
import static org.keycloak.testsuite.broker.BrokerTestTools.getProviderRoot;
|
import static org.keycloak.testsuite.broker.BrokerTestTools.getProviderRoot;
|
||||||
|
@ -1007,6 +1008,16 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
||||||
Assert.assertEquals("no-first-name", accountUpdateProfilePage.getUsername());
|
Assert.assertEquals("no-first-name", accountUpdateProfilePage.getUsername());
|
||||||
|
|
||||||
RealmRepresentation consumerRealmRep = adminClient.realm(bc.consumerRealmName()).toRepresentation();
|
RealmRepresentation consumerRealmRep = adminClient.realm(bc.consumerRealmName()).toRepresentation();
|
||||||
|
|
||||||
|
events.expectAccount(EventType.IDENTITY_PROVIDER_FIRST_LOGIN).realm(consumerRealmRep).user((String)null)
|
||||||
|
.detail(Details.IDENTITY_PROVIDER, bc.getIDPAlias())
|
||||||
|
.detail(Details.IDENTITY_PROVIDER_USERNAME, "no-first-name")
|
||||||
|
.assertEvent(getFirstConsumerEvent());
|
||||||
|
|
||||||
|
events.expectAccount(EventType.UPDATE_PROFILE).realm(consumerRealmRep).user((String)null)
|
||||||
|
.detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name())
|
||||||
|
.assertEvent(getFirstConsumerEvent());
|
||||||
|
|
||||||
events.expectAccount(EventType.REGISTER).realm(consumerRealmRep).user(Matchers.any(String.class)).session((String) null)
|
events.expectAccount(EventType.REGISTER).realm(consumerRealmRep).user(Matchers.any(String.class)).session((String) null)
|
||||||
.detail(Details.IDENTITY_PROVIDER_USERNAME, "no-first-name")
|
.detail(Details.IDENTITY_PROVIDER_USERNAME, "no-first-name")
|
||||||
.detail(Details.REGISTER_METHOD, "broker")
|
.detail(Details.REGISTER_METHOD, "broker")
|
||||||
|
@ -1044,6 +1055,16 @@ public abstract class AbstractFirstBrokerLoginTest extends AbstractInitializedBa
|
||||||
Assert.assertEquals("no-first-name", accountUpdateProfilePage.getUsername());
|
Assert.assertEquals("no-first-name", accountUpdateProfilePage.getUsername());
|
||||||
|
|
||||||
RealmRepresentation consumerRealmRep = adminClient.realm(bc.consumerRealmName()).toRepresentation();
|
RealmRepresentation consumerRealmRep = adminClient.realm(bc.consumerRealmName()).toRepresentation();
|
||||||
|
|
||||||
|
events.expectAccount(EventType.IDENTITY_PROVIDER_FIRST_LOGIN).realm(consumerRealmRep).user((String)null)
|
||||||
|
.detail(Details.IDENTITY_PROVIDER, bc.getIDPAlias())
|
||||||
|
.detail(Details.IDENTITY_PROVIDER_USERNAME, "no-first-name")
|
||||||
|
.assertEvent(getFirstConsumerEvent());
|
||||||
|
|
||||||
|
events.expectAccount(EventType.UPDATE_PROFILE).realm(consumerRealmRep).user((String)null)
|
||||||
|
.detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name())
|
||||||
|
.assertEvent(getFirstConsumerEvent());
|
||||||
|
|
||||||
events.expectAccount(EventType.UPDATE_EMAIL).realm(consumerRealmRep).user((String)null).session((String) null)
|
events.expectAccount(EventType.UPDATE_EMAIL).realm(consumerRealmRep).user((String)null).session((String) null)
|
||||||
.detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name())
|
.detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name())
|
||||||
.detail(Details.IDENTITY_PROVIDER_USERNAME, "no-first-name")
|
.detail(Details.IDENTITY_PROVIDER_USERNAME, "no-first-name")
|
||||||
|
|
|
@ -27,6 +27,10 @@ import org.keycloak.events.Details;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
import org.keycloak.testsuite.AssertEvents;
|
||||||
|
import org.keycloak.userprofile.UserProfileContext;
|
||||||
|
|
||||||
|
import static org.keycloak.testsuite.AssertEvents.DEFAULT_USERNAME;
|
||||||
|
import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_ALIAS;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple test to check the events after a broker login using OIDC. It also
|
* Simple test to check the events after a broker login using OIDC. It also
|
||||||
|
@ -68,6 +72,21 @@ public final class KcOidcBrokerEventTest extends AbstractBrokerTest {
|
||||||
.client(bc.getIDPClientIdInProviderRealm())
|
.client(bc.getIDPClientIdInProviderRealm())
|
||||||
.assertEvent();
|
.assertEvent();
|
||||||
|
|
||||||
|
events.expect(EventType.IDENTITY_PROVIDER_FIRST_LOGIN)
|
||||||
|
.realm(consumerRealm.toRepresentation().getId())
|
||||||
|
.client("account")
|
||||||
|
.user((String)null)
|
||||||
|
.detail(Details.IDENTITY_PROVIDER, IDP_OIDC_ALIAS)
|
||||||
|
.detail(Details.IDENTITY_PROVIDER_USERNAME, bc.getUserLogin())
|
||||||
|
.assertEvent();
|
||||||
|
|
||||||
|
events.expect(EventType.UPDATE_PROFILE)
|
||||||
|
.realm(consumerRealm.toRepresentation().getId())
|
||||||
|
.client("account")
|
||||||
|
.user((String)null)
|
||||||
|
.detail(Details.CONTEXT, UserProfileContext.IDP_REVIEW.name())
|
||||||
|
.assertEvent();
|
||||||
|
|
||||||
events.expect(EventType.REGISTER)
|
events.expect(EventType.REGISTER)
|
||||||
.realm(consumerRealm.toRepresentation().getId())
|
.realm(consumerRealm.toRepresentation().getId())
|
||||||
.client("account")
|
.client("account")
|
||||||
|
@ -87,7 +106,7 @@ public final class KcOidcBrokerEventTest extends AbstractBrokerTest {
|
||||||
.detail(Details.IDENTITY_PROVIDER_USERNAME, bc.getUserLogin())
|
.detail(Details.IDENTITY_PROVIDER_USERNAME, bc.getUserLogin())
|
||||||
.detail(Details.IDENTITY_PROVIDER, bc.getIDPAlias())
|
.detail(Details.IDENTITY_PROVIDER, bc.getIDPAlias())
|
||||||
.assertEvent();
|
.assertEvent();
|
||||||
|
|
||||||
events.clear();
|
events.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue