From 0266a424e4c18f3288154450039af8b46789e295 Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Tue, 3 Sep 2024 17:26:11 +0200 Subject: [PATCH 01/12] Enable configs in required actions Signed-off-by: Laureat Grepi --- .goreleaser.yaml | 46 +++++++++++++ .goreleaser.yml | 69 +++++++++---------- docs/resources/required_action.md | 13 ++-- example/main.tf | 42 +++++++---- keycloak/required_action.go | 22 +++--- provider/resource_keycloak_required_action.go | 16 ++++- .../resource_keycloak_required_action_test.go | 41 +++++++++++ 7 files changed, 179 insertions(+), 70 deletions(-) create mode 100644 .goreleaser.yaml diff --git a/.goreleaser.yaml b/.goreleaser.yaml new file mode 100644 index 000000000..f0ff055c0 --- /dev/null +++ b/.goreleaser.yaml @@ -0,0 +1,46 @@ +# This is an example .goreleaser.yml file with some sensible defaults. +# Make sure to check the documentation at https://goreleaser.com + +# The lines below are called `modelines`. See `:help modeline` +# Feel free to remove those if you don't want/need to use them. +# yaml-language-server: $schema=https://goreleaser.com/static/schema.json +# vim: set ts=2 sw=2 tw=0 fo=cnqoj + +version: 2 + +before: + hooks: + # You may remove this if you don't use go modules. + - go mod tidy + # you may remove this if you don't need go generate + - go generate ./... + +builds: + - env: + - CGO_ENABLED=0 + goos: + - linux + - windows + - darwin + +archives: + - format: tar.gz + # this name template makes the OS and Arch compatible with the results of `uname`. + name_template: >- + {{ .ProjectName }}_ + {{- title .Os }}_ + {{- if eq .Arch "amd64" }}x86_64 + {{- else if eq .Arch "386" }}i386 + {{- else }}{{ .Arch }}{{ end }} + {{- if .Arm }}v{{ .Arm }}{{ end }} + # use zip for windows archives + format_overrides: + - goos: windows + format: zip + +changelog: + sort: asc + filters: + exclude: + - "^docs:" + - "^test:" diff --git a/.goreleaser.yml b/.goreleaser.yml index 9f94cdfb3..6d3c7ec50 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,46 +1,42 @@ # Visit https://goreleaser.com for documentation on how to customize this # behavior. version: 2 - before: hooks: # this is just an example and not a requirement for provider building/publishing - go mod tidy builds: - - env: - # goreleaser does not work with CGO, it could also complicate - # usage by users in CI/CD systems like Terraform Cloud where - # they are unable to install libraries. - - CGO_ENABLED=0 - mod_timestamp: '{{ .CommitTimestamp }}' - flags: - - -trimpath - ldflags: - - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' - goos: - - freebsd - - openbsd - - solaris - - windows - - linux - - darwin - goarch: - - amd64 - - '386' - - arm - - arm64 - ignore: - - goos: darwin - goarch: '386' - - goos: openbsd - goarch: arm - - goos: openbsd - goarch: arm64 - binary: '{{ .ProjectName }}_v{{ .Version }}' +- env: + # goreleaser does not work with CGO, it could also complicate + # usage by users in CI/CD systems like HCP Terraform where + # they are unable to install libraries. + - CGO_ENABLED=0 + mod_timestamp: '{{ .CommitTimestamp }}' + flags: + - -trimpath + ldflags: + - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' + goos: + - freebsd + - windows + - linux + - darwin + goarch: + - amd64 + - '386' + - arm + - arm64 + ignore: + - goos: darwin + goarch: '386' + binary: '{{ .ProjectName }}_v{{ .Version }}' archives: - - format: zip - name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' +- format: zip + name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' checksum: + extra_files: + - glob: 'terraform-registry-manifest.json' + name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' algorithm: sha256 signs: @@ -56,7 +52,10 @@ signs: - "--detach-sign" - "${artifact}" release: -# If you want to manually examine the release before its live, uncomment this line: -# draft: true + extra_files: + - glob: 'terraform-registry-manifest.json' + name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' + # If you want to manually examine the release before its live, uncomment this line: + # draft: true changelog: disable: true diff --git a/docs/resources/required_action.md b/docs/resources/required_action.md index 9ca6901a6..19bab8b72 100644 --- a/docs/resources/required_action.md +++ b/docs/resources/required_action.md @@ -12,16 +12,14 @@ Allows for creating and managing required actions within Keycloak. ## Example Usage ```hcl -resource "keycloak_realm" "realm" { - realm = "my-realm" - enabled = true -} - resource "keycloak_required_action" "required_action" { realm_id = keycloak_realm.realm.realm - alias = "webauthn-register" + alias = "UPDATE_PASSWORD" enabled = true - name = "Webauthn Register" + name = "Update Password" + config = { + max_auth_age = "600" + } } ``` @@ -33,6 +31,7 @@ resource "keycloak_required_action" "required_action" { - `enabled` - (Optional) When `false`, the required action is not enabled for new users. Defaults to `false`. - `default_action` - (Optional) When `true`, the required action is set as the default action for new users. Defaults to `false`. - `priority`- (Optional) The priority of the required action. +- `config`- (Optional) The configuration. Keys are specific to each configurable required action and not checked when applying. ## Import diff --git a/example/main.tf b/example/main.tf index 90172fd1e..017086927 100644 --- a/example/main.tf +++ b/example/main.tf @@ -109,6 +109,18 @@ resource "keycloak_required_action" "custom-terms-and-conditions" { name = "Custom Terms and Conditions" } +resource "keycloak_required_action" "update-password" { + realm_id = keycloak_realm.test.realm + alias = "UPDATE_PASSWORD" + default_action = true + enabled = true + name = "Update Password" + + config { + max_auth_age = "600" + } +} + resource "keycloak_required_action" "custom-configured_totp" { realm_id = keycloak_realm.test.realm alias = "CONFIGURE_TOTP" @@ -427,25 +439,25 @@ resource "keycloak_ldap_full_name_mapper" "full_name_mapper" { } resource "keycloak_ldap_custom_mapper" "custom_mapper" { - name = "custom-mapper" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + name = "custom-mapper" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - provider_id = "msad-user-account-control-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + provider_id = "msad-user-account-control-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" } resource "keycloak_ldap_custom_mapper" "custom_mapper_with_config" { - name = "custom-mapper-with-config" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - - provider_id = "user-attribute-ldap-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" - config = { - "user.model.attribute" = "username" - "ldap.attribute" = "cn" - } + name = "custom-mapper-with-config" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + + provider_id = "user-attribute-ldap-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + config = { + "user.model.attribute" = "username" + "ldap.attribute" = "cn" + } } diff --git a/keycloak/required_action.go b/keycloak/required_action.go index d46c3db94..300613957 100644 --- a/keycloak/required_action.go +++ b/keycloak/required_action.go @@ -6,27 +6,27 @@ import ( ) type RequiredAction struct { - Id string `json:"-"` - RealmId string `json:"-"` - Alias string `json:"alias"` - Name string `json:"name"` - ProviderId string `json:"providerId"` - Enabled bool `json:"enabled"` - DefaultAction bool `json:"defaultAction"` - Priority int `json:"priority"` - Config map[string][]string `json:"config"` + Id string `json:"-"` + RealmId string `json:"-"` + Alias string `json:"alias"` + Name string `json:"name"` + ProviderId string `json:"providerId"` + Enabled bool `json:"enabled"` + DefaultAction bool `json:"defaultAction"` + Priority int `json:"priority"` + Config map[string]string `json:"config"` } func (requiredActions *RequiredAction) getConfig(val string) string { if len(requiredActions.Config[val]) == 0 { return "" } - return requiredActions.Config[val][0] + return requiredActions.Config[val] } func (requiredActions *RequiredAction) getConfigOk(val string) (string, bool) { if v, ok := requiredActions.Config[val]; ok { - return v[0], true + return v, true } return "", false } diff --git a/provider/resource_keycloak_required_action.go b/provider/resource_keycloak_required_action.go index f9ccce2c0..289a7ea40 100644 --- a/provider/resource_keycloak_required_action.go +++ b/provider/resource_keycloak_required_action.go @@ -4,10 +4,11 @@ import ( "context" "errors" "fmt" + "strings" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/keycloak/terraform-provider-keycloak/keycloak" - "strings" ) func resourceKeycloakRequiredAction() *schema.Resource { @@ -47,11 +48,21 @@ func resourceKeycloakRequiredAction() *schema.Resource { Optional: true, Computed: true, }, + "config": { + Type: schema.TypeMap, + Elem: &schema.Schema{Type: schema.TypeString}, + Optional: true, + }, }, } } func getRequiredActionFromData(data *schema.ResourceData) (*keycloak.RequiredAction, error) { + config := make(map[string]string) + for key, value := range data.Get("config").(map[string]interface{}) { + config[key] = value.(string) + } + action := &keycloak.RequiredAction{ Id: fmt.Sprintf("%s/%s", data.Get("realm_id").(string), data.Get("alias").(string)), RealmId: data.Get("realm_id").(string), @@ -60,7 +71,7 @@ func getRequiredActionFromData(data *schema.ResourceData) (*keycloak.RequiredAct Enabled: data.Get("enabled").(bool), DefaultAction: data.Get("default_action").(bool), Priority: data.Get("priority").(int), - Config: make(map[string][]string), + Config: config, } return action, nil @@ -74,6 +85,7 @@ func setRequiredActionData(data *schema.ResourceData, action *keycloak.RequiredA data.Set("enabled", action.Enabled) data.Set("default_action", action.DefaultAction) data.Set("priority", action.Priority) + data.Set("config", action.Config) } func resourceKeycloakRequiredActionsCreate(ctx context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics { diff --git a/provider/resource_keycloak_required_action_test.go b/provider/resource_keycloak_required_action_test.go index 989d80ec8..8380e7814 100644 --- a/provider/resource_keycloak_required_action_test.go +++ b/provider/resource_keycloak_required_action_test.go @@ -26,6 +26,28 @@ func TestAccKeycloakRequiredAction_basic(t *testing.T) { }) } +func TestAccKeycloakRequiredAction_withConfig(t *testing.T) { + realmName := acctest.RandomWithPrefix("tf-acc") + requiredActionAlias := "UPDATE_PASSWORD" + maxAuthAgeConfig := "3600" + + resource.Test(t, resource.TestCase{ + ProviderFactories: testAccProviderFactories, + PreCheck: func() { testAccPreCheck(t) }, + Steps: []resource.TestStep{ + { + Config: testKeycloakRequiredAction_withConfig(realmName, requiredActionAlias, 37, maxAuthAgeConfig), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakRequiresActionExists(realmName, requiredActionAlias), + resource.TestCheckResourceAttr("keycloak_required_action.required_action", "realm_id", realmName), + resource.TestCheckResourceAttr("keycloak_required_action.required_action", "config.%", "1"), + resource.TestCheckResourceAttr("keycloak_required_action.required_action", "config.max_auth_age", maxAuthAgeConfig), + ), + }, + }, + }) +} + func TestAccKeycloakRequiredAction_unregisteredAction(t *testing.T) { realmName := acctest.RandomWithPrefix("tf-acc") requiredActionAlias := "webauthn-register" @@ -128,6 +150,25 @@ resource "keycloak_required_action" "required_action" { `, realm, requiredActionAlias, priority) } +func testKeycloakRequiredAction_withConfig(realm, requiredActionAlias string, priority int, maxAuthAgeConfig string) string { + return fmt.Sprintf(` +resource "keycloak_realm" "realm" { + realm = "%s" +} +resource "keycloak_required_action" "required_action" { + realm_id = "${keycloak_realm.realm.realm}" + alias = "%s" + default_action = true + enabled = true + name = "My required Action" + priority = %d + config = { + max_auth_age = "%s" + } +} + `, realm, requiredActionAlias, priority, maxAuthAgeConfig) +} + func testKeycloakRequiredAction_import(realm, requiredActionAlias string) string { return fmt.Sprintf(` resource "keycloak_realm" "realm" { From d25d890ef0280c24204ae22b75b8f8214e2d91c7 Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Tue, 3 Sep 2024 17:34:46 +0200 Subject: [PATCH 02/12] registry json file Signed-off-by: Laureat Grepi --- terraform-registry-manifest.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 terraform-registry-manifest.json diff --git a/terraform-registry-manifest.json b/terraform-registry-manifest.json new file mode 100644 index 000000000..acf1daa8b --- /dev/null +++ b/terraform-registry-manifest.json @@ -0,0 +1,6 @@ +{ + "version": 1, + "metadata": { + "protocol_versions": ["5.0"] + } +} \ No newline at end of file From d3ba3aa5cdd875c7de778afb333430346d853a93 Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Tue, 3 Sep 2024 17:38:05 +0200 Subject: [PATCH 03/12] newline Signed-off-by: Laureat Grepi --- terraform-registry-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform-registry-manifest.json b/terraform-registry-manifest.json index acf1daa8b..5d14f2e9d 100644 --- a/terraform-registry-manifest.json +++ b/terraform-registry-manifest.json @@ -3,4 +3,4 @@ "metadata": { "protocol_versions": ["5.0"] } -} \ No newline at end of file +} From fecd867288e2b9cbdcdff9aebf58eec4afa0fd16 Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Mon, 2 Sep 2024 18:12:03 +0200 Subject: [PATCH 04/12] Enable configuring required action from terraform Signed-off-by: Laureat Grepi --- provider/resource_keycloak_required_action.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/provider/resource_keycloak_required_action.go b/provider/resource_keycloak_required_action.go index 289a7ea40..1ced64ee6 100644 --- a/provider/resource_keycloak_required_action.go +++ b/provider/resource_keycloak_required_action.go @@ -50,7 +50,6 @@ func resourceKeycloakRequiredAction() *schema.Resource { }, "config": { Type: schema.TypeMap, - Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, }, }, @@ -71,7 +70,7 @@ func getRequiredActionFromData(data *schema.ResourceData) (*keycloak.RequiredAct Enabled: data.Get("enabled").(bool), DefaultAction: data.Get("default_action").(bool), Priority: data.Get("priority").(int), - Config: config, + Config: data.Get("config").(map[string][]string), } return action, nil From d12d6ee95045863c722aaf6ec766c4f4dcebe34d Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Tue, 3 Sep 2024 12:28:55 +0200 Subject: [PATCH 05/12] Allow required action config values to be passed from terraform Signed-off-by: Laureat Grepi --- keycloak/required_action.go | 17 ++++++++--------- provider/resource_keycloak_required_action.go | 9 +++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/keycloak/required_action.go b/keycloak/required_action.go index 300613957..5893f556b 100644 --- a/keycloak/required_action.go +++ b/keycloak/required_action.go @@ -7,14 +7,14 @@ import ( type RequiredAction struct { Id string `json:"-"` - RealmId string `json:"-"` - Alias string `json:"alias"` - Name string `json:"name"` - ProviderId string `json:"providerId"` - Enabled bool `json:"enabled"` - DefaultAction bool `json:"defaultAction"` - Priority int `json:"priority"` - Config map[string]string `json:"config"` + RealmId string `json:"-"` + Alias string `json:"alias"` + Name string `json:"name"` + ProviderId string `json:"providerId"` + Enabled bool `json:"enabled"` + DefaultAction bool `json:"defaultAction"` + Priority int `json:"priority"` + Config map[string]string `json:"config"` } func (requiredActions *RequiredAction) getConfig(val string) string { @@ -30,7 +30,6 @@ func (requiredActions *RequiredAction) getConfigOk(val string) (string, bool) { } return "", false } - func (keycloakClient *KeycloakClient) GetRequiredActions(ctx context.Context, realmId string) ([]*RequiredAction, error) { var requiredActions []*RequiredAction diff --git a/provider/resource_keycloak_required_action.go b/provider/resource_keycloak_required_action.go index 1ced64ee6..dd52459e3 100644 --- a/provider/resource_keycloak_required_action.go +++ b/provider/resource_keycloak_required_action.go @@ -50,6 +50,7 @@ func resourceKeycloakRequiredAction() *schema.Resource { }, "config": { Type: schema.TypeMap, + Elem: &schema.Schema{Type: schema.TypeString}, Optional: true, }, }, @@ -58,9 +59,9 @@ func resourceKeycloakRequiredAction() *schema.Resource { func getRequiredActionFromData(data *schema.ResourceData) (*keycloak.RequiredAction, error) { config := make(map[string]string) - for key, value := range data.Get("config").(map[string]interface{}) { - config[key] = value.(string) - } + for key, value := range data.Get("config").(map[string]interface{}) { + config[key] = value.(string) + } action := &keycloak.RequiredAction{ Id: fmt.Sprintf("%s/%s", data.Get("realm_id").(string), data.Get("alias").(string)), @@ -70,7 +71,7 @@ func getRequiredActionFromData(data *schema.ResourceData) (*keycloak.RequiredAct Enabled: data.Get("enabled").(bool), DefaultAction: data.Get("default_action").(bool), Priority: data.Get("priority").(int), - Config: data.Get("config").(map[string][]string), + Config: config, } return action, nil From 1c9922daca59974b70c92c7c1fafbc38e70d15e7 Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Tue, 3 Sep 2024 12:38:33 +0200 Subject: [PATCH 06/12] update examples Signed-off-by: Laureat Grepi --- example/main.tf | 1 - 1 file changed, 1 deletion(-) diff --git a/example/main.tf b/example/main.tf index 017086927..1328b6edd 100644 --- a/example/main.tf +++ b/example/main.tf @@ -120,7 +120,6 @@ resource "keycloak_required_action" "update-password" { max_auth_age = "600" } } - resource "keycloak_required_action" "custom-configured_totp" { realm_id = keycloak_realm.test.realm alias = "CONFIGURE_TOTP" From 60ad0a5ed6c4fdd5d3c57183f48aa6c90ffe93ae Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Mon, 30 Sep 2024 11:05:50 +0200 Subject: [PATCH 07/12] Add multivalued config in user profile Signed-off-by: Laureat Grepi --- docs/resources/realm_user_profile.md | 2 ++ example/main.tf | 3 ++- keycloak/realm_user_profile.go | 1 + provider/resource_keycloak_realm_user_profile.go | 7 +++++++ provider/resource_keycloak_realm_user_profile_test.go | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/resources/realm_user_profile.md b/docs/resources/realm_user_profile.md index 26a8aec82..ae56b2fa7 100644 --- a/docs/resources/realm_user_profile.md +++ b/docs/resources/realm_user_profile.md @@ -58,6 +58,7 @@ resource "keycloak_realm_user_profile" "userprofile" { attribute { name = "field2" + multivalued = true validator { name = "options" @@ -101,6 +102,7 @@ resource "keycloak_realm_user_profile" "userprofile" { - `display_name` - (Optional) The display name of the attribute. - `multi_valued` - (Optional) If the attribute supports multiple values. Defaults to `false`. - `group` - (Optional) The group that the attribute belong to. +- `multivalued` - (Optional) The attribute can contain multiple values. Defaults to `false`. - `enabled_when_scope` - (Optional) A list of scopes. The attribute will only be enabled when these scopes are requested by clients. - `required_for_roles` - (Optional) A list of roles for which the attribute will be required. - `required_for_scopes` - (Optional) A list of scopes for which the attribute will be required. diff --git a/example/main.tf b/example/main.tf index 1328b6edd..580980f8d 100644 --- a/example/main.tf +++ b/example/main.tf @@ -1141,7 +1141,8 @@ resource "keycloak_realm_user_profile" "userprofile" { } attribute { - name = "field2" + name = "field2" + multivalued = true } group { diff --git a/keycloak/realm_user_profile.go b/keycloak/realm_user_profile.go index 582ef2b0a..cf8d8771a 100644 --- a/keycloak/realm_user_profile.go +++ b/keycloak/realm_user_profile.go @@ -32,6 +32,7 @@ type RealmUserProfileAttribute struct { Required *RealmUserProfileRequired `json:"required,omitempty"` Selector *RealmUserProfileSelector `json:"selector,omitempty"` Validations map[string]RealmUserProfileValidationConfig `json:"validations,omitempty"` + Multivalued bool `json:"multivalued"` } type RealmUserProfileGroup struct { diff --git a/provider/resource_keycloak_realm_user_profile.go b/provider/resource_keycloak_realm_user_profile.go index be760dbe6..e4802caf6 100644 --- a/provider/resource_keycloak_realm_user_profile.go +++ b/provider/resource_keycloak_realm_user_profile.go @@ -55,6 +55,11 @@ func resourceKeycloakRealmUserProfile() *schema.Resource { Type: schema.TypeString, Optional: true, }, + "multivalued": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, "enabled_when_scope": { Type: schema.TypeSet, Optional: true, @@ -156,6 +161,7 @@ func getRealmUserProfileAttributeFromData(m map[string]interface{}) *keycloak.Re Name: m["name"].(string), DisplayName: m["display_name"].(string), Group: m["group"].(string), + Multivalued: m["multivalued"].(bool), } if v, ok := m["multi_valued"].(bool); ok { @@ -343,6 +349,7 @@ func getRealmUserProfileAttributeData(attr *keycloak.RealmUserProfileAttribute) attributeData["multi_valued"] = attr.MultiValued attributeData["group"] = attr.Group + attributeData["multivalued"] = attr.Multivalued if attr.Selector != nil && len(attr.Selector.Scopes) != 0 { attributeData["enabled_when_scope"] = attr.Selector.Scopes } diff --git a/provider/resource_keycloak_realm_user_profile_test.go b/provider/resource_keycloak_realm_user_profile_test.go index f4d3c1fdc..5c6717502 100644 --- a/provider/resource_keycloak_realm_user_profile_test.go +++ b/provider/resource_keycloak_realm_user_profile_test.go @@ -130,6 +130,7 @@ func TestAccKeycloakRealmUserProfile_basicFull(t *testing.T) { "foo": "\"bar\"", "inputOptionLabels": "{\"a\":\"b\"}", }, + Multivalued: true, }, }, Groups: []*keycloak.RealmUserProfileGroup{ From 7850ba4dc0ffe5a574809a73a60f404072f799ef Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Mon, 30 Sep 2024 11:10:42 +0200 Subject: [PATCH 08/12] fmt Signed-off-by: Laureat Grepi --- keycloak/realm_user_profile.go | 2 +- provider/resource_keycloak_realm_user_profile.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/keycloak/realm_user_profile.go b/keycloak/realm_user_profile.go index cf8d8771a..bd4170517 100644 --- a/keycloak/realm_user_profile.go +++ b/keycloak/realm_user_profile.go @@ -32,7 +32,7 @@ type RealmUserProfileAttribute struct { Required *RealmUserProfileRequired `json:"required,omitempty"` Selector *RealmUserProfileSelector `json:"selector,omitempty"` Validations map[string]RealmUserProfileValidationConfig `json:"validations,omitempty"` - Multivalued bool `json:"multivalued"` + Multivalued bool `json:"multivalued"` } type RealmUserProfileGroup struct { diff --git a/provider/resource_keycloak_realm_user_profile.go b/provider/resource_keycloak_realm_user_profile.go index e4802caf6..3b67db105 100644 --- a/provider/resource_keycloak_realm_user_profile.go +++ b/provider/resource_keycloak_realm_user_profile.go @@ -58,7 +58,7 @@ func resourceKeycloakRealmUserProfile() *schema.Resource { "multivalued": { Type: schema.TypeBool, Optional: true, - Default: false, + Default: false, }, "enabled_when_scope": { Type: schema.TypeSet, From 1341da42984204d2fe41c045979e939ba276f51a Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Mon, 30 Sep 2024 12:09:04 +0200 Subject: [PATCH 09/12] remove default value Signed-off-by: Laureat Grepi --- keycloak/realm_user_profile.go | 2 +- provider/resource_keycloak_realm_user_profile.go | 1 - provider/resource_keycloak_realm_user_profile_test.go | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/keycloak/realm_user_profile.go b/keycloak/realm_user_profile.go index bd4170517..2377ffafa 100644 --- a/keycloak/realm_user_profile.go +++ b/keycloak/realm_user_profile.go @@ -32,7 +32,7 @@ type RealmUserProfileAttribute struct { Required *RealmUserProfileRequired `json:"required,omitempty"` Selector *RealmUserProfileSelector `json:"selector,omitempty"` Validations map[string]RealmUserProfileValidationConfig `json:"validations,omitempty"` - Multivalued bool `json:"multivalued"` + Multivalued bool `json:"multivalued,omitempty"` } type RealmUserProfileGroup struct { diff --git a/provider/resource_keycloak_realm_user_profile.go b/provider/resource_keycloak_realm_user_profile.go index 3b67db105..a9413a7a4 100644 --- a/provider/resource_keycloak_realm_user_profile.go +++ b/provider/resource_keycloak_realm_user_profile.go @@ -58,7 +58,6 @@ func resourceKeycloakRealmUserProfile() *schema.Resource { "multivalued": { Type: schema.TypeBool, Optional: true, - Default: false, }, "enabled_when_scope": { Type: schema.TypeSet, diff --git a/provider/resource_keycloak_realm_user_profile_test.go b/provider/resource_keycloak_realm_user_profile_test.go index 5c6717502..f4d3c1fdc 100644 --- a/provider/resource_keycloak_realm_user_profile_test.go +++ b/provider/resource_keycloak_realm_user_profile_test.go @@ -130,7 +130,6 @@ func TestAccKeycloakRealmUserProfile_basicFull(t *testing.T) { "foo": "\"bar\"", "inputOptionLabels": "{\"a\":\"b\"}", }, - Multivalued: true, }, }, Groups: []*keycloak.RealmUserProfileGroup{ From 1f80a25a7e97b685538175c8ac7bda10c0a04938 Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Mon, 10 Feb 2025 15:26:32 +0100 Subject: [PATCH 10/12] format Signed-off-by: Laureat Grepi --- .goreleaser.yaml | 46 - .goreleaser.yml | 69 +- docs/resources/required_action.md | 5 + example/main.tf | 1084 ++++++++++++++++- provider/resource_keycloak_required_action.go | 3 +- terraform-registry-manifest.json | 6 - 6 files changed, 1114 insertions(+), 99 deletions(-) delete mode 100644 .goreleaser.yaml delete mode 100644 terraform-registry-manifest.json diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index f0ff055c0..000000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,46 +0,0 @@ -# This is an example .goreleaser.yml file with some sensible defaults. -# Make sure to check the documentation at https://goreleaser.com - -# The lines below are called `modelines`. See `:help modeline` -# Feel free to remove those if you don't want/need to use them. -# yaml-language-server: $schema=https://goreleaser.com/static/schema.json -# vim: set ts=2 sw=2 tw=0 fo=cnqoj - -version: 2 - -before: - hooks: - # You may remove this if you don't use go modules. - - go mod tidy - # you may remove this if you don't need go generate - - go generate ./... - -builds: - - env: - - CGO_ENABLED=0 - goos: - - linux - - windows - - darwin - -archives: - - format: tar.gz - # this name template makes the OS and Arch compatible with the results of `uname`. - name_template: >- - {{ .ProjectName }}_ - {{- title .Os }}_ - {{- if eq .Arch "amd64" }}x86_64 - {{- else if eq .Arch "386" }}i386 - {{- else }}{{ .Arch }}{{ end }} - {{- if .Arm }}v{{ .Arm }}{{ end }} - # use zip for windows archives - format_overrides: - - goos: windows - format: zip - -changelog: - sort: asc - filters: - exclude: - - "^docs:" - - "^test:" diff --git a/.goreleaser.yml b/.goreleaser.yml index 6d3c7ec50..9f94cdfb3 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,42 +1,46 @@ # Visit https://goreleaser.com for documentation on how to customize this # behavior. version: 2 + before: hooks: # this is just an example and not a requirement for provider building/publishing - go mod tidy builds: -- env: - # goreleaser does not work with CGO, it could also complicate - # usage by users in CI/CD systems like HCP Terraform where - # they are unable to install libraries. - - CGO_ENABLED=0 - mod_timestamp: '{{ .CommitTimestamp }}' - flags: - - -trimpath - ldflags: - - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' - goos: - - freebsd - - windows - - linux - - darwin - goarch: - - amd64 - - '386' - - arm - - arm64 - ignore: - - goos: darwin - goarch: '386' - binary: '{{ .ProjectName }}_v{{ .Version }}' + - env: + # goreleaser does not work with CGO, it could also complicate + # usage by users in CI/CD systems like Terraform Cloud where + # they are unable to install libraries. + - CGO_ENABLED=0 + mod_timestamp: '{{ .CommitTimestamp }}' + flags: + - -trimpath + ldflags: + - '-s -w -X main.version={{.Version}} -X main.commit={{.Commit}}' + goos: + - freebsd + - openbsd + - solaris + - windows + - linux + - darwin + goarch: + - amd64 + - '386' + - arm + - arm64 + ignore: + - goos: darwin + goarch: '386' + - goos: openbsd + goarch: arm + - goos: openbsd + goarch: arm64 + binary: '{{ .ProjectName }}_v{{ .Version }}' archives: -- format: zip - name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' + - format: zip + name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}' checksum: - extra_files: - - glob: 'terraform-registry-manifest.json' - name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' name_template: '{{ .ProjectName }}_{{ .Version }}_SHA256SUMS' algorithm: sha256 signs: @@ -52,10 +56,7 @@ signs: - "--detach-sign" - "${artifact}" release: - extra_files: - - glob: 'terraform-registry-manifest.json' - name_template: '{{ .ProjectName }}_{{ .Version }}_manifest.json' - # If you want to manually examine the release before its live, uncomment this line: - # draft: true +# If you want to manually examine the release before its live, uncomment this line: +# draft: true changelog: disable: true diff --git a/docs/resources/required_action.md b/docs/resources/required_action.md index 19bab8b72..28b0eaa97 100644 --- a/docs/resources/required_action.md +++ b/docs/resources/required_action.md @@ -12,6 +12,11 @@ Allows for creating and managing required actions within Keycloak. ## Example Usage ```hcl +resource "keycloak_realm" "realm" { + realm = "my-realm" + enabled = true +} + resource "keycloak_required_action" "required_action" { realm_id = keycloak_realm.realm.realm alias = "UPDATE_PASSWORD" diff --git a/example/main.tf b/example/main.tf index 580980f8d..e38654d02 100644 --- a/example/main.tf +++ b/example/main.tf @@ -438,25 +438,1087 @@ resource "keycloak_ldap_full_name_mapper" "full_name_mapper" { } resource "keycloak_ldap_custom_mapper" "custom_mapper" { - name = "custom-mapper" + name = "custom-mapper" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + + provider_id = "msad-user-account-control-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" +} + +resource "keycloak_ldap_custom_mapper" "custom_mapper_with_config" { + name = "custom-mapper-with-config" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + + provider_id = "user-attribute-ldap-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + config = { + "user.model.attribute" = "username" + "ldap.attribute" = "cn" + } +} + + +resource "keycloak_custom_user_federation" "custom" { + name = "custom1" + realm_id = "master" + provider_id = "custom" + + enabled = true +} + +resource "keycloak_openid_user_attribute_protocol_mapper" "map_user_attributes_client" { + name = "tf-test-open-id-user-attribute-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + user_attribute = "description" + claim_name = "description" +} + +resource "keycloak_openid_user_attribute_protocol_mapper" "map_user_permissions_attributes_client" { + name = "tf-test-open-id-user-multivalue-attribute-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + user_attribute = "permissions" + claim_name = "permissions" + multivalued = true +} + + +resource "keycloak_openid_user_attribute_protocol_mapper" "map_user_attributes_client_scope" { + name = "tf-test-open-id-user-attribute-protocol-mapper-client-scope" + realm_id = keycloak_realm.test.id + client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id + user_attribute = "foo2" + claim_name = "bar2" +} + +resource "keycloak_openid_group_membership_protocol_mapper" "map_group_memberships_client" { + name = "tf-test-open-id-group-membership-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + claim_name = "bar" +} + +resource "keycloak_openid_group_membership_protocol_mapper" "map_group_memberships_client_scope" { + name = "tf-test-open-id-group-membership-protocol-mapper-client-scope" + realm_id = keycloak_realm.test.id + client_scope_id = keycloak_openid_client_scope.test_optional_client_scope.id + claim_name = "bar2" +} + +resource "keycloak_openid_full_name_protocol_mapper" "map_full_names_client" { + name = "tf-test-open-id-full-name-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id +} + +resource "keycloak_openid_full_name_protocol_mapper" "map_full_names_client_scope" { + name = "tf-test-open-id-full-name-protocol-mapper-client-scope" + realm_id = keycloak_realm.test.id + client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id +} + +resource "keycloak_openid_user_property_protocol_mapper" "map_user_properties_client" { + name = "tf-test-open-id-user-property-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + user_property = "foo" + claim_name = "bar" +} + +resource "keycloak_openid_user_property_protocol_mapper" "map_user_properties_client_scope" { + name = "tf-test-open-id-user-property-protocol-mapper-client-scope" + realm_id = keycloak_realm.test.id + client_scope_id = keycloak_openid_client_scope.test_optional_client_scope.id + user_property = "foo2" + claim_name = "bar2" +} + +resource "keycloak_openid_hardcoded_claim_protocol_mapper" "hardcoded_claim_client" { + name = "tf-test-open-id-hardcoded-claim-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + + claim_name = "foo" + claim_value = "bar" +} + +resource "keycloak_openid_hardcoded_claim_protocol_mapper" "hardcoded_claim_client_scope" { + name = "tf-test-open-id-hardcoded-claim-protocol-mapper-client-scope" + realm_id = keycloak_realm.test.id + client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id + + claim_name = "foo" + claim_value = "bar" +} + +resource "keycloak_openid_user_realm_role_protocol_mapper" "user_realm_role_client" { + name = "tf-test-open-id-user-realm-role-claim-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + + claim_name = "foo" +} + +resource "keycloak_openid_user_realm_role_protocol_mapper" "user_realm_role_client_scope" { + name = "tf-test-open-id-user-realm-role-protocol-mapper-client-scope" + realm_id = keycloak_realm.test.id + client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id + + claim_name = "foo" +} + +resource "keycloak_openid_user_client_role_protocol_mapper" "user_client_role_client" { + name = "tf-test-open-id-user-client-role-claim-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + + claim_name = "foo" + multivalued = false + + client_id_for_role_mappings = keycloak_openid_client.bearer_only_client.client_id + client_role_prefix = "prefixValue" + + add_to_id_token = true + add_to_access_token = false + add_to_userinfo = false +} + +resource "keycloak_openid_user_client_role_protocol_mapper" "user_client_role_client_scope" { + name = "tf-test-open-id-user-client-role-protocol-mapper-client-scope" + realm_id = keycloak_realm.test.id + client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id + + claim_name = "foo" + multivalued = false + + client_id_for_role_mappings = keycloak_openid_client.bearer_only_client.client_id + client_role_prefix = "prefixValue" + + add_to_id_token = true + add_to_access_token = false + add_to_userinfo = false +} + +resource "keycloak_openid_user_session_note_protocol_mapper" "user_session_note_client" { + name = "tf-test-open-id-user-session-note-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + + claim_name = "foo" + claim_value_type = "String" + session_note = "bar" + + add_to_id_token = true + add_to_access_token = false +} + +resource "keycloak_openid_user_session_note_protocol_mapper" "user_session_note_client_scope" { + name = "tf-test-open-id-user-session-note-protocol-mapper-client-scope" + realm_id = keycloak_realm.test.id + client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id + + claim_name = "foo2" + claim_value_type = "String" + session_note = "bar2" + + add_to_id_token = true + add_to_access_token = false +} + +resource "keycloak_openid_client" "bearer_only_client" { + client_id = "test-bearer-only-client" + name = "test-bearer-only-client" + realm_id = keycloak_realm.test.id + description = "a test openid client using bearer-only" + + access_type = "BEARER-ONLY" +} + +resource "keycloak_openid_audience_protocol_mapper" "audience_client_scope" { + name = "tf-test-openid-audience-protocol-mapper-client-scope" + realm_id = keycloak_realm.test.id + client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id + + add_to_id_token = true + add_to_access_token = false + + included_client_audience = keycloak_openid_client.bearer_only_client.client_id +} + +resource "keycloak_openid_audience_protocol_mapper" "audience_client" { + name = "tf-test-openid-audience-protocol-mapper-client" + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + + add_to_id_token = false + add_to_access_token = true + + included_custom_audience = "foo" +} + +resource "keycloak_saml_client" "saml_client" { + realm_id = keycloak_realm.test.id + client_id = "test-saml-client" + name = "test-saml-client" + + sign_documents = false + sign_assertions = true + include_authn_statement = true + + signing_certificate = file("../provider/misc/saml-cert.pem") + signing_private_key = file("../provider/misc/saml-key.pem") +} + +resource "keycloak_saml_user_attribute_protocol_mapper" "saml_user_attribute_mapper" { + realm_id = keycloak_realm.test.id + client_id = keycloak_saml_client.saml_client.id + name = "test-saml-user-attribute-mapper" + + user_attribute = "user-attribute" + friendly_name = "friendly-name" + saml_attribute_name = "saml-attribute-name" + saml_attribute_name_format = "Unspecified" +} + +resource "keycloak_saml_user_property_protocol_mapper" "saml_user_property_mapper" { + realm_id = keycloak_realm.test.id + client_id = keycloak_saml_client.saml_client.id + name = "test-saml-user-property-mapper" + + user_property = "email" + saml_attribute_name = "email" + saml_attribute_name_format = "Unspecified" +} + +resource "keycloak_oidc_identity_provider" "oidc" { + realm = keycloak_realm.test.id + alias = "oidc" + authorization_url = "https://example.com/auth" + token_url = "https://example.com/token" + client_id = "example_id" + client_secret = "example_token" + default_scopes = "openid random profile" + sync_mode = "FORCE" + gui_order = 1 +} + +resource "keycloak_oidc_google_identity_provider" "google" { + realm = keycloak_realm.test.id + client_id = "myclientid.apps.googleusercontent.com" + client_secret = "myclientsecret" + hosted_domain = "mycompany.com" + request_refresh_token = true + default_scopes = "openid random profile" + accepts_prompt_none_forward_from_client = false + sync_mode = "FORCE" + gui_order = 2 +} + +//This example does not work in keycloak 10, because the interfaces that our customIdp implements, have changed in the keycloak latest version. +//We need to make decide which keycloak version we going to support and test for the customIdp +//resource keycloak_oidc_identity_provider custom_oidc_idp { +// realm = "${keycloak_realm.test.id}" +// provider_id = "customIdp" +// alias = "custom" +// authorization_url = "https://example.com/auth" +// token_url = "https://example.com/token" +// client_id = "example_id" +// client_secret = "example_token" +// +// extra_config = { +// dummyConfig = "dummyValue" +// } +//} + +resource "keycloak_attribute_importer_identity_provider_mapper" "oidc" { + realm = keycloak_realm.test.id + name = "attributeImporter" + claim_name = "upn" + identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias + user_attribute = "email" + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_attribute_to_role_identity_provider_mapper" "oidc" { + realm = keycloak_realm.test.id + name = "attributeToRole" + claim_name = "upn" + identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias + claim_value = "value" + role = "testRole" + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_user_template_importer_identity_provider_mapper" "oidc" { + realm = keycloak_realm.test.id + name = "userTemplate" + identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias + template = "$${ALIAS}/$${CLAIM.upn}" + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_hardcoded_role_identity_provider_mapper" "oidc" { + realm = keycloak_realm.test.id + name = "hardcodedRole" + identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias + role = "testrole" + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_hardcoded_attribute_identity_provider_mapper" "oidc" { + realm = keycloak_realm.test.id + name = "hardcodedUserSessionAttribute" + identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias + attribute_name = "attribute" + attribute_value = "value" + user_session = true + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_saml_identity_provider" "saml" { + realm = keycloak_realm.test.id + alias = "saml" + entity_id = "https://example.com/entity_id" + single_sign_on_service_url = "https://example.com/auth" + sync_mode = "FORCE" + gui_order = 3 +} + +resource "keycloak_attribute_importer_identity_provider_mapper" "saml" { + realm = keycloak_realm.test.id + name = "Attribute: email" + attribute_name = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" + identity_provider_alias = keycloak_saml_identity_provider.saml.alias + user_attribute = "email" + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_attribute_to_role_identity_provider_mapper" "saml" { + realm = keycloak_realm.test.id + name = "attributeToRole" + attribute_name = "upn" + identity_provider_alias = keycloak_saml_identity_provider.saml.alias + attribute_value = "value" + role = "testRole" + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_user_template_importer_identity_provider_mapper" "saml" { + realm = keycloak_realm.test.id + name = "userTemplate" + identity_provider_alias = keycloak_saml_identity_provider.saml.alias + template = "$${ALIAS}/$${NAMEID}" + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_hardcoded_role_identity_provider_mapper" "saml" { + realm = keycloak_realm.test.id + name = "hardcodedRole" + identity_provider_alias = keycloak_saml_identity_provider.saml.alias + role = "testrole" + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_hardcoded_attribute_identity_provider_mapper" "saml" { + realm = keycloak_realm.test.id + name = "hardcodedAttribute" + identity_provider_alias = keycloak_saml_identity_provider.saml.alias + attribute_name = "attribute" + attribute_value = "value" + user_session = false + + #KC10 support + extra_config = { + syncMode = "INHERIT" + } +} + +resource "keycloak_saml_identity_provider" "saml_custom" { + realm = keycloak_realm.test.id + alias = "custom_saml" + provider_id = "saml" + entity_id = "https://example.com/entity_id" + single_sign_on_service_url = "https://example.com/auth" + sync_mode = "FORCE" + gui_order = 4 + extra_config = { + mycustomAttribute = "aValue" + } +} + +data "keycloak_openid_client" "broker" { + realm_id = keycloak_realm.test.id + client_id = "broker" +} + +data "keycloak_openid_client_authorization_policy" "default" { + realm_id = keycloak_realm.test.id + resource_server_id = keycloak_openid_client.test_client_auth.resource_server_id + name = "default" +} + +resource "keycloak_openid_client" "test_client_auth" { + client_id = "test-client-auth" + name = "test-client-auth" + realm_id = keycloak_realm.test.id + description = "a test openid client" + + access_type = "CONFIDENTIAL" + direct_access_grants_enabled = true + implicit_flow_enabled = true + service_accounts_enabled = true + + valid_redirect_uris = [ + "http://localhost:5555/callback", + ] + + authorization { + policy_enforcement_mode = "ENFORCING" + } + + client_secret = "secret" +} + +resource "keycloak_openid_client" "test_open_id_client_with_consent_text" { + client_id = "test_open_id_client_with_consent_text" + name = "test_open_id_client_with_consent_text" + realm_id = keycloak_realm.test.id + description = "a test openid client that has consent text" + + standard_flow_enabled = true + service_accounts_enabled = true + + access_type = "CONFIDENTIAL" + + valid_redirect_uris = [ + "http://localhost:5555/callback", + ] + + client_secret = "secret" + + pkce_code_challenge_method = "plain" + + login_theme = "keycloak" + + backchannel_logout_url = "http://localhost:3333/backchannel" + backchannel_logout_session_required = true + backchannel_logout_revoke_offline_sessions = true + + extra_config = { + customAttribute = "a test custom value" + } + + consent_required = true + display_on_consent_screen = true + consent_screen_text = "some consent screen text" +} + + +resource "keycloak_openid_client_authorization_permission" "resource" { + resource_server_id = keycloak_openid_client.test_client_auth.resource_server_id + realm_id = keycloak_realm.test.id + name = "test" + + policies = [ + data.keycloak_openid_client_authorization_policy.default.id, + ] + + resources = [ + keycloak_openid_client_authorization_resource.resource.id, + ] + + scopes = [ + keycloak_openid_client_authorization_scope.resource.id + ] +} + +resource "keycloak_openid_client_authorization_resource" "resource" { + resource_server_id = keycloak_openid_client.test_client_auth.resource_server_id + name = "test-openid-client1" + realm_id = keycloak_realm.test.id + + uris = [ + "/endpoint/*", + ] + + attributes = { + "asdads" = "asdasd" + } +} + +resource "keycloak_openid_client_authorization_scope" "resource" { + resource_server_id = keycloak_openid_client.test_client_auth.resource_server_id + name = "test-openid-client1" + realm_id = keycloak_realm.test.id +} + +resource "keycloak_user" "user_with_multivalueattributes" { + realm_id = keycloak_realm.test.id + username = "user-with-mutivalueattributes" + + attributes = { + "permissions" = "permission1##permission2" + } + initial_password { + value = "My password" + temporary = false + } +} + +resource "keycloak_user" "resource" { + realm_id = keycloak_realm.test.id + username = "test" + + attributes = { + "key" = "value" + } +} + +resource "keycloak_openid_client_service_account_role" "read_token" { + realm_id = keycloak_realm.test.id + client_id = data.keycloak_openid_client.broker.id + service_account_user_id = keycloak_openid_client.test_client_auth.service_account_user_id + role = "read-token" +} + +resource "keycloak_authentication_flow" "browser-copy-flow" { + alias = "browserCopyFlow" + realm_id = keycloak_realm.test.id + description = "browser based authentication" +} + +resource "keycloak_authentication_execution" "browser-copy-cookie" { + realm_id = keycloak_realm.test.id + parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias + authenticator = "auth-cookie" + requirement = "ALTERNATIVE" + priority = 20 +} + +resource "keycloak_authentication_execution" "browser-copy-kerberos" { + realm_id = keycloak_realm.test.id + parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias + authenticator = "auth-spnego" + requirement = "DISABLED" + priority = 10 +} + +resource "keycloak_authentication_execution" "browser-copy-idp-redirect" { + realm_id = keycloak_realm.test.id + parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias + authenticator = "identity-provider-redirector" + requirement = "ALTERNATIVE" + priority = 30 +} + +resource "keycloak_authentication_subflow" "browser-copy-flow-forms" { + realm_id = keycloak_realm.test.id + parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias + alias = "browser-copy-flow-forms" + requirement = "ALTERNATIVE" + priority = 40 +} + +resource "keycloak_authentication_execution" "browser-copy-auth-username-password-form" { + realm_id = keycloak_realm.test.id + parent_flow_alias = keycloak_authentication_subflow.browser-copy-flow-forms.alias + authenticator = "auth-username-password-form" + requirement = "REQUIRED" + priority = 50 +} + +resource "keycloak_authentication_execution" "browser-copy-otp" { + realm_id = keycloak_realm.test.id + parent_flow_alias = keycloak_authentication_subflow.browser-copy-flow-forms.alias + authenticator = "auth-otp-form" + requirement = "REQUIRED" +terraform { + required_providers { + keycloak = { + source = "terraform.local/keycloak/keycloak" + version = ">= 5.0.0" + } + } +} + +provider "keycloak" { + client_id = "terraform" + client_secret = "884e0f95-0f42-4a63-9b1f-94274655669e" + url = "http://localhost:8080" + additional_headers = { + foo = "bar" + } +} + +resource "keycloak_realm" "test" { + realm = "test" + enabled = true + display_name = "foo" + display_name_html = "foo" + + smtp_server { + host = "mysmtphost.com" + port = 25 + from_display_name = "Tom" + from = "tom@myhost.com" + reply_to_display_name = "Tom" + reply_to = "tom@myhost.com" + ssl = true + starttls = true + envelope_from = "nottom@myhost.com" + + auth { + username = "tom" + password = "tom" + } + } + + account_theme = "base" + access_code_lifespan = "30m" + + internationalization { + supported_locales = [ + "en", + "de", + "es", + ] + + default_locale = "en" + } + + security_defenses { + headers { + x_frame_options = "DENY" + content_security_policy = "frame-src 'self'; frame-ancestors 'self'; object-src 'none';" + content_security_policy_report_only = "" + x_content_type_options = "nosniff" + x_robots_tag = "none" + x_xss_protection = "1; mode=block" + strict_transport_security = "max-age=31536000; includeSubDomains" + } + + brute_force_detection { + permanent_lockout = false + max_login_failures = 31 + wait_increment_seconds = 61 + quick_login_check_milli_seconds = 1000 + minimum_quick_login_wait_seconds = 120 + max_failure_wait_seconds = 900 + failure_reset_time_seconds = 43200 + } + } + + ssl_required = "external" + password_policy = "upperCase(1) and length(8) and forceExpiredPasswordChange(365) and notUsername" + + attributes = { + mycustomAttribute = "myCustomValue" + userProfileEnabled = true + } + + web_authn_policy { + relying_party_entity_name = "Example" + relying_party_id = "keycloak.example.com" + signature_algorithms = [ + "ES256", + "RS256" + ] + } + + web_authn_passwordless_policy { + relying_party_entity_name = "Example" + relying_party_id = "keycloak.example.com" + signature_algorithms = [ + "ES256", + "RS256" + ] + } +} + +resource "keycloak_required_action" "custom-terms-and-conditions" { + realm_id = keycloak_realm.test.realm + alias = "TERMS_AND_CONDITIONS" + default_action = true + enabled = true + name = "Custom Terms and Conditions" +} + +resource "keycloak_required_action" "custom-configured_totp" { + realm_id = keycloak_realm.test.realm + alias = "CONFIGURE_TOTP" + default_action = true + enabled = true + name = "Custom configure totp" + priority = keycloak_required_action.custom-terms-and-conditions.priority + 15 +} + +resource "keycloak_required_action" "required_action" { + realm_id = keycloak_realm.test.realm + alias = "webauthn-register" + enabled = true + name = "Webauthn Register" +} + +resource "keycloak_group" "foo" { + realm_id = keycloak_realm.test.id + name = "foo" +} + +resource "keycloak_group" "nested_foo" { + realm_id = keycloak_realm.test.id + parent_id = keycloak_group.foo.id + name = "nested-foo" +} + +resource "keycloak_group" "bar" { + realm_id = keycloak_realm.test.id + name = "bar" +} + +resource "keycloak_user" "user" { + realm_id = keycloak_realm.test.id + username = "test-user" + + email = "test-user@fakedomain.com" + first_name = "Testy" + last_name = "Tester" +} + +resource "keycloak_user" "another_user" { + realm_id = keycloak_realm.test.id + username = "another-test-user" + + email = "another-test-user@fakedomain.com" + first_name = "Testy" + last_name = "Tester" +} + +resource "keycloak_user" "user_with_password" { + realm_id = keycloak_realm.test.id + username = "user-with-password" + + email = "user-with-password@fakedomain.com" + first_name = "Testy" + last_name = "Tester" + + initial_password { + value = "My password" + temporary = false + } +} + +resource "keycloak_group_memberships" "foo_members" { + realm_id = keycloak_realm.test.id + group_id = keycloak_group.foo.id + + members = [ + keycloak_user.user.username, + keycloak_user.another_user.username, + ] +} + +resource "keycloak_group" "baz" { + realm_id = keycloak_realm.test.id + name = "baz" +} + +resource "keycloak_default_groups" "default" { + realm_id = keycloak_realm.test.id + group_ids = [ + keycloak_group.baz.id + ] +} + +resource "keycloak_openid_client" "test_client" { + client_id = "test-openid-client" + name = "test-openid-client" + realm_id = keycloak_realm.test.id + description = "a test openid client" + + standard_flow_enabled = true + service_accounts_enabled = true + + access_type = "CONFIDENTIAL" + + valid_redirect_uris = [ + "http://localhost:5555/callback", + ] + valid_post_logout_redirect_uris = [ + "http://localhost:5555/post-logout", + "http://localhost:5555/post-logout3", + ] + + client_secret = "secret" + + pkce_code_challenge_method = "plain" + + login_theme = "keycloak" + + backchannel_logout_url = "http://localhost:3333/backchannel" + backchannel_logout_session_required = true + backchannel_logout_revoke_offline_sessions = true + + extra_config = { + customAttribute = "a test custom value" + } +} + +resource "keycloak_openid_client_scope" "test_default_client_scope" { + name = "test-default-client-scope" + realm_id = keycloak_realm.test.id + + description = "test" + consent_screen_text = "hello" +} + +resource "keycloak_openid_client_scope" "test_optional_client_scope" { + name = "test-optional-client-scope" + realm_id = keycloak_realm.test.id + + description = "test" + consent_screen_text = "hello" +} + +resource "keycloak_openid_client_default_scopes" "default_client_scopes" { + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + + default_scopes = [ + "profile", + "email", + "roles", + "web-origins", + keycloak_openid_client_scope.test_default_client_scope.name, + ] +} + +resource "keycloak_openid_client_optional_scopes" "optional_client_scopes" { + realm_id = keycloak_realm.test.id + client_id = keycloak_openid_client.test_client.id + + optional_scopes = [ + "address", + "phone", + "offline_access", + "microprofile-jwt", + keycloak_openid_client_scope.test_optional_client_scope.name, + ] +} + +resource "keycloak_ldap_user_federation" "openldap" { + name = "openldap" + realm_id = keycloak_realm.test.id + + enabled = true + import_enabled = false + + username_ldap_attribute = "cn" + rdn_ldap_attribute = "cn" + uuid_ldap_attribute = "entryDN" + + user_object_classes = [ + "simpleSecurityObject", + "organizationalRole", + ] + + connection_url = "ldap://openldap" + users_dn = "dc=example,dc=org" + bind_dn = "cn=admin,dc=example,dc=org" + bind_credential = "adminpassword" + + connection_timeout = "5s" + read_timeout = "10s" + + kerberos { + server_principal = "HTTP/keycloak.local@FOO.LOCAL" + use_kerberos_for_password_authentication = false + key_tab = "/etc/keycloak.keytab" + kerberos_realm = "FOO.LOCAL" + } + + cache { + policy = "NO_CACHE" + } +} + + +resource "keycloak_ldap_user_federation" "openldap_no_default_mappers" { + name = "openldap-no-default-mappers" + realm_id = keycloak_realm.test.id + + enabled = true + import_enabled = false + + username_ldap_attribute = "cn" + rdn_ldap_attribute = "cn" + uuid_ldap_attribute = "entryDN" + + user_object_classes = [ + "simpleSecurityObject", + "organizationalRole", + ] + + connection_url = "ldap://openldap" + users_dn = "dc=example,dc=org" + bind_dn = "cn=admin,dc=example,dc=org" + bind_credential = "adminpassword" + + connection_timeout = "5s" + read_timeout = "10s" + + kerberos { + server_principal = "HTTP/keycloak.local@FOO.LOCAL" + use_kerberos_for_password_authentication = false + key_tab = "/etc/keycloak.keytab" + kerberos_realm = "FOO.LOCAL" + } + + cache { + policy = "NO_CACHE" + } + + delete_default_mappers = true +} + +resource "keycloak_ldap_role_mapper" "ldap_role_mapper" { + realm_id = keycloak_realm.test.id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + name = "role-mapper" + + ldap_roles_dn = "dc=example,dc=org" + role_name_ldap_attribute = "cn" + role_object_classes = [ + "groupOfNames" + ] + membership_attribute_type = "DN" + membership_ldap_attribute = "member" + membership_user_ldap_attribute = "cn" + user_roles_retrieve_strategy = "GET_ROLES_FROM_USER_MEMBEROF_ATTRIBUTE" + memberof_ldap_attribute = "memberOf" +} + +resource "keycloak_ldap_user_attribute_mapper" "description_attr_mapper" { + name = "description-mapper" realm_id = keycloak_ldap_user_federation.openldap.realm_id ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - provider_id = "msad-user-account-control-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + user_model_attribute = "description" + ldap_attribute = "description" + + always_read_value_from_ldap = false } -resource "keycloak_ldap_custom_mapper" "custom_mapper_with_config" { - name = "custom-mapper-with-config" +resource "keycloak_ldap_user_attribute_mapper" "default_attr_mapper" { + name = "defaultval-mapper" realm_id = keycloak_ldap_user_federation.openldap.realm_id ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - provider_id = "user-attribute-ldap-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" - config = { - "user.model.attribute" = "username" - "ldap.attribute" = "cn" - } + user_model_attribute = "defaultval" + ldap_attribute = "defaultval" + + always_read_value_from_ldap = false + is_mandatory_in_ldap = true + attribute_default_value = "testing" +} + +resource "keycloak_ldap_group_mapper" "group_mapper" { + name = "group mapper" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + + ldap_groups_dn = "dc=example,dc=org" + group_name_ldap_attribute = "cn" + + group_object_classes = [ + "groupOfNames", + ] + + membership_attribute_type = "DN" + membership_ldap_attribute = "member" + membership_user_ldap_attribute = "cn" + memberof_ldap_attribute = "memberOf" +} + +resource "keycloak_ldap_msad_user_account_control_mapper" "msad_uac_mapper" { + name = "uac-mapper1" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id +} + +resource "keycloak_ldap_msad_lds_user_account_control_mapper" "msad_lds_uac_mapper" { + name = "msad-lds-uac-mapper" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id +} + +resource "keycloak_ldap_full_name_mapper" "full_name_mapper" { + name = "full-name-mapper" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + + ldap_full_name_attribute = "cn" + read_only = true +} + +resource "keycloak_ldap_custom_mapper" "custom_mapper" { + name = "custom-mapper" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + + provider_id = "msad-user-account-control-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" +} + +resource "keycloak_ldap_custom_mapper" "custom_mapper_with_config" { + name = "custom-mapper-with-config" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + + provider_id = "user-attribute-ldap-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + config = { + "user.model.attribute" = "username" + "ldap.attribute" = "cn" + } } diff --git a/provider/resource_keycloak_required_action.go b/provider/resource_keycloak_required_action.go index dd52459e3..c9e046651 100644 --- a/provider/resource_keycloak_required_action.go +++ b/provider/resource_keycloak_required_action.go @@ -4,11 +4,10 @@ import ( "context" "errors" "fmt" - "strings" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/keycloak/terraform-provider-keycloak/keycloak" + "strings" ) func resourceKeycloakRequiredAction() *schema.Resource { diff --git a/terraform-registry-manifest.json b/terraform-registry-manifest.json deleted file mode 100644 index 5d14f2e9d..000000000 --- a/terraform-registry-manifest.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "version": 1, - "metadata": { - "protocol_versions": ["5.0"] - } -} From 00a07b49ce4951e73a2b7e73166f633caf94886f Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Mon, 10 Feb 2025 17:50:02 +0100 Subject: [PATCH 11/12] remove multivalued Signed-off-by: Laureat Grepi --- docs/resources/realm_user_profile.md | 2 - example/main.tf | 1089 +---------------- keycloak/realm_user_profile.go | 1 - .../resource_keycloak_realm_user_profile.go | 6 - 4 files changed, 21 insertions(+), 1077 deletions(-) diff --git a/docs/resources/realm_user_profile.md b/docs/resources/realm_user_profile.md index ae56b2fa7..26a8aec82 100644 --- a/docs/resources/realm_user_profile.md +++ b/docs/resources/realm_user_profile.md @@ -58,7 +58,6 @@ resource "keycloak_realm_user_profile" "userprofile" { attribute { name = "field2" - multivalued = true validator { name = "options" @@ -102,7 +101,6 @@ resource "keycloak_realm_user_profile" "userprofile" { - `display_name` - (Optional) The display name of the attribute. - `multi_valued` - (Optional) If the attribute supports multiple values. Defaults to `false`. - `group` - (Optional) The group that the attribute belong to. -- `multivalued` - (Optional) The attribute can contain multiple values. Defaults to `false`. - `enabled_when_scope` - (Optional) A list of scopes. The attribute will only be enabled when these scopes are requested by clients. - `required_for_roles` - (Optional) A list of roles for which the attribute will be required. - `required_for_scopes` - (Optional) A list of scopes for which the attribute will be required. diff --git a/example/main.tf b/example/main.tf index e38654d02..b7ad672e4 100644 --- a/example/main.tf +++ b/example/main.tf @@ -136,1052 +136,6 @@ resource "keycloak_required_action" "required_action" { name = "Webauthn Register" } -resource "keycloak_group" "foo" { - realm_id = keycloak_realm.test.id - name = "foo" -} - -resource "keycloak_group" "nested_foo" { - realm_id = keycloak_realm.test.id - parent_id = keycloak_group.foo.id - name = "nested-foo" -} - -resource "keycloak_group" "bar" { - realm_id = keycloak_realm.test.id - name = "bar" -} - -resource "keycloak_user" "user" { - realm_id = keycloak_realm.test.id - username = "test-user" - - email = "test-user@fakedomain.com" - first_name = "Testy" - last_name = "Tester" -} - -resource "keycloak_user" "another_user" { - realm_id = keycloak_realm.test.id - username = "another-test-user" - - email = "another-test-user@fakedomain.com" - first_name = "Testy" - last_name = "Tester" -} - -resource "keycloak_user" "user_with_password" { - realm_id = keycloak_realm.test.id - username = "user-with-password" - - email = "user-with-password@fakedomain.com" - first_name = "Testy" - last_name = "Tester" - - initial_password { - value = "My password" - temporary = false - } -} - -resource "keycloak_group_memberships" "foo_members" { - realm_id = keycloak_realm.test.id - group_id = keycloak_group.foo.id - - members = [ - keycloak_user.user.username, - keycloak_user.another_user.username, - ] -} - -resource "keycloak_group" "baz" { - realm_id = keycloak_realm.test.id - name = "baz" -} - -resource "keycloak_default_groups" "default" { - realm_id = keycloak_realm.test.id - group_ids = [ - keycloak_group.baz.id - ] -} - -resource "keycloak_openid_client" "test_client" { - client_id = "test-openid-client" - name = "test-openid-client" - realm_id = keycloak_realm.test.id - description = "a test openid client" - - standard_flow_enabled = true - service_accounts_enabled = true - - access_type = "CONFIDENTIAL" - - valid_redirect_uris = [ - "http://localhost:5555/callback", - ] - valid_post_logout_redirect_uris = [ - "http://localhost:5555/post-logout", - "http://localhost:5555/post-logout3", - ] - - client_secret = "secret" - - pkce_code_challenge_method = "plain" - - login_theme = "keycloak" - - backchannel_logout_url = "http://localhost:3333/backchannel" - backchannel_logout_session_required = true - backchannel_logout_revoke_offline_sessions = true - - extra_config = { - customAttribute = "a test custom value" - } -} - -resource "keycloak_openid_client_scope" "test_default_client_scope" { - name = "test-default-client-scope" - realm_id = keycloak_realm.test.id - - description = "test" - consent_screen_text = "hello" -} - -resource "keycloak_openid_client_scope" "test_optional_client_scope" { - name = "test-optional-client-scope" - realm_id = keycloak_realm.test.id - - description = "test" - consent_screen_text = "hello" -} - -resource "keycloak_openid_client_default_scopes" "default_client_scopes" { - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - - default_scopes = [ - "profile", - "email", - "roles", - "web-origins", - keycloak_openid_client_scope.test_default_client_scope.name, - ] -} - -resource "keycloak_openid_client_optional_scopes" "optional_client_scopes" { - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - - optional_scopes = [ - "address", - "phone", - "offline_access", - "microprofile-jwt", - keycloak_openid_client_scope.test_optional_client_scope.name, - ] -} - -resource "keycloak_ldap_user_federation" "openldap" { - name = "openldap" - realm_id = keycloak_realm.test.id - - enabled = true - import_enabled = false - - username_ldap_attribute = "cn" - rdn_ldap_attribute = "cn" - uuid_ldap_attribute = "entryDN" - - user_object_classes = [ - "simpleSecurityObject", - "organizationalRole", - ] - - connection_url = "ldap://openldap" - users_dn = "dc=example,dc=org" - bind_dn = "cn=admin,dc=example,dc=org" - bind_credential = "adminpassword" - - connection_timeout = "5s" - read_timeout = "10s" - - kerberos { - server_principal = "HTTP/keycloak.local@FOO.LOCAL" - use_kerberos_for_password_authentication = false - key_tab = "/etc/keycloak.keytab" - kerberos_realm = "FOO.LOCAL" - } - - cache { - policy = "NO_CACHE" - } -} - - -resource "keycloak_ldap_user_federation" "openldap_no_default_mappers" { - name = "openldap-no-default-mappers" - realm_id = keycloak_realm.test.id - - enabled = true - import_enabled = false - - username_ldap_attribute = "cn" - rdn_ldap_attribute = "cn" - uuid_ldap_attribute = "entryDN" - - user_object_classes = [ - "simpleSecurityObject", - "organizationalRole", - ] - - connection_url = "ldap://openldap" - users_dn = "dc=example,dc=org" - bind_dn = "cn=admin,dc=example,dc=org" - bind_credential = "adminpassword" - - connection_timeout = "5s" - read_timeout = "10s" - - kerberos { - server_principal = "HTTP/keycloak.local@FOO.LOCAL" - use_kerberos_for_password_authentication = false - key_tab = "/etc/keycloak.keytab" - kerberos_realm = "FOO.LOCAL" - } - - cache { - policy = "NO_CACHE" - } - - delete_default_mappers = true -} - -resource "keycloak_ldap_role_mapper" "ldap_role_mapper" { - realm_id = keycloak_realm.test.id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - name = "role-mapper" - - ldap_roles_dn = "dc=example,dc=org" - role_name_ldap_attribute = "cn" - role_object_classes = [ - "groupOfNames" - ] - membership_attribute_type = "DN" - membership_ldap_attribute = "member" - membership_user_ldap_attribute = "cn" - user_roles_retrieve_strategy = "GET_ROLES_FROM_USER_MEMBEROF_ATTRIBUTE" - memberof_ldap_attribute = "memberOf" -} - -resource "keycloak_ldap_user_attribute_mapper" "description_attr_mapper" { - name = "description-mapper" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - - user_model_attribute = "description" - ldap_attribute = "description" - - always_read_value_from_ldap = false -} - -resource "keycloak_ldap_user_attribute_mapper" "default_attr_mapper" { - name = "defaultval-mapper" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - - user_model_attribute = "defaultval" - ldap_attribute = "defaultval" - - always_read_value_from_ldap = false - is_mandatory_in_ldap = true - attribute_default_value = "testing" -} - -resource "keycloak_ldap_group_mapper" "group_mapper" { - name = "group mapper" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - - ldap_groups_dn = "dc=example,dc=org" - group_name_ldap_attribute = "cn" - - group_object_classes = [ - "groupOfNames", - ] - - membership_attribute_type = "DN" - membership_ldap_attribute = "member" - membership_user_ldap_attribute = "cn" - memberof_ldap_attribute = "memberOf" -} - -resource "keycloak_ldap_msad_user_account_control_mapper" "msad_uac_mapper" { - name = "uac-mapper1" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id -} - -resource "keycloak_ldap_msad_lds_user_account_control_mapper" "msad_lds_uac_mapper" { - name = "msad-lds-uac-mapper" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id -} - -resource "keycloak_ldap_full_name_mapper" "full_name_mapper" { - name = "full-name-mapper" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - - ldap_full_name_attribute = "cn" - read_only = true -} - -resource "keycloak_ldap_custom_mapper" "custom_mapper" { - name = "custom-mapper" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - - provider_id = "msad-user-account-control-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" -} - -resource "keycloak_ldap_custom_mapper" "custom_mapper_with_config" { - name = "custom-mapper-with-config" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - - provider_id = "user-attribute-ldap-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" - config = { - "user.model.attribute" = "username" - "ldap.attribute" = "cn" - } -} - - -resource "keycloak_custom_user_federation" "custom" { - name = "custom1" - realm_id = "master" - provider_id = "custom" - - enabled = true -} - -resource "keycloak_openid_user_attribute_protocol_mapper" "map_user_attributes_client" { - name = "tf-test-open-id-user-attribute-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - user_attribute = "description" - claim_name = "description" -} - -resource "keycloak_openid_user_attribute_protocol_mapper" "map_user_permissions_attributes_client" { - name = "tf-test-open-id-user-multivalue-attribute-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - user_attribute = "permissions" - claim_name = "permissions" - multivalued = true -} - - -resource "keycloak_openid_user_attribute_protocol_mapper" "map_user_attributes_client_scope" { - name = "tf-test-open-id-user-attribute-protocol-mapper-client-scope" - realm_id = keycloak_realm.test.id - client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id - user_attribute = "foo2" - claim_name = "bar2" -} - -resource "keycloak_openid_group_membership_protocol_mapper" "map_group_memberships_client" { - name = "tf-test-open-id-group-membership-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - claim_name = "bar" -} - -resource "keycloak_openid_group_membership_protocol_mapper" "map_group_memberships_client_scope" { - name = "tf-test-open-id-group-membership-protocol-mapper-client-scope" - realm_id = keycloak_realm.test.id - client_scope_id = keycloak_openid_client_scope.test_optional_client_scope.id - claim_name = "bar2" -} - -resource "keycloak_openid_full_name_protocol_mapper" "map_full_names_client" { - name = "tf-test-open-id-full-name-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id -} - -resource "keycloak_openid_full_name_protocol_mapper" "map_full_names_client_scope" { - name = "tf-test-open-id-full-name-protocol-mapper-client-scope" - realm_id = keycloak_realm.test.id - client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id -} - -resource "keycloak_openid_user_property_protocol_mapper" "map_user_properties_client" { - name = "tf-test-open-id-user-property-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - user_property = "foo" - claim_name = "bar" -} - -resource "keycloak_openid_user_property_protocol_mapper" "map_user_properties_client_scope" { - name = "tf-test-open-id-user-property-protocol-mapper-client-scope" - realm_id = keycloak_realm.test.id - client_scope_id = keycloak_openid_client_scope.test_optional_client_scope.id - user_property = "foo2" - claim_name = "bar2" -} - -resource "keycloak_openid_hardcoded_claim_protocol_mapper" "hardcoded_claim_client" { - name = "tf-test-open-id-hardcoded-claim-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - - claim_name = "foo" - claim_value = "bar" -} - -resource "keycloak_openid_hardcoded_claim_protocol_mapper" "hardcoded_claim_client_scope" { - name = "tf-test-open-id-hardcoded-claim-protocol-mapper-client-scope" - realm_id = keycloak_realm.test.id - client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id - - claim_name = "foo" - claim_value = "bar" -} - -resource "keycloak_openid_user_realm_role_protocol_mapper" "user_realm_role_client" { - name = "tf-test-open-id-user-realm-role-claim-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - - claim_name = "foo" -} - -resource "keycloak_openid_user_realm_role_protocol_mapper" "user_realm_role_client_scope" { - name = "tf-test-open-id-user-realm-role-protocol-mapper-client-scope" - realm_id = keycloak_realm.test.id - client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id - - claim_name = "foo" -} - -resource "keycloak_openid_user_client_role_protocol_mapper" "user_client_role_client" { - name = "tf-test-open-id-user-client-role-claim-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - - claim_name = "foo" - multivalued = false - - client_id_for_role_mappings = keycloak_openid_client.bearer_only_client.client_id - client_role_prefix = "prefixValue" - - add_to_id_token = true - add_to_access_token = false - add_to_userinfo = false -} - -resource "keycloak_openid_user_client_role_protocol_mapper" "user_client_role_client_scope" { - name = "tf-test-open-id-user-client-role-protocol-mapper-client-scope" - realm_id = keycloak_realm.test.id - client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id - - claim_name = "foo" - multivalued = false - - client_id_for_role_mappings = keycloak_openid_client.bearer_only_client.client_id - client_role_prefix = "prefixValue" - - add_to_id_token = true - add_to_access_token = false - add_to_userinfo = false -} - -resource "keycloak_openid_user_session_note_protocol_mapper" "user_session_note_client" { - name = "tf-test-open-id-user-session-note-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - - claim_name = "foo" - claim_value_type = "String" - session_note = "bar" - - add_to_id_token = true - add_to_access_token = false -} - -resource "keycloak_openid_user_session_note_protocol_mapper" "user_session_note_client_scope" { - name = "tf-test-open-id-user-session-note-protocol-mapper-client-scope" - realm_id = keycloak_realm.test.id - client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id - - claim_name = "foo2" - claim_value_type = "String" - session_note = "bar2" - - add_to_id_token = true - add_to_access_token = false -} - -resource "keycloak_openid_client" "bearer_only_client" { - client_id = "test-bearer-only-client" - name = "test-bearer-only-client" - realm_id = keycloak_realm.test.id - description = "a test openid client using bearer-only" - - access_type = "BEARER-ONLY" -} - -resource "keycloak_openid_audience_protocol_mapper" "audience_client_scope" { - name = "tf-test-openid-audience-protocol-mapper-client-scope" - realm_id = keycloak_realm.test.id - client_scope_id = keycloak_openid_client_scope.test_default_client_scope.id - - add_to_id_token = true - add_to_access_token = false - - included_client_audience = keycloak_openid_client.bearer_only_client.client_id -} - -resource "keycloak_openid_audience_protocol_mapper" "audience_client" { - name = "tf-test-openid-audience-protocol-mapper-client" - realm_id = keycloak_realm.test.id - client_id = keycloak_openid_client.test_client.id - - add_to_id_token = false - add_to_access_token = true - - included_custom_audience = "foo" -} - -resource "keycloak_saml_client" "saml_client" { - realm_id = keycloak_realm.test.id - client_id = "test-saml-client" - name = "test-saml-client" - - sign_documents = false - sign_assertions = true - include_authn_statement = true - - signing_certificate = file("../provider/misc/saml-cert.pem") - signing_private_key = file("../provider/misc/saml-key.pem") -} - -resource "keycloak_saml_user_attribute_protocol_mapper" "saml_user_attribute_mapper" { - realm_id = keycloak_realm.test.id - client_id = keycloak_saml_client.saml_client.id - name = "test-saml-user-attribute-mapper" - - user_attribute = "user-attribute" - friendly_name = "friendly-name" - saml_attribute_name = "saml-attribute-name" - saml_attribute_name_format = "Unspecified" -} - -resource "keycloak_saml_user_property_protocol_mapper" "saml_user_property_mapper" { - realm_id = keycloak_realm.test.id - client_id = keycloak_saml_client.saml_client.id - name = "test-saml-user-property-mapper" - - user_property = "email" - saml_attribute_name = "email" - saml_attribute_name_format = "Unspecified" -} - -resource "keycloak_oidc_identity_provider" "oidc" { - realm = keycloak_realm.test.id - alias = "oidc" - authorization_url = "https://example.com/auth" - token_url = "https://example.com/token" - client_id = "example_id" - client_secret = "example_token" - default_scopes = "openid random profile" - sync_mode = "FORCE" - gui_order = 1 -} - -resource "keycloak_oidc_google_identity_provider" "google" { - realm = keycloak_realm.test.id - client_id = "myclientid.apps.googleusercontent.com" - client_secret = "myclientsecret" - hosted_domain = "mycompany.com" - request_refresh_token = true - default_scopes = "openid random profile" - accepts_prompt_none_forward_from_client = false - sync_mode = "FORCE" - gui_order = 2 -} - -//This example does not work in keycloak 10, because the interfaces that our customIdp implements, have changed in the keycloak latest version. -//We need to make decide which keycloak version we going to support and test for the customIdp -//resource keycloak_oidc_identity_provider custom_oidc_idp { -// realm = "${keycloak_realm.test.id}" -// provider_id = "customIdp" -// alias = "custom" -// authorization_url = "https://example.com/auth" -// token_url = "https://example.com/token" -// client_id = "example_id" -// client_secret = "example_token" -// -// extra_config = { -// dummyConfig = "dummyValue" -// } -//} - -resource "keycloak_attribute_importer_identity_provider_mapper" "oidc" { - realm = keycloak_realm.test.id - name = "attributeImporter" - claim_name = "upn" - identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias - user_attribute = "email" - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_attribute_to_role_identity_provider_mapper" "oidc" { - realm = keycloak_realm.test.id - name = "attributeToRole" - claim_name = "upn" - identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias - claim_value = "value" - role = "testRole" - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_user_template_importer_identity_provider_mapper" "oidc" { - realm = keycloak_realm.test.id - name = "userTemplate" - identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias - template = "$${ALIAS}/$${CLAIM.upn}" - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_hardcoded_role_identity_provider_mapper" "oidc" { - realm = keycloak_realm.test.id - name = "hardcodedRole" - identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias - role = "testrole" - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_hardcoded_attribute_identity_provider_mapper" "oidc" { - realm = keycloak_realm.test.id - name = "hardcodedUserSessionAttribute" - identity_provider_alias = keycloak_oidc_identity_provider.oidc.alias - attribute_name = "attribute" - attribute_value = "value" - user_session = true - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_saml_identity_provider" "saml" { - realm = keycloak_realm.test.id - alias = "saml" - entity_id = "https://example.com/entity_id" - single_sign_on_service_url = "https://example.com/auth" - sync_mode = "FORCE" - gui_order = 3 -} - -resource "keycloak_attribute_importer_identity_provider_mapper" "saml" { - realm = keycloak_realm.test.id - name = "Attribute: email" - attribute_name = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" - identity_provider_alias = keycloak_saml_identity_provider.saml.alias - user_attribute = "email" - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_attribute_to_role_identity_provider_mapper" "saml" { - realm = keycloak_realm.test.id - name = "attributeToRole" - attribute_name = "upn" - identity_provider_alias = keycloak_saml_identity_provider.saml.alias - attribute_value = "value" - role = "testRole" - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_user_template_importer_identity_provider_mapper" "saml" { - realm = keycloak_realm.test.id - name = "userTemplate" - identity_provider_alias = keycloak_saml_identity_provider.saml.alias - template = "$${ALIAS}/$${NAMEID}" - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_hardcoded_role_identity_provider_mapper" "saml" { - realm = keycloak_realm.test.id - name = "hardcodedRole" - identity_provider_alias = keycloak_saml_identity_provider.saml.alias - role = "testrole" - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_hardcoded_attribute_identity_provider_mapper" "saml" { - realm = keycloak_realm.test.id - name = "hardcodedAttribute" - identity_provider_alias = keycloak_saml_identity_provider.saml.alias - attribute_name = "attribute" - attribute_value = "value" - user_session = false - - #KC10 support - extra_config = { - syncMode = "INHERIT" - } -} - -resource "keycloak_saml_identity_provider" "saml_custom" { - realm = keycloak_realm.test.id - alias = "custom_saml" - provider_id = "saml" - entity_id = "https://example.com/entity_id" - single_sign_on_service_url = "https://example.com/auth" - sync_mode = "FORCE" - gui_order = 4 - extra_config = { - mycustomAttribute = "aValue" - } -} - -data "keycloak_openid_client" "broker" { - realm_id = keycloak_realm.test.id - client_id = "broker" -} - -data "keycloak_openid_client_authorization_policy" "default" { - realm_id = keycloak_realm.test.id - resource_server_id = keycloak_openid_client.test_client_auth.resource_server_id - name = "default" -} - -resource "keycloak_openid_client" "test_client_auth" { - client_id = "test-client-auth" - name = "test-client-auth" - realm_id = keycloak_realm.test.id - description = "a test openid client" - - access_type = "CONFIDENTIAL" - direct_access_grants_enabled = true - implicit_flow_enabled = true - service_accounts_enabled = true - - valid_redirect_uris = [ - "http://localhost:5555/callback", - ] - - authorization { - policy_enforcement_mode = "ENFORCING" - } - - client_secret = "secret" -} - -resource "keycloak_openid_client" "test_open_id_client_with_consent_text" { - client_id = "test_open_id_client_with_consent_text" - name = "test_open_id_client_with_consent_text" - realm_id = keycloak_realm.test.id - description = "a test openid client that has consent text" - - standard_flow_enabled = true - service_accounts_enabled = true - - access_type = "CONFIDENTIAL" - - valid_redirect_uris = [ - "http://localhost:5555/callback", - ] - - client_secret = "secret" - - pkce_code_challenge_method = "plain" - - login_theme = "keycloak" - - backchannel_logout_url = "http://localhost:3333/backchannel" - backchannel_logout_session_required = true - backchannel_logout_revoke_offline_sessions = true - - extra_config = { - customAttribute = "a test custom value" - } - - consent_required = true - display_on_consent_screen = true - consent_screen_text = "some consent screen text" -} - - -resource "keycloak_openid_client_authorization_permission" "resource" { - resource_server_id = keycloak_openid_client.test_client_auth.resource_server_id - realm_id = keycloak_realm.test.id - name = "test" - - policies = [ - data.keycloak_openid_client_authorization_policy.default.id, - ] - - resources = [ - keycloak_openid_client_authorization_resource.resource.id, - ] - - scopes = [ - keycloak_openid_client_authorization_scope.resource.id - ] -} - -resource "keycloak_openid_client_authorization_resource" "resource" { - resource_server_id = keycloak_openid_client.test_client_auth.resource_server_id - name = "test-openid-client1" - realm_id = keycloak_realm.test.id - - uris = [ - "/endpoint/*", - ] - - attributes = { - "asdads" = "asdasd" - } -} - -resource "keycloak_openid_client_authorization_scope" "resource" { - resource_server_id = keycloak_openid_client.test_client_auth.resource_server_id - name = "test-openid-client1" - realm_id = keycloak_realm.test.id -} - -resource "keycloak_user" "user_with_multivalueattributes" { - realm_id = keycloak_realm.test.id - username = "user-with-mutivalueattributes" - - attributes = { - "permissions" = "permission1##permission2" - } - initial_password { - value = "My password" - temporary = false - } -} - -resource "keycloak_user" "resource" { - realm_id = keycloak_realm.test.id - username = "test" - - attributes = { - "key" = "value" - } -} - -resource "keycloak_openid_client_service_account_role" "read_token" { - realm_id = keycloak_realm.test.id - client_id = data.keycloak_openid_client.broker.id - service_account_user_id = keycloak_openid_client.test_client_auth.service_account_user_id - role = "read-token" -} - -resource "keycloak_authentication_flow" "browser-copy-flow" { - alias = "browserCopyFlow" - realm_id = keycloak_realm.test.id - description = "browser based authentication" -} - -resource "keycloak_authentication_execution" "browser-copy-cookie" { - realm_id = keycloak_realm.test.id - parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias - authenticator = "auth-cookie" - requirement = "ALTERNATIVE" - priority = 20 -} - -resource "keycloak_authentication_execution" "browser-copy-kerberos" { - realm_id = keycloak_realm.test.id - parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias - authenticator = "auth-spnego" - requirement = "DISABLED" - priority = 10 -} - -resource "keycloak_authentication_execution" "browser-copy-idp-redirect" { - realm_id = keycloak_realm.test.id - parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias - authenticator = "identity-provider-redirector" - requirement = "ALTERNATIVE" - priority = 30 -} - -resource "keycloak_authentication_subflow" "browser-copy-flow-forms" { - realm_id = keycloak_realm.test.id - parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias - alias = "browser-copy-flow-forms" - requirement = "ALTERNATIVE" - priority = 40 -} - -resource "keycloak_authentication_execution" "browser-copy-auth-username-password-form" { - realm_id = keycloak_realm.test.id - parent_flow_alias = keycloak_authentication_subflow.browser-copy-flow-forms.alias - authenticator = "auth-username-password-form" - requirement = "REQUIRED" - priority = 50 -} - -resource "keycloak_authentication_execution" "browser-copy-otp" { - realm_id = keycloak_realm.test.id - parent_flow_alias = keycloak_authentication_subflow.browser-copy-flow-forms.alias - authenticator = "auth-otp-form" - requirement = "REQUIRED" -terraform { - required_providers { - keycloak = { - source = "terraform.local/keycloak/keycloak" - version = ">= 5.0.0" - } - } -} - -provider "keycloak" { - client_id = "terraform" - client_secret = "884e0f95-0f42-4a63-9b1f-94274655669e" - url = "http://localhost:8080" - additional_headers = { - foo = "bar" - } -} - -resource "keycloak_realm" "test" { - realm = "test" - enabled = true - display_name = "foo" - display_name_html = "foo" - - smtp_server { - host = "mysmtphost.com" - port = 25 - from_display_name = "Tom" - from = "tom@myhost.com" - reply_to_display_name = "Tom" - reply_to = "tom@myhost.com" - ssl = true - starttls = true - envelope_from = "nottom@myhost.com" - - auth { - username = "tom" - password = "tom" - } - } - - account_theme = "base" - access_code_lifespan = "30m" - - internationalization { - supported_locales = [ - "en", - "de", - "es", - ] - - default_locale = "en" - } - - security_defenses { - headers { - x_frame_options = "DENY" - content_security_policy = "frame-src 'self'; frame-ancestors 'self'; object-src 'none';" - content_security_policy_report_only = "" - x_content_type_options = "nosniff" - x_robots_tag = "none" - x_xss_protection = "1; mode=block" - strict_transport_security = "max-age=31536000; includeSubDomains" - } - - brute_force_detection { - permanent_lockout = false - max_login_failures = 31 - wait_increment_seconds = 61 - quick_login_check_milli_seconds = 1000 - minimum_quick_login_wait_seconds = 120 - max_failure_wait_seconds = 900 - failure_reset_time_seconds = 43200 - } - } - - ssl_required = "external" - password_policy = "upperCase(1) and length(8) and forceExpiredPasswordChange(365) and notUsername" - - attributes = { - mycustomAttribute = "myCustomValue" - userProfileEnabled = true - } - - web_authn_policy { - relying_party_entity_name = "Example" - relying_party_id = "keycloak.example.com" - signature_algorithms = [ - "ES256", - "RS256" - ] - } - - web_authn_passwordless_policy { - relying_party_entity_name = "Example" - relying_party_id = "keycloak.example.com" - signature_algorithms = [ - "ES256", - "RS256" - ] - } -} - -resource "keycloak_required_action" "custom-terms-and-conditions" { - realm_id = keycloak_realm.test.realm - alias = "TERMS_AND_CONDITIONS" - default_action = true - enabled = true - name = "Custom Terms and Conditions" -} - resource "keycloak_required_action" "custom-configured_totp" { realm_id = keycloak_realm.test.realm alias = "CONFIGURE_TOTP" @@ -1500,25 +454,25 @@ resource "keycloak_ldap_full_name_mapper" "full_name_mapper" { } resource "keycloak_ldap_custom_mapper" "custom_mapper" { - name = "custom-mapper" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + name = "custom-mapper" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - provider_id = "msad-user-account-control-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + provider_id = "msad-user-account-control-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" } resource "keycloak_ldap_custom_mapper" "custom_mapper_with_config" { - name = "custom-mapper-with-config" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + name = "custom-mapper-with-config" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - provider_id = "user-attribute-ldap-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" - config = { - "user.model.attribute" = "username" - "ldap.attribute" = "cn" - } + provider_id = "user-attribute-ldap-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + config = { + "user.model.attribute" = "username" + "ldap.attribute" = "cn" + } } @@ -2093,7 +1047,7 @@ resource "keycloak_authentication_execution" "browser-copy-cookie" { parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias authenticator = "auth-cookie" requirement = "ALTERNATIVE" - priority = 20 + priority = 20 } resource "keycloak_authentication_execution" "browser-copy-kerberos" { @@ -2101,7 +1055,7 @@ resource "keycloak_authentication_execution" "browser-copy-kerberos" { parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias authenticator = "auth-spnego" requirement = "DISABLED" - priority = 10 + priority = 10 } resource "keycloak_authentication_execution" "browser-copy-idp-redirect" { @@ -2109,7 +1063,7 @@ resource "keycloak_authentication_execution" "browser-copy-idp-redirect" { parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias authenticator = "identity-provider-redirector" requirement = "ALTERNATIVE" - priority = 30 + priority = 30 } resource "keycloak_authentication_subflow" "browser-copy-flow-forms" { @@ -2117,7 +1071,7 @@ resource "keycloak_authentication_subflow" "browser-copy-flow-forms" { parent_flow_alias = keycloak_authentication_flow.browser-copy-flow.alias alias = "browser-copy-flow-forms" requirement = "ALTERNATIVE" - priority = 40 + priority = 40 } resource "keycloak_authentication_execution" "browser-copy-auth-username-password-form" { @@ -2125,7 +1079,7 @@ resource "keycloak_authentication_execution" "browser-copy-auth-username-passwor parent_flow_alias = keycloak_authentication_subflow.browser-copy-flow-forms.alias authenticator = "auth-username-password-form" requirement = "REQUIRED" - priority = 50 + priority = 50 } resource "keycloak_authentication_execution" "browser-copy-otp" { @@ -2133,7 +1087,7 @@ resource "keycloak_authentication_execution" "browser-copy-otp" { parent_flow_alias = keycloak_authentication_subflow.browser-copy-flow-forms.alias authenticator = "auth-otp-form" requirement = "REQUIRED" - priority = 60 + priority = 60 } resource "keycloak_authentication_execution_config" "config" { @@ -2203,8 +1157,7 @@ resource "keycloak_realm_user_profile" "userprofile" { } attribute { - name = "field2" - multivalued = true + name = "field2" } group { diff --git a/keycloak/realm_user_profile.go b/keycloak/realm_user_profile.go index 2377ffafa..582ef2b0a 100644 --- a/keycloak/realm_user_profile.go +++ b/keycloak/realm_user_profile.go @@ -32,7 +32,6 @@ type RealmUserProfileAttribute struct { Required *RealmUserProfileRequired `json:"required,omitempty"` Selector *RealmUserProfileSelector `json:"selector,omitempty"` Validations map[string]RealmUserProfileValidationConfig `json:"validations,omitempty"` - Multivalued bool `json:"multivalued,omitempty"` } type RealmUserProfileGroup struct { diff --git a/provider/resource_keycloak_realm_user_profile.go b/provider/resource_keycloak_realm_user_profile.go index a9413a7a4..be760dbe6 100644 --- a/provider/resource_keycloak_realm_user_profile.go +++ b/provider/resource_keycloak_realm_user_profile.go @@ -55,10 +55,6 @@ func resourceKeycloakRealmUserProfile() *schema.Resource { Type: schema.TypeString, Optional: true, }, - "multivalued": { - Type: schema.TypeBool, - Optional: true, - }, "enabled_when_scope": { Type: schema.TypeSet, Optional: true, @@ -160,7 +156,6 @@ func getRealmUserProfileAttributeFromData(m map[string]interface{}) *keycloak.Re Name: m["name"].(string), DisplayName: m["display_name"].(string), Group: m["group"].(string), - Multivalued: m["multivalued"].(bool), } if v, ok := m["multi_valued"].(bool); ok { @@ -348,7 +343,6 @@ func getRealmUserProfileAttributeData(attr *keycloak.RealmUserProfileAttribute) attributeData["multi_valued"] = attr.MultiValued attributeData["group"] = attr.Group - attributeData["multivalued"] = attr.Multivalued if attr.Selector != nil && len(attr.Selector.Scopes) != 0 { attributeData["enabled_when_scope"] = attr.Selector.Scopes } From d6589be2d22d2fd0caf739fd67daaa7c6c529e51 Mon Sep 17 00:00:00 2001 From: Laureat Grepi Date: Mon, 10 Feb 2025 17:56:48 +0100 Subject: [PATCH 12/12] format Signed-off-by: Laureat Grepi --- example/main.tf | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) diff --git a/example/main.tf b/example/main.tf index b7ad672e4..ae2d1acce 100644 --- a/example/main.tf +++ b/example/main.tf @@ -120,21 +120,6 @@ resource "keycloak_required_action" "update-password" { max_auth_age = "600" } } -resource "keycloak_required_action" "custom-configured_totp" { - realm_id = keycloak_realm.test.realm - alias = "CONFIGURE_TOTP" - default_action = true - enabled = true - name = "Custom configure totp" - priority = keycloak_required_action.custom-terms-and-conditions.priority + 15 -} - -resource "keycloak_required_action" "required_action" { - realm_id = keycloak_realm.test.realm - alias = "webauthn-register" - enabled = true - name = "Webauthn Register" -} resource "keycloak_required_action" "custom-configured_totp" { realm_id = keycloak_realm.test.realm @@ -454,25 +439,25 @@ resource "keycloak_ldap_full_name_mapper" "full_name_mapper" { } resource "keycloak_ldap_custom_mapper" "custom_mapper" { - name = "custom-mapper" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + name = "custom-mapper" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - provider_id = "msad-user-account-control-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + provider_id = "msad-user-account-control-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" } resource "keycloak_ldap_custom_mapper" "custom_mapper_with_config" { - name = "custom-mapper-with-config" - realm_id = keycloak_ldap_user_federation.openldap.realm_id - ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id - - provider_id = "user-attribute-ldap-mapper" - provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" - config = { - "user.model.attribute" = "username" - "ldap.attribute" = "cn" - } + name = "custom-mapper-with-config" + realm_id = keycloak_ldap_user_federation.openldap.realm_id + ldap_user_federation_id = keycloak_ldap_user_federation.openldap.id + + provider_id = "user-attribute-ldap-mapper" + provider_type = "org.keycloak.storage.ldap.mappers.LDAPStorageMapper" + config = { + "user.model.attribute" = "username" + "ldap.attribute" = "cn" + } }