From 71b52bd4d2eee147d5d79ff0960bd0f4ea555ce0 Mon Sep 17 00:00:00 2001 From: Alberto Ricart Date: Mon, 16 Dec 2024 19:15:29 -0600 Subject: [PATCH] Add support for issuing authorization responses. Introduced the `IssueAuthorizationResponse` method for handling JWT authorization response claims. Fixed an issue where users that were issued by a signing key would be marked as being scoped. Changed to use API that returns whether there's a scope or just signing key --- accounts.go | 14 ++++++++++++++ tests/accounts_test.go | 28 ++++++++++++++++++++++++++++ types.go | 2 ++ users.go | 5 +++-- 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/accounts.go b/accounts.go index 28c4313..5ec7d54 100644 --- a/accounts.go +++ b/accounts.go @@ -179,6 +179,20 @@ func (a *AccountData) ExternalAuthorization() ([]string, []string, string) { return config.AuthUsers, config.AllowedAccounts, config.XKey } +func (a *AccountData) IssueAuthorizationResponse(claim *jwt.AuthorizationResponseClaims, key string) (string, error) { + if key == "" { + key = a.Key.Public + } + k, signingKey, err := a.getKey(key) + if err != nil { + return "", err + } + if signingKey { + claim.IssuerAccount = a.Key.Public + } + return a.Operator.SigningService.Sign(claim, k) +} + type exports struct { *AccountData } diff --git a/tests/accounts_test.go b/tests/accounts_test.go index c1f01d8..952258a 100644 --- a/tests/accounts_test.go +++ b/tests/accounts_test.go @@ -166,6 +166,34 @@ func (t *ProviderSuite) Test_ScopedUserPermissionLimitsSetter() { t.Equal(scope.PubPermissions().Allow(), []string{"test.>"}) } +func (t *ProviderSuite) Test_ScopedOrNot() { + auth, err := authb.NewAuth(t.Provider) + t.NoError(err) + o, err := auth.Operators().Add("O") + t.NoError(err) + + a, err := o.Accounts().Add("A") + t.NoError(err) + + scope, err := a.ScopedSigningKeys().AddScope("test") + t.NoError(err) + + lim, err := a.ScopedSigningKeys().GetScope(scope.Key()) + t.NoError(err) + t.NotNil(lim) + + pk, err := a.ScopedSigningKeys().Add() + t.NoError(err) + + lim, err = a.ScopedSigningKeys().GetScope(pk) + t.Error(err) + t.Nil(lim) + + ok, scoped := a.ScopedSigningKeys().Contains(pk) + t.True(ok) + t.False(scoped) +} + func setupTestWithOperatorAndAccount(p *ProviderSuite) (authb.Auth, authb.Operator, authb.Account) { auth, err := authb.NewAuth(p.Provider) p.NoError(err) diff --git a/types.go b/types.go index f890c98..e8ad8b2 100644 --- a/types.go +++ b/types.go @@ -331,6 +331,8 @@ type Account interface { // ExternalAuthorization retrieves a list of authorized users, associated accounts, and encryption key. // if the users value is nil, ExternalAuthorization is not enabled ExternalAuthorization() ([]string, []string, string) + + IssueAuthorizationResponse(claim *jwt.AuthorizationResponseClaims, key string) (string, error) } // Users is an interface for managing users diff --git a/users.go b/users.go index 9df7703..e5733b2 100644 --- a/users.go +++ b/users.go @@ -25,13 +25,14 @@ func (a *UsersImpl) add(name string, key string, uk *Key) (User, error) { if err != nil { return nil, err } - _, scoped := a.accountData.Claim.SigningKeys.GetScope(key) + // scope will be nil if just a signing key + ok, scoped := a.accountData.ScopedSigningKeys().Contains(key) d := &UserData{ BaseData: BaseData{EntityName: name, Key: uk, Modified: true}, AccountData: a.accountData, Claim: jwt.NewUserClaims(uk.Public), - RejectEdits: scoped, + RejectEdits: ok && scoped, Ephemeral: uk.Seed == nil, } d.Claim.Name = name