Skip to content

Commit

Permalink
Implement CheckPermissionForRole
Browse files Browse the repository at this point in the history
  • Loading branch information
john-odonnell committed Jan 25, 2023
1 parent fd1cf34 commit bb97949
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 27 deletions.
36 changes: 30 additions & 6 deletions conjurapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -342,19 +342,43 @@ func (c *Client) ChangeUserPasswordRequest(username string, password string, new
return req, nil
}

func (c *Client) CheckPermissionRequest(resourceID string, roleID string, privilege string) (*http.Request, error) {
// CheckPermissionForRoleRequest crafts an HTTP request to Conjur's /resource endpoint
// to check if the authenticated user has the given privilege on the given resourceID.
func (c *Client) CheckPermissionRequest(resourceID, privilege string) (*http.Request, error) {
account, kind, id, err := parseID(resourceID)
if err != nil {
return nil, err
}

var checkURL string
if len(roleID) != 0 {
checkURL = makeRouterURL(c.resourcesURL(account), kind, url.QueryEscape(id)).withFormattedQuery("check=true&role=%s&privilege=%s", url.QueryEscape(roleID), url.QueryEscape(privilege)).String()
} else {
checkURL = makeRouterURL(c.resourcesURL(account), kind, url.QueryEscape(id)).withFormattedQuery("check=true&privilege=%s", url.QueryEscape(privilege)).String()
query := fmt.Sprintf("check=true&privilege=%s", url.QueryEscape(privilege))

checkURL := makeRouterURL(c.resourcesURL(account), kind, url.QueryEscape(id)).withQuery(query).String()

return http.NewRequest(
"GET",
checkURL,
nil,
)
}

// CheckPermissionForRoleRequest crafts an HTTP request to Conjur's /resource endpoint
// to check if a given role has the given privilege on the given resourceID.
func (c *Client) CheckPermissionForRoleRequest(resourceID, roleID, privilege string) (*http.Request, error) {
account, kind, id, err := parseID(resourceID)
if err != nil {
return nil, err
}

roleAccount, roleKind, roleIdentifier, err := parseID(roleID)
if err != nil {
return nil, err
}
fullyQualifiedRoleID := strings.Join([]string{roleAccount, roleKind, roleIdentifier}, ":")

query := fmt.Sprintf("check=true&privilege=%s&role=%s", url.QueryEscape(privilege), url.QueryEscape(fullyQualifiedRoleID))

checkURL := makeRouterURL(c.resourcesURL(account), kind, url.QueryEscape(id)).withQuery(query).String()

return http.NewRequest(
"GET",
checkURL,
Expand Down
20 changes: 18 additions & 2 deletions conjurapi/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package conjurapi
import (
"encoding/json"
"fmt"
"net/http"

"github.com/cyberark/conjur-api-go/conjurapi/response"
)
Expand All @@ -16,12 +17,27 @@ type ResourceFilter struct {

// CheckPermission determines whether the authenticated user has a specified privilege
// on a resource.
func (c *Client) CheckPermission(resourceID string, roleID string, privilege string) (bool, error) {
req, err := c.CheckPermissionRequest(resourceID, roleID, privilege)
func (c *Client) CheckPermission(resourceID string, privilege string) (bool, error) {
req, err := c.CheckPermissionRequest(resourceID, privilege)
if err != nil {
return false, err
}

return c.processPermissionCheck(req)
}

// CheckPermissionForRole determines whether the provided role has a specific
// privilege on a resource.
func (c *Client) CheckPermissionForRole(resourceID string, roleID string, privilege string) (bool, error) {
req, err := c.CheckPermissionForRoleRequest(resourceID, roleID, privilege)
if err != nil {
return false, err
}

return c.processPermissionCheck(req)
}

func (c *Client) processPermissionCheck(req *http.Request) (bool, error) {
resp, err := c.SubmitRequest(req)
if err != nil {
return false, err
Expand Down
82 changes: 63 additions & 19 deletions conjurapi/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,88 @@ import (
"github.com/stretchr/testify/assert"
)

func TestClient_CheckPermission(t *testing.T) {
checkAllowed := func(conjur *Client, id string, role string) func(t *testing.T) {
return func(t *testing.T) {
allowed, err := conjur.CheckPermission(id, role, "execute")
type checkAssertion func(t *testing.T, result bool, err error)

assert.NoError(t, err)
assert.True(t, allowed)
}
}
func assertSuccess(t *testing.T, result bool, err error) {
assert.True(t, result)
assert.NoError(t, err)
}

checkNotAllowed := func(conjur *Client, id string, role string) func(t *testing.T) {
return func(t *testing.T) {
allowed, err := conjur.CheckPermission(id, role, "execute")
func assertFailure(t *testing.T, result bool, err error) {
assert.False(t, result)
assert.NoError(t, err)
}

assert.NoError(t, err)
assert.False(t, allowed)
func assertError(t *testing.T, result bool, err error) {
assert.False(t, result)
assert.Error(t, err)
}

func checkAndAssert(
conjur *Client,
assertion checkAssertion,
args ...string,
) func(t *testing.T) {
return func(t *testing.T) {
var result bool
var err error

if len(args) == 1 {
result, err = conjur.CheckPermission(args[0], "execute")
} else if len(args) == 2 {
result, err = conjur.CheckPermissionForRole(args[0], args[1], "execute")
}

assertion(t, result, err)
}
}

func TestClient_CheckPermission(t *testing.T) {
conjur, err := conjurSetup(&Config{}, defaultTestPolicy)
assert.NoError(t, err)

t.Run(
"Check an allowed permission for default role",
checkAndAssert(conjur, assertSuccess, "cucumber:variable:db-password"),
)
t.Run(
"Check a permission on a non-existent resource",
checkAndAssert(conjur, assertFailure, "cucumber:variable:foobar"),
)
}

func TestClient_CheckPermissionForRole(t *testing.T) {
conjur, err := conjurSetup(&Config{}, defaultTestPolicy)
assert.NoError(t, err)

t.Run("Check an allowed permission for default admin role", checkAllowed(conjur, "cucumber:variable:db-password", ""))
t.Run("Check an allowed permission for a role", checkAllowed(conjur, "cucumber:variable:db-password", "cucumber:user:alice"))
t.Run("Check a permission on a non-existent resource", checkNotAllowed(conjur, "cucumber:variable:foobar", "cucumber:user:alice"))
t.Run("Check no permission for a role", checkNotAllowed(conjur, "cucumber:variable:db-password", "cucumber:host:bob"))
t.Run(
"Check an allowed permission for a role",
checkAndAssert(conjur, assertSuccess, "cucumber:variable:db-password", "cucumber:user:alice"),
)
t.Run(
"Check a permission on a non-existent resource",
checkAndAssert(conjur, assertFailure, "cucumber:variable:foobar", "cucumber:user:alice"),
)
t.Run(
"Check no permission for a role",
checkAndAssert(conjur, assertFailure, "cucumber:variable:db-password", "cucumber:host:bob"),
)
t.Run(
"Check a permission with empty role",
checkAndAssert(conjur, assertError, "cucumber:variable:db-password", ""),
)
}

func TestClient_ResourceExists(t *testing.T) {
resourceExistent := func(conjur *Client, id string) func (t *testing.T) {
resourceExistent := func(conjur *Client, id string) func(t *testing.T) {
return func(t *testing.T) {
exists, err := conjur.ResourceExists(id)
assert.NoError(t, err)
assert.True(t, exists)
}
}

resourceNonexistent := func(conjur *Client, id string) func (t *testing.T) {
resourceNonexistent := func(conjur *Client, id string) func(t *testing.T) {
return func(t *testing.T) {
exists, err := conjur.ResourceExists(id)
assert.NoError(t, err)
Expand Down

0 comments on commit bb97949

Please sign in to comment.