From 24481fc80f0a039a1b181cc5c96a272b65dcbdb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Hauan?= Date: Tue, 9 Nov 2021 17:24:10 +0100 Subject: [PATCH 1/6] Enable custom client_authenticator_type. --- keycloak/openid_client.go | 10 ++- .../data_source_keycloak_openid_client.go | 4 ++ provider/resource_keycloak_openid_client.go | 7 +++ .../resource_keycloak_openid_client_test.go | 61 +++++++++++++++++++ 4 files changed, 79 insertions(+), 3 deletions(-) diff --git a/keycloak/openid_client.go b/keycloak/openid_client.go index 01d96414d..4f14a63f2 100644 --- a/keycloak/openid_client.go +++ b/keycloak/openid_client.go @@ -32,7 +32,7 @@ type OpenidClient struct { RealmId string `json:"-"` Name string `json:"name"` Protocol string `json:"protocol"` // always openid-connect for this resource - ClientAuthenticatorType string `json:"clientAuthenticatorType"` // always client-secret for now, don't have a need for JWT here + ClientAuthenticatorType string `json:"clientAuthenticatorType"` ClientSecret string `json:"secret,omitempty"` Enabled bool `json:"enabled"` Description string `json:"description"` @@ -116,7 +116,9 @@ func (keycloakClient *KeycloakClient) ValidateOpenidClient(client *OpenidClient) func (keycloakClient *KeycloakClient) NewOpenidClient(client *OpenidClient) error { client.Protocol = "openid-connect" - client.ClientAuthenticatorType = "client-secret" + if client.ClientAuthenticatorType == "" { + client.ClientAuthenticatorType = "client-secret" + } _, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/clients", client.RealmId), client) if err != nil { @@ -219,7 +221,9 @@ func (keycloakClient *KeycloakClient) GetOpenidClientByClientId(realmId, clientI func (keycloakClient *KeycloakClient) UpdateOpenidClient(client *OpenidClient) error { client.Protocol = "openid-connect" - client.ClientAuthenticatorType = "client-secret" + if client.ClientAuthenticatorType == "" { + client.ClientAuthenticatorType = "client-secret" + } return keycloakClient.put(fmt.Sprintf("/realms/%s/clients/%s", client.RealmId, client.Id), client) } diff --git a/provider/data_source_keycloak_openid_client.go b/provider/data_source_keycloak_openid_client.go index 5ade33cd6..f048a86c4 100644 --- a/provider/data_source_keycloak_openid_client.go +++ b/provider/data_source_keycloak_openid_client.go @@ -39,6 +39,10 @@ func dataSourceKeycloakOpenidClient() *schema.Resource { Computed: true, Sensitive: true, }, + "client_authenticator_type": { + Type: schema.TypeString, + Computed: true, + }, "standard_flow_enabled": { Type: schema.TypeBool, Computed: true, diff --git a/provider/resource_keycloak_openid_client.go b/provider/resource_keycloak_openid_client.go index e95348dd1..9ba67e862 100644 --- a/provider/resource_keycloak_openid_client.go +++ b/provider/resource_keycloak_openid_client.go @@ -64,6 +64,11 @@ func resourceKeycloakOpenidClient() *schema.Resource { Computed: true, Sensitive: true, }, + "client_authenticator_type": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, "standard_flow_enabled": { Type: schema.TypeBool, Optional: true, @@ -280,6 +285,7 @@ func getOpenidClientFromData(data *schema.ResourceData) (*keycloak.OpenidClient, Enabled: data.Get("enabled").(bool), Description: data.Get("description").(string), ClientSecret: data.Get("client_secret").(string), + ClientAuthenticatorType: data.Get("client_authenticator_type").(string), StandardFlowEnabled: data.Get("standard_flow_enabled").(bool), ImplicitFlowEnabled: data.Get("implicit_flow_enabled").(bool), DirectAccessGrantsEnabled: data.Get("direct_access_grants_enabled").(bool), @@ -372,6 +378,7 @@ func setOpenidClientData(keycloakClient *keycloak.KeycloakClient, data *schema.R data.Set("enabled", client.Enabled) data.Set("description", client.Description) data.Set("client_secret", client.ClientSecret) + data.Set("client_authenticator_type", client.ClientAuthenticatorType) data.Set("standard_flow_enabled", client.StandardFlowEnabled) data.Set("implicit_flow_enabled", client.ImplicitFlowEnabled) data.Set("direct_access_grants_enabled", client.DirectAccessGrantsEnabled) diff --git a/provider/resource_keycloak_openid_client_test.go b/provider/resource_keycloak_openid_client_test.go index 56062d66a..e287ad462 100644 --- a/provider/resource_keycloak_openid_client_test.go +++ b/provider/resource_keycloak_openid_client_test.go @@ -120,6 +120,37 @@ func TestAccKeycloakOpenidClient_accessType(t *testing.T) { }, }) } +func TestAccKeycloakOpenidClient_clientAuthenticatorType(t *testing.T) { + t.Parallel() + clientId := acctest.RandomWithPrefix("tf-acc") + + resource.Test(t, resource.TestCase{ + ProviderFactories: testAccProviderFactories, + PreCheck: func() { testAccPreCheck(t) }, + CheckDestroy: testAccCheckKeycloakOpenidClientDestroy(), + Steps: []resource.TestStep{ + { + Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, "client-secret"), + Check: testAccCheckKeycloakOpenidClientAuthenticatorType("keycloak_openid_client.client", "client-secret"), + },{ + Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, ""), + Check: testAccCheckKeycloakOpenidClientAuthenticatorType("keycloak_openid_client.client", "client-secret"), + }, + { + Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, "client-jwt"), + Check: testAccCheckKeycloakOpenidClientAuthenticatorType("keycloak_openid_client.client", "client-jwt"), + }, + { + Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, "client-secret-jwt"), + Check: testAccCheckKeycloakOpenidClientAuthenticatorType("keycloak_openid_client.client", "client-secret-jwt"), + }, + { + Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, "client-x509"), + Check: testAccCheckKeycloakOpenidClientAuthenticatorType("keycloak_openid_client.client", "client-x509"), + }, + }, + }) +} func TestAccKeycloakOpenidClient_updateInPlace(t *testing.T) { t.Parallel() @@ -711,6 +742,21 @@ func testAccCheckKeycloakOpenidClientAccessType(resourceName string, public, bea } } +func testAccCheckKeycloakOpenidClientAuthenticatorType(resourceName string, authType string) resource.TestCheckFunc { + return func(s *terraform.State) error { + client, err := getOpenidClientFromState(s, resourceName) + if err != nil { + return err + } + + if client.ClientAuthenticatorType != authType { + return fmt.Errorf("expected openid client to have client_authenticator_type set to %s, but got %s", authType, client.ClientAuthenticatorType) + } + + return nil + } +} + func testAccCheckKeycloakOpenidClientBelongsToRealm(resourceName, realm string) resource.TestCheckFunc { return func(s *terraform.State) error { client, err := getOpenidClientFromState(s, resourceName) @@ -992,6 +1038,21 @@ resource "keycloak_openid_client" "client" { `, testAccRealm.Realm, clientId, accessType) } +func testKeycloakOpenidClient_clientAuthenticatorType(clientId, authType string) string { + return fmt.Sprintf(` +data "keycloak_realm" "realm" { + realm = "%s" +} + +resource "keycloak_openid_client" "client" { + client_id = "%s" + realm_id = data.keycloak_realm.realm.id + access_type = "CONFIDENTIAL" + client_authenticator_type="%s" +} + `, testAccRealm.Realm, clientId, authType) +} + func testKeycloakOpenidClient_pkceChallengeMethod(clientId, pkceChallengeMethod string) string { return fmt.Sprintf(` From 4611e156249ba82b2b07b718d5b712beb2015c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Hauan?= Date: Thu, 11 Nov 2021 10:49:49 +0100 Subject: [PATCH 2/6] Updated docs with client_authenticator_type --- docs/resources/openid_client.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/resources/openid_client.md b/docs/resources/openid_client.md index 0a9831192..5e1248dbc 100644 --- a/docs/resources/openid_client.md +++ b/docs/resources/openid_client.md @@ -53,6 +53,11 @@ resource "keycloak_openid_client" "openid_client" { URIs for security. This client should be used for applications using the Implicit grant flow. - `BEARER-ONLY` - Used for services that never initiate a login. This client will only allow bearer token requests. - `client_secret` - (Optional) The secret for clients with an `access_type` of `CONFIDENTIAL` or `BEARER-ONLY`. This value is sensitive and should be treated with the same care as a password. If omitted, this will be generated by Keycloak. +- `client_authenticator_type` - (Optional) Defaults to `client-secret` The authenticator type for clients with an `access_type` of `CONFIDENTIAL` or `BEARER-ONLY`. Can be one of the following: + - `client-secret` (Default) Use client id and client secret to authenticate client. + - `client-jwt` Use signed JWT to authenticate client. Set signing algorithm in `extra_config` with `attributes.token.endpoint.auth.signing.alg = ` + - `client-x509` Use x509 certificate to authenticate client. Set Subject DN in `extra_config` with `attributes.x509.subjectdn = ` + - `client-secret-jwt` Use signed JWT with client secret to authenticate client. Set signing algorithm in `extra_config` with `attributes.token.endpoint.auth.signing.alg = ` - `standard_flow_enabled` - (Optional) When `true`, the OAuth2 Authorization Code Grant will be enabled for this client. Defaults to `false`. - `implicit_flow_enabled` - (Optional) When `true`, the OAuth2 Implicit Grant will be enabled for this client. Defaults to `false`. - `direct_access_grants_enabled` - (Optional) When `true`, the OAuth2 Resource Owner Password Grant will be enabled for this client. Defaults to `false`. From f172f9336d062e13e8bd4a123595d0aab4cfaad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Hauan?= Date: Tue, 14 Dec 2021 13:25:27 +0100 Subject: [PATCH 3/6] Add client-secret as default value to ClientAuthenticatorType --- keycloak/openid_client.go | 6 ------ provider/resource_keycloak_openid_client.go | 1 + 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/keycloak/openid_client.go b/keycloak/openid_client.go index 4f14a63f2..098ee49db 100644 --- a/keycloak/openid_client.go +++ b/keycloak/openid_client.go @@ -116,9 +116,6 @@ func (keycloakClient *KeycloakClient) ValidateOpenidClient(client *OpenidClient) func (keycloakClient *KeycloakClient) NewOpenidClient(client *OpenidClient) error { client.Protocol = "openid-connect" - if client.ClientAuthenticatorType == "" { - client.ClientAuthenticatorType = "client-secret" - } _, location, err := keycloakClient.post(fmt.Sprintf("/realms/%s/clients", client.RealmId), client) if err != nil { @@ -221,9 +218,6 @@ func (keycloakClient *KeycloakClient) GetOpenidClientByClientId(realmId, clientI func (keycloakClient *KeycloakClient) UpdateOpenidClient(client *OpenidClient) error { client.Protocol = "openid-connect" - if client.ClientAuthenticatorType == "" { - client.ClientAuthenticatorType = "client-secret" - } return keycloakClient.put(fmt.Sprintf("/realms/%s/clients/%s", client.RealmId, client.Id), client) } diff --git a/provider/resource_keycloak_openid_client.go b/provider/resource_keycloak_openid_client.go index 9ba67e862..4c26d0050 100644 --- a/provider/resource_keycloak_openid_client.go +++ b/provider/resource_keycloak_openid_client.go @@ -68,6 +68,7 @@ func resourceKeycloakOpenidClient() *schema.Resource { Type: schema.TypeString, Optional: true, Computed: true, + Default: "client-secret", }, "standard_flow_enabled": { Type: schema.TypeBool, From dd3b7f75cef42dcdc9fe66d8009e8681508f34f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=98ystein=20Hauan?= Date: Tue, 11 Jan 2022 14:15:22 +0100 Subject: [PATCH 4/6] remove Computed as default is client-secret --- provider/resource_keycloak_openid_client.go | 1 - 1 file changed, 1 deletion(-) diff --git a/provider/resource_keycloak_openid_client.go b/provider/resource_keycloak_openid_client.go index bda8726ff..80185af57 100644 --- a/provider/resource_keycloak_openid_client.go +++ b/provider/resource_keycloak_openid_client.go @@ -67,7 +67,6 @@ func resourceKeycloakOpenidClient() *schema.Resource { "client_authenticator_type": { Type: schema.TypeString, Optional: true, - Computed: true, Default: "client-secret", }, "standard_flow_enabled": { From 49e53c65dc534f068306e347fdeb379fd508fbc0 Mon Sep 17 00:00:00 2001 From: Michael Parker Date: Wed, 19 Jan 2022 14:17:59 -0600 Subject: [PATCH 5/6] fix: fmt --- keycloak/openid_client.go | 2 +- provider/data_source_keycloak_openid_client.go | 4 ++-- provider/resource_keycloak_openid_client.go | 6 +++--- provider/resource_keycloak_openid_client_test.go | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/keycloak/openid_client.go b/keycloak/openid_client.go index 4416bf053..87f3fcf2a 100644 --- a/keycloak/openid_client.go +++ b/keycloak/openid_client.go @@ -31,7 +31,7 @@ type OpenidClient struct { ClientId string `json:"clientId"` RealmId string `json:"-"` Name string `json:"name"` - Protocol string `json:"protocol"` // always openid-connect for this resource + Protocol string `json:"protocol"` // always openid-connect for this resource ClientAuthenticatorType string `json:"clientAuthenticatorType"` ClientSecret string `json:"secret,omitempty"` Enabled bool `json:"enabled"` diff --git a/provider/data_source_keycloak_openid_client.go b/provider/data_source_keycloak_openid_client.go index d634c3a04..dbfd12d0d 100644 --- a/provider/data_source_keycloak_openid_client.go +++ b/provider/data_source_keycloak_openid_client.go @@ -40,8 +40,8 @@ func dataSourceKeycloakOpenidClient() *schema.Resource { Sensitive: true, }, "client_authenticator_type": { - Type: schema.TypeString, - Computed: true, + Type: schema.TypeString, + Computed: true, }, "standard_flow_enabled": { Type: schema.TypeBool, diff --git a/provider/resource_keycloak_openid_client.go b/provider/resource_keycloak_openid_client.go index 80185af57..1e44429c4 100644 --- a/provider/resource_keycloak_openid_client.go +++ b/provider/resource_keycloak_openid_client.go @@ -65,9 +65,9 @@ func resourceKeycloakOpenidClient() *schema.Resource { Sensitive: true, }, "client_authenticator_type": { - Type: schema.TypeString, - Optional: true, - Default: "client-secret", + Type: schema.TypeString, + Optional: true, + Default: "client-secret", }, "standard_flow_enabled": { Type: schema.TypeBool, diff --git a/provider/resource_keycloak_openid_client_test.go b/provider/resource_keycloak_openid_client_test.go index 1ef343f67..ce84ef274 100644 --- a/provider/resource_keycloak_openid_client_test.go +++ b/provider/resource_keycloak_openid_client_test.go @@ -132,7 +132,7 @@ func TestAccKeycloakOpenidClient_clientAuthenticatorType(t *testing.T) { { Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, "client-secret"), Check: testAccCheckKeycloakOpenidClientAuthenticatorType("keycloak_openid_client.client", "client-secret"), - },{ + }, { Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, ""), Check: testAccCheckKeycloakOpenidClientAuthenticatorType("keycloak_openid_client.client", "client-secret"), }, From 1aee4dbfe7cf9782b4549d35370b23a4fbc417b0 Mon Sep 17 00:00:00 2001 From: Michael Parker Date: Wed, 19 Jan 2022 16:06:19 -0600 Subject: [PATCH 6/6] fix: validate client authenticator types, remove test for default case --- provider/resource_keycloak_openid_client.go | 8 +++++--- provider/resource_keycloak_openid_client_test.go | 11 ++++------- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/provider/resource_keycloak_openid_client.go b/provider/resource_keycloak_openid_client.go index 1e44429c4..70b261e0f 100644 --- a/provider/resource_keycloak_openid_client.go +++ b/provider/resource_keycloak_openid_client.go @@ -18,6 +18,7 @@ var ( keycloakOpenidClientAuthorizationPolicyEnforcementMode = []string{"ENFORCING", "PERMISSIVE", "DISABLED"} keycloakOpenidClientResourcePermissionDecisionStrategies = []string{"UNANIMOUS", "AFFIRMATIVE", "CONSENSUS"} keycloakOpenidClientPkceCodeChallengeMethod = []string{"", "plain", "S256"} + keycloakOpenidClientAuthenticatorTypes = []string{"client-secret", "client-jwt", "client-x509", "client-secret-jwt"} ) func resourceKeycloakOpenidClient() *schema.Resource { @@ -65,9 +66,10 @@ func resourceKeycloakOpenidClient() *schema.Resource { Sensitive: true, }, "client_authenticator_type": { - Type: schema.TypeString, - Optional: true, - Default: "client-secret", + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(keycloakOpenidClientAuthenticatorTypes, false), + Default: "client-secret", }, "standard_flow_enabled": { Type: schema.TypeBool, diff --git a/provider/resource_keycloak_openid_client_test.go b/provider/resource_keycloak_openid_client_test.go index ce84ef274..72bf273d1 100644 --- a/provider/resource_keycloak_openid_client_test.go +++ b/provider/resource_keycloak_openid_client_test.go @@ -132,9 +132,6 @@ func TestAccKeycloakOpenidClient_clientAuthenticatorType(t *testing.T) { { Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, "client-secret"), Check: testAccCheckKeycloakOpenidClientAuthenticatorType("keycloak_openid_client.client", "client-secret"), - }, { - Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, ""), - Check: testAccCheckKeycloakOpenidClientAuthenticatorType("keycloak_openid_client.client", "client-secret"), }, { Config: testKeycloakOpenidClient_clientAuthenticatorType(clientId, "client-jwt"), @@ -1145,10 +1142,10 @@ data "keycloak_realm" "realm" { } resource "keycloak_openid_client" "client" { - client_id = "%s" - realm_id = data.keycloak_realm.realm.id - access_type = "CONFIDENTIAL" - client_authenticator_type="%s" + realm_id = data.keycloak_realm.realm.id + client_id = "%s" + access_type = "CONFIDENTIAL" + client_authenticator_type = "%s" } `, testAccRealm.Realm, clientId, authType) }