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

Adding resource_authentication_bindings #668

Merged
merged 8 commits into from
May 4, 2022
68 changes: 68 additions & 0 deletions docs/resources/authentication_bindings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
page_title: "keycloak_authentication_bindings Resource"
---

# keycloak\_authentication\_bindings Resource

Allows for creating and managing realm authentication flow bindings within Keycloak.

[Authentication flows](https://www.keycloak.org/docs/latest/server_admin/index.html#_authentication-flows) describe a sequence
of actions that a user or service must perform in order to be authenticated to Keycloak. The authentication flow itself
is a container for these actions, which are otherwise known as executions.

Realms assign authentication flows to supported user flows such as `registration` and `browser`. This resource allows the
updating of realm authentication flow bindings to custom authentication flows created by `keycloak_authentication_flow`.

Note that you can also use the `keycloak_realm` resource to assign authentication flow bindings at the realm level. This
resource is useful if you would like to create a realm and an authentication flow, and assign this flow to the realm within
a single run of `terraform apply`. In any case, do not attempt to use both the arguments within the `keycloak_realm` resource
and this resource to manage authentication flow bindings, you should choose one or the other.

## Example Usage

```hcl
resource "keycloak_realm" "realm" {
realm = "my-realm"
enabled = true
}

resource "keycloak_authentication_flow" "flow" {
realm_id = keycloak_realm.realm.id
alias = "my-flow-alias"
}

# first execution
resource "keycloak_authentication_execution" "execution_one" {
realm_id = "${keycloak_realm.realm.id}"
parent_flow_alias = "${keycloak_authentication_flow.flow.alias}"
authenticator = "auth-cookie"
requirement = "ALTERNATIVE"
}

# second execution
resource "keycloak_authentication_execution" "execution_two" {
realm_id = "${keycloak_realm.realm.id}"
parent_flow_alias = "${keycloak_authentication_flow.flow.alias}"
authenticator = "identity-provider-redirector"
requirement = "ALTERNATIVE"

depends_on = [
keycloak_authentication_execution.execution_one
]
}

resource "keycloak_authentication_bindings" "browser_authentication_binding" {
realm_id = keycloak_realm.realm.id
browser_flow = keycloak_authentication_flow.flow.alias
}
```

## Argument Reference

- `realm_id` - (Required) The realm the authentication flow binding exists in.
- `browser_flow` - (Optional) The alias of the flow to assign to the realm BrowserFlow.
- `registration_flow` - (Optional) The alias of the flow to assign to the realm RegistrationFlow.
- `direct_grant_flow` - (Optional) The alias of the flow to assign to the realm DirectGrantFlow.
- `reset_credentials_flow` - (Optional) The alias of the flow to assign to the realm ResetCredentialsFlow.
- `client_authentication_flow` - (Optional) The alias of the flow to assign to the realm ClientAuthenticationFlow.
- `docker_authentication_flow` - (Optional) The alias of the flow to assign to the realm DockerAuthenticationFlow.
5 changes: 5 additions & 0 deletions example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -1009,6 +1009,11 @@ resource "keycloak_authentication_execution_config" "config" {
}
}

resource "keycloak_authentication_bindings" "test_bindings" {
realm_id = keycloak_realm.test.id
browser_flow = keycloak_authentication_flow.browser-copy-flow.alias
}

resource "keycloak_openid_client" "client" {
client_id = "my-override-flow-binding-client"
realm_id = keycloak_realm.test.id
Expand Down
12 changes: 6 additions & 6 deletions keycloak/realm.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ type Realm struct {
PasswordPolicy string `json:"passwordPolicy"`

//flow bindings
BrowserFlow string `json:"browserFlow,omitempty"`
RegistrationFlow string `json:"registrationFlow,omitempty"`
DirectGrantFlow string `json:"directGrantFlow,omitempty"`
ResetCredentialsFlow string `json:"resetCredentialsFlow,omitempty"`
ClientAuthenticationFlow string `json:"clientAuthenticationFlow,omitempty"`
DockerAuthenticationFlow string `json:"dockerAuthenticationFlow,omitempty"`
BrowserFlow *string `json:"browserFlow,omitempty"`
RegistrationFlow *string `json:"registrationFlow,omitempty"`
DirectGrantFlow *string `json:"directGrantFlow,omitempty"`
ResetCredentialsFlow *string `json:"resetCredentialsFlow,omitempty"`
ClientAuthenticationFlow *string `json:"clientAuthenticationFlow,omitempty"`
DockerAuthenticationFlow *string `json:"dockerAuthenticationFlow,omitempty"`

// OTP Policy
OTPPolicyAlgorithm string `json:"otpPolicyAlgorithm,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func KeycloakProvider(client *keycloak.KeycloakClient) *schema.Provider {
"keycloak_users_permissions": resourceKeycloakUsersPermissions(),
"keycloak_user_groups": resourceKeycloakUserGroups(),
"keycloak_group_permissions": resourceKeycloakGroupPermissions(),
"keycloak_authentication_bindings": resourceKeycloakAuthenticationBindings(),
},
Schema: map[string]*schema.Schema{
"client_id": {
Expand Down
165 changes: 165 additions & 0 deletions provider/resource_keycloak_authentication_bindings.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
package provider

import (
"context"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/mrparkers/terraform-provider-keycloak/keycloak"
)

func resourceKeycloakAuthenticationBindings() *schema.Resource {
return &schema.Resource{
CreateContext: resourceKeycloakAuthenticationBindingsCreate,
ReadContext: resourceKeycloakAuthenticationBindingsRead,
DeleteContext: resourceKeycloakAuthenticationBindingsDelete,
UpdateContext: resourceKeycloakAuthenticationBindingsUpdate,
Schema: map[string]*schema.Schema{
"realm_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"browser_flow": {
Type: schema.TypeString,
Description: "Which flow should be used for BrowserFlow",
Optional: true,
Computed: true,
},
"registration_flow": {
Type: schema.TypeString,
Description: "Which flow should be used for RegistrationFlow",
Optional: true,
Computed: true,
},
"direct_grant_flow": {
Type: schema.TypeString,
Description: "Which flow should be used for DirectGrantFlow",
Optional: true,
Computed: true,
},
"reset_credentials_flow": {
Type: schema.TypeString,
Description: "Which flow should be used for ResetCredentialsFlow",
Optional: true,
Computed: true,
},
"client_authentication_flow": {
Type: schema.TypeString,
Description: "Which flow should be used for ClientAuthenticationFlow",
Optional: true,
Computed: true,
},
"docker_authentication_flow": {
Type: schema.TypeString,
Description: "Which flow should be used for DockerAuthenticationFlow",
Optional: true,
Computed: true,
},
},
}
}

func setAuthenticationBindingsData(data *schema.ResourceData, realm *keycloak.Realm) {
data.SetId(realm.Realm)
data.Set("browser_flow", realm.BrowserFlow)
data.Set("registration_flow", realm.RegistrationFlow)
data.Set("direct_grant_flow", realm.DirectGrantFlow)
data.Set("reset_credentials_flow", realm.ResetCredentialsFlow)
data.Set("client_authentication_flow", realm.ClientAuthenticationFlow)
data.Set("docker_authentication_flow", realm.DockerAuthenticationFlow)
}

func resetAuthenticationBindingsForRealm(realm *keycloak.Realm) {
realm.BrowserFlow = stringPointer("browser")
realm.RegistrationFlow = stringPointer("registration")
realm.DirectGrantFlow = stringPointer("direct grant")
realm.ResetCredentialsFlow = stringPointer("reset credentials")
realm.ClientAuthenticationFlow = stringPointer("clients")
realm.DockerAuthenticationFlow = stringPointer("docker auth")
}

func resourceKeycloakAuthenticationBindingsCreate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
keycloakClient := meta.(*keycloak.KeycloakClient)

realm, err := keycloakClient.GetRealm(ctx, data.Get("realm_id").(string))
if err != nil {
return diag.FromErr(err)
}

setRealmFlowBindings(data, realm)

err = keycloakClient.ValidateRealm(ctx, realm)
if err != nil {
return diag.FromErr(err)
}

err = keycloakClient.UpdateRealm(ctx, realm)
if err != nil {
return diag.FromErr(err)
}

realm, err = keycloakClient.GetRealm(ctx, realm.Id)
if err != nil {
return diag.FromErr(err)
}

setAuthenticationBindingsData(data, realm)

return resourceKeycloakAuthenticationBindingsRead(ctx, data, meta)
}

func resourceKeycloakAuthenticationBindingsRead(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
keycloakClient := meta.(*keycloak.KeycloakClient)

realm, err := keycloakClient.GetRealm(ctx, data.Id())
if err != nil {
return handleNotFoundError(ctx, err, data)
}

setAuthenticationBindingsData(data, realm)

return nil
}

func resourceKeycloakAuthenticationBindingsDelete(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
keycloakClient := meta.(*keycloak.KeycloakClient)

realm, err := keycloakClient.GetRealm(ctx, data.Id())
if err != nil {
return diag.FromErr(err)
}

resetAuthenticationBindingsForRealm(realm)

err = keycloakClient.UpdateRealm(ctx, realm)
if err != nil {
return diag.FromErr(err)
}

return nil
}

func resourceKeycloakAuthenticationBindingsUpdate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
keycloakClient := meta.(*keycloak.KeycloakClient)

realm, err := keycloakClient.GetRealm(ctx, data.Id())
if err != nil {
return diag.FromErr(err)
}

setRealmFlowBindings(data, realm)

err = keycloakClient.ValidateRealm(ctx, realm)
if err != nil {
return diag.FromErr(err)
}

err = keycloakClient.UpdateRealm(ctx, realm)
if err != nil {
return diag.FromErr(err)
}

setAuthenticationBindingsData(data, realm)

return resourceKeycloakAuthenticationBindingsRead(ctx, data, meta)
}
Loading