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

OpenId and SAML Client's attributes #389

Closed
wants to merge 75 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
c2a38fe
Initial implementation of CRUD operations (no importer yet)
slavko-vega May 13, 2020
0a8b15e
Map resource name with function
slavko-vega May 13, 2020
f106a11
Importer added
slavko-vega May 13, 2020
b771841
Tests support
slavko-vega May 14, 2020
85c768e
Fix path and Id
slavko-vega May 14, 2020
f095332
Fix path and Id
slavko-vega May 14, 2020
dc8b565
Fix the url problem
slavko-vega May 15, 2020
11c5d74
extend resource_keycloak_generic_client_role_mapper to support realm-…
branislav-vega May 15, 2020
c1b1a93
Test fixies
slavko-vega May 15, 2020
baa414d
Basic test
slavko-vega May 16, 2020
7788f36
Streamline the structure, code and tests
slavko-vega May 16, 2020
cadf3fc
remove local files
slavko-vega May 16, 2020
0b42ddc
Set up CI with Azure Pipelines
m-v-k May 19, 2020
fc31223
Update azure-pipelines.yml for Azure Pipelines
m-v-k May 19, 2020
2afe728
add CIRCLE_TAG
m-v-k May 19, 2020
eef89cc
bash inline with variable
m-v-k May 19, 2020
073eca1
add release
m-v-k May 19, 2020
ffdd878
add ability to provide custom configuration to idp mappers
branislav-vega Jun 5, 2020
7299677
extend tests and examples
branislav-vega Jun 8, 2020
0e1c2fd
test fix
branislav-vega Jun 8, 2020
880fa5d
Merge pull request #1 from embracesbs/features/resource-keycloak-gene…
branislav-vega Jun 10, 2020
019fdf8
Merge pull request #2 from embracesbs/features/management-permission-…
slavko-vega Jun 10, 2020
cd94268
Merge pull request #3 from embracesbs/features/idp-mapper-extra-config
branislav-vega Jun 10, 2020
2586bfd
remove embracesbs azure pipeline
Jun 10, 2020
bae0f66
Revert "Extension of keycloak_generic_client_role_mapper resource to …
branislav-vega Jun 10, 2020
138a7f1
Merge pull request #5 from embracesbs/revert-1-features/resource-keyc…
branislav-vega Jun 10, 2020
a83b13b
Merge pull request #4 from mrparkers/master
branislav-vega Jun 10, 2020
8aa881c
Merge pull request #6 from embracesbs/master
m-v-k Jun 10, 2020
53b2291
Revert "Revert "Extension of keycloak_generic_client_role_mapper reso…
branislav-vega Jun 10, 2020
87d405b
Merge pull request #7 from embracesbs/features/resource-keycloak-gene…
branislav-vega Jun 10, 2020
72d490c
Merge pull request #8 from embracesbs/master
m-v-k Jun 11, 2020
c8139f9
test fix
branislav-vega Jun 11, 2020
547eb47
Merge pull request #9 from embracesbs/features/resource-keycloak-gene…
branislav-vega Jun 11, 2020
da03d4d
Merge pull request #10 from embracesbs/master
m-v-k Jun 11, 2020
8aceb20
Merge branch 'master' into upstream
m-v-k Jun 18, 2020
877b2e4
Revert "Merge pull request #2 from embracesbs/features/management-per…
slavko-vega Jul 1, 2020
14d61e5
Use TF 0.12 references format
slavko-vega Jul 1, 2020
7439ddf
Merge pull request #12 from embracesbs/hotfixes/remove-management-per…
slavko-vega Jul 1, 2020
3b2ca21
Merge pull request #13 from embracesbs/hotfixes/remove-management-per…
slavko-vega Jul 2, 2020
2597e88
Merge pull request #14 from embracesbs/master
slavko-vega Jul 2, 2020
1a459d3
Merge branch 'master' into upstream
slavko-vega Jul 2, 2020
0fc6e3e
Initial implementation with test
slavko-vega Sep 23, 2020
681c97e
Cleanup
slavko-vega Sep 23, 2020
df4e2d3
Fix test
slavko-vega Sep 23, 2020
6b406ba
SAML client attributes
slavko-vega Sep 23, 2020
48a4745
SAML client's attributes test
slavko-vega Sep 24, 2020
73f0219
Remove side effects
slavko-vega Sep 24, 2020
eb2e668
Fix bug with equality
slavko-vega Sep 24, 2020
792d95f
OpenId and SAML Clients' attributes
slavko-vega Sep 24, 2020
28c4aef
Merge pull request #15 from embracesbs/features/client-attributes
slavko-vega Sep 24, 2020
a465b8e
Merge remote-tracking branch 'remotes/origin/upstream' into features/…
slavko-vega Sep 25, 2020
d4631d9
Merge pull request #16 from embracesbs/features/merge-from-upstream
slavko-vega Sep 25, 2020
88c36ff
GetReservedKeys on OpenidClientAttributes
slavko-vega Oct 23, 2020
6c60368
SAML Client attribute tags
slavko-vega Oct 23, 2020
3475085
Get json tag value
slavko-vega Oct 23, 2020
639fd69
More general tag extraction
slavko-vega Oct 23, 2020
e806095
Merge pull request #17 from embracesbs/features/using-reflection-for-…
m-v-k Oct 23, 2020
b9b943c
Use general marshaling based on reflection
slavko-vega Nov 1, 2020
5779104
Fix SAML Client typo
slavko-vega Nov 1, 2020
a2bd71d
Change unmarshaling in resources
slavko-vega Nov 1, 2020
c5193c2
Deal with pointers
slavko-vega Nov 1, 2020
4027547
Deal with pointers
slavko-vega Nov 1, 2020
076d232
Just get an Elem
slavko-vega Nov 1, 2020
63bcca8
Check if Elem is Zero
slavko-vega Nov 2, 2020
1ac4628
Cleanup
slavko-vega Nov 4, 2020
d7f6551
Fix nasty issue with default values of SAML client attributes
slavko-vega Nov 15, 2020
aa1a144
KeycolakBool instead of *string(s)
slavko-vega Nov 15, 2020
35bd466
Clean up the Open ID Client test
slavko-vega Nov 15, 2020
29b20ad
Rename Attributes into ExtraConfig
slavko-vega Nov 15, 2020
a263756
SAML Client: OtherAttributes into ExtraConfig
slavko-vega Nov 15, 2020
9ea8420
OtherAttributes into ExtraConfig
slavko-vega Nov 15, 2020
fd018f2
Revert from KeycloakBool to *string
slavko-vega Nov 15, 2020
1af5d59
Merge pull request #18 from embracesbs/features/client-attributes-wit…
slavko-vega Nov 24, 2020
618baea
Fix nil valueOf
slavko-vega Nov 24, 2020
200c9cd
Merge pull request #19 from embracesbs/features/client-attributes-wit…
slavko-vega Nov 24, 2020
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: 6 additions & 0 deletions docs/resources/keycloak_openid_client.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ resource "keycloak_openid_client" "openid_client" {
]

login_theme = "keycloak"

extra_config = {
"key1" = "value1"
"key2" = "value2"
}
}
```

Expand Down Expand Up @@ -67,6 +72,7 @@ is set to `true`.
- `browers_id` - (Optional) - Browser flow id, (flow needs to exist)
- `direct_grant_id` - (Optional) - Direct grant flow id (flow needs to exist)
- `login_theme` - (Optional) - Override realm login theme
- `extra_config` - (Optional) A map of key/value pairs to set as custom attributes for the client.

### Attributes Reference

Expand Down
6 changes: 6 additions & 0 deletions docs/resources/keycloak_saml_client.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ resource "keycloak_saml_client" "saml_client" {

signing_certificate = "${file("saml-cert.pem")}"
signing_private_key = "${file("saml-key.pem")}"

extra_config = {
"key1" = "value1"
"key2" = "value2"
}
}
```

Expand Down Expand Up @@ -58,6 +63,7 @@ The following arguments are supported:
- `logout_service_post_binding_url` - (Optional) SAML POST Binding URL for the client's single logout service.
- `logout_service_redirect_binding_url` - (Optional) SAML Redirect Binding URL for the client's single logout service.
- `full_scope_allowed` - (Optional) - Allow to include all roles mappings in the access token
- `extra_config` - (Optional) A map of key/value pairs to set as custom attributes for the client.

### Import

Expand Down
50 changes: 50 additions & 0 deletions example/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,11 @@ resource keycloak_attribute_importer_identity_provider_mapper oidc {
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 {
Expand All @@ -576,20 +581,35 @@ resource keycloak_attribute_to_role_identity_provider_mapper oidc {
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 {
Expand All @@ -599,6 +619,11 @@ resource keycloak_hardcoded_attribute_identity_provider_mapper oidc {
attribute_name = "attribute"
attribute_value = "value"
user_session = true

#KC10 support
extra_config = {
syncMode = "INHERIT"
}
}

resource keycloak_saml_identity_provider saml {
Expand All @@ -613,6 +638,11 @@ resource keycloak_attribute_importer_identity_provider_mapper saml {
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 {
Expand All @@ -622,20 +652,35 @@ resource keycloak_attribute_to_role_identity_provider_mapper saml {
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 {
Expand All @@ -645,6 +690,11 @@ resource keycloak_hardcoded_attribute_identity_provider_mapper saml {
attribute_name = "attribute"
attribute_value = "value"
user_session = false

#KC10 support
extra_config = {
syncMode = "INHERIT"
}
}

data "keycloak_openid_client" "broker" {
Expand Down
38 changes: 38 additions & 0 deletions example/roles.tf
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,44 @@ resource "keycloak_generic_client_role_mapper" "pet_app_pet_api_admin_role_mappi
role_id = keycloak_role.pet_api_admin.id
}

// Realm roles

resource "keycloak_role" "realm_reader" {
realm_id = keycloak_realm.roles_example.id
name = "realm_reader"
description = "Reader realm role"
}

resource "keycloak_role" "realm_writer" {
realm_id = keycloak_realm.roles_example.id
name = "realm_writer"
description = "Writer realm role"
}

resource "keycloak_role" "realm_admin" {
realm_id = keycloak_realm.roles_example.id
name = "realm_admin"
description = "Admin realm composite role"
composite_roles = [
keycloak_role.realm_reader.id,
keycloak_role.realm_writer.id
]
}

// Client scope for realm roles mapping

resource "keycloak_openid_client_scope" "petstore_api_access_scope" {
realm_id = keycloak_realm.roles_example.id
name = "petstore-api-access"
description = "Optional scope offering additional information for petstore api access"
}

resource "keycloak_generic_client_role_mapper" "petstore_api_access_scope_admin" {
realm_id = keycloak_realm.roles_example.id
client_scope_id = keycloak_openid_client_scope.petstore_api_access_scope.id
role_id = keycloak_role.realm_admin.id
}

// Users and groups

resource "keycloak_group" "pet_api_base" {
Expand Down
77 changes: 68 additions & 9 deletions keycloak/identity_provider_mapper.go
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package keycloak

import (
"encoding/json"
"fmt"
"log"
"reflect"
"strconv"
"strings"
)

type IdentityProviderMapperConfig struct {
UserAttribute string `json:"user.attribute,omitempty"`
Claim string `json:"claim,omitempty"`
ClaimValue string `json:"claim.value,omitempty"`
HardcodedAttribute string `json:"attribute,omitempty"`
Attribute string `json:"attribute.name,omitempty"`
AttributeValue string `json:"attribute.value,omitempty"`
AttributeFriendlyName string `json:"attribute.friendly.name,omitempty"`
Template string `json:"template,omitempty"`
Role string `json:"role,omitempty"`
UserAttribute string `json:"user.attribute,omitempty"`
Claim string `json:"claim,omitempty"`
ClaimValue string `json:"claim.value,omitempty"`
HardcodedAttribute string `json:"attribute,omitempty"`
Attribute string `json:"attribute.name,omitempty"`
AttributeValue string `json:"attribute.value,omitempty"`
AttributeFriendlyName string `json:"attribute.friendly.name,omitempty"`
Template string `json:"template,omitempty"`
Role string `json:"role,omitempty"`
ExtraConfig map[string]interface{} `json:"-"`
}

type IdentityProviderMapper struct {
Expand Down Expand Up @@ -59,3 +64,57 @@ func (keycloakClient *KeycloakClient) UpdateIdentityProviderMapper(identityProvi
func (keycloakClient *KeycloakClient) DeleteIdentityProviderMapper(realm, alias, id string) error {
return keycloakClient.delete(fmt.Sprintf("/realms/%s/identity-provider/instances/%s/mappers/%s", realm, alias, id), nil)
}

func (f *IdentityProviderMapperConfig) UnmarshalJSON(data []byte) error {
f.ExtraConfig = map[string]interface{}{}
err := json.Unmarshal(data, &f.ExtraConfig)
if err != nil {
return err
}
v := reflect.ValueOf(f).Elem()
for i := 0; i < v.NumField(); i++ {
structField := v.Type().Field(i)
jsonKey := strings.Split(structField.Tag.Get("json"), ",")[0]
if jsonKey != "-" {
value, ok := f.ExtraConfig[jsonKey]
if ok {
field := v.FieldByName(structField.Name)
if field.IsValid() && field.CanSet() {
if field.Kind() == reflect.String {
field.SetString(value.(string))
} else if field.Kind() == reflect.Bool {
boolVal, err := strconv.ParseBool(value.(string))
if err == nil {
field.Set(reflect.ValueOf(KeycloakBoolQuoted(boolVal)))
}
}
delete(f.ExtraConfig, jsonKey)
}
}
}
}
return nil
}

func (f *IdentityProviderMapperConfig) MarshalJSON() ([]byte, error) {
out := map[string]interface{}{}

for k, v := range f.ExtraConfig {
out[k] = v
}
v := reflect.ValueOf(f).Elem()
for i := 0; i < v.NumField(); i++ {
jsonKey := strings.Split(v.Type().Field(i).Tag.Get("json"), ",")[0]
if jsonKey != "-" {
field := v.Field(i)
if field.IsValid() && field.CanSet() {
if field.Kind() == reflect.String {
out[jsonKey] = field.String()
} else if field.Kind() == reflect.Bool {
out[jsonKey] = KeycloakBoolQuoted(field.Bool())
}
}
}
}
return json.Marshal(out)
}
67 changes: 63 additions & 4 deletions keycloak/openid_client.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
package keycloak

import (
"encoding/json"
"fmt"
"reflect"
"strconv"
"strings"
)

type OpenidClientRole struct {
Expand Down Expand Up @@ -54,10 +58,65 @@ type OpenidClient struct {
}

type OpenidClientAttributes struct {
PkceCodeChallengeMethod string `json:"pkce.code.challenge.method"`
ExcludeSessionStateFromAuthResponse KeycloakBoolQuoted `json:"exclude.session.state.from.auth.response"`
AccessTokenLifespan string `json:"access.token.lifespan"`
LoginTheme string `json:"login_theme"`
PkceCodeChallengeMethod string `json:"pkce.code.challenge.method"`
ExcludeSessionStateFromAuthResponse KeycloakBoolQuoted `json:"exclude.session.state.from.auth.response"`
AccessTokenLifespan string `json:"access.token.lifespan"`
LoginTheme string `json:"login_theme"`
ExtraConfig map[string]interface{} `json:"-"`
}

func (f *OpenidClientAttributes) UnmarshalJSON(data []byte) error {
f.ExtraConfig = map[string]interface{}{}
err := json.Unmarshal(data, &f.ExtraConfig)
if err != nil {
return err
}
v := reflect.ValueOf(f).Elem()
for i := 0; i < v.NumField(); i++ {
structField := v.Type().Field(i)
jsonKey := strings.Split(structField.Tag.Get("json"), ",")[0]
if jsonKey != "-" {
value, ok := f.ExtraConfig[jsonKey]
if ok {
field := v.FieldByName(structField.Name)
if field.IsValid() && field.CanSet() {
if field.Kind() == reflect.String {
field.SetString(value.(string))
} else if field.Kind() == reflect.Bool {
boolVal, err := strconv.ParseBool(value.(string))
if err == nil {
field.Set(reflect.ValueOf(KeycloakBoolQuoted(boolVal)))
}
}
delete(f.ExtraConfig, jsonKey)
}
}
}
}
return nil
}

func (f *OpenidClientAttributes) MarshalJSON() ([]byte, error) {
out := map[string]interface{}{}

for k, v := range f.ExtraConfig {
out[k] = v
}
v := reflect.ValueOf(f).Elem()
for i := 0; i < v.NumField(); i++ {
jsonKey := strings.Split(v.Type().Field(i).Tag.Get("json"), ",")[0]
if jsonKey != "-" {
field := v.Field(i)
if field.IsValid() && field.CanSet() {
if field.Kind() == reflect.String {
out[jsonKey] = field.String()
} else if field.Kind() == reflect.Bool {
out[jsonKey] = KeycloakBoolQuoted(field.Bool())
}
}
}
}
return json.Marshal(out)
}

type OpenidAuthenticationFlowBindingOverrides struct {
Expand Down
Loading