Add read/list/cancel:self actions and support for ACL subactions. (#882)
Update perms table in anticipation of session support for these.
This commit is contained in:
1 parent
558f9220a5
commit
0629526319
7 files changed
+125
-6
No files matched your search
+25
-5
@@ -14,6 +14,8 @@ construction is thus synthesizing something reasonable from a set of Grants.
|
||||
*/
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/boundary/internal/types/action"
|
||||
"github.com/hashicorp/boundary/internal/types/resource"
|
||||
)
|
||||
@@ -70,9 +72,25 @@ func (a ACL) Allowed(r Resource, aType action.Type) (results ACLResults) {
|
||||
grants := a.scopeMap[r.ScopeId]
|
||||
results.scopeMap = a.scopeMap
|
||||
|
||||
var parentAction action.Type
|
||||
split := strings.Split(aType.String(), ":")
|
||||
if len(split) == 2 {
|
||||
parentAction = action.Map[split[0]]
|
||||
}
|
||||
// Now, go through and check the cases indicated above
|
||||
for _, grant := range grants {
|
||||
if !(grant.actions[aType] || grant.actions[action.All]) {
|
||||
switch {
|
||||
case grant.actions[aType]:
|
||||
// We have this action
|
||||
case grant.actions[parentAction]:
|
||||
// We don't have this action, but it's a subaction and we have the
|
||||
// parent action. As an example, if we are looking for "list:self"
|
||||
// and have "list", this is sufficient.
|
||||
case grant.actions[action.All]:
|
||||
// All actions are allowed
|
||||
default:
|
||||
// No actions in the grant match what we're looking for, so continue
|
||||
// with the next grant
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
@@ -85,15 +103,17 @@ func (a ACL) Allowed(r Resource, aType action.Type) (results ACLResults) {
|
||||
results.Allowed = true
|
||||
return
|
||||
|
||||
// type=<resource.type>;actions=<action> when action is list or create.
|
||||
// Must be a top level collection, otherwise must be one of the two
|
||||
// formats specified below.
|
||||
// type=<resource.type>;actions=<action> when action is list(:self) or
|
||||
// create. Must be a top level collection, otherwise must be one of the
|
||||
// two formats specified below.
|
||||
case grant.id == "" &&
|
||||
r.Id == "" &&
|
||||
grant.typ == r.Type &&
|
||||
grant.typ != resource.Unknown &&
|
||||
topLevelType(r.Type) &&
|
||||
(aType == action.List || aType == action.Create):
|
||||
(aType == action.List ||
|
||||
aType == action.ListSelf ||
|
||||
aType == action.Create):
|
||||
|
||||
results.Allowed = true
|
||||
return
|
||||
|
||||
@@ -35,6 +35,7 @@ func Test_ACLAllowed(t *testing.T) {
|
||||
scope: "o_a",
|
||||
grants: []string{
|
||||
"id=a_bar;actions=read,update",
|
||||
"id=a_baz;actions=read:self,update",
|
||||
"type=host-catalog;actions=create",
|
||||
"type=target;actions=list",
|
||||
"id=*;type=host-set;actions=list,create",
|
||||
@@ -59,6 +60,7 @@ func Test_ACLAllowed(t *testing.T) {
|
||||
scope: "o_d",
|
||||
grants: []string{
|
||||
"id=*;type=*;actions=create,update",
|
||||
"type=session;actions=list:self",
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -252,6 +254,42 @@ func Test_ACLAllowed(t *testing.T) {
|
||||
},
|
||||
userId: "u_abcd1234",
|
||||
},
|
||||
{
|
||||
name: "list self with top level list",
|
||||
resource: Resource{ScopeId: "o_a", Type: resource.Target},
|
||||
scopeGrants: commonGrants,
|
||||
actionsAllowed: []actionAllowed{
|
||||
{action: action.List, allowed: true},
|
||||
{action: action.ListSelf, allowed: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "list self with top level list self",
|
||||
resource: Resource{ScopeId: "o_d", Type: resource.Session},
|
||||
scopeGrants: commonGrants,
|
||||
actionsAllowed: []actionAllowed{
|
||||
{action: action.List},
|
||||
{action: action.ListSelf, allowed: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "read self with top level read",
|
||||
resource: Resource{ScopeId: "o_a", Id: "a_bar"},
|
||||
scopeGrants: commonGrants,
|
||||
actionsAllowed: []actionAllowed{
|
||||
{action: action.Read, allowed: true},
|
||||
{action: action.ReadSelf, allowed: true},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "read self only",
|
||||
resource: Resource{ScopeId: "o_a", Id: "a_baz"},
|
||||
scopeGrants: commonGrants,
|
||||
actionsAllowed: []actionAllowed{
|
||||
{action: action.Read},
|
||||
{action: action.ReadSelf, allowed: true},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -60,7 +60,7 @@ func Test_ActionParsingValidation(t *testing.T) {
|
||||
{
|
||||
name: "all valid",
|
||||
input: Grant{
|
||||
actionsBeingParsed: []string{"list", "create", "update", "read", "delete", "authenticate", "authorize-session"},
|
||||
actionsBeingParsed: []string{"list", "create", "update", "list:self", "read", "delete", "authenticate", "authorize-session"},
|
||||
},
|
||||
result: Grant{
|
||||
actions: map[action.Type]bool{
|
||||
@@ -71,6 +71,7 @@ func Test_ActionParsingValidation(t *testing.T) {
|
||||
action.Delete: true,
|
||||
action.Authenticate: true,
|
||||
action.AuthorizeSession: true,
|
||||
action.ListSelf: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -37,6 +37,9 @@ const (
|
||||
AddAccounts Type = 28
|
||||
SetAccounts Type = 29
|
||||
RemoveAccounts Type = 30
|
||||
ReadSelf Type = 31
|
||||
ListSelf Type = 32
|
||||
CancelSelf Type = 33
|
||||
)
|
||||
|
||||
var Map = map[string]Type{
|
||||
@@ -70,6 +73,9 @@ var Map = map[string]Type{
|
||||
AddAccounts.String(): AddAccounts,
|
||||
SetAccounts.String(): SetAccounts,
|
||||
RemoveAccounts.String(): RemoveAccounts,
|
||||
ReadSelf.String(): ReadSelf,
|
||||
ListSelf.String(): ListSelf,
|
||||
CancelSelf.String(): CancelSelf,
|
||||
}
|
||||
|
||||
func (a Type) String() string {
|
||||
@@ -105,6 +111,9 @@ func (a Type) String() string {
|
||||
"add-accounts",
|
||||
"set-accounts",
|
||||
"remove-accounts",
|
||||
"read:self",
|
||||
"list:self",
|
||||
"cancel:self",
|
||||
}[a]
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,18 @@ func TestAction(t *testing.T) {
|
||||
action: Deauthenticate,
|
||||
want: "deauthenticate",
|
||||
},
|
||||
{
|
||||
action: ReadSelf,
|
||||
want: "read:self",
|
||||
},
|
||||
{
|
||||
action: CancelSelf,
|
||||
want: "cancel:self",
|
||||
},
|
||||
{
|
||||
action: ListSelf,
|
||||
want: "list:self",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.want, func(t *testing.T) {
|
||||
|
||||
@@ -687,6 +687,27 @@ var session = &Resource{
|
||||
"id=<id>;actions=cancel",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "read:self",
|
||||
Description: "Read a session, which must belong to the calling user",
|
||||
Examples: []string{
|
||||
"id=*;type=session;actions=read:self",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "list:self",
|
||||
Description: "List sessions that belong to the calling user",
|
||||
Examples: []string{
|
||||
"type=session;actions=list:self",
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cancel:self",
|
||||
Description: "Cancel a session, which must belong to the calling user",
|
||||
Examples: []string{
|
||||
"id=*;type=session;actions=cancel:self",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1092,6 +1092,24 @@ wildcard or templated grant strings.
|
||||
<ul>
|
||||
<li><code>id=<id>;actions=cancel</code></li>
|
||||
</ul>
|
||||
<li>
|
||||
<code>read:self</code>: Read a session, which must belong to the calling user
|
||||
</li>
|
||||
<ul>
|
||||
<li><code>id=*;type=session;actions=read:self</code></li>
|
||||
</ul>
|
||||
<li>
|
||||
<code>list:self</code>: List sessions that belong to the calling user
|
||||
</li>
|
||||
<ul>
|
||||
<li><code>type=session;actions=list:self</code></li>
|
||||
</ul>
|
||||
<li>
|
||||
<code>cancel:self</code>: Cancel a session, which must belong to the calling user
|
||||
</li>
|
||||
<ul>
|
||||
<li><code>id=*;type=session;actions=cancel:self</code></li>
|
||||
</ul>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
Reference in new issue
Block a user