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 support for authentication execution configuration #241

Merged
merged 1 commit into from
Mar 9, 2020
Merged
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
53 changes: 53 additions & 0 deletions docs/resources/keycloak_authentication_execution_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# keycloak_authentication_execution_config

Allows for managing an authentication execution configuration.

### 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"
}

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

resource "keycloak_authentication_execution_config" "config" {
realm_id = "${keycloak_realm.realm.id}"
execution_id = "${keycloak_authentication_execution.execution.id}"
alias = "my-config-alias"
config = {
defaultProvider = "my-config-default-idp"
}
}
```

### Argument Reference

The following arguments are supported:

- `realm_id` - (Required) The realm the authentication execution exists in.
- `execution_id` - (Required) The authentication execution this configuration is attached to.
- `alias` - (Required) The name of the configuration.
- `config` - (Optional) The configuration. Keys are specific to each configurable authentication execution and not checked when applying.

### Import

Configurations can be imported using the format `{{realm}}/{{authenticationExecutionId}}/{{authenticationExecutionConfigId}}`.
If the `authenticationExecutionId` is incorrect, the import will still be successful.
A subsequent apply will change the `authenticationExecutionId` to the correct one, which causes the configuration to be replaced.

Example:

```bash
$ terraform import keycloak_authentication_execution_config.config my-realm/be081463-ddbf-4b42-9eff-9c97886f24ff/30559fcf-6fb8-45ea-8c46-2b86f46ebc17
```
9 changes: 9 additions & 0 deletions example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -714,3 +714,12 @@ resource "keycloak_authentication_execution" "browser-copy-otp" {
requirement = "REQUIRED"
depends_on = ["keycloak_authentication_execution.browser-copy-auth-username-password-form"]
}

resource "keycloak_authentication_execution_config" "config" {
realm_id = "${keycloak_realm.test.id}"
execution_id = "${keycloak_authentication_execution.browser-copy-idp-redirect.id}"
alias = "idp-XXX-config"
config = {
defaultProvider = "idp-XXX"
}
}
38 changes: 38 additions & 0 deletions keycloak/authentication_execution_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package keycloak

import (
"fmt"
)

// https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_authenticatorconfigrepresentation
type AuthenticationExecutionConfig struct {
RealmId string `json:"-"`
ExecutionId string `json:"-"`
Id string `json:"id"`
Alias string `json:"alias"`
Config map[string]string `json:"config"`
}

// https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_newexecutionconfig
func (keycloakClient *KeycloakClient) NewAuthenticationExecutionConfig(config *AuthenticationExecutionConfig) (string, error) {
_, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/authentication/executions/%s/config", config.RealmId, config.ExecutionId), config)
if err != nil {
return "", err
}
return getIdFromLocationHeader(location), nil
}

// https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_getauthenticatorconfig
func (keycloakClient *KeycloakClient) GetAuthenticationExecutionConfig(config *AuthenticationExecutionConfig) error {
return keycloakClient.get(fmt.Sprintf("/realms/%s/authentication/config/%s", config.RealmId, config.Id), config, nil)
}

// https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_updateauthenticatorconfig
func (keycloakClient *KeycloakClient) UpdateAuthenticationExecutionConfig(config *AuthenticationExecutionConfig) error {
return keycloakClient.put(fmt.Sprintf("/realms/%s/authentication/config/%s", config.RealmId, config.Id), config)
}

// https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_removeauthenticatorconfig
func (keycloakClient *KeycloakClient) DeleteAuthenticationExecutionConfig(config *AuthenticationExecutionConfig) error {
return keycloakClient.delete(fmt.Sprintf("/realms/%s/authentication/config/%s", config.RealmId, config.Id), nil)
}
1 change: 1 addition & 0 deletions provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ func KeycloakProvider() *schema.Provider {
"keycloak_authentication_flow": resourceKeycloakAuthenticationFlow(),
"keycloak_authentication_subflow": resourceKeycloakAuthenticationSubFlow(),
"keycloak_authentication_execution": resourceKeycloakAuthenticationExecution(),
"keycloak_authentication_execution_config": resourceKeycloakAuthenticationExecutionConfig(),
},
Schema: map[string]*schema.Schema{
"client_id": {
Expand Down
137 changes: 137 additions & 0 deletions provider/resource_keycloak_authentication_execution_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package provider

import (
"fmt"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/mrparkers/terraform-provider-keycloak/keycloak"
)

func resourceKeycloakAuthenticationExecutionConfig() *schema.Resource {
return &schema.Resource{
Create: resourceKeycloakAuthenticationExecutionConfigCreate,
Read: resourceKeycloakAuthenticationExecutionConfigRead,
Delete: resourceKeycloakAuthenticationExecutionConfigDelete,
Update: resourceKeycloakAuthenticationExecutionConfigUpdate,
Importer: &schema.ResourceImporter{
State: resourceKeycloakAuthenticationExecutionConfigImport,
},
Schema: map[string]*schema.Schema{
"realm_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"execution_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"alias": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"config": {
Type: schema.TypeMap,
Elem: &schema.Schema{Type: schema.TypeString},
Required: true,
},
},
}
}

func getAuthenticationExecutionConfigFromData(data *schema.ResourceData) *keycloak.AuthenticationExecutionConfig {
config := make(map[string]string)
for key, value := range data.Get("config").(map[string]interface{}) {
config[key] = value.(string)
}
return &keycloak.AuthenticationExecutionConfig{
Id: data.Id(),
RealmId: data.Get("realm_id").(string),
ExecutionId: data.Get("execution_id").(string),
Alias: data.Get("alias").(string),
Config: config,
}
}

func setAuthenticationExecutionConfigData(data *schema.ResourceData, config *keycloak.AuthenticationExecutionConfig) {
data.SetId(config.Id)
data.Set("realm_id", config.RealmId)
data.Set("execution_id", config.ExecutionId)
data.Set("alias", config.Alias)
data.Set("config", config.Config)
}

func resourceKeycloakAuthenticationExecutionConfigCreate(data *schema.ResourceData, meta interface{}) error {
keycloakClient := meta.(*keycloak.KeycloakClient)

config := getAuthenticationExecutionConfigFromData(data)

id, err := keycloakClient.NewAuthenticationExecutionConfig(config)
if err != nil {
return err
}

data.SetId(id)

return resourceKeycloakAuthenticationExecutionConfigRead(data, meta)
}

func resourceKeycloakAuthenticationExecutionConfigRead(data *schema.ResourceData, meta interface{}) error {
keycloakClient := meta.(*keycloak.KeycloakClient)

config := &keycloak.AuthenticationExecutionConfig{
RealmId: data.Get("realm_id").(string),
ExecutionId: data.Get("execution_id").(string),
Id: data.Id(),
}

err := keycloakClient.GetAuthenticationExecutionConfig(config)
if err != nil {
return handleNotFoundError(err, data)
}

setAuthenticationExecutionConfigData(data, config)

return nil
}

func resourceKeycloakAuthenticationExecutionConfigUpdate(data *schema.ResourceData, meta interface{}) error {
keycloakClient := meta.(*keycloak.KeycloakClient)

config := getAuthenticationExecutionConfigFromData(data)

err := keycloakClient.UpdateAuthenticationExecutionConfig(config)
if err != nil {
return err
}

return resourceKeycloakAuthenticationExecutionConfigRead(data, meta)
}

func resourceKeycloakAuthenticationExecutionConfigDelete(data *schema.ResourceData, meta interface{}) error {
keycloakClient := meta.(*keycloak.KeycloakClient)

config := &keycloak.AuthenticationExecutionConfig{
RealmId: data.Get("realm_id").(string),
Id: data.Id(),
}

return keycloakClient.DeleteAuthenticationExecutionConfig(config)
}

func resourceKeycloakAuthenticationExecutionConfigImport(data *schema.ResourceData, _ interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(data.Id(), "/")

if len(parts) != 3 || parts[0] == "" || parts[1] == "" || parts[2] == "" {
return nil, fmt.Errorf("invalid import. Supported import formats: {{realm}}/{{authenticationExecutionId}}/{{authenticationExecutionConfigId}}")
}

data.Set("realm_id", parts[0])
data.Set("execution_id", parts[1])
data.SetId(parts[2])

return []*schema.ResourceData{data}, nil
}
Loading