Something went wrong on our end
-
Alena Petraki authored388f0dcf
user.go 7.42 KiB
package auth
import (
"context"
"fmt"
"git.perx.ru/perxis/perxis-go/pkg/collaborators"
"git.perx.ru/perxis/perxis-go/pkg/environments"
"git.perx.ru/perxis/perxis-go/pkg/errors"
"git.perx.ru/perxis/perxis-go/pkg/members"
"git.perx.ru/perxis/perxis-go/pkg/permission"
"git.perx.ru/perxis/perxis-go/pkg/roles"
"git.perx.ru/perxis/perxis-go/pkg/spaces"
"git.perx.ru/perxis/perxis-go/pkg/users"
"git.perx.ru/perxis/perxis/services"
)
type UserPrincipal struct {
id string
identity string
user *users.User
invalid bool
spaceID string
orgID string
users users.Users
members members.Members
hasMemberRole bool
memberRole members.Role
collaborators collaborators.Collaborators
spaces spaces.Spaces
environments environments.Environments
roles roles.Roles
}
func (u UserPrincipal) Format(f fmt.State, verb rune) {
f.Write([]byte(fmt.Sprintf("UserPrincipal{ID: '%s', Identity: '%s'}", u.id, u.identity)))
}
func (u *UserPrincipal) Space(spaceID string) SpaceAccessor {
u.spaceID = spaceID
u.orgID = ""
return u
}
func (u *UserPrincipal) getSpace(ctx context.Context, spaceID string) *spaces.Space {
if spaceID == "" {
return nil
}
space, _ := u.spaces.Get(WithSystem(ctx), spaceID)
return space
}
func (u UserPrincipal) Organization(orgID string) OrganizationAccessor {
u.orgID = orgID
return &u
}
func (u *UserPrincipal) GetID(ctx context.Context) string {
user := u.User(ctx)
if user == nil {
return ""
}
return user.ID
}
func (u *UserPrincipal) GetIdentity(ctx context.Context) string {
return u.identity
}
func (u *UserPrincipal) IsValid(ctx context.Context) bool {
if u == nil {
return false
}
return u.User(ctx) != nil
}
func (u *UserPrincipal) IsSystem(ctx context.Context) bool {
user := u.User(ctx)
if user != nil {
return user.IsSystem()
}
return false
}
func (u *UserPrincipal) IsManagementAllowed(ctx context.Context, spaceID string) error {
if !u.IsValid(ctx) {
return ErrAccessDenied
}
if u.IsSystem(ctx) {
return nil
}
if u.Member(ctx).IsPrivileged() {
return nil
}
if role := u.Role(ctx, spaceID); role != nil && role.AllowManagement {
return nil
}
return ErrAccessDenied
}
func (u *UserPrincipal) User(ctx context.Context) *users.User {
if u.invalid {
return nil
}
if u.user != nil {
return u.user
}
if u.users == nil {
u.invalid = true
return nil
}
var user *users.User
var err error
switch {
case u.id != "":
user, err = u.users.Get(WithSystem(ctx), u.id)
case u.identity != "":
ctx = WithSystem(ctx)
user, err = u.users.GetByIdentity(WithSystem(ctx), u.identity)
}
if err != nil || user == nil {
u.invalid = true
return nil
}
u.user = user
return u.user
}
func (u *UserPrincipal) Member(ctx context.Context) members.Role {
if u.hasMemberRole {
return u.memberRole
}
if u.members == nil || (u.orgID == "" && u.spaceID == "") {
u.hasMemberRole = true
return members.NotMember
}
if u.orgID == "" && u.spaceID != "" {
sp := u.getSpace(ctx, u.spaceID)
if sp == nil {
u.hasMemberRole = true
return members.NotMember
}
u.orgID = sp.OrgID
}
role, err := u.members.Get(WithSystem(ctx), u.orgID, u.GetID(ctx))
if err != nil {
role = members.NotMember
}
u.memberRole = role
u.hasMemberRole = true
return u.memberRole
}
// HasSpaceAccess проверяет, есть ли у пользователя доступ к пространству
// Пользователь имеет доступ к пространству если:
// - Является участником пространства (даже если его роль не существует)
// - Пространство позволяет доступ для не участников (есть роли AnonymousRole/AuthorizedRole/ViewRole)
// Deprecated :use HasAccess
func (u *UserPrincipal) HasSpaceAccess(ctx context.Context, spaceID string) bool {
res, _ := u.hasRole(ctx, spaceID)
return res
}
// HasAccess проверяет, есть ли у пользователя доступ к пространству
// Пользователь имеет доступ к пространству если:
// - Является участником пространства (даже если его роль не существует)
// - Пространство позволяет доступ для не участников (есть роли AnonymousRole/AuthorizedRole/ViewRole)
func (u *UserPrincipal) HasAccess(ctx context.Context, spaceID, orgID string) error {
if !u.IsValid(ctx) {
return services.ErrAccessDenied
}
if u.IsSystem(ctx) {
return nil
}
if spaceID != "" {
hasAllow, err := u.hasRole(ctx, spaceID)
if err != nil {
return err
}
if hasAllow {
return nil
}
}
if orgID != "" {
if u.Organization(orgID).Member(ctx).IsPrivileged() {
return nil
}
} else {
if u.Member(ctx).IsPrivileged() {
return nil
}
}
return services.ErrAccessDenied
}
func (u *UserPrincipal) hasRole(ctx context.Context, spaceID string) (bool, error) {
if u.spaceID == "" || spaceID == "" {
return false, nil
}
ctx = WithSystem(ctx)
if spaceID != u.spaceID {
_, cErr := u.collaborators.Get(ctx, spaceID, u.spaceID)
if cErr == nil {
return true, nil
}
_, rErr := u.roles.Get(ctx, spaceID, roles.ViewRole)
if rErr == nil {
return true, nil
}
if errors.Is(cErr, services.ErrNotFound) || errors.Is(rErr, services.ErrNotFound) {
if sp := u.getSpace(ctx, spaceID); sp == nil {
return false, services.ErrNotFound
}
}
return false, nil
}
_, cErr := u.collaborators.Get(ctx, spaceID, u.GetID(ctx))
if cErr == nil {
return true, nil
}
_, rErr := u.roles.Get(ctx, spaceID, roles.AuthorizedRole)
if rErr == nil {
return true, nil
}
if errors.Is(cErr, services.ErrNotFound) || errors.Is(rErr, services.ErrNotFound) {
if sp := u.getSpace(ctx, spaceID); sp == nil {
return false, services.ErrNotFound
}
}
return false, nil
}
func (u *UserPrincipal) getRoleID(ctx context.Context, spaceID string) string {
if u.spaceID == "" || spaceID == "" {
return ""
}
ctx = WithSystem(ctx)
if spaceID != u.spaceID {
rID, err := u.collaborators.Get(ctx, spaceID, u.spaceID)
if err != nil {
rID = roles.ViewRole
}
return rID
}
if roleID, err := u.collaborators.Get(ctx, spaceID, u.GetID(ctx)); err == nil {
return roleID
}
return roles.AuthorizedRole
}
func (u *UserPrincipal) Role(ctx context.Context, spaceID string) *roles.Role {
if roleID := u.getRoleID(ctx, spaceID); roleID != "" {
role, _ := u.roles.Get(WithSystem(ctx), spaceID, roleID)
return role
}
return nil
}
func (u *UserPrincipal) Rules(ctx context.Context, spaceID, envID string) permission.Ruleset {
if spaceID == "" || envID == "" {
return nil
}
if u.spaceID == spaceID && (u.IsSystem(ctx) || u.Member(ctx).IsPrivileged()) {
return permission.PrivilegedRuleset{}
}
role := u.Role(ctx, spaceID)
if role == nil {
return nil
}
if !hasEnvironmentAccess(ctx, u.environments, role, envID) {
return nil
}
return role.Rules
}
func IsValidUser(ctx context.Context, p Principal) bool {
if p == nil {
return false
}
if u, ok := p.(*UserPrincipal); ok {
return u.IsValid(ctx)
}
return false
}
func User(ctx context.Context, p Principal) *users.User {
if u, ok := p.(*UserPrincipal); ok {
return u.User(ctx)
}
return nil
}
func (u *UserPrincipal) HasEnvironmentAccess(ctx context.Context, spaceID, env string) bool {
return hasEnvironmentAccess(ctx, u.environments, u.Role(ctx, spaceID), env)
}