forked from ory/keto
/
warden_local.go
111 lines (98 loc) · 2.74 KB
/
warden_local.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
/*
* Copyright © 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
*
* 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.
*
* @author Aeneas Rekkas <aeneas+oss@aeneas.io>
* @copyright 2015-2018 Aeneas Rekkas <aeneas+oss@aeneas.io>
* @license Apache-2.0
*/
package warden
import (
"context"
"github.com/ory/fosite"
"github.com/ory/keto/role"
"github.com/ory/ladon"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
func NewWarden(
warden ladon.Warden,
roles role.Manager,
l logrus.FieldLogger) *Warden {
return &Warden{
Warden: warden,
Roles: roles,
L: l,
}
}
type Warden struct {
Warden ladon.Warden
Roles role.Manager
L logrus.FieldLogger
}
func (w *Warden) IsAllowed(ctx context.Context, a *AccessRequest) error {
if err := w.isAllowed(ctx, &ladon.Request{
Resource: a.Resource,
Action: a.Action,
Subject: a.Subject,
Context: a.Context,
}); err != nil {
w.L.WithFields(logrus.Fields{
"subject": a.Subject,
"request": a,
"reason": "The policy decision point denied the request",
}).WithError(err).Infof("Access denied")
return err
}
w.L.WithFields(logrus.Fields{
"subject": a.Subject,
"request": a,
"reason": "The policy decision point allowed the request",
}).Infof("Access allowed")
return nil
}
func (w *Warden) isAllowed(ctx context.Context, a *ladon.Request) error {
groups, err := w.Roles.FindRolesByMember(a.Subject, 10000, 0)
if err != nil {
return err
}
errs := make([]error, len(groups)+1)
return w.Warden.IsAllowed(&ladon.Request{
Resource: a.Resource,
Action: a.Action,
Subject: a.Subject,
Context: a.Context,
})
for k, g := range groups {
errs[k+1] = w.Warden.IsAllowed(&ladon.Request{
Resource: a.Resource,
Action: a.Action,
Subject: g.ID,
Context: a.Context,
})
}
for _, err := range errs {
if errors.Cause(err) == ladon.ErrRequestForcefullyDenied {
return errors.Wrap(fosite.ErrRequestForbidden, err.Error())
}
}
// If no one explicitly denies the access request (e.g. some group), it's ok to return with "access granted"
// if at least one of the decisions is positive (no error)
for _, err := range errs {
if err == nil {
return nil
}
}
return errors.Wrap(fosite.ErrRequestForbidden, ladon.ErrRequestDenied.Error())
}