diff --git a/keycloak/openid_client.go b/keycloak/openid_client.go index 03ea0f4b8..6d997d2df 100644 --- a/keycloak/openid_client.go +++ b/keycloak/openid_client.go @@ -49,7 +49,8 @@ type OpenidClient struct { } type OpenidClientAttributes struct { - PkceCodeChallengeMethod string `json:"pkce.code.challenge.method"` + PkceCodeChallengeMethod string `json:"pkce.code.challenge.method"` + ExcludeSessionStateFromAuthResponse KeycloakBoolQuoted `json:"exclude.session.state.from.auth.response"` } func (keycloakClient *KeycloakClient) GetOpenidClientServiceAccountUserId(realmId, clientId string) (*User, error) { diff --git a/provider/resource_keycloak_openid_client.go b/provider/resource_keycloak_openid_client.go index 16f56a6db..2c42a3892 100644 --- a/provider/resource_keycloak_openid_client.go +++ b/provider/resource_keycloak_openid_client.go @@ -96,6 +96,11 @@ func resourceKeycloakOpenidClient() *schema.Resource { Optional: true, ValidateFunc: validation.StringInSlice(keycloakOpenidClientPkceCodeChallengeMethod, false), }, + "exclude_session_state_from_auth_response": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, "service_account_user_id": { Type: schema.TypeString, Computed: true, @@ -167,7 +172,8 @@ func getOpenidClientFromData(data *schema.ResourceData) (*keycloak.OpenidClient, ServiceAccountsEnabled: data.Get("service_accounts_enabled").(bool), FullScopeAllowed: data.Get("full_scope_allowed").(bool), Attributes: keycloak.OpenidClientAttributes{ - PkceCodeChallengeMethod: data.Get("pkce_code_challenge_method").(string), + PkceCodeChallengeMethod: data.Get("pkce_code_challenge_method").(string), + ExcludeSessionStateFromAuthResponse: keycloak.KeycloakBoolQuoted(data.Get("exclude_session_state_from_auth_response").(bool)), }, ValidRedirectUris: validRedirectUris, WebOrigins: webOrigins, diff --git a/provider/resource_keycloak_openid_client_test.go b/provider/resource_keycloak_openid_client_test.go index 4faf60ae9..31b1c5606 100644 --- a/provider/resource_keycloak_openid_client_test.go +++ b/provider/resource_keycloak_openid_client_test.go @@ -24,10 +24,11 @@ func TestAccKeycloakOpenidClient_basic(t *testing.T) { Check: testAccCheckKeycloakOpenidClientExistsWithCorrectProtocol("keycloak_openid_client.client"), }, { - ResourceName: "keycloak_openid_client.client", - ImportState: true, - ImportStateVerify: true, - ImportStateIdPrefix: realmName + "/", + ResourceName: "keycloak_openid_client.client", + ImportState: true, + ImportStateVerify: true, + ImportStateIdPrefix: realmName + "/", + ImportStateVerifyIgnore: []string{"exclude_session_state_from_auth_response"}, }, }, }) @@ -303,15 +304,65 @@ func TestAccKeycloakOpenidClient_pkceCodeChallengeMethod(t *testing.T) { }, { Config: testKeycloakOpenidClient_omitPkceChallengeMethod(realmName, clientId), - Check: testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", ""), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", ""), + testAccCheckKeycloakOpenidClientHasExcludeSessionStateFromAuthResponse("keycloak_openid_client.client", false), + ), }, { Config: testKeycloakOpenidClient_pkceChallengeMethod(realmName, clientId, "plain"), - Check: testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", "plain"), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", "plain"), + testAccCheckKeycloakOpenidClientHasExcludeSessionStateFromAuthResponse("keycloak_openid_client.client", false), + ), }, { Config: testKeycloakOpenidClient_pkceChallengeMethod(realmName, clientId, "S256"), - Check: testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", "S256"), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", "S256"), + testAccCheckKeycloakOpenidClientHasExcludeSessionStateFromAuthResponse("keycloak_openid_client.client", false), + ), + }, + }, + }) +} + +func TestAccKeycloakOpenidClient_excludeSessionStateFromAuthResponse(t *testing.T) { + realmName := "terraform-" + acctest.RandString(10) + clientId := "terraform-" + acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + Providers: testAccProviders, + PreCheck: func() { testAccPreCheck(t) }, + CheckDestroy: testAccCheckKeycloakOpenidClientDestroy(), + Steps: []resource.TestStep{ + { + Config: testKeycloakOpenidClient_omitExcludeSessionStateFromAuthResponse(realmName, clientId, "plain"), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakOpenidClientHasExcludeSessionStateFromAuthResponse("keycloak_openid_client.client", false), + testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", "plain"), + ), + }, + { + Config: testKeycloakOpenidClient_excludeSessionStateFromAuthResponse(realmName, clientId, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakOpenidClientHasExcludeSessionStateFromAuthResponse("keycloak_openid_client.client", false), + testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", ""), + ), + }, + { + Config: testKeycloakOpenidClient_excludeSessionStateFromAuthResponse(realmName, clientId, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakOpenidClientHasExcludeSessionStateFromAuthResponse("keycloak_openid_client.client", true), + testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", ""), + ), + }, + { + Config: testKeycloakOpenidClient_excludeSessionStateFromAuthResponse(realmName, clientId, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakOpenidClientHasExcludeSessionStateFromAuthResponse("keycloak_openid_client.client", false), + testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod("keycloak_openid_client.client", ""), + ), }, }, }) @@ -440,7 +491,22 @@ func testAccCheckKeycloakOpenidClientHasPkceCodeChallengeMethod(resourceName, pk } if client.Attributes.PkceCodeChallengeMethod != pkceCodeChallengeMethod { - return fmt.Errorf("expected openid client %s to have pkce code challenge method value of %s, but got %s", client.ClientId, pkceCodeChallengeMethod, client.ClientSecret) + return fmt.Errorf("expected openid client %s to have pkce code challenge method value of %s, but got %s", client.ClientId, pkceCodeChallengeMethod, client.Attributes.PkceCodeChallengeMethod) + } + + return nil + } +} + +func testAccCheckKeycloakOpenidClientHasExcludeSessionStateFromAuthResponse(resourceName string, excludeSessionStateFromAuthResponse keycloak.KeycloakBoolQuoted) resource.TestCheckFunc { + return func(s *terraform.State) error { + client, err := getOpenidClientFromState(s, resourceName) + if err != nil { + return err + } + + if client.Attributes.ExcludeSessionStateFromAuthResponse != excludeSessionStateFromAuthResponse { + return fmt.Errorf("expected openid client %s to have exclude_session_state_from_auth_response value of %t, but got %t", client.ClientId, excludeSessionStateFromAuthResponse, client.Attributes.ExcludeSessionStateFromAuthResponse) } return nil @@ -510,6 +576,22 @@ resource "keycloak_openid_client" "client" { `, realm, clientId, pkceChallengeMethod) } +func testKeycloakOpenidClient_excludeSessionStateFromAuthResponse(realm, clientId string, excludeSessionStateFromAuthResponse bool) string { + + return fmt.Sprintf(` +resource "keycloak_realm" "realm" { + realm = "%s" +} + +resource "keycloak_openid_client" "client" { + client_id = "%s" + realm_id = "${keycloak_realm.realm.id}" + access_type = "CONFIDENTIAL" + exclude_session_state_from_auth_response = %t +} + `, realm, clientId, excludeSessionStateFromAuthResponse) +} + func testKeycloakOpenidClient_omitPkceChallengeMethod(realm, clientId string) string { return fmt.Sprintf(` @@ -525,6 +607,22 @@ resource "keycloak_openid_client" "client" { `, realm, clientId) } +func testKeycloakOpenidClient_omitExcludeSessionStateFromAuthResponse(realm, clientId, pkceChallengeMethod string) string { + + return fmt.Sprintf(` +resource "keycloak_realm" "realm" { + realm = "%s" +} + +resource "keycloak_openid_client" "client" { + client_id = "%s" + realm_id = "${keycloak_realm.realm.id}" + access_type = "CONFIDENTIAL" + pkce_code_challenge_method = "%s" +} + `, realm, clientId, pkceChallengeMethod) +} + func testKeycloakOpenidClient_updateRealmBefore(realmOne, realmTwo, clientId string) string { return fmt.Sprintf(` resource "keycloak_realm" "realm_1" {