File size: 2,966 Bytes
b110593
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//                           _       _
// __      _____  __ ___   ___  __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
//  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
//   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
//  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
//
//  CONTACT: [email protected]
//

package adminlist

import (
	"github.com/weaviate/weaviate/entities/models"
	"github.com/weaviate/weaviate/usecases/auth/authorization/errors"
)

const AnonymousPrincipalUsername = "anonymous"

// Authorizer provides either full (admin) or no access
type Authorizer struct {
	adminUsers     map[string]int
	readOnlyUsers  map[string]int
	adminGroups    map[string]int
	readOnlyGroups map[string]int
}

// New Authorizer using the AdminList method
func New(cfg Config) *Authorizer {
	a := &Authorizer{}
	a.addAdminUserList(cfg.Users)
	a.addReadOnlyUserList(cfg.ReadOnlyUsers)
	a.addAdminGroupList(cfg.Groups)
	a.addReadOnlyGroupList(cfg.ReadOnlyGroups)
	return a
}

// Authorize will give full access (to any resource!) if the user is part of
// the admin list or no access at all if they are not
func (a *Authorizer) Authorize(principal *models.Principal, verb, resource string) error {
	if principal == nil {
		principal = newAnonymousPrincipal()
	}

	if _, ok := a.adminUsers[principal.Username]; ok {
		return nil
	}

	for _, group := range principal.Groups {
		if _, ok := a.adminGroups[group]; ok {
			return nil
		}
	}

	if verb == "get" || verb == "list" {
		if _, ok := a.readOnlyUsers[principal.Username]; ok {
			return nil
		}
		for _, group := range principal.Groups {
			if _, ok := a.readOnlyGroups[group]; ok {
				return nil
			}
		}
	}

	return errors.NewForbidden(principal, verb, resource)
}

func (a *Authorizer) addAdminUserList(users []string) {
	// build a map for more efficient lookup on long lists
	if a.adminUsers == nil {
		a.adminUsers = map[string]int{}
	}

	for _, user := range users {
		a.adminUsers[user] = 1
	}
}

func (a *Authorizer) addReadOnlyUserList(users []string) {
	// build a map for more efficient lookup on long lists
	if a.readOnlyUsers == nil {
		a.readOnlyUsers = map[string]int{}
	}

	for _, user := range users {
		a.readOnlyUsers[user] = 1
	}
}

func (a *Authorizer) addAdminGroupList(groups []string) {
	// build a map for more efficient lookup on long lists
	if a.adminGroups == nil {
		a.adminGroups = map[string]int{}
	}

	for _, group := range groups {
		a.adminGroups[group] = 1
	}
}

func (a *Authorizer) addReadOnlyGroupList(groups []string) {
	// build a map for more efficient lookup on long lists
	if a.readOnlyGroups == nil {
		a.readOnlyGroups = map[string]int{}
	}

	for _, group := range groups {
		a.readOnlyGroups[group] = 1
	}
}

func newAnonymousPrincipal() *models.Principal {
	return &models.Principal{
		Username: AnonymousPrincipalUsername,
	}
}