-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* add casbin for authorization * rebase commit, tidy up doc sentences, 80 col, refactor if enforcer section * add punctuation on casbin doc
- Loading branch information
1 parent
33fad1e
commit da7ac23
Showing
5 changed files
with
140 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package casbin | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
|
||
stdcasbin "github.com/casbin/casbin" | ||
"github.com/go-kit/kit/endpoint" | ||
) | ||
|
||
type contextKey string | ||
|
||
const ( | ||
// CasbinModelContextKey holds the key to store the access control model | ||
// in context, it can be a path to configuration file or a casbin/model | ||
// Model. | ||
CasbinModelContextKey contextKey = "CasbinModel" | ||
|
||
// CasbinPolicyContextKey holds the key to store the access control policy | ||
// in context, it can be a path to policy file or an implementation of | ||
// casbin/persist Adapter interface. | ||
CasbinPolicyContextKey contextKey = "CasbinPolicy" | ||
|
||
// CasbinEnforcerContextKey holds the key to retrieve the active casbin | ||
// Enforcer. | ||
CasbinEnforcerContextKey contextKey = "CasbinEnforcer" | ||
) | ||
|
||
var ( | ||
// ErrModelContextMissing denotes a casbin model was not passed into | ||
// the parsing of middleware's context. | ||
ErrModelContextMissing = errors.New("CasbinModel is required in context") | ||
|
||
// ErrPolicyContextMissing denotes a casbin policy was not passed into | ||
// the parsing of middleware's context. | ||
ErrPolicyContextMissing = errors.New("CasbinPolicy is required in context") | ||
|
||
// ErrUnauthorized denotes the subject is not authorized to do the action | ||
// intended on the given object, based on the context model and policy. | ||
ErrUnauthorized = errors.New("Unauthorized Access") | ||
) | ||
|
||
// NewEnforcer checks whether the subject is authorized to do the specified | ||
// action on the given object. If a valid access control model and policy | ||
// is given, then the generated casbin Enforcer is stored in the context | ||
// with CasbinEnforcer as the key. | ||
func NewEnforcer( | ||
subject string, object interface{}, action string, | ||
) endpoint.Middleware { | ||
return func(next endpoint.Endpoint) endpoint.Endpoint { | ||
return func(ctx context.Context, request interface{}) ( | ||
response interface{}, err error, | ||
) { | ||
casbinModel := ctx.Value(CasbinModelContextKey) | ||
casbinPolicy := ctx.Value(CasbinPolicyContextKey) | ||
|
||
enforcer := stdcasbin.NewEnforcer(casbinModel, casbinPolicy) | ||
ctx = context.WithValue(ctx, CasbinEnforcerContextKey, enforcer) | ||
if !enforcer.Enforce(subject, object, action) { | ||
return nil, ErrUnauthorized | ||
} | ||
return next(ctx, request) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
package casbin | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
|
||
stdcasbin "github.com/casbin/casbin" | ||
fileadapter "github.com/casbin/casbin/persist/file-adapter" | ||
) | ||
|
||
func TestStructBaseContext(t *testing.T) { | ||
e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil } | ||
|
||
m := stdcasbin.NewModel() | ||
m.AddDef("r", "r", "sub, obj, act") | ||
m.AddDef("p", "p", "sub, obj, act") | ||
m.AddDef("e", "e", "some(where (p.eft == allow))") | ||
m.AddDef("m", "m", "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)") | ||
|
||
a := fileadapter.NewAdapter("testdata/keymatch_policy.csv") | ||
|
||
ctx := context.WithValue(context.Background(), CasbinModelContextKey, m) | ||
ctx = context.WithValue(ctx, CasbinPolicyContextKey, a) | ||
|
||
// positive case | ||
middleware := NewEnforcer("alice", "/alice_data/resource1", "GET")(e) | ||
ctx1, err := middleware(ctx, struct{}{}) | ||
if err != nil { | ||
t.Fatalf("Enforcer returned error: %s", err) | ||
} | ||
_, ok := ctx1.(context.Context).Value(CasbinEnforcerContextKey).(*stdcasbin.Enforcer) | ||
if !ok { | ||
t.Fatalf("context should contains the active enforcer") | ||
} | ||
|
||
// negative case | ||
middleware = NewEnforcer("alice", "/alice_data/resource2", "POST")(e) | ||
_, err = middleware(ctx, struct{}{}) | ||
if err == nil { | ||
t.Fatalf("Enforcer should return error") | ||
} | ||
} | ||
|
||
func TestFileBaseContext(t *testing.T) { | ||
e := func(ctx context.Context, i interface{}) (interface{}, error) { return ctx, nil } | ||
ctx := context.WithValue(context.Background(), CasbinModelContextKey, "testdata/basic_model.conf") | ||
ctx = context.WithValue(ctx, CasbinPolicyContextKey, "testdata/basic_policy.csv") | ||
|
||
// positive case | ||
middleware := NewEnforcer("alice", "data1", "read")(e) | ||
_, err := middleware(ctx, struct{}{}) | ||
if err != nil { | ||
t.Fatalf("Enforcer returned error: %s", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
[request_definition] | ||
r = sub, obj, act | ||
|
||
[policy_definition] | ||
p = sub, obj, act | ||
|
||
[policy_effect] | ||
e = some(where (p.eft == allow)) | ||
|
||
[matchers] | ||
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
p, alice, data1, read | ||
p, bob, data2, write |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
p, alice, /alice_data/*, GET | ||
p, alice, /alice_data/resource1, POST | ||
|
||
p, bob, /alice_data/resource2, GET | ||
p, bob, /bob_data/*, POST | ||
|
||
p, cathy, /cathy_data, (GET)|(POST) |