diff --git a/client.go b/client.go index 918ed95f..231acaa0 100644 --- a/client.go +++ b/client.go @@ -2204,6 +2204,15 @@ func (client *gocloak) DeleteAuthenticationExecution(ctx context.Context, token, return checkForError(resp, err, errMessage) } +//CreateAuthenticationExecutionFlow creates a new execution for the given flow name in the given realm +func (client *gocloak) CreateAuthenticationExecutionFlow(ctx context.Context, token, realm, flow string, executionFlow CreateAuthenticationExecutionFlowRepresentation) error { + const errMessage = "could not create authentication execution flow" + resp, err := client.getRequestWithBearerAuth(ctx, token).SetBody(executionFlow). + Post(client.getAdminRealmURL(realm, "authentication", "flows", flow, "executions", "flow")) + + return checkForError(resp, err, errMessage) +} + // ----- // Users // ----- diff --git a/client_test.go b/client_test.go index a3d36b7a..7f694e76 100644 --- a/client_test.go +++ b/client_test.go @@ -6149,7 +6149,7 @@ func TestGocloak_GetAuthenticationFlows(t *testing.T) { require.Error(t, err) } -func TestGocloak_CreateAuthenticationFlowsAndCreateAuthenticationExecution(t *testing.T) { +func TestGocloak_CreateAuthenticationFlowsAndCreateAuthenticationExecutionAndFlow(t *testing.T) { t.Parallel() cfg := GetConfig(t) client := NewClientWithDebug(t) @@ -6166,6 +6166,13 @@ func TestGocloak_CreateAuthenticationFlowsAndCreateAuthenticationExecution(t *te ProviderID: gocloak.StringP("basic-flow"), } + authExecFlow := gocloak.CreateAuthenticationExecutionFlowRepresentation{ + Alias: gocloak.StringP("testauthexecflow"), + Description: gocloak.StringP("test"), + Provider: gocloak.StringP("basic-flow"), + Type: gocloak.StringP("basic-flow"), + } + err := client.CreateAuthenticationFlow( context.Background(), token.AccessToken, @@ -6184,25 +6191,40 @@ func TestGocloak_CreateAuthenticationFlowsAndCreateAuthenticationExecution(t *te ) require.NoError(t, err, "Failed to create authentication execution") - authExecs, err := client.GetAuthenticationExecutions( + err = client.CreateAuthenticationExecutionFlow( context.Background(), token.AccessToken, cfg.GoCloak.Realm, *authFlow.Alias, + authExecFlow, ) + require.NoError(t, err, "Failed to create authentication execution flow") - t.Logf("authentication executions: %+v", authExecs) - require.NoError(t, err, "Failed to get authentication executions") - - authExecs[0].Requirement = gocloak.StringP("ALTERNATIVE") - err = client.UpdateAuthenticationExecution( + authExecs, err := client.GetAuthenticationExecutions( context.Background(), token.AccessToken, cfg.GoCloak.Realm, *authFlow.Alias, - *authExecs[0], ) - require.NoError(t, err, "Failed to update authentication executions") + + t.Logf("authentication executions: %+v", authExecs) + require.NoError(t, err, "Failed to get authentication executions") + + // UpdateAuthenticationExecution + for _, execution := range authExecs { + if execution.ProviderID != nil && *execution.ProviderID == *authExec.Provider { + execution.Requirement = gocloak.StringP("ALTERNATIVE") + err = client.UpdateAuthenticationExecution( + context.Background(), + token.AccessToken, + cfg.GoCloak.Realm, + *authFlow.Alias, + *execution, + ) + require.NoError(t, err, fmt.Sprintf("Failed to update authentication executions, realm: %+v, flow: %+v, execution: %+v", cfg.GoCloak.Realm, *authFlow.Alias, *execution.ProviderID)) + break + } + } authExecs, err = client.GetAuthenticationExecutions( context.Background(), token.AccessToken, @@ -6212,6 +6234,34 @@ func TestGocloak_CreateAuthenticationFlowsAndCreateAuthenticationExecution(t *te require.NoError(t, err, "Failed to get authentication executions second time") t.Logf("authentication executions after update: %+v", authExecs) + var ( + execDeleted bool + execFlowFound bool + ) + for _, execution := range authExecs { + if execution.DisplayName != nil && *execution.DisplayName == *authExecFlow.Alias { + execFlowFound = true + continue + } + if execution.ProviderID != nil && *execution.ProviderID == *authExec.Provider { + require.NotNil(t, execution.Requirement) + require.Equal(t, *execution.Requirement, "ALTERNATIVE") + err = client.DeleteAuthenticationExecution( + context.Background(), + token.AccessToken, + cfg.GoCloak.Realm, + *execution.ID, + ) + require.NoError(t, err, "Failed to delete authentication execution") + execDeleted = true + } + if execDeleted && execFlowFound { + break + } + } + require.True(t, execDeleted, "Failed to delete authentication execution, no execution was deleted") + require.True(t, execFlowFound, "Failed to find authentication execution flow") + flows, err := client.GetAuthenticationFlows(context.Background(), token.AccessToken, cfg.GoCloak.Realm) require.NoError(t, err, "Failed to get authentication flows") deleted := false diff --git a/gocloak.go b/gocloak.go index f8401806..8afb1309 100644 --- a/gocloak.go +++ b/gocloak.go @@ -316,6 +316,9 @@ type GoCloak interface { // DeleteAuthenticationExecution delete a single execution with the given ID DeleteAuthenticationExecution(ctx context.Context, token, realm, executionID string) error + //CreateAuthenticationExecutionFlow creates a new flow execution for the given flow name in the given realm + CreateAuthenticationExecutionFlow(ctx context.Context, token, realm, flow string, execution CreateAuthenticationExecutionFlowRepresentation) error + // *** Users *** // CreateUser creates a new user CreateUser(ctx context.Context, token, realm string, user User) (string, error) diff --git a/models.go b/models.go index 6635d098..551b8298 100644 --- a/models.go +++ b/models.go @@ -793,6 +793,14 @@ type CreateAuthenticationExecutionRepresentation struct { Provider *string `json:"provider,omitempty"` } +// CreateAuthenticationExecutionFlowRepresentation contains the provider to be used for a new authentication representation +type CreateAuthenticationExecutionFlowRepresentation struct { + Alias *string `json:"alias,omitempty"` + Description *string `json:"description,omitempty"` + Provider *string `json:"provider,omitempty"` + Type *string `json:"type,omitempty"` +} + // ModifyAuthenticationExecutionRepresentation is the payload for updating an execution representation type ModifyAuthenticationExecutionRepresentation struct { ID *string `json:"id,omitempty"`