diff --git a/keycloak/role_scope_mapping.go b/keycloak/role_scope_mapping.go index eeb91679..7cecc27d 100644 --- a/keycloak/role_scope_mapping.go +++ b/keycloak/role_scope_mapping.go @@ -5,6 +5,15 @@ import ( "fmt" ) +type RealmRoleRepresentation 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]RealmRoleRepresentation{ + { + Id: role.Id, + Name: role.Name, + Description: role.Description, + Composite: role.Composite, + ClientRole: role.ClientRole, + ContainerId: role.ContainerId, + }, + } + return keycloakClient.delete(ctx, roleUrl, body) + } } 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) +}