Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get matched roles and permissions #343

Merged
merged 3 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,10 @@ if !descopeClient.Auth.ValidateTenantPermissions(sessionToken, "my-tenant-ID", [
if !descopeClient.Auth.ValidateTenantRoles(sessionToken, "my-tenant-ID", []string{"Role to validate"}) {
// Deny access
}

matchedTenantRoles := descopeClient.Auth.GetTenantRoles(sessionToken, "my-tenant-ID", []string{"role-name1", "role-name2"})

matchedTenantPermissions := descopeClient.Auth.GetTenantPermissions(sessionToken, "my-tenant-ID", []string{"permission-name1", "permission-name2"})
```

When not using tenants use:
Expand All @@ -491,6 +495,11 @@ if !descopeClient.Auth.ValidatePermissions(sessionToken, []string{"Permission to
if !descopeClient.Auth.ValidateRoles(sessionToken, []string{"Role to validate"}) {
// Deny access
}

// Or get the matched roles/permissions
matchedRoles := descopeClient.Auth.GetMatchedRoles(sessionToken, []string{"role-name1", "role-name2"})

matchedPermissions := descopeClient.Auth.GetMatchedPermissions(sessionToken, []string{"permission-name1", "permission-name2"})
```

### Tenant selection
Expand Down
36 changes: 36 additions & 0 deletions descope/internal/auth/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,10 @@ func (auth *authenticationService) ValidatePermissions(token *descope.Token, per
return auth.ValidateTenantPermissions(token, "", permissions)
}

func (auth *authenticationService) GetMatchedPermissions(token *descope.Token, permissions []string) []string {
return auth.GetMatchedTenantPermissions(token, "", permissions)
}

func (auth *authenticationService) ValidateTenantPermissions(token *descope.Token, tenant string, permissions []string) bool {
if tenant != "" && !isAssociatedWithTenant(token, tenant) {
return false
Expand All @@ -358,10 +362,28 @@ func (auth *authenticationService) ValidateTenantPermissions(token *descope.Toke
return true
}

func (auth *authenticationService) GetMatchedTenantPermissions(token *descope.Token, tenant string, permissions []string) []string {
if tenant != "" && !isAssociatedWithTenant(token, tenant) {
return []string{}
}
granted := getAuthorizationClaimItems(token, tenant, claimPermissions)
matched := []string{}
for i := range permissions {
if slices.Contains(granted, permissions[i]) {
matched = append(matched, permissions[i])
}
}
return matched
}

func (auth *authenticationService) ValidateRoles(token *descope.Token, roles []string) bool {
return auth.ValidateTenantRoles(token, "", roles)
}

func (auth *authenticationService) GetMatchedRoles(token *descope.Token, roles []string) []string {
return auth.GetMatchedTenantRoles(token, "", roles)
}

func (auth *authenticationService) ValidateTenantRoles(token *descope.Token, tenant string, roles []string) bool {
if tenant != "" && !isAssociatedWithTenant(token, tenant) {
return false
Expand All @@ -375,6 +397,20 @@ func (auth *authenticationService) ValidateTenantRoles(token *descope.Token, ten
return true
}

func (auth *authenticationService) GetMatchedTenantRoles(token *descope.Token, tenant string, roles []string) []string {
if tenant != "" && !isAssociatedWithTenant(token, tenant) {
return []string{}
}
membership := getAuthorizationClaimItems(token, tenant, claimRoles)
matched := []string{}
for i := range roles {
if slices.Contains(membership, roles[i]) {
matched = append(matched, roles[i])
}
}
return matched
}

// Select Tenant

func (auth *authenticationService) SelectTenantWithRequest(tenantID string, request *http.Request, w http.ResponseWriter) (*descope.AuthenticationInfo, error) {
Expand Down
35 changes: 35 additions & 0 deletions descope/internal/auth/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -924,7 +924,24 @@ func TestValidatePermissions(t *testing.T) {
"t1",
[]string{"foo"},
))
}

func TestGetMatchedPermissions(t *testing.T) {
a, err := newTestAuth(nil, DoOkWithBody(nil, ""))
require.NoError(t, err)

require.Equal(t, []string{}, a.GetMatchedPermissions(nil, []string{}))
require.Equal(t, []string{}, a.GetMatchedPermissions(nil, []string{"abc"}))

require.Equal(t, []string{}, a.GetMatchedPermissions(mockAuthorizationToken, []string{}))
require.Equal(t, []string{"foo"}, a.GetMatchedPermissions(mockAuthorizationToken, []string{"foo"}))
require.Equal(t, []string{"foo", "bar"}, a.GetMatchedPermissions(mockAuthorizationToken, []string{"foo", "bar"}))
require.Equal(t, []string{"foo", "bar"}, a.GetMatchedPermissions(mockAuthorizationToken, []string{"foo", "bar", "qux"}))

require.Equal(t, []string{}, a.GetMatchedTenantPermissions(mockAuthorizationTenantToken, "kuku", []string{}))
require.Equal(t, []string{"foo"}, a.GetMatchedTenantPermissions(mockAuthorizationTenantToken, "kuku", []string{"foo"}))
require.Equal(t, []string{"foo", "bar"}, a.GetMatchedTenantPermissions(mockAuthorizationTenantToken, "kuku", []string{"foo", "bar"}))
require.Equal(t, []string{"foo", "bar"}, a.GetMatchedTenantPermissions(mockAuthorizationTenantToken, "kuku", []string{"foo", "bar", "qux"}))
}

func TestValidateRoles(t *testing.T) {
Expand Down Expand Up @@ -958,6 +975,24 @@ func TestValidateRoles(t *testing.T) {
require.False(t, a.ValidateTenantRoles(mockAuthorizationTenantToken, "t2", []string{}))
}

func TestGetMatchedRoles(t *testing.T) {
a, err := newTestAuth(nil, DoOkWithBody(nil, ""))
require.NoError(t, err)

require.Equal(t, []string{}, a.GetMatchedRoles(nil, []string{}))
require.Equal(t, []string{}, a.GetMatchedRoles(nil, []string{"foo"}))

require.Equal(t, []string{}, a.GetMatchedRoles(mockAuthorizationToken, []string{}))
require.Equal(t, []string{"abc"}, a.GetMatchedRoles(mockAuthorizationToken, []string{"abc"}))
require.Equal(t, []string{"abc", "xyz"}, a.GetMatchedRoles(mockAuthorizationToken, []string{"abc", "xyz"}))
require.Equal(t, []string{"abc", "xyz"}, a.GetMatchedRoles(mockAuthorizationToken, []string{"abc", "xyz", "tuv"}))

require.Equal(t, []string{}, a.GetMatchedTenantRoles(mockAuthorizationTenantToken, "kuku", []string{}))
require.Equal(t, []string{"abc"}, a.GetMatchedTenantRoles(mockAuthorizationTenantToken, "kuku", []string{"abc"}))
require.Equal(t, []string{"abc", "xyz"}, a.GetMatchedTenantRoles(mockAuthorizationTenantToken, "kuku", []string{"abc", "xyz"}))
require.Equal(t, []string{"abc", "xyz"}, a.GetMatchedTenantRoles(mockAuthorizationTenantToken, "kuku", []string{"abc", "xyz", "tuv"}))
}

func TestMe(t *testing.T) {
a, err := newTestAuth(nil, func(r *http.Request) (*http.Response, error) {
return &http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewBufferString(mockUserResponseBody))}, nil
Expand Down
15 changes: 15 additions & 0 deletions descope/sdk/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -300,19 +300,34 @@ type Authentication interface {
// This is a shortcut for ValidateTenantPermissions(token, "", permissions)
ValidatePermissions(token *descope.Token, permissions []string) bool

// GetMatchedPermissions - Use toeRetrieves the permissions from top level token's claims
// that match the specified permissions list
GetMatchedPermissions(token *descope.Token, permissions []string) []string

// ValidateTenantPermissions - Use to ensure that a validated session token has been
// granted the specified permissions for a specific tenant.
ValidateTenantPermissions(token *descope.Token, tenant string, permissions []string) bool

// GetMatchedTenantPermissions - Use to retrieve the permissions token's claims of a specific tenant
// that match the specified permissions list
GetMatchedTenantPermissions(token *descope.Token, tenant string, permissions []string) []string

// ValidateRoles - Use to ensure that a validated session token has been granted the
// specified roles.
// This is a shortcut for ValidateTenantRoles(token, "", roles)
ValidateRoles(token *descope.Token, roles []string) bool

// GetMatchedRoles - Use to retrieve the roles token's claims that match the specified roles list
GetMatchedRoles(token *descope.Token, roles []string) []string

// ValidateTenantRoles - Use to ensure that a validated session token has been granted
// the specified roles for a specific tenant.
ValidateTenantRoles(token *descope.Token, tenant string, roles []string) bool

// GetMatchedTenantRoles - Use to retrieve the roles token's claims of a specific tenant
// that match the specified roles list
GetMatchedTenantRoles(token *descope.Token, tenant string, roles []string) []string

// SelectTenantWithRequest - Adds a dedicated claim to the JWTs to indicate the tenant on which the user is currently authenticated
SelectTenantWithRequest(tenantID string, request *http.Request, w http.ResponseWriter) (*descope.AuthenticationInfo, error)

Expand Down
44 changes: 44 additions & 0 deletions descope/tests/mocks/auth/authenticationmock.go
Original file line number Diff line number Diff line change
Expand Up @@ -522,15 +522,27 @@ type MockSession struct {
ValidatePermissionsAssert func(token *descope.Token, permissions []string)
ValidatePermissionsResponse bool

GetMatchedPermissionsAssert func(token *descope.Token, permissions []string)
GetMatchedPermissionsResponse []string

ValidateTenantPermissionsAssert func(token *descope.Token, tenant string, permissions []string)
ValidateTenantPermissionsResponse bool

GetMatchedTenantPermissionsAssert func(token *descope.Token, tenant string, permissions []string)
GetMatchedTenantPermissionsResponse []string

ValidateRolesAssert func(token *descope.Token, roles []string)
ValidateRolesResponse bool

GetMatchedRolesAssert func(token *descope.Token, roles []string)
GetMatchedRolesResponse []string

ValidateTenantRolesAssert func(token *descope.Token, tenant string, roles []string)
ValidateTenantRolesResponse bool

GetMatchedTenantRolesAssert func(token *descope.Token, tenant string, roles []string)
GetMatchedTenantRolesResponse []string

SelectTenantWithRequestAssert func(tenantID string, r *http.Request, w http.ResponseWriter)
SelectTenantWithRequestResponse *descope.AuthenticationInfo
SelectTenantWithRequestError error
Expand Down Expand Up @@ -635,27 +647,59 @@ func (m *MockSession) ValidatePermissions(token *descope.Token, permissions []st
return m.ValidatePermissionsResponse
}

func (m *MockSession) GetMatchedPermissions(token *descope.Token, permissions []string) []string {
if m.GetMatchedPermissionsAssert != nil {
m.GetMatchedPermissionsAssert(token, permissions)
}

return m.GetMatchedPermissionsResponse
}

func (m *MockSession) ValidateTenantPermissions(token *descope.Token, tenant string, permissions []string) bool {
if m.ValidateTenantPermissionsAssert != nil {
m.ValidateTenantPermissionsAssert(token, tenant, permissions)
}
return m.ValidateTenantPermissionsResponse
}

func (m *MockSession) GetMatchedTenantPermissions(token *descope.Token, tenant string, permissions []string) []string {
if m.GetMatchedTenantPermissionsAssert != nil {
m.GetMatchedTenantPermissionsAssert(token, tenant, permissions)
}

return m.GetMatchedTenantPermissionsResponse
}

func (m *MockSession) ValidateRoles(token *descope.Token, roles []string) bool {
if m.ValidateRolesAssert != nil {
m.ValidateRolesAssert(token, roles)
}
return m.ValidateRolesResponse
}

func (m *MockSession) GetMatchedRoles(token *descope.Token, roles []string) []string {
if m.GetMatchedRolesAssert != nil {
m.GetMatchedRolesAssert(token, roles)
}

return m.GetMatchedRolesResponse
}

func (m *MockSession) ValidateTenantRoles(token *descope.Token, tenant string, roles []string) bool {
if m.ValidateTenantRolesAssert != nil {
m.ValidateTenantRolesAssert(token, tenant, roles)
}
return m.ValidateTenantRolesResponse
}

func (m *MockSession) GetMatchedTenantRoles(token *descope.Token, tenant string, roles []string) []string {
if m.GetMatchedTenantRolesAssert != nil {
m.GetMatchedTenantRolesAssert(token, tenant, roles)
}

return m.GetMatchedTenantRolesResponse
}

func (m *MockSession) SelectTenantWithRequest(tenantID string, request *http.Request, w http.ResponseWriter) (*descope.AuthenticationInfo, error) {
if m.SelectTenantWithRequestAssert != nil {
m.SelectTenantWithRequestAssert(tenantID, request, w)
Expand Down