-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Add client support to workflows #44209
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| List<WorkflowStepRepresentation> steps = ofNullable(rep.getSteps()).orElse(List.of()); | ||
|
|
||
| if (steps.isEmpty()) { | ||
| // Do we really want to allow workflows with no steps? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it make sense to support workflows with no steps? Why not throw a validation error?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably reject this, doesn't make any sense IMO.
| // - Should we allow workflows to have more than one supported type ? | ||
| // - allowedTypes should probably be saved in config, since we do not allow changing steps, | ||
| // so that we don't recompute it. | ||
| if (allowedTypes.isEmpty()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we discuss the comments above? What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to persist the resource type of the workflow, and enforce that all conditions and steps operate on the same type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So if we persist this as part of the workflow, every step needs to support the same type (including the restart step that supports all types and can be used in any workflow).
4ca9edc to
9647ee2
Compare
9647ee2 to
5fc0824
Compare
|
Hey @sguilhen , I've rebased the branch on main. Would you please have a look at the comments I've made above? |
|
Hey @Hathoute, Pedro and I will try to take a look this week - we're wrapping up a sprint, but we plan on checking this right after that. Thanks a lot for the work you've put into it, will get back to you asap. |
Signed-off-by: Hathoute <[email protected]>
| ClientModel client = session.clients().getClientById(realm, context.getResourceId()); | ||
|
|
||
| if (client != null && client.isEnabled()) { | ||
| log.debugv("Disabling user {0} ({1})", client.getName(), client.getId()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be "Disabling client" instead of "Disabling user".
| } else { | ||
| entity.setScheduledStepId(step.getId()); | ||
| entity.setScheduledStepTimestamp(Instant.now().plus(duration).toEpochMilli()); | ||
| entity.setScheduledStepTimestamp(Time.currentTimeMillis() + duration.toMillis()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious - any particular reason for this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've seen that Workflows use the Time utils, so I just replaced it here.
| if (debug) { | ||
| if (true) { | ||
| builder.environment().put("DEBUG_SUSPEND", "y"); | ||
| builder.environment().put("DEBUG_PORT", "5005"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes here need probably to be reverted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct, I forgot to exclude this change
| org.keycloak.events.admin.ResourceType.CLIENT, | ||
| List.of(OperationType.CREATE), | ||
| List.of(EventType.CLIENT_LOGIN, EventType.CLIENT_REGISTER), | ||
| (session, id) -> session.users().getUserById(session.getContext().getRealm(), id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function is used in the ResourceTypeSelector.resolveResource impl that you moved to the AbstractResourceTypeWorkflowProvider, and it needs to resolve to the actual resource - in this case it should be client, not user.
| USER_ROLE_REMOVED(ResourceType.USERS, List.of(RoleModel.RoleRevokedEvent.class), roleMembershipPredicate()), | ||
|
|
||
| CLIENT_ADDED(ResourceType.CLIENTS, List.of(OperationType.CREATE, ClientCreationEvent.class)), | ||
| CLIENT_LOGGED_IN(ResourceType.CLIENTS, List.of(EventType.CLIENT_LOGIN)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder about this - the CLIENT_LOGIN event is, if I recall correctly, only issued in the Client Credentials Grant scenario. However, when trying to identify whether a client is not being used, we should probably also check the user LOGIN event and get the client from the that event as well. In other words, do we want to track only explicit client logins, or do we want to track if the client is being used as part of a user login?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pedroigor What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, it would be bad to disable a client used for authentication flow. Maybe have a dedicated ResourceOperationType ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tbh I haven't reached a good conclusion yet on how to best handle this ;-)
We could perhaps make CLIENT_LOGGED_IN also accept the regular LOGIN event type and get the resourceId using that event's clientId. In this case, a single LOGIN event would result in two distinct workflow events - USER_LOGGED_IN and CLIENT_LOGGED_IN. But it mixes CLIENT_LOGIN with LOGIN and I'm not sure this is wanted all the time. Perhaps it is if the intention is to disable clients not used for any authentication in a period of time.
If we mix the two events, then we should perhaps have some conditions in place to allow admins to differentiate the clients that should be affected by the workflow. For example, you might want a particular policy for service accounts (AFAIK they only trigger CLIENT_LOGIN events, not regular LOGIN events), and a different one for the other clients involved in user authentication flows (would trigger only regular LOGIN events), but have them both activated on CLIENT_LOGGED_IN. What do you think?
@vramik @pedroigor Any opinions on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it help to introduce a separate event USER_CLIENT_LOGGED_IN? Reading it as the client involved during a user logged in event.
|
@sguilhen I actually have another WIP branch in fork where I have implemented what we discussed previously. I'll push everything here (with your latest comments). Do you prefer it being in a new commit or squashed into one? |
I think having separate commits is better to review. We can always squash when merging. |
Signed-off-by: Hathoute <[email protected]>
5fc0824 to
3ed45c9
Compare
Signed-off-by: Hathoute <[email protected]> Signed-off-by: Hamza HATHOUTE <[email protected]>
3ed45c9 to
5b14728
Compare
| throw new ModelValidationException("Steps provided should support a single type, actual: " + formattedTypes); | ||
| } | ||
|
|
||
| ResourceType supported = allowedTypes.stream().findFirst().orElseThrow(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TBH I am not a fan of detecting the resource type of the workflow this way. I'd rather let the user choose it in a dropdown and then visually display the conditions/steps that are compatible (thinking about a create workflow UI)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@sguilhen what do you think?
Closes #43870