app/registry/admins.go (184 lines of code) (raw):

package registry import ( "context" "fmt" "strings" "github.com/gosimple/slug" "github.com/pkg/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "ddm-admin-console/service/keycloak" ) type Admin struct { Username string `json:"username" yaml:"username"` Email string `json:"email" yaml:"email"` FirstName string `json:"firstName" yaml:"firstName"` LastName string `json:"lastName" yaml:"lastName"` TmpPassword string `json:"tmpPassword,omitempty" yaml:"tmpPassword,omitempty"` PasswordVaultSecret string `yaml:"passwordVaultSecret" json:"passwordVaultSecret"` PasswordVaultSecretKey string `yaml:"passwordVaultSecretKey" json:"passwordVaultSecretKey"` } type Admins struct { keycloakService keycloak.ServiceInterface usersRealm string usersNamespace string } func MakeAdmins(keycloakService keycloak.ServiceInterface, usersRealm, usersNamespace string) *Admins { return &Admins{ keycloakService: keycloakService, usersRealm: usersRealm, usersNamespace: usersNamespace, } } func (a *Admins) GetAdmins(ctx context.Context, registryName string) ([]Admin, error) { usrs, err := a.keycloakService.GetUsersByRealm(ctx, a.usersRealm) if err != nil { return nil, errors.Wrap(err, "unable to get users by realm") } admins := []Admin{} for _, u := range usrs { for _, g := range u.Spec.Groups { if g == userGroupRoleNameFromRegistry(registryName) { admins = append(admins, Admin{ Username: u.Spec.Username, Email: u.Spec.Email, FirstName: u.Spec.FirstName, LastName: u.Spec.LastName, }) } } } return admins, nil } //deprecated func (a *Admins) SyncAdmins(ctx context.Context, registryName string, admins []Admin) error { usrs, err := a.keycloakService.GetUsersByRealm(ctx, a.usersRealm) if err != nil { return errors.Wrap(err, "unable to get users by realm") } adminsDict := make(map[string]Admin) for i, v := range admins { adminsDict[v.Email] = admins[i] } for i := range usrs { if _, ok := adminsDict[usrs[i].Spec.Email]; ok { // add to groups and roles // remove from dict if err := a.adminAddToGroupsAndRoles(ctx, registryName, &usrs[i]); err != nil { return errors.Wrap(err, "unable to add registry to realm user groups and roles") } delete(adminsDict, usrs[i].Spec.Email) } else { // remove from groups and roles if err := a.adminRemoveFromGroupsAndRoles(ctx, registryName, &usrs[i]); err != nil { return errors.Wrap(err, "unable to remote registry from realm user groups and roles") } } } for _, adm := range adminsDict { if err := a.adminCreate(ctx, registryName, &adm); err != nil { return errors.Wrap(err, "unable to create admin") } } return nil } func (a *Admins) adminCreate(ctx context.Context, registryName string, adm *Admin) error { if err := a.keycloakService.CreateUser(ctx, &keycloak.KeycloakRealmUser{ ObjectMeta: metav1.ObjectMeta{ Name: userK8SNameFromUsername(adm.Username), Namespace: a.usersNamespace, }, Spec: keycloak.KeycloakRealmUserSpec{ FirstName: adm.FirstName, LastName: adm.LastName, Username: adm.Username, Roles: []string{userGroupRoleNameFromRegistry(registryName)}, Groups: []string{userGroupRoleNameFromRegistry(registryName)}, Email: adm.Email, Realm: a.usersRealm, Password: adm.TmpPassword, KeepResource: true, Enabled: true, EmailVerified: true, RequiredUserActions: []string{"UPDATE_PASSWORD"}, }, }); err != nil { return errors.Wrap(err, "unable to create realm user from admin") } return nil } func userGroupRoleNameFromRegistry(registryName string) string { return fmt.Sprintf("cp-registry-admin-%s", registryName) } func userK8SNameFromUsername(username string) string { return fmt.Sprintf("admin-%s", strings.Replace(slug.Make(username), "_", "-", -1)) } func (a *Admins) adminRemoveFromGroupsAndRoles(ctx context.Context, registryName string, u *keycloak.KeycloakRealmUser) error { groupRemoved, roleRemoved := false, false var newGroups, newRoles []string for _, g := range u.Spec.Groups { if g == userGroupRoleNameFromRegistry(registryName) { groupRemoved = true continue } newGroups = append(newGroups, g) } if groupRemoved { u.Spec.Groups = newGroups } for _, r := range u.Spec.Roles { if r == userGroupRoleNameFromRegistry(registryName) { roleRemoved = true continue } newRoles = append(newRoles, r) } if roleRemoved { u.Spec.Roles = newRoles } if groupRemoved || roleRemoved { if err := a.keycloakService.UpdateUser(ctx, u); err != nil { return errors.Wrap(err, "unable to update user") } } return nil } func (a *Admins) adminAddToGroupsAndRoles(ctx context.Context, registryName string, u *keycloak.KeycloakRealmUser) error { addToGroups, addToRoles := true, true for _, g := range u.Spec.Groups { if g == userGroupRoleNameFromRegistry(registryName) { addToGroups = false break } } if addToGroups { u.Spec.Groups = append(u.Spec.Groups, userGroupRoleNameFromRegistry(registryName)) } for _, r := range u.Spec.Roles { if r == userGroupRoleNameFromRegistry(registryName) { addToRoles = false break } } if addToRoles { u.Spec.Roles = append(u.Spec.Roles, userGroupRoleNameFromRegistry(registryName)) } if addToRoles || addToGroups { if err := a.keycloakService.UpdateUser(ctx, u); err != nil { return errors.Wrap(err, "unable to update user") } } return nil } func (a *Admins) formatViewAdmins(ctx context.Context, registryName string) (string, error) { usrs, err := a.keycloakService.GetUsersByRealm(ctx, a.usersRealm) if err != nil { return "", errors.Wrap(err, "unable to load admins") } var registryAdmins []string for _, u := range usrs { for _, role := range u.Spec.Roles { if role == userGroupRoleNameFromRegistry(registryName) { registryAdmins = append(registryAdmins, u.Spec.Email) break } } } return strings.Join(registryAdmins, ", "), nil }