-
Notifications
You must be signed in to change notification settings - Fork 325
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
Support for flows, subflows and executions #215
Merged
mrparkers
merged 3 commits into
keycloak:master
from
tomrutsaert:auth_flows_and_exec_on_latest_master
Feb 20, 2020
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package keycloak | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
// this is only used when creating an execution on a flow. | ||
// other fields can be provided to the API but they are ignored | ||
// POST /realms/${realmId}/authentication/flows/${flowAlias}/executions/execution | ||
type authenticationExecutionCreate struct { | ||
Provider string `json:"provider"` //authenticator of the execution | ||
} | ||
|
||
type authenticationExecutionRequirementUpdate struct { | ||
RealmId string `json:"-"` | ||
ParentFlowAlias string `json:"-"` | ||
Id string `json:"id"` | ||
Requirement string `json:"requirement"` | ||
} | ||
|
||
// this type is returned by GET /realms/${realmId}/authentication/flows/${flowAlias}/executions | ||
type AuthenticationExecution struct { | ||
Id string `json:"id"` | ||
RealmId string `json:"-"` | ||
ParentFlowAlias string `json:"-"` | ||
Authenticator string `json:"authenticator"` //can be any authenticator from GET realms/{realm}/authentication/authenticator-providers OR GET realms/{realm}/authentication/client-authenticator-providers OR GET realms/{realm}/authentication/form-action-providers | ||
AuthenticationConfig string `json:"authenticationConfig"` | ||
AuthenticationFlow bool `json:"authenticationFlow"` | ||
FlowId string `json:"flowId"` | ||
ParentFlowId string `json:"parentFlow"` | ||
Priority int `json:"priority"` | ||
Requirement string `json:"requirement"` | ||
} | ||
|
||
// another model is used for GET /realms/${realmId}/authentication/executions/${executionId}, but I am going to try to avoid using this API | ||
type AuthenticationExecutionInfo struct { | ||
Id string `json:"id"` | ||
RealmId string `json:"-"` | ||
ParentFlowAlias string `json:"-"` | ||
Alias string `json:"alias"` | ||
AuthenticationConfig string `json:"authenticationConfig"` | ||
AuthenticationFlow bool `json:"authenticationFlow"` | ||
Configurable bool `json:"configurable"` | ||
FlowId string `json:"flowId"` | ||
Index int `json:"index"` | ||
Level int `json:"level"` | ||
ProviderId string `json:"providerId"` | ||
Requirement string `json:"requirement"` | ||
} | ||
|
||
type AuthenticationExecutionList []*AuthenticationExecutionInfo | ||
|
||
func (list AuthenticationExecutionList) Len() int { | ||
return len(list) | ||
} | ||
|
||
func (list AuthenticationExecutionList) Less(i, j int) bool { | ||
return list[i].Index < list[j].Index | ||
} | ||
|
||
func (list AuthenticationExecutionList) Swap(i, j int) { | ||
list[i], list[j] = list[j], list[i] | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) ListAuthenticationExecutions(realmId, parentFlowAlias string) (AuthenticationExecutionList, error) { | ||
var authenticationExecutions []*AuthenticationExecutionInfo | ||
|
||
err := keycloakClient.get(fmt.Sprintf("/realms/%s/authentication/flows/%s/executions", realmId, parentFlowAlias), &authenticationExecutions, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return authenticationExecutions, err | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) NewAuthenticationExecution(execution *AuthenticationExecution) error { | ||
_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/authentication/flows/%s/executions/execution", execution.RealmId, execution.ParentFlowAlias), &authenticationExecutionCreate{Provider: execution.Authenticator}) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
execution.Id = getIdFromLocationHeader(location) | ||
|
||
err = keycloakClient.UpdateAuthenticationExecution(execution) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) GetAuthenticationExecution(realmId, parentFlowAlias, id string) (*AuthenticationExecution, error) { | ||
var authenticationExecution AuthenticationExecution | ||
|
||
err := keycloakClient.get(fmt.Sprintf("/realms/%s/authentication/executions/%s", realmId, id), &authenticationExecution, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
authenticationExecution.RealmId = realmId | ||
authenticationExecution.ParentFlowAlias = parentFlowAlias | ||
|
||
return &authenticationExecution, nil | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) UpdateAuthenticationExecution(execution *AuthenticationExecution) error { | ||
authenticationExecutionUpdateRequirement := &authenticationExecutionRequirementUpdate{ | ||
RealmId: execution.RealmId, | ||
ParentFlowAlias: execution.ParentFlowAlias, | ||
Id: execution.Id, | ||
Requirement: execution.Requirement, | ||
} | ||
return keycloakClient.UpdateAuthenticationExecutionRequirement(authenticationExecutionUpdateRequirement) | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) UpdateAuthenticationExecutionRequirement(executionRequirementUpdate *authenticationExecutionRequirementUpdate) error { | ||
return keycloakClient.put(fmt.Sprintf("/realms/%s/authentication/flows/%s/executions", executionRequirementUpdate.RealmId, executionRequirementUpdate.ParentFlowAlias), executionRequirementUpdate) | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) DeleteAuthenticationExecution(realmId, id string) error { | ||
err := keycloakClient.delete(fmt.Sprintf("/realms/%s/authentication/executions/%s", realmId, id), nil) | ||
if err != nil { | ||
// For whatever reason, this fails sometimes with a 500 during acceptance tests. try again | ||
return keycloakClient.delete(fmt.Sprintf("/realms/%s/authentication/executions/%s", realmId, id), nil) | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) RaiseAuthenticationExecutionPriority(realmId, id string) error { | ||
_, _, err := keycloakClient.post(fmt.Sprintf("/realms/%s/authentication/executions/%s/raise-priority", realmId, id), nil) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) LowerAuthenticationExecutionPriority(realmId, id string) error { | ||
_, _, err := keycloakClient.post(fmt.Sprintf("/realms/%s/authentication/executions/%s/lower-priority", realmId, id), nil) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package keycloak | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
type AuthenticationFlow struct { | ||
Id string `json:"id,omitempty"` | ||
RealmId string `json:"-"` | ||
Alias string `json:"alias"` | ||
Description string `json:"description"` | ||
ProviderId string `json:"providerId"` // "basic-flow" or "client-flow" | ||
TopLevel bool `json:"topLevel"` | ||
BuiltIn bool `json:"builtIn"` | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) NewAuthenticationFlow(authenticationFlow *AuthenticationFlow) error { | ||
authenticationFlow.TopLevel = true | ||
authenticationFlow.BuiltIn = false | ||
|
||
_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/authentication/flows", authenticationFlow.RealmId), authenticationFlow) | ||
if err != nil { | ||
return err | ||
} | ||
authenticationFlow.Id = getIdFromLocationHeader(location) | ||
|
||
return nil | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) GetAuthenticationFlow(realmId, id string) (*AuthenticationFlow, error) { | ||
var authenticationFlow AuthenticationFlow | ||
err := keycloakClient.get(fmt.Sprintf("/realms/%s/authentication/flows/%s", realmId, id), &authenticationFlow, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
authenticationFlow.RealmId = realmId | ||
return &authenticationFlow, nil | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) UpdateAuthenticationFlow(authenticationFlow *AuthenticationFlow) error { | ||
authenticationFlow.TopLevel = true | ||
authenticationFlow.BuiltIn = false | ||
|
||
return keycloakClient.put(fmt.Sprintf("/realms/%s/authentication/flows/%s", authenticationFlow.RealmId, authenticationFlow.Id), authenticationFlow) | ||
} | ||
|
||
func (keycloakClient *KeycloakClient) DeleteAuthenticationFlow(realmId, id string) error { | ||
err := keycloakClient.delete(fmt.Sprintf("/realms/%s/authentication/flows/%s", realmId, id), nil) | ||
if err != nil { | ||
// For whatever reason, this fails sometimes with a 500 during acceptance tests. try again | ||
return keycloakClient.delete(fmt.Sprintf("/realms/%s/authentication/flows/%s", realmId, id), nil) | ||
} | ||
return nil | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
are these two functions used? if not, how should users raise and lower the priority for executions?
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.
There are not used, but they do work.
I left in here in the case some one worked out a better solution, and could use these methods....
Should I remove them?
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.
No, I was just curious how the priority was determined, but then I realized in your example that you used
depends_on
in order to ensure subflows with higher priorities were created before subflows with lower priorities.This approach makes sense, although it would be impossible to update this aftwards. But if that's good enough for you then I'm okay with this. I'm hoping that this is good enough for most users until Keycloak X is released, in which case I'll probably have to rewrite a lot of this provider anyways.