Skip to content
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

Add priority field support in authentication flow executions #970

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion docs/resources/authentication_execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ Allows for creating and managing an authentication execution within Keycloak.
An authentication execution is an action that the user or service may or may not take when authenticating through an authentication
flow.

~> Due to limitations in the Keycloak API, the ordering of authentication executions within a flow must be specified using `depends_on`. Authentication executions that are created first will appear first within the flow.
~> Due to limitations in the Keycloak API, the ordering of authentication executions within a flow must be specified using `depends_on` in versions prior to Keycloak 25. Authentication executions that are created first will appear first within the flow.

## Example Usage

Expand All @@ -30,6 +30,7 @@ resource "keycloak_authentication_execution" "execution_one" {
parent_flow_alias = "${keycloak_authentication_flow.flow.alias}"
authenticator = "auth-cookie"
requirement = "ALTERNATIVE"
priority = 10 # Starting from Keycloak 25
}

# second execution
Expand All @@ -38,7 +39,9 @@ resource "keycloak_authentication_execution" "execution_two" {
parent_flow_alias = "${keycloak_authentication_flow.flow.alias}"
authenticator = "identity-provider-redirector"
requirement = "ALTERNATIVE"
priority = 20 # Starting from Keycloak 25

# Workaround for older Keycloak versions (Keycloak 24 and older)
depends_on = [
keycloak_authentication_execution.execution_one
]
Expand All @@ -51,6 +54,7 @@ resource "keycloak_authentication_execution" "execution_two" {
- `parent_flow_alias` - (Required) The alias of the flow this execution is attached to.
- `authenticator` - (Required) The name of the authenticator. This can be found by experimenting with the GUI and looking at HTTP requests within the network tab of your browser's development tools.
- `requirement`- (Optional) The requirement setting, which can be one of `REQUIRED`, `ALTERNATIVE`, `OPTIONAL`, `CONDITIONAL`, or `DISABLED`. Defaults to `DISABLED`.
- `priority`- (Optional) The authenticator priority, the lower the value the higher it will be placed in the parent flow. This option is supported only by Keycloak 25 and onwards.

## Import

Expand Down
2 changes: 2 additions & 0 deletions docs/resources/authentication_subflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ resource "keycloak_authentication_subflow" "subflow" {
parent_flow_alias = keycloak_authentication_flow.flow.alias
provider_id = "basic-flow"
requirement = "ALTERNATIVE"
priority = 10 # Starting from Keycloak 25
}
```

Expand All @@ -43,6 +44,7 @@ and `client-flow`. Defaults to `basic-flow`.
authenticators. In general this will remain empty.
- `requirement`- (Optional) The requirement setting, which can be one of `REQUIRED`, `ALTERNATIVE`, `OPTIONAL`, `CONDITIONAL`,
or `DISABLED`. Defaults to `DISABLED`.
- `priority`- (Optional) The subflow priority, the lower the value the higher it will be placed in the parent flow. This option is supported only by Keycloak 25 and onwards.

## Import

Expand Down
33 changes: 15 additions & 18 deletions keycloak/authentication_execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ import (
// POST /realms/${realmId}/authentication/flows/${flowAlias}/executions/execution
type authenticationExecutionCreate struct {
Provider string `json:"provider"` //authenticator of the execution
Priority int `json:"priority,omitempty"`
}

type authenticationExecutionRequirementUpdate struct {
RealmId string `json:"-"`
ParentFlowAlias string `json:"-"`
Id string `json:"id"`
Requirement string `json:"requirement"`
Priority int `json:"priority,omitempty"`
}

// this type is returned by GET /realms/${realmId}/authentication/flows/${flowAlias}/executions
Expand All @@ -30,7 +32,7 @@ type AuthenticationExecution struct {
AuthenticationFlow bool `json:"authenticationFlow"`
FlowId string `json:"flowId"`
ParentFlowId string `json:"parentFlow"`
Priority int `json:"priority"`
Priority int `json:"priority,omitempty"`
Requirement string `json:"requirement"`
}

Expand All @@ -47,6 +49,7 @@ type AuthenticationExecutionInfo struct {
Index int `json:"index"`
Level int `json:"level"`
ProviderId string `json:"providerId"`
Priority int `json:"priority,omitempty"`
Requirement string `json:"requirement"`
}

Expand Down Expand Up @@ -119,7 +122,14 @@ func (keycloakClient *KeycloakClient) GetAuthenticationExecutionInfoFromProvider
}

func (keycloakClient *KeycloakClient) NewAuthenticationExecution(ctx context.Context, execution *AuthenticationExecution) error {
_, location, err := keycloakClient.post(ctx, fmt.Sprintf("/realms/%s/authentication/flows/%s/executions/execution", execution.RealmId, execution.ParentFlowAlias), &authenticationExecutionCreate{Provider: execution.Authenticator})
executionCreate := &authenticationExecutionCreate{
Provider: execution.Authenticator,
}
if prioritySupported, _ := keycloakClient.VersionIsGreaterThanOrEqualTo(ctx, Version_25); prioritySupported {
executionCreate.Priority = execution.Priority
}
_, location, err := keycloakClient.post(ctx, fmt.Sprintf("/realms/%s/authentication/flows/%s/executions/execution", execution.RealmId, execution.ParentFlowAlias), executionCreate)

if err != nil {
return err
}
Expand Down Expand Up @@ -155,6 +165,9 @@ func (keycloakClient *KeycloakClient) UpdateAuthenticationExecution(ctx context.
Id: execution.Id,
Requirement: execution.Requirement,
}
if prioritySupported, _ := keycloakClient.VersionIsGreaterThanOrEqualTo(ctx, Version_25); prioritySupported {
authenticationExecutionUpdateRequirement.Priority = execution.Priority
}
return keycloakClient.UpdateAuthenticationExecutionRequirement(ctx, authenticationExecutionUpdateRequirement)
}

Expand All @@ -171,19 +184,3 @@ func (keycloakClient *KeycloakClient) DeleteAuthenticationExecution(ctx context.

return nil
}

func (keycloakClient *KeycloakClient) RaiseAuthenticationExecutionPriority(ctx context.Context, realmId, id string) error {
_, _, err := keycloakClient.post(ctx, fmt.Sprintf("/realms/%s/authentication/executions/%s/raise-priority", realmId, id), nil)
if err != nil {
return err
}
return nil
}

func (keycloakClient *KeycloakClient) LowerAuthenticationExecutionPriority(ctx context.Context, realmId, id string) error {
_, _, err := keycloakClient.post(ctx, fmt.Sprintf("/realms/%s/authentication/executions/%s/lower-priority", realmId, id), nil)
if err != nil {
return err
}
return nil
}
34 changes: 6 additions & 28 deletions keycloak/authentication_subflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ func (keycloakClient *KeycloakClient) GetAuthenticationSubFlow(ctx context.Conte
}
authenticationSubFlow.Authenticator = subFlowExecution.Authenticator
authenticationSubFlow.Requirement = subFlowExecution.Requirement
if prioritySupported, _ := keycloakClient.VersionIsGreaterThanOrEqualTo(ctx, Version_25); prioritySupported {
authenticationSubFlow.Priority = subFlowExecution.Priority
}

return &authenticationSubFlow, nil
}
Expand Down Expand Up @@ -111,6 +114,9 @@ func (keycloakClient *KeycloakClient) UpdateAuthenticationSubFlow(ctx context.Co
Id: executionId,
Requirement: authenticationSubFlow.Requirement,
}
if prioritySupported, _ := keycloakClient.VersionIsGreaterThanOrEqualTo(ctx, Version_25); prioritySupported {
authenticationExecutionUpdateRequirement.Priority = authenticationSubFlow.Priority
}
return keycloakClient.UpdateAuthenticationExecutionRequirement(ctx, authenticationExecutionUpdateRequirement)

}
Expand All @@ -128,31 +134,3 @@ func (keycloakClient *KeycloakClient) DeleteAuthenticationSubFlow(ctx context.Co

return keycloakClient.DeleteAuthenticationExecution(ctx, authenticationSubFlow.RealmId, executionId)
}

func (keycloakClient *KeycloakClient) RaiseAuthenticationSubFlowPriority(ctx context.Context, realmId, parentFlowAlias, id string) error {
authenticationSubFlow := AuthenticationSubFlow{
Id: id,
ParentFlowAlias: parentFlowAlias,
RealmId: realmId,
}
executionId, err := keycloakClient.getExecutionId(ctx, &authenticationSubFlow)
if err != nil {
return err
}

return keycloakClient.RaiseAuthenticationExecutionPriority(ctx, authenticationSubFlow.RealmId, executionId)
}

func (keycloakClient *KeycloakClient) LowerAuthenticationSubFlowPriority(ctx context.Context, realmId, parentFlowAlias, id string) error {
authenticationSubFlow := AuthenticationSubFlow{
Id: id,
ParentFlowAlias: parentFlowAlias,
RealmId: realmId,
}
executionId, err := keycloakClient.getExecutionId(ctx, &authenticationSubFlow)
if err != nil {
return err
}

return keycloakClient.LowerAuthenticationExecutionPriority(ctx, authenticationSubFlow.RealmId, executionId)
}
6 changes: 6 additions & 0 deletions keycloak/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ const (
Version_17 Version = "17.0.0"
Version_18 Version = "18.0.0"
Version_19 Version = "19.0.0"
Version_20 Version = "20.0.0"
Version_21 Version = "21.0.0"
Version_22 Version = "22.0.0"
Version_23 Version = "23.0.0"
Version_24 Version = "24.0.0"
Version_25 Version = "25.0.0"
)

func (keycloakClient *KeycloakClient) VersionIsGreaterThanOrEqualTo(ctx context.Context, versionString Version) (bool, error) {
Expand Down
2 changes: 1 addition & 1 deletion provider/data_source_keycloak_authentication_execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func dataSourceKeycloakAuthenticationExecutionRead(ctx context.Context, data *sc
return diag.FromErr(err)
}

mapFromAuthenticationExecutionInfoToData(data, authenticationExecutionInfo)
mapFromAuthenticationExecutionInfoToData(keycloakClient, ctx, data, authenticationExecutionInfo)

return nil
}
21 changes: 16 additions & 5 deletions provider/resource_keycloak_authentication_execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ func resourceKeycloakAuthenticationExecution() *schema.Resource {
ValidateFunc: validation.StringInSlice([]string{"REQUIRED", "ALTERNATIVE", "OPTIONAL", "CONDITIONAL", "DISABLED"}, false), //OPTIONAL is removed from 8.0.0 onwards
Default: "DISABLED",
},
"priority": {
Type: schema.TypeInt,
Optional: true,
},
},
}
}
Expand All @@ -54,25 +58,32 @@ func mapFromDataToAuthenticationExecution(data *schema.ResourceData) *keycloak.A
ParentFlowAlias: data.Get("parent_flow_alias").(string),
Authenticator: data.Get("authenticator").(string),
Requirement: data.Get("requirement").(string),
Priority: data.Get("priority").(int),
}

return authenticationExecution
}

func mapFromAuthenticationExecutionToData(data *schema.ResourceData, authenticationExecution *keycloak.AuthenticationExecution) {
func mapFromAuthenticationExecutionToData(keycloakClient *keycloak.KeycloakClient, ctx context.Context, data *schema.ResourceData, authenticationExecution *keycloak.AuthenticationExecution) {
data.SetId(authenticationExecution.Id)

data.Set("realm_id", authenticationExecution.RealmId)
data.Set("parent_flow_alias", authenticationExecution.ParentFlowAlias)
data.Set("authenticator", authenticationExecution.Authenticator)
data.Set("requirement", authenticationExecution.Requirement)
if prioritySupported, _ := keycloakClient.VersionIsGreaterThanOrEqualTo(ctx, keycloak.Version_25); prioritySupported {
data.Set("priority", authenticationExecution.Priority)
}
}

func mapFromAuthenticationExecutionInfoToData(data *schema.ResourceData, authenticationExecutionInfo *keycloak.AuthenticationExecutionInfo) {
func mapFromAuthenticationExecutionInfoToData(keycloakClient *keycloak.KeycloakClient, ctx context.Context, data *schema.ResourceData, authenticationExecutionInfo *keycloak.AuthenticationExecutionInfo) {
data.SetId(authenticationExecutionInfo.Id)

data.Set("realm_id", authenticationExecutionInfo.RealmId)
data.Set("parent_flow_alias", authenticationExecutionInfo.ParentFlowAlias)
if prioritySupported, _ := keycloakClient.VersionIsGreaterThanOrEqualTo(ctx, keycloak.Version_25); prioritySupported {
data.Set("priority", authenticationExecutionInfo.Priority)
}
}

func resourceKeycloakAuthenticationExecutionCreate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
Expand All @@ -85,7 +96,7 @@ func resourceKeycloakAuthenticationExecutionCreate(ctx context.Context, data *sc
return diag.FromErr(err)
}

mapFromAuthenticationExecutionToData(data, authenticationExecution)
mapFromAuthenticationExecutionToData(keycloakClient, ctx, data, authenticationExecution)

return resourceKeycloakAuthenticationExecutionRead(ctx, data, meta)
}
Expand All @@ -102,7 +113,7 @@ func resourceKeycloakAuthenticationExecutionRead(ctx context.Context, data *sche
return handleNotFoundError(ctx, err, data)
}

mapFromAuthenticationExecutionToData(data, authenticationExecution)
mapFromAuthenticationExecutionToData(keycloakClient, ctx, data, authenticationExecution)

return nil
}
Expand All @@ -117,7 +128,7 @@ func resourceKeycloakAuthenticationExecutionUpdate(ctx context.Context, data *sc
return diag.FromErr(err)
}

mapFromAuthenticationExecutionToData(data, authenticationExecution)
mapFromAuthenticationExecutionToData(keycloakClient, ctx, data, authenticationExecution)

return nil
}
Expand Down
16 changes: 12 additions & 4 deletions provider/resource_keycloak_authentication_subflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ func resourceKeycloakAuthenticationSubFlow() *schema.Resource {
ValidateFunc: validation.StringInSlice([]string{"REQUIRED", "ALTERNATIVE", "OPTIONAL", "CONDITIONAL", "DISABLED"}, false), //OPTIONAL is removed from 8.0.0 onwards
Default: "DISABLED",
},
"priority": {
Type: schema.TypeInt,
Optional: true,
},
},
}
}
Expand All @@ -73,12 +77,13 @@ func mapFromDataToAuthenticationSubFlow(data *schema.ResourceData) *keycloak.Aut
Description: data.Get("description").(string),
Authenticator: data.Get("authenticator").(string),
Requirement: data.Get("requirement").(string),
Priority: data.Get("priority").(int),
}

return authenticationSubFlow
}

func mapFromAuthenticationSubFlowToData(data *schema.ResourceData, authenticationSubFlow *keycloak.AuthenticationSubFlow) {
func mapFromAuthenticationSubFlowToData(keycloakClient *keycloak.KeycloakClient, ctx context.Context, data *schema.ResourceData, authenticationSubFlow *keycloak.AuthenticationSubFlow) {
data.SetId(authenticationSubFlow.Id)
data.Set("realm_id", authenticationSubFlow.RealmId)
data.Set("parent_flow_alias", authenticationSubFlow.ParentFlowAlias)
Expand All @@ -87,6 +92,9 @@ func mapFromAuthenticationSubFlowToData(data *schema.ResourceData, authenticatio
data.Set("description", authenticationSubFlow.Description)
data.Set("authenticator", authenticationSubFlow.Authenticator)
data.Set("requirement", authenticationSubFlow.Requirement)
if prioritySupported, _ := keycloakClient.VersionIsGreaterThanOrEqualTo(ctx, keycloak.Version_25); prioritySupported {
data.Set("priority", authenticationSubFlow.Priority)
}
}

func resourceKeycloakAuthenticationSubFlowCreate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
Expand All @@ -98,7 +106,7 @@ func resourceKeycloakAuthenticationSubFlowCreate(ctx context.Context, data *sche
if err != nil {
return diag.FromErr(err)
}
mapFromAuthenticationSubFlowToData(data, authenticationFlow)
mapFromAuthenticationSubFlowToData(keycloakClient, ctx, data, authenticationFlow)
return resourceKeycloakAuthenticationSubFlowRead(ctx, data, meta)
}

Expand All @@ -113,7 +121,7 @@ func resourceKeycloakAuthenticationSubFlowRead(ctx context.Context, data *schema
if err != nil {
return handleNotFoundError(ctx, err, data)
}
mapFromAuthenticationSubFlowToData(data, authenticationFlow)
mapFromAuthenticationSubFlowToData(keycloakClient, ctx, data, authenticationFlow)
return nil
}

Expand All @@ -126,7 +134,7 @@ func resourceKeycloakAuthenticationSubFlowUpdate(ctx context.Context, data *sche
if err != nil {
return diag.FromErr(err)
}
mapFromAuthenticationSubFlowToData(data, authenticationFlow)
mapFromAuthenticationSubFlowToData(keycloakClient, ctx, data, authenticationFlow)
return nil
}

Expand Down
Loading