/
authz.go
128 lines (105 loc) · 3.83 KB
/
authz.go
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
120
121
122
123
124
125
126
127
128
package auth
import (
"fmt"
"net/http"
"time"
"github.com/banzaicloud/pipeline/model"
"github.com/casbin/casbin"
"github.com/casbin/gorm-adapter"
"github.com/gin-gonic/gin"
"github.com/spf13/viper"
)
const modelDefinition = `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*")
`
const logging = false
var enforcer *casbin.SyncedEnforcer
// NewAuthorizer returns the MySQL based default authorizer
func NewAuthorizer() gin.HandlerFunc {
dbName := viper.GetString("database.dbname")
adapter := gormadapter.NewAdapter("mysql", model.GetDataSource(dbName), true)
model := casbin.NewModel(modelDefinition)
enforcer = casbin.NewSyncedEnforcer(model, adapter, logging)
enforcer.StartAutoLoadPolicy(10 * time.Second)
addDefaultPolicies()
return newAuthorizer(enforcer)
}
// NewAuthorizer returns the authorizer, uses a Casbin enforcer as input
func newAuthorizer(e *casbin.SyncedEnforcer) gin.HandlerFunc {
return func(c *gin.Context) {
a := &BearerAuthorizer{enforcer: e}
if !a.CheckPermission(c.Request) {
a.RequirePermission(c)
}
}
}
// BearerAuthorizer stores the casbin handler
type BearerAuthorizer struct {
enforcer *casbin.SyncedEnforcer
}
// GetUserID gets the user name from the request.
// Currently, only HTTP Bearer token authentication is supported
func (a *BearerAuthorizer) GetUserID(r *http.Request) string {
user := GetCurrentUser(r)
if user.ID == 0 {
return user.Login // This is needed for Drone virtual user tokens
}
return user.IDString()
}
// CheckPermission checks the user/method/path combination from the request.
// Returns true (permission granted) or false (permission forbidden)
func (a *BearerAuthorizer) CheckPermission(r *http.Request) bool {
userID := a.GetUserID(r)
method := r.Method
path := r.URL.Path
return a.enforcer.Enforce(userID, path, method)
}
// RequirePermission returns the 403 Forbidden to the client
func (a *BearerAuthorizer) RequirePermission(c *gin.Context) {
c.AbortWithStatus(http.StatusForbidden)
}
func addDefaultPolicies() {
basePath := viper.GetString("pipeline.basepath")
enforcer.AddPolicy("default", basePath+"/api/v1/orgs", "*")
enforcer.AddPolicy("default", basePath+"/api/v1/token", "*") // DEPRECATED
enforcer.AddPolicy("default", basePath+"/api/v1/tokens", "*")
enforcer.AddPolicy("defaultVirtual", basePath+"/api/v1/orgs", "GET")
}
// AddDefaultRoleForUser adds all the default non-org-specific role to a user.
func AddDefaultRoleForUser(userID interface{}) {
enforcer.AddRoleForUser(fmt.Sprint(userID), "default")
}
// AddDefaultRoleForVirtualUser adds org list role to a virtual user.
func AddDefaultRoleForVirtualUser(userID interface{}) {
enforcer.AddRoleForUser(fmt.Sprint(userID), "defaultVirtual")
}
// AddOrgRoles creates an organization role, by adding the default (*) org policies for the given organization.
func AddOrgRoles(orgids ...uint) {
basePath := viper.GetString("pipeline.basepath")
for _, orgid := range orgids {
enforcer.AddPolicy(orgRoleName(orgid), fmt.Sprintf("%s/api/v1/orgs/%d", basePath, orgid), "*")
enforcer.AddPolicy(orgRoleName(orgid), fmt.Sprintf("%s/api/v1/orgs/%d/*", basePath, orgid), "*")
}
}
// AddOrgRoleForUser adds a user to an organization by adding the associated organization role.
func AddOrgRoleForUser(userID interface{}, orgids ...uint) {
for _, orgid := range orgids {
enforcer.AddRoleForUser(fmt.Sprint(userID), orgRoleName(orgid))
}
}
// DeleteOrgRoleForUser removes a user from an organization by removing the associated organization role.
func DeleteOrgRoleForUser(userID uint, orgid uint) {
enforcer.DeleteRoleForUser(fmt.Sprint(userID), orgRoleName(orgid))
}
func orgRoleName(orgid uint) string {
return fmt.Sprint("org-", orgid)
}