Skip to content

Commit

Permalink
fix(resource): format path for DB
Browse files Browse the repository at this point in the history
* Also used prepared statement for performance
* Rewrote the lexter to support slashes and quotes
* Faster AND/OR check
  • Loading branch information
fantix committed Mar 21, 2019
1 parent c068233 commit 3e67fb0
Show file tree
Hide file tree
Showing 4 changed files with 308 additions and 93 deletions.
64 changes: 39 additions & 25 deletions arborist/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,31 @@ package arborist

import (
"encoding/json"
"github.com/jmoiron/sqlx"
"github.com/lib/pq"
)

const AUTH_QUERY = `
SELECT coalesce(text2ltree("unnest") @> allowed, FALSE) FROM (
SELECT array_agg(resource.path) AS allowed FROM usr
LEFT JOIN usr_policy ON usr_policy.usr_id = usr.id
LEFT JOIN policy_resource ON policy_resource.policy_id = usr_policy.policy_id
LEFT JOIN resource ON resource.id = policy_resource.resource_id
WHERE usr.name = $1
AND EXISTS (
SELECT 1 FROM policy_role
LEFT JOIN permission ON permission.role_id = policy_role.role_id
WHERE policy_role.policy_id = usr_policy.policy_id
AND permission.service = $2
AND permission.method = $3
) AND (
$4 OR usr_policy.policy_id IN (
SELECT id FROM policy
WHERE policy.name = ANY($5)
)
)
) _, unnest($6::text[]);
`

type AuthRequestJSON struct {
User AuthRequestJSON_User `json:"user"`
Request AuthRequestJSON_Request `json:"request"`
Expand Down Expand Up @@ -79,45 +100,37 @@ func (requestJSON *AuthRequestJSON_Request) UnmarshalJSON(data []byte) error {
return nil
}

func authorize(db *sqlx.DB, token *TokenInfo, resource string, service string, method string) (bool, error) {
// Authorize the given token to access resources by service and method.
// The given resource can be an expression of slash-separated resource paths
// connected with `and`, `or` or `not`. The priority of these boolean operators
// is: `not > and > or`. When in doubt, use parenthesises to specify explicitly.
func authorize(server *Server, token *TokenInfo, resource string,service string, method string) (bool, error) {
// parse the resource string
exp, args, err := Parse(resource)
if err != nil {
return false, err
}

var stmt = `
SELECT coalesce(text2ltree("unnest") @> allowed, FALSE) FROM (
SELECT array_agg(resource.path) AS allowed FROM usr
LEFT JOIN usr_policy ON usr_policy.usr_id = usr.id
LEFT JOIN policy_resource ON policy_resource.policy_id = usr_policy.policy_id
LEFT JOIN resource ON resource.id = policy_resource.resource_id
WHERE usr.name = $1
AND EXISTS (
SELECT 1 FROM policy_role
LEFT JOIN permission ON permission.role_id = policy_role.role_id
WHERE policy_role.policy_id = usr_policy.policy_id
AND permission.service = $2
AND permission.method = $3
) AND (
$4 OR usr_policy.policy_id IN (
SELECT id FROM policy
WHERE policy.name = ANY($5)
)
)
) _, unnest($6::text[]);
`
rows, err := db.Query(stmt,
resources := make([]string, len(args))
// format resource path for DB
for i, arg := range args {
resources[i] = formatPathForDb(arg)
}

// run authorization query
rows, err := server.authQuery.Query(
token.username, // $1
service, // $2
method, // $3
len(token.policies) == 0, // $4
pq.Array(token.policies), // $5
pq.Array(args), // $6
pq.Array(resources), // $6
)
if err != nil {
return false, err
}

// build the map for evaluation
i := 0
vars := make(map[string]bool)
for rows.Next() {
Expand All @@ -130,5 +143,6 @@ SELECT coalesce(text2ltree("unnest") @> allowed, FALSE) FROM (
i ++
}

// evaluate the result
return Eval(exp, vars)
}
180 changes: 138 additions & 42 deletions arborist/resource_rules.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3e67fb0

Please sign in to comment.