Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support for multivalue attributes for users, groups and roles #499

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions docs/resources/group.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ resource "keycloak_group" "child_group_with_optional_attributes" {
parent_id = keycloak_group.parent_group.id
name = "child-group-with-optional-attributes"
attributes = {
"key1" = "value1"
"key2" = "value2"
"foo" = "bar"
"multivalue" = "value1##value2"
}
}
```
Expand All @@ -49,7 +49,7 @@ resource "keycloak_group" "child_group_with_optional_attributes" {
- `realm_id` - (Required) The realm this group exists in.
- `parent_id` - (Optional) The ID of this group's parent. If omitted, this group will be defined at the root level.
- `name` - (Required) The name of the group.
- `attributes` - (Optional) A map of key/value pairs to set as custom attributes for the group.
- `attributes` - (Optional) A map representing attributes for the group. In order to add multivalue attributes, use `##` to seperate the values. Max length for each value is 255 chars

## Attributes Reference

Expand Down
3 changes: 2 additions & 1 deletion docs/resources/role.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ resource "keycloak_role" "realm_role" {
description = "My Realm Role"
attributes = {
key = "value"
multivalue = "value1##value2"
}
}
```
Expand Down Expand Up @@ -150,7 +151,7 @@ resource "keycloak_role" "admin_role" {
- `client_id` - (Optional) When specified, this role will be created as a client role attached to the client with the provided ID
- `description` - (Optional) The description of the role
- `composite_roles` - (Optional) When specified, this role will be a composite role, composed of all roles that have an ID present within this list.
- `attributes` - (Optional) Attribute key/value pairs
- `attributes` - (Optional) A map representing attributes for the role. In order to add multivalue attributes, use `##` to seperate the values. Max length for each value is 255 chars


## Import
Expand Down
3 changes: 2 additions & 1 deletion docs/resources/user.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ resource "keycloak_user" "user_with_initial_password" {

attributes = {
foo = "bar"
multivalue = "value1##value2"
}

initial_password {
Expand All @@ -60,7 +61,7 @@ resource "keycloak_user" "user_with_initial_password" {
- `email_verified` - (Optional) Whether the email address was validated or not. Default to `false`.
- `first_name` - (Optional) The user's first name.
- `last_name` - (Optional) The user's last name.
- `attributes` - (Optional) A map representing attributes for the user
- `attributes` - (Optional) A map representing attributes for the user. In order to add multivalue attributes, use `##` to seperate the values. Max length for each value is 255 chars
- `federated_identity` - (Optional) When specified, the user will be linked to a federated identity provider. Refer to the [federated user example](https://github.com/mrparkers/terraform-provider-keycloak/blob/master/example/federated_user_example.tf) for more details.
- `identity_provider` - (Required) The name of the identity provider
- `user_id` - (Required) The ID of the user defined in the identity provider
Expand Down
23 changes: 23 additions & 0 deletions example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,16 @@ resource "keycloak_openid_user_attribute_protocol_mapper" "map_user_attributes_c
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
Expand Down Expand Up @@ -806,6 +816,19 @@ resource "keycloak_openid_client_authorization_scope" "resource" {
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"
Expand Down
4 changes: 2 additions & 2 deletions provider/resource_keycloak_group.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func mapFromDataToGroup(data *schema.ResourceData) *keycloak.Group {
attributes := map[string][]string{}
if v, ok := data.GetOk("attributes"); ok {
for key, value := range v.(map[string]interface{}) {
attributes[key] = splitLen(value.(string), MAX_ATTRIBUTE_VALUE_LEN)
attributes[key] = strings.Split(value.(string), MULTIVALUE_ATTRIBUTE_SEPARATOR)
}
}

Expand All @@ -67,7 +67,7 @@ func mapFromDataToGroup(data *schema.ResourceData) *keycloak.Group {
func mapFromGroupToData(data *schema.ResourceData, group *keycloak.Group) {
attributes := map[string]string{}
for k, v := range group.Attributes {
attributes[k] = strings.Join(v, "")
attributes[k] = strings.Join(v, MULTIVALUE_ATTRIBUTE_SEPARATOR)
}
data.SetId(group.Id)
data.Set("realm_id", group.RealmId)
Expand Down
4 changes: 2 additions & 2 deletions provider/resource_keycloak_role.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func mapFromDataToRole(data *schema.ResourceData) *keycloak.Role {
attributes := map[string][]string{}
if v, ok := data.GetOk("attributes"); ok {
for key, value := range v.(map[string]interface{}) {
attributes[key] = splitLen(value.(string), MAX_ATTRIBUTE_VALUE_LEN)
attributes[key] = strings.Split(value.(string), MULTIVALUE_ATTRIBUTE_SEPARATOR)
}
}

Expand All @@ -76,7 +76,7 @@ func mapFromDataToRole(data *schema.ResourceData) *keycloak.Role {
func mapFromRoleToData(data *schema.ResourceData, role *keycloak.Role) {
attributes := map[string]string{}
for k, v := range role.Attributes {
attributes[k] = strings.Join(v, "")
attributes[k] = strings.Join(v, MULTIVALUE_ATTRIBUTE_SEPARATOR)
}
data.SetId(role.Id)

Expand Down
6 changes: 3 additions & 3 deletions provider/resource_keycloak_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"strings"
)

const MAX_ATTRIBUTE_VALUE_LEN = 255
const MULTIVALUE_ATTRIBUTE_SEPARATOR = "##"

func resourceKeycloakUser() *schema.Resource {
return &schema.Resource{
Expand Down Expand Up @@ -117,7 +117,7 @@ func mapFromDataToUser(data *schema.ResourceData) *keycloak.User {
attributes := map[string][]string{}
if v, ok := data.GetOk("attributes"); ok {
for key, value := range v.(map[string]interface{}) {
attributes[key] = splitLen(value.(string), MAX_ATTRIBUTE_VALUE_LEN)
attributes[key] = strings.Split(value.(string), MULTIVALUE_ATTRIBUTE_SEPARATOR)
}
}

Expand Down Expand Up @@ -167,7 +167,7 @@ func mapFromUserToData(data *schema.ResourceData, user *keycloak.User) {
}
attributes := map[string]string{}
for k, v := range user.Attributes {
attributes[k] = strings.Join(v, "")
attributes[k] = strings.Join(v, MULTIVALUE_ATTRIBUTE_SEPARATOR)
}
data.SetId(user.Id)
data.Set("realm_id", user.RealmId)
Expand Down
18 changes: 0 additions & 18 deletions provider/utils.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,13 @@
package provider

import (
"bytes"
"log"
"time"

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

func splitLen(s string, n int) []string {
sub := ""
subs := []string{}
runes := bytes.Runes([]byte(s))
l := len(runes)
for i, r := range runes {
sub = sub + string(r)
if (i+1)%n == 0 {
subs = append(subs, sub)
sub = ""
} else if (i + 1) == l {
subs = append(subs, sub)
}
}
return subs
}

func keys(data map[string]string) []string {
var result = []string{}
for k := range data {
Expand Down