Select Git revision
client.go 5.45 KiB
package auth
import (
"context"
"fmt"
"git.perx.ru/perxis/perxis-go/pkg/clients"
"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/service"
"git.perx.ru/perxis/perxis-go/pkg/spaces"
)
type ClientPrincipal struct {
identity *clients.GetByParams
spaceID string
space *spaces.Space
client *clients.Client
invalid bool
spaces spaces.Spaces
environments environments.Environments
clients clients.Clients
roles roles.Roles
collaborators collaborators.Collaborators
}
func NewClientPrincipal(identity *clients.GetByParams) *ClientPrincipal {
return &ClientPrincipal{identity: identity}
}
func (c ClientPrincipal) Format(f fmt.State, verb rune) {
var identity string
switch {
case c.identity == nil:
identity = "<nil>"
case c.identity.APIKey != "":
identity = fmt.Sprintf("APIKey: '%s'", c.identity.APIKey)
case c.identity.OAuthClientID != "":
identity = fmt.Sprintf("OAuthClientID: '%s'", c.identity.OAuthClientID)
case c.identity.TLSSubject != "":
identity = fmt.Sprintf("TLSSubject: '%s'", c.identity.TLSSubject)
}
var id string
if c.client != nil {
id = c.client.ID
}
_, _ = f.Write([]byte(fmt.Sprintf("ClientPrincipal{ID: '%s', Identity: {%s}}", id, identity)))
}
func (c *ClientPrincipal) Space(spaceID string) SpaceAccessor {
c.spaceID = spaceID
c.space = nil
c.invalid = false
c.client = nil
return c
}
// nolint:unused
func (c *ClientPrincipal) getSpace(ctx context.Context, spaceID string) *spaces.Space {
if spaceID == "" {
return nil
}
space, _ := c.spaces.Get(WithSystem(ctx), spaceID)
return space
}
func (ClientPrincipal) IsSystem(ctx context.Context) bool {
return false
}
func (c *ClientPrincipal) IsManagementAllowed(ctx context.Context, spaceID string) error {
if !c.IsValid(ctx) {
return service.ErrAccessDenied
}
if role := c.Role(ctx, spaceID); role != nil && role.AllowManagement {
return nil
}
return service.ErrAccessDenied
}
func (c *ClientPrincipal) Member(ctx context.Context) members.Role {
return members.NotMember
}
func (c *ClientPrincipal) HasSpaceAccess(ctx context.Context, spaceID string) bool {
if c.spaceID == "" {
return false
}
client, _ := c.Client(ctx)
return client != nil && client.SpaceID == spaceID
}
func (c *ClientPrincipal) GetID(ctx context.Context) string {
client, _ := c.Client(ctx)
if client == nil {
return ""
}
return client.ID
}
func (c *ClientPrincipal) GetIdentity(ctx context.Context) *clients.GetByParams {
return c.identity
}
func (c *ClientPrincipal) IsValid(ctx context.Context) bool {
if c == nil {
return false
}
client, _ := c.Client(ctx)
return client != nil
}
func (c *ClientPrincipal) Client(ctx context.Context) (*clients.Client, error) {
if c.invalid {
return nil, nil
}
if c.client != nil {
return c.client, nil
}
if c.clients == nil {
c.invalid = true
return nil, nil
}
client, err := c.clients.GetBy(WithSystem(ctx), c.spaceID, c.identity)
if err != nil || client == nil || client.IsDisabled() {
c.invalid = true
return nil, err
}
c.client = client
return c.client, nil
}
func (c *ClientPrincipal) HasEnvironmentAccess(ctx context.Context, spaceID, envID string) bool {
return hasEnvironmentAccess(ctx, c.environments, c.Role(ctx, spaceID), envID)
}
func (c *ClientPrincipal) getRoleID(ctx context.Context, spaceID string) (string, bool) {
if c.spaceID == "" || spaceID == "" {
return "", false
}
if spaceID == c.spaceID {
cl, _ := c.Client(ctx)
if cl == nil || cl.RoleID == "" {
return "", false
}
return cl.RoleID, true
}
rID, err := c.collaborators.Get(WithSystem(ctx), spaceID, c.spaceID)
if err != nil {
rID = roles.ViewRole
}
return rID, true
}
func (c *ClientPrincipal) Role(ctx context.Context, spaceID string) *roles.Role {
if c.spaceID == "" {
return nil
}
rID, ok := c.getRoleID(ctx, spaceID)
if !ok {
return nil
}
role, err := c.roles.Get(WithSystem(ctx), spaceID, rID)
if err == nil {
// c.hasRole = true
// c.role = role
return role
}
return nil
}
func (c *ClientPrincipal) Rules(ctx context.Context, spaceID, envID string) permission.Ruleset {
if c.spaceID == "" || spaceID == "" || envID == "" {
return nil
}
role := c.Role(ctx, spaceID)
if role == nil {
return nil
}
if role.AllowManagement {
return permission.PrivilegedRuleset{}
}
if hasEnvironmentAccess(ctx, c.environments, role, envID) {
return role.Rules
}
return nil
}
func (c *ClientPrincipal) HasAccess(ctx context.Context, spaceID, orgID string) error {
if !c.IsValid(ctx) {
return service.ErrAccessDenied
}
if c.IsSystem(ctx) {
return nil
}
if spaceID != "" {
if c.spaceID == "" {
return service.ErrAccessDenied
}
client, _ := c.Client(ctx)
if client != nil && client.SpaceID == spaceID {
return nil
}
}
if c.Member(ctx).IsPrivileged() {
return nil
}
return service.ErrAccessDenied
}
// nolint:unused
func (c *ClientPrincipal) hasRole(ctx context.Context, spaceID string) (bool, error) {
if c.spaceID == "" {
return false, nil
}
client, err := c.Client(ctx)
if err != nil && errors.Is(err, service.ErrNotFound) {
if sp := c.getSpace(ctx, spaceID); sp == nil {
return false, service.ErrNotFound
}
}
if client != nil && client.SpaceID == spaceID {
return true, nil
}
return false, nil
}