-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #17 for v0.12.0 Release
- Loading branch information
Showing
20 changed files
with
1,663 additions
and
778 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
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 |
---|---|---|
@@ -1,17 +1,21 @@ | ||
# router - aah framework | ||
[![Build Status](https://travis-ci.org/go-aah/router.svg?branch=master)](https://travis-ci.org/go-aah/router) [![codecov](https://codecov.io/gh/go-aah/router/branch/master/graph/badge.svg)](https://codecov.io/gh/go-aah/router/branch/master) [![Go Report Card](https://goreportcard.com/badge/aahframework.org/router.v0)](https://goreportcard.com/report/aahframework.org/router.v0) [![Version](https://img.shields.io/badge/version-0.11-blue.svg)](https://github.com/go-aah/router/releases/latest) [![GoDoc](https://godoc.org/aahframework.org/router.v0?status.svg)](https://godoc.org/aahframework.org/router.v0) [![License](https://img.shields.io/github/license/go-aah/router.svg)](LICENSE) [![Twitter](https://img.shields.io/badge/twitter-@aahframework-55acee.svg)](https://twitter.com/aahframework) | ||
<p align="center"> | ||
<img src="https://cdn.aahframework.org/assets/img/aah-logo-64x64.png" /> | ||
<h2 align="center">Router by aah framework</h2> | ||
</p> | ||
<p align="center"> | ||
<p align="center"><a href="https://travis-ci.org/go-aah/router"><img src="https://travis-ci.org/go-aah/router.svg?branch=master" alt="Build Status"></a> <a href="https://codecov.io/gh/go-aah/router/branch/master"><img src="https://codecov.io/gh/go-aah/router/branch/master/graph/badge.svg" alt="Code Coverage"></a> <a href="https://goreportcard.com/report/aahframework.org/router.v0"><img src="https://goreportcard.com/badge/aahframework.org/router.v0" alt="Go Report Card"></a> <a href="https://github.com/go-aah/router/releases/latest"><img src="https://img.shields.io/badge/version-0.12.0-blue.svg" alt="Release Version"></a> <a href="https://godoc.org/aahframework.org/router.v0"><img src="https://godoc.org/aahframework.org/router.v0?status.svg" alt="Godoc"></a> <a href="https://twitter.com/aahframework"><img src="https://img.shields.io/badge/twitter-@aahframework-55acee.svg" alt="Twitter @aahframework"></a></p> | ||
</p> | ||
|
||
***v0.11 [released](https://github.com/go-aah/router/releases/latest) and tagged on Mar 27, 2018*** | ||
[HTTP Router](http://docs.aahframework.org/routing.html) brings domain and sub-domains routing, it internally uses customized version of radix tree implementation from `github.com/julienschmidt/httprouter` developer by `@julienschmidt`. | ||
|
||
HTTP Router it supports domain and sub-domains routing. It's built using radix tree routing algorithm of [httprouter](https://github.com/julienschmidt/httprouter) library. | ||
### News | ||
|
||
*`router` developed for aah framework. However, it's an independent library, can be used separately with any `Go` language project. Feel free to use it.* | ||
* `v0.12.0` [released](https://github.com/go-aah/router/releases/latest) and tagged on Jul 06, 2018. | ||
|
||
# Installation | ||
#### Stable Version - Production Ready | ||
```sh | ||
# install the library | ||
## Installation | ||
|
||
```bash | ||
go get -u aahframework.org/router.v0 | ||
``` | ||
|
||
Visit official website https://aahframework.org to learn more. | ||
Visit official website https://aahframework.org to learn more about `aah` framework. |
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,290 @@ | ||
// Copyright (c) Jeevanandam M. (https://github.com/jeevatkm) | ||
// aahframework.org/router source code and usage is governed by a MIT style | ||
// license that can be found in the LICENSE file. | ||
|
||
package router | ||
|
||
import ( | ||
"errors" | ||
"testing" | ||
|
||
"aahframework.org/config.v0" | ||
"aahframework.org/security.v0" | ||
"aahframework.org/security.v0/authz" | ||
"aahframework.org/test.v0/assert" | ||
) | ||
|
||
func TestRouteAuthorizationConfig(t *testing.T) { | ||
cfg, err := config.ParseString(` | ||
user_info { | ||
authorization { | ||
roles = [ | ||
"hasrole(manager)", | ||
"hasanyrole(role1, role2, role3)" | ||
] | ||
permissions = [ | ||
"ispermitted(newsletter:read,write)", | ||
"ispermittedall(newsletter:read,write | newsletter:12345)" | ||
] | ||
} | ||
} | ||
`) | ||
assert.Nil(t, err) | ||
|
||
info, err := parseAuthorizationInfo(cfg, "user_info", &parentRouteInfo{AuthorizationInfo: &authorizationInfo{Satisfy: "either"}}) | ||
assert.Nil(t, err) | ||
assert.NotNil(t, info) | ||
assert.Equal(t, "either", info.Satisfy) | ||
assert.Equal(t, []string{"manager"}, info.Roles["hasrole"]) | ||
assert.Equal(t, []string{"role1", "role2", "role3"}, info.Roles["hasanyrole"]) | ||
assert.Equal(t, []string{"newsletter:read,write"}, info.Permissions["ispermitted"]) | ||
assert.Equal(t, []string{"newsletter:read,write", "newsletter:12345"}, info.Permissions["ispermittedall"]) | ||
assert.True(t, len(info.String()) > 0) | ||
} | ||
|
||
func TestRouteAuthorizationConfigParentRoute(t *testing.T) { | ||
cfg, err := config.ParseString(` | ||
user_info { | ||
} | ||
`) | ||
assert.Nil(t, err) | ||
|
||
info, err := parseAuthorizationInfo(cfg, "user_info", &parentRouteInfo{ | ||
AuthorizationInfo: &authorizationInfo{ | ||
Satisfy: "either", | ||
Roles: map[string][]string{ | ||
"hasrole": []string{"manager"}, | ||
"hasanyrole": []string{"role1", "role2", "role3"}, | ||
}, | ||
Permissions: map[string][]string{ | ||
"ispermitted": []string{"newsletter:read,write"}, | ||
"ispermittedall": []string{"newsletter:read,write", "newsletter:12345"}, | ||
}, | ||
}, | ||
}) | ||
assert.Nil(t, err) | ||
assert.NotNil(t, info) | ||
assert.Equal(t, "either", info.Satisfy) | ||
assert.Equal(t, []string{"manager"}, info.Roles["hasrole"]) | ||
assert.Equal(t, []string{"role1", "role2", "role3"}, info.Roles["hasanyrole"]) | ||
assert.Equal(t, []string{"newsletter:read,write"}, info.Permissions["ispermitted"]) | ||
assert.Equal(t, []string{"newsletter:read,write", "newsletter:12345"}, info.Permissions["ispermittedall"]) | ||
} | ||
|
||
func TestRouteAuthorizationConfigErrorRolesPermissions(t *testing.T) { | ||
testcases := []struct { | ||
label string | ||
configStr string | ||
err error | ||
}{ | ||
{ | ||
label: "Test missing right bracket", | ||
configStr: ` | ||
user_info { | ||
authorization { | ||
roles = [ | ||
"hasrole(manager", | ||
"hasanyrole(role1, role2, role3)" | ||
] | ||
} | ||
} | ||
`, | ||
err: errors.New("user_info.authorization.roles at index 1 have incorrect open/close brackets 'hasrole(manager'"), | ||
}, | ||
{ | ||
label: "Test additional left bracket", | ||
configStr: ` | ||
user_info { | ||
authorization { | ||
roles = [ | ||
"hasrole((manager)", | ||
"hasanyrole(role1, role2, role3)" | ||
] | ||
} | ||
} | ||
`, | ||
err: errors.New("user_info.authorization.roles at index 1 have incorrect open/close brackets 'hasrole((manager)'"), | ||
}, | ||
{ | ||
label: "Test missing both brackets and inputs", | ||
configStr: ` | ||
user_info { | ||
authorization { | ||
roles = [ | ||
"hasrole(manager)", | ||
"hasanyrole" | ||
] | ||
} | ||
} | ||
`, | ||
err: errors.New("user_info.authorization.roles at index 2 have incorrect open/close brackets 'hasanyrole'"), | ||
}, | ||
{ | ||
label: "Test missing inputs", | ||
configStr: ` | ||
user_info { | ||
authorization { | ||
roles = [ | ||
"hasrole(manager)", | ||
"hasanyrole()" | ||
] | ||
} | ||
} | ||
`, | ||
err: errors.New("user_info.authorization.roles at index 2 have func 'hasanyrole()' without input"), | ||
}, | ||
{ | ||
label: "Test hasrole has more than one input", | ||
configStr: ` | ||
user_info { | ||
authorization { | ||
roles = [ | ||
"hasrole(manager, role1)" | ||
] | ||
} | ||
} | ||
`, | ||
err: errors.New("user_info.authorization.roles at index 1 have func 'hasrole' supports only one input param"), | ||
}, | ||
{ | ||
label: "Test satisfy is both and permission is not configured", | ||
configStr: ` | ||
user_info { | ||
authorization { | ||
satisfy = "both" | ||
roles = [ | ||
"hasrole(manager)" | ||
] | ||
} | ||
} | ||
`, | ||
err: errors.New("user_info.authorization.satisfy configured as 'both', however roles and permissions is not configured"), | ||
}, | ||
{ | ||
label: "Test ispermitted has more than one input", | ||
configStr: ` | ||
user_info { | ||
authorization { | ||
permissions = [ | ||
"ispermitted(newsletter:read,write | newsletter:12345)" | ||
] | ||
} | ||
} | ||
`, | ||
err: errors.New("user_info.authorization.permissions at index 1 have func 'ispermitted' supports only one input param"), | ||
}, | ||
} | ||
|
||
for _, tc := range testcases { | ||
t.Run(tc.label, func(t *testing.T) { | ||
cfg, err := config.ParseString(tc.configStr) | ||
assert.Nil(t, err) | ||
|
||
info, err := parseAuthorizationInfo(cfg, "user_info", &parentRouteInfo{AuthorizationInfo: &authorizationInfo{Satisfy: "either"}}) | ||
assert.NotNil(t, err) | ||
assert.Nil(t, info) | ||
assert.Equal(t, tc.err, err) | ||
}) | ||
} | ||
} | ||
|
||
func TestHasAccess(t *testing.T) { | ||
allfuncsCfgStr := ` | ||
user_info { | ||
authorization { | ||
roles = [ | ||
"hasrole(manager)", | ||
"hasanyrole(role1, role2, role3)", | ||
"hasallroles(manager, role3)" | ||
] | ||
permissions = [ | ||
"ispermitted(newsletter:read,write)", | ||
"ispermittedall(newsletter:read,write | newsletter:12345)" | ||
] | ||
} | ||
} | ||
` | ||
|
||
testcases := []struct { | ||
label string | ||
configStr string | ||
satisfy string | ||
subjectRoles []string | ||
subjectPermissions []string | ||
result bool | ||
}{ | ||
{ | ||
label: "All roles func and permissions func", | ||
configStr: allfuncsCfgStr, | ||
satisfy: "either", | ||
subjectRoles: []string{"manager", "role3"}, | ||
subjectPermissions: []string{"newsletter:read,write", "newsletter:12345"}, | ||
result: true, | ||
}, | ||
{ | ||
label: "Only roles check, satisfy: either", | ||
configStr: allfuncsCfgStr, | ||
satisfy: "either", | ||
subjectRoles: []string{"manager", "role3"}, | ||
result: true, | ||
}, | ||
{ | ||
label: "Only roles check, satisfy: both", | ||
configStr: allfuncsCfgStr, | ||
satisfy: "both", | ||
subjectRoles: []string{"manager", "role3"}, | ||
}, | ||
{ | ||
label: "Only permissions check, satisfy: either", | ||
configStr: allfuncsCfgStr, | ||
satisfy: "either", | ||
subjectPermissions: []string{"newsletter:read,write", "newsletter:12345"}, | ||
result: true, | ||
}, | ||
{ | ||
label: "Only permissions check, satisfy: both", | ||
configStr: allfuncsCfgStr, | ||
satisfy: "both", | ||
subjectPermissions: []string{"newsletter:read,write", "newsletter:12345"}, | ||
}, | ||
{ | ||
label: "All roles and permissions not exists", | ||
configStr: allfuncsCfgStr, | ||
satisfy: "either", | ||
subjectRoles: []string{"notexist1", "notexist2"}, | ||
subjectPermissions: []string{"notexist:read,write", "notexist:12345"}, | ||
}, | ||
} | ||
|
||
for _, tc := range testcases { | ||
t.Run(tc.label, func(t *testing.T) { | ||
cfg, err := config.ParseString(tc.configStr) | ||
assert.Nil(t, err) | ||
|
||
authInfo, err := parseAuthorizationInfo(cfg, "user_info", &parentRouteInfo{AuthorizationInfo: &authorizationInfo{Satisfy: tc.satisfy}}) | ||
assert.Nil(t, err) | ||
assert.NotNil(t, authInfo) | ||
|
||
r := &Route{authorizationInfo: authInfo} | ||
result, _ := r.HasAccess(createSubject(tc.subjectRoles, tc.subjectPermissions)) | ||
assert.Equal(t, tc.result, result) | ||
}) | ||
} | ||
|
||
r := &Route{} | ||
result, _ := r.HasAccess(createSubject([]string{"manager", "role3"}, []string{})) | ||
assert.True(t, result) | ||
} | ||
|
||
func createSubject(roles []string, permissions []string) *security.Subject { | ||
authInfo := authz.NewAuthorizationInfo() | ||
|
||
authInfo.AddRole(roles...) | ||
authInfo.AddPermissionString(permissions...) | ||
|
||
return &security.Subject{ | ||
AuthorizationInfo: authInfo, | ||
} | ||
} |
Oops, something went wrong.