forked from harness/harness
-
Notifications
You must be signed in to change notification settings - Fork 0
/
check.go
146 lines (132 loc) · 4.54 KB
/
check.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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
// Copyright 2019 Drone IO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package acl
import (
"net/http"
"github.com/drone/drone/core"
"github.com/drone/drone/handler/api/errors"
"github.com/drone/drone/handler/api/render"
"github.com/drone/drone/handler/api/request"
"github.com/drone/drone/logger"
"github.com/go-chi/chi"
"github.com/sirupsen/logrus"
)
// CheckReadAccess returns an http.Handler middleware that authorizes only
// authenticated users with read repository access to proceed to the next
// handler in the chain.
func CheckReadAccess() func(http.Handler) http.Handler {
return CheckAccess(true, false, false)
}
// CheckWriteAccess returns an http.Handler middleware that authorizes only
// authenticated users with write repository access to proceed to the next
// handler in the chain.
func CheckWriteAccess() func(http.Handler) http.Handler {
return CheckAccess(true, true, false)
}
// CheckAdminAccess returns an http.Handler middleware that authorizes only
// authenticated users with admin repository access to proceed to the next
// handler in the chain.
func CheckAdminAccess() func(http.Handler) http.Handler {
return CheckAccess(true, true, true)
}
// CheckAccess returns an http.Handler middleware that authorizes only
// authenticated users with the required read, write or admin access
// permissions to the requested repository resource.
func CheckAccess(read, write, admin bool) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var (
ctx = r.Context()
owner = chi.URLParam(r, "owner")
name = chi.URLParam(r, "name")
)
log := logger.FromRequest(r).
WithField("namespace", owner).
WithField("name", name)
user, ok := request.UserFrom(ctx)
switch {
case ok == false && write == true:
render.Unauthorized(w, errors.ErrUnauthorized)
log.Debugln("api: authentication required for write access")
return
case ok == false && admin == true:
render.Unauthorized(w, errors.ErrUnauthorized)
log.Debugln("api: authentication required for admin access")
return
case ok == true && user.Admin == true:
log.Debugln("api: root access granted")
next.ServeHTTP(w, r)
return
}
repo, noRepo := request.RepoFrom(ctx)
if !noRepo {
// this should never happen. the repository
// should always be injected into the context
// by an upstream handler in the chain.
log.Errorln("api: null repository in context")
render.NotFound(w, errors.ErrNotFound)
return
}
log = log.WithField("visibility", repo.Visibility)
switch {
case admin == true: // continue
case write == true: // continue
case repo.Visibility == core.VisibilityPublic:
log.Debugln("api: read access granted")
next.ServeHTTP(w, r)
return
case ok == false:
render.Unauthorized(w, errors.ErrUnauthorized)
log.Debugln("api: authentication required")
return
case ok == true && repo.Visibility == core.VisibilityInternal:
log.Debugln("api: read access granted")
next.ServeHTTP(w, r)
return
}
perm, ok := request.PermFrom(ctx)
if !ok {
render.NotFound(w, errors.ErrNotFound)
log.Debugln("api: repository permissions not found")
return
}
log = log.WithFields(
logrus.Fields{
"read": perm.Read,
"write": perm.Write,
"admin": perm.Admin,
},
)
switch {
case user.Active == false:
render.Forbidden(w, errors.ErrForbidden)
log.Debugln("api: active account required")
case read == true && perm.Read == false:
render.NotFound(w, errors.ErrNotFound)
log.Debugln("api: read access required")
case write == true && perm.Write == false:
render.NotFound(w, errors.ErrNotFound)
log.Debugln("api: write access required")
case admin == true && perm.Admin == false:
render.NotFound(w, errors.ErrNotFound)
log.Debugln("api: admin access required")
default:
log.Debug("api: access granted")
next.ServeHTTP(w, r.WithContext(
request.WithPerm(ctx, perm),
))
}
})
}
}