pkg/client/keycloak/adapter/gocloak_adapter_sync_entity_roles.go (176 lines of code) (raw):
package adapter
import (
"context"
"github.com/Nerzal/gocloak/v12"
"github.com/pkg/errors"
)
func (a GoCloakAdapter) syncEntityRealmRoles(
entityID string,
realm string,
claimedRealmRoles []string,
currentRealmRoles *[]gocloak.Role,
addRoleFunc func(ctx context.Context, token, realm, entityID string, roles []gocloak.Role) error,
delRoleFunc func(ctx context.Context, token, realm, entityID string, roles []gocloak.Role) error,
) error {
currentRealmRoleMap := a.makeCurrentEntityRoles(currentRealmRoles)
claimedRoleMap := a.makeClimedEntityRoles(claimedRealmRoles)
realmRolesToAdd, err := a.makeEntityRolesToAdd(realm, claimedRealmRoles, currentRealmRoleMap)
if err != nil {
return err
}
if len(realmRolesToAdd) > 0 {
if err := addRoleFunc(context.Background(), a.token.AccessToken, realm, entityID,
realmRolesToAdd); err != nil {
return errors.Wrapf(err, "unable to add realm roles to entity, realm: %s, entity id: %s, roles: %v",
realm, entityID, realmRolesToAdd)
}
}
realmRolesToDelete := make([]gocloak.Role, 0, len(currentRealmRoleMap))
for currentRoleName, role := range currentRealmRoleMap {
if _, ok := claimedRoleMap[currentRoleName]; !ok {
realmRolesToDelete = append(realmRolesToDelete, role)
}
}
if len(realmRolesToDelete) > 0 {
if err := delRoleFunc(context.Background(), a.token.AccessToken, realm, entityID,
realmRolesToDelete); err != nil {
return errors.Wrapf(err, "unable to delete realm roles from group, realm: %s, entity id: %s, roles: %v",
realm, entityID, realmRolesToDelete)
}
}
return nil
}
func (a GoCloakAdapter) syncOneEntityClientRole(
realm,
entityID,
clientID string,
claimedRoles []string,
currentRoles map[string]*gocloak.ClientMappingsRepresentation,
addRoleFunc func(ctx context.Context, token, realm, clientID, entityID string, roles []gocloak.Role) error,
delRoleFunc func(ctx context.Context, token, realm, clientID, entityID string, roles []gocloak.Role) error,
) error {
CID, err := a.GetClientID(clientID, realm)
if err != nil {
return errors.Wrapf(err, "unable to get client id, realm: %s, clientID %s", realm, clientID)
}
currentClientRoles := a.makeCurrentClientRoles(clientID, currentRoles)
claimedClientRoles := a.makeClaimedClientRoles(claimedRoles)
rolesToAdd, err := a.makeClientRolesToAdd(realm, CID, currentClientRoles, claimedClientRoles)
if err != nil {
return err
}
if len(rolesToAdd) > 0 {
if err := addRoleFunc(context.Background(), a.token.AccessToken, realm, CID, entityID, rolesToAdd); err != nil {
return errors.Wrapf(err, "unable to add realm role to entity, realm: %s, clientID: %s, entityID: %s", realm, CID, entityID)
}
}
rolesToDelete := make([]gocloak.Role, 0, len(currentClientRoles))
for k, v := range currentClientRoles {
if _, ok := claimedClientRoles[k]; !ok {
rolesToDelete = append(rolesToDelete, *v)
}
}
if len(rolesToDelete) > 0 {
if err := delRoleFunc(context.Background(), a.token.AccessToken, realm, CID, entityID, rolesToDelete); err != nil {
return errors.Wrapf(err, "unable to del client role from entity, realm: %s, clientID: %s, entityID: %s", realm, CID, entityID)
}
}
return nil
}
func (a GoCloakAdapter) syncEntityClientRoles(
realm,
entityID string,
claimedRoles map[string][]string,
currentRoles map[string]*gocloak.ClientMappingsRepresentation,
addRoleFunc func(ctx context.Context, token, realm, clientID, entityID string, roles []gocloak.Role) error,
delRoleFunc func(ctx context.Context, token, realm, clientID, groupID string, roles []gocloak.Role) error,
) error {
for clientID, roles := range claimedRoles {
if err := a.syncOneEntityClientRole(realm, entityID, clientID, roles, currentRoles, addRoleFunc, delRoleFunc); err != nil {
return errors.Wrap(err, "error during syncOneEntityClientRole")
}
}
for clientName, client := range currentRoles {
if _, ok := claimedRoles[clientName]; !ok && client.Mappings != nil {
rolesToDelete := make([]gocloak.Role, 0, len(currentRoles))
rolesToDelete = append(rolesToDelete, *client.Mappings...)
if len(rolesToDelete) > 0 {
if err := delRoleFunc(context.Background(), a.token.AccessToken, realm,
*client.ID, entityID, rolesToDelete); err != nil {
return errors.Wrap(err, "unable to delete client role from user")
}
}
}
}
return nil
}
func (a GoCloakAdapter) makeCurrentClientRoles(
clientID string,
currentRoles map[string]*gocloak.ClientMappingsRepresentation,
) map[string]*gocloak.Role {
currentClientRoles := make(map[string]*gocloak.Role)
if client, ok := currentRoles[clientID]; ok && client != nil && client.Mappings != nil {
for k, role := range *client.Mappings {
currentClientRoles[*role.Name] = &(*client.Mappings)[k]
}
}
return currentClientRoles
}
func (a GoCloakAdapter) makeClaimedClientRoles(claimedRoles []string) map[string]struct{} {
claimedClientRoles := make(map[string]struct{})
for _, claimedRole := range claimedRoles {
claimedClientRoles[claimedRole] = struct{}{}
}
return claimedClientRoles
}
func (a GoCloakAdapter) makeClientRolesToAdd(
realm,
clientId string,
currentClientRoles map[string]*gocloak.Role,
claimedClientRoles map[string]struct{},
) ([]gocloak.Role, error) {
rolesToAdd := make([]gocloak.Role, 0, len(claimedClientRoles))
for k := range claimedClientRoles {
if _, ok := currentClientRoles[k]; !ok {
role, err := a.client.GetClientRole(context.Background(), a.token.AccessToken, realm, clientId, k)
if err != nil {
return nil, errors.Wrapf(err, "unable to get client role, realm: %s, clientID: %s, role: %s", realm, clientId, k)
}
rolesToAdd = append(rolesToAdd, *role)
}
}
return rolesToAdd, nil
}
func (a GoCloakAdapter) makeCurrentEntityRoles(currentRealmRoles *[]gocloak.Role) map[string]gocloak.Role {
currentRealmRoleMap := make(map[string]gocloak.Role)
if currentRealmRoles != nil {
for i, currentRole := range *currentRealmRoles {
currentRealmRoleMap[*currentRole.Name] = (*currentRealmRoles)[i]
}
}
return currentRealmRoleMap
}
func (a GoCloakAdapter) makeClimedEntityRoles(claimedRealmRoles []string) map[string]struct{} {
claimedRoleMap := make(map[string]struct{})
for _, r := range claimedRealmRoles {
claimedRoleMap[r] = struct{}{}
}
return claimedRoleMap
}
func (a GoCloakAdapter) makeEntityRolesToAdd(
realm string,
claimedRealmRoles []string,
currentRealmRoleMap map[string]gocloak.Role,
) ([]gocloak.Role, error) {
realmRolesToAdd := make([]gocloak.Role, 0, len(claimedRealmRoles))
for _, r := range claimedRealmRoles {
if _, ok := currentRealmRoleMap[r]; !ok {
role, err := a.client.GetRealmRole(context.Background(), a.token.AccessToken, realm, r)
if err != nil {
return nil, errors.Wrapf(err, "unable to get realm role, realm: %s, role: %s", realm, r)
}
realmRolesToAdd = append(realmRolesToAdd, *role)
}
}
return realmRolesToAdd, nil
}