From 6ffbb42601c6d7fcc7129e98da7167eec53b30a6 Mon Sep 17 00:00:00 2001 From: Robert Avram Date: Tue, 15 Nov 2022 13:50:32 +0100 Subject: [PATCH 1/2] Use payload when deleting client realm roles --- keycloak/role_scope_mapping.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/keycloak/role_scope_mapping.go b/keycloak/role_scope_mapping.go index eeb91679..12f131ae 100644 --- a/keycloak/role_scope_mapping.go +++ b/keycloak/role_scope_mapping.go @@ -5,6 +5,15 @@ import ( "fmt" ) +type RealmRoleScopeMapping struct { + Id string `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + Composite bool `json:"composite"` + ClientRole bool `json:"clientRole"` + ContainerId string `json:"containerId"` +} + func roleScopeMappingUrl(realmId, clientId string, clientScopeId string, role *Role) string { if clientId != "" { if role.ClientRole { @@ -52,5 +61,19 @@ func (keycloakClient *KeycloakClient) GetRoleScopeMapping(ctx context.Context, r func (keycloakClient *KeycloakClient) DeleteRoleScopeMapping(ctx context.Context, realmId string, clientId string, clientScopeId string, role *Role) error { roleUrl := roleScopeMappingUrl(realmId, clientId, clientScopeId, role) - return keycloakClient.delete(ctx, roleUrl, nil) + if role.ClientRole { + return keycloakClient.delete(ctx, roleUrl, nil) + } else { + body := [1]RealmRoleScopeMapping{ + { + Id: role.Id, + Name: role.Name, + Description: role.Description, + Composite: role.Composite, + ClientRole: role.ClientRole, + ContainerId: role.ContainerId, + }, + } + return keycloakClient.delete(ctx, roleUrl, body) + } } From 99a1cfe2e0319b2e9bcff9c015dc4aa85182a841 Mon Sep 17 00:00:00 2001 From: Robert Avram Date: Tue, 15 Nov 2022 16:34:05 +0100 Subject: [PATCH 2/2] Write test for corner case --- keycloak/role_scope_mapping.go | 4 +- ...ource_keycloak_generic_role_mapper_test.go | 112 ++++++++++++++++++ 2 files changed, 114 insertions(+), 2 deletions(-) diff --git a/keycloak/role_scope_mapping.go b/keycloak/role_scope_mapping.go index 12f131ae..7cecc27d 100644 --- a/keycloak/role_scope_mapping.go +++ b/keycloak/role_scope_mapping.go @@ -5,7 +5,7 @@ import ( "fmt" ) -type RealmRoleScopeMapping struct { +type RealmRoleRepresentation struct { Id string `json:"id"` Name string `json:"name"` Description string `json:"description"` @@ -64,7 +64,7 @@ func (keycloakClient *KeycloakClient) DeleteRoleScopeMapping(ctx context.Context if role.ClientRole { return keycloakClient.delete(ctx, roleUrl, nil) } else { - body := [1]RealmRoleScopeMapping{ + body := [1]RealmRoleRepresentation{ { Id: role.Id, Name: role.Name, diff --git a/provider/resource_keycloak_generic_role_mapper_test.go b/provider/resource_keycloak_generic_role_mapper_test.go index 5cc2c1dd..f60ef07f 100644 --- a/provider/resource_keycloak_generic_role_mapper_test.go +++ b/provider/resource_keycloak_generic_role_mapper_test.go @@ -156,6 +156,42 @@ func TestAccKeycloakGenericRoleMapper_basicClientScopeRealmRole(t *testing.T) { }) } +func TestAccKeycloakGenericRoleMapper_deleteIndividualMappers(t *testing.T) { + t.Parallel() + + var someRole = &keycloak.Role{} + var someOtherRole = &keycloak.Role{} + var client = &keycloak.GenericClient{} + + clientName := acctest.RandomWithPrefix("tf-acc") + someRoleName := acctest.RandomWithPrefix("tf-acc") + someOtherRoleName := acctest.RandomWithPrefix("tf-acc") + + resource.Test(t, resource.TestCase{ + ProviderFactories: testAccProviderFactories, + PreCheck: func() { testAccPreCheck(t) }, + CheckDestroy: testAccCheckKeycloakGenericRoleMapperDestroy("keycloak_generic_role_mapper.client-with-some-role"), + Steps: []resource.TestStep{ + { + Config: testKeycloakGenericRoleMapper_basicClientDedicatedAllRealmRoles(clientName, someRoleName, someOtherRoleName), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakGenericClientRoleMapperExists("keycloak_generic_role_mapper.client-with-some-role"), + testAccCheckKeycloakGenericClientRoleMapperExists("keycloak_generic_role_mapper.client-with-some-other-role"), + testAccCheckKeycloakRoleFetch("keycloak_role.some-role", someRole), + testAccCheckKeycloakRoleFetch("keycloak_role.some-other-role", someOtherRole), + testAccCheckKeycloakGenericClientFetch("keycloak_openid_client.client", client), + ), + }, + { + Config: testKeycloakGenericRoleMapper_basicClientDedicatedPartialRealmRoles(clientName, someRoleName, someOtherRoleName), + Check: resource.ComposeTestCheckFunc( + testAccCheckKeycloakGenericClientRoleMapperExists("keycloak_generic_role_mapper.client-with-some-other-role"), + ), + }, + }, + }) +} + func testAccCheckKeycloakGenericRoleMapperExists(resourceName string) resource.TestCheckFunc { return func(s *terraform.State) error { _, ok := s.RootModule().Resources[resourceName] @@ -178,6 +214,16 @@ func getGenericRoleMapperId(resourceName string) resource.ImportStateIdFunc { } } +func testAccCheckKeycloakGenericRoleMapperDestroy(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[resourceName] + if ok { + return fmt.Errorf("resource should not exist: %s", resourceName) + } + return nil + } +} + func testKeycloakGenericRoleMapper_basic(parentClientName, parentRoleName, childClientName string) string { return fmt.Sprintf(` data "keycloak_realm" "realm" { @@ -264,3 +310,69 @@ resource "keycloak_generic_role_mapper" "clientscope-with-realm-role" { } `, testAccRealm.Realm, roleName, clientScopeName) } + +func testKeycloakGenericRoleMapper_basicClientDedicatedAllRealmRoles(clientName, someRoleName, someOtherRoleName string) string { + return fmt.Sprintf(` +data "keycloak_realm" "realm" { + realm = "%s" +} + +resource "keycloak_openid_client" "client" { + realm_id = data.keycloak_realm.realm.id + client_id = "%s" + access_type = "PUBLIC" +} + +resource "keycloak_role" "some-role" { + realm_id = data.keycloak_realm.realm.id + name = "%s" +} + +resource "keycloak_role" "some-other-role" { + realm_id = data.keycloak_realm.realm.id + name = "%s" +} + +resource "keycloak_generic_role_mapper" "client-with-some-role" { + realm_id = data.keycloak_realm.realm.id + client_id = keycloak_openid_client.client.id + role_id = keycloak_role.some-role.id +} + +resource "keycloak_generic_role_mapper" "client-with-some-other-role" { + realm_id = data.keycloak_realm.realm.id + client_id = keycloak_openid_client.client.id + role_id = keycloak_role.some-other-role.id +} + `, testAccRealm.Realm, clientName, someRoleName, someOtherRoleName) +} + +func testKeycloakGenericRoleMapper_basicClientDedicatedPartialRealmRoles(clientName, someRoleName, someOtherRoleName string) string { + return fmt.Sprintf(` +data "keycloak_realm" "realm" { + realm = "%s" +} + +resource "keycloak_openid_client" "client" { + realm_id = data.keycloak_realm.realm.id + client_id = "%s" + access_type = "PUBLIC" +} + +resource "keycloak_role" "some-role" { + realm_id = data.keycloak_realm.realm.id + name = "%s" +} + +resource "keycloak_role" "some-other-role" { + realm_id = data.keycloak_realm.realm.id + name = "%s" +} + +resource "keycloak_generic_role_mapper" "client-with-some-other-role" { + realm_id = data.keycloak_realm.realm.id + client_id = keycloak_openid_client.client.id + role_id = keycloak_role.some-other-role.id +} + `, testAccRealm.Realm, clientName, someRoleName, someOtherRoleName) +}