* Moving POC files from #64283 to a new branch
Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
* Adding missing permission definition
Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
* Force the service instantiation while client isn't merged
Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
* Merge conf with main
Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
* Leave go-sqlite3 version unchanged
Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
* tidy
Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
* User SearchUserPermissions instead of SearchUsersPermissions
* Replace DummyKeyService with signingkeys.Service
* Use user🆔<id> as subject
* Fix introspection endpoint issue
* Add X-Grafana-Org-Id to get_resources.bash script
* Regenerate toggles_gen.go
* Fix basic.go
* Add GetExternalService tests
* Add GetPublicKeyScopes tests
* Add GetScopesOnUser tests
* Add GetScopes tests
* Add ParsePublicKeyPem tests
* Add database test for GetByName
* re-add comments
* client tests added
* Add GetExternalServicePublicKey tests
* Add other test case to GetExternalServicePublicKey
* client_credentials grant test
* Add test to jwtbearer grant
* Test Comments
* Add handleKeyOptions tests
* Add RSA key generation test
* Add ECDSA by default to EmbeddedSigningKeysService
* Clean up org id scope and audiences
* Add audiences to the DB
* Fix check on Audience
* Fix double import
* Add AC Store mock and align oauthserver tests
* Fix test after rebase
* Adding missing store function to mock
* Fix double import
* Add CODEOWNER
* Fix some linting errors
* errors don't need type assertion
* Typo codeowners
* use mockery for oauthserver store
* Add feature toggle check
* Fix db tests to handle the feature flag
* Adding call to DeleteExternalServiceRole
* Fix flaky test
* Re-organize routes comments and plan futur work
* Add client_id check to Extended JWT client
* Clean up
* Fix
* Remove background service registry instantiation of the OAuth server
* Comment cleanup
* Remove unused client function
* Update go.mod to use the latest ory/fosite commit
* Remove oauth2_server related configs from defaults.ini
* Add audiences to DTO
* Fix flaky test
* Remove registration endpoint and demo scripts. Document code
* Rename packages
* Remove the OAuthService vs OAuthServer confusion
* fix incorrect import ext_jwt_test
* Comments and order
* Comment basic auth
* Remove unecessary todo
* Clean api
* Moving ParsePublicKeyPem to utils
* re ordering functions in service.go
* Fix comment
* comment on the redirect uri
* Add RBAC actions, not only scopes
* Fix tests
* re-import featuremgmt in migrations
* Fix wire
* Fix scopes in test
* Fix flaky test
* Remove todo, the intersection should always return the minimal set
* Remove unecessary check from intersection code
* Allow env overrides on settings
* remove the term app name
* Remove app keyword for client instead and use Name instead of ExternalServiceName
* LogID remove ExternalService ref
* Use Name instead of ExternalServiceName
* Imports order
* Inline
* Using ExternalService and ExternalServiceDTO
* Remove xorm tags
* comment
* Rename client files
* client -> external service
* comments
* Move test to correct package
* slimmer test
* cachedUser -> cachedExternalService
* Fix aggregate store test
* PluginAuthSession -> AuthSession
* Revert the nil cehcks
* Remove unecessary extra
* Removing custom session
* fix typo in test
* Use constants for tests
* Simplify HandleToken tests
* Refactor the HandleTokenRequest test
* test message
* Review test
* Prevent flacky test on client as well
* go imports
* Revert changes from 526e48ad45
* AuthN: Change the External Service registration form (#68649)
* AuthN: change the External Service registration form
* Gen default permissions
* Change demo script registration form
* Remove unecessary comment
* Nit.
* Reduce cyclomatic complexity
* Remove demo_scripts
* Handle case with no service account
* Comments
* Group key gen
* Nit.
* Check the SaveExternalService test
* Rename cachedUser to cachedClient in test
* One more test case to database test
* Comments
* Remove last org scope
Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
* Update pkg/services/oauthserver/utils/utils_test.go
* Update pkg/services/sqlstore/migrations/oauthserver/migrations.go
Remove comment
* Update pkg/setting/setting.go
Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
---------
Co-authored-by: Mihály Gyöngyösi <mgyongyosi@users.noreply.github.com>
163 lines
7.5 KiB
Go
163 lines
7.5 KiB
Go
package oasimpl
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/ory/fosite"
|
|
"github.com/ory/fosite/handler/oauth2"
|
|
"github.com/ory/fosite/handler/rfc7523"
|
|
"gopkg.in/square/go-jose.v2"
|
|
|
|
"github.com/grafana/grafana/pkg/services/oauthserver/utils"
|
|
)
|
|
|
|
var _ fosite.ClientManager = &OAuth2ServiceImpl{}
|
|
var _ oauth2.AuthorizeCodeStorage = &OAuth2ServiceImpl{}
|
|
var _ oauth2.AccessTokenStorage = &OAuth2ServiceImpl{}
|
|
var _ oauth2.RefreshTokenStorage = &OAuth2ServiceImpl{}
|
|
var _ rfc7523.RFC7523KeyStorage = &OAuth2ServiceImpl{}
|
|
var _ oauth2.TokenRevocationStorage = &OAuth2ServiceImpl{}
|
|
|
|
// GetClient loads the client by its ID or returns an error
|
|
// if the client does not exist or another error occurred.
|
|
func (s *OAuth2ServiceImpl) GetClient(ctx context.Context, id string) (fosite.Client, error) {
|
|
return s.GetExternalService(ctx, id)
|
|
}
|
|
|
|
// ClientAssertionJWTValid returns an error if the JTI is
|
|
// known or the DB check failed and nil if the JTI is not known.
|
|
func (s *OAuth2ServiceImpl) ClientAssertionJWTValid(ctx context.Context, jti string) error {
|
|
return s.memstore.ClientAssertionJWTValid(ctx, jti)
|
|
}
|
|
|
|
// SetClientAssertionJWT marks a JTI as known for the given
|
|
// expiry time. Before inserting the new JTI, it will clean
|
|
// up any existing JTIs that have expired as those tokens can
|
|
// not be replayed due to the expiry.
|
|
func (s *OAuth2ServiceImpl) SetClientAssertionJWT(ctx context.Context, jti string, exp time.Time) error {
|
|
return s.memstore.SetClientAssertionJWT(ctx, jti, exp)
|
|
}
|
|
|
|
// GetAuthorizeCodeSession stores the authorization request for a given authorization code.
|
|
func (s *OAuth2ServiceImpl) CreateAuthorizeCodeSession(ctx context.Context, code string, request fosite.Requester) (err error) {
|
|
return s.memstore.CreateAuthorizeCodeSession(ctx, code, request)
|
|
}
|
|
|
|
// GetAuthorizeCodeSession hydrates the session based on the given code and returns the authorization request.
|
|
// If the authorization code has been invalidated with `InvalidateAuthorizeCodeSession`, this
|
|
// method should return the ErrInvalidatedAuthorizeCode error.
|
|
//
|
|
// Make sure to also return the fosite.Requester value when returning the fosite.ErrInvalidatedAuthorizeCode error!
|
|
func (s *OAuth2ServiceImpl) GetAuthorizeCodeSession(ctx context.Context, code string, session fosite.Session) (request fosite.Requester, err error) {
|
|
return s.memstore.GetAuthorizeCodeSession(ctx, code, session)
|
|
}
|
|
|
|
// InvalidateAuthorizeCodeSession is called when an authorize code is being used. The state of the authorization
|
|
// code should be set to invalid and consecutive requests to GetAuthorizeCodeSession should return the
|
|
// ErrInvalidatedAuthorizeCode error.
|
|
func (s *OAuth2ServiceImpl) InvalidateAuthorizeCodeSession(ctx context.Context, code string) (err error) {
|
|
return s.memstore.InvalidateAuthorizeCodeSession(ctx, code)
|
|
}
|
|
|
|
func (s *OAuth2ServiceImpl) CreateAccessTokenSession(ctx context.Context, signature string, request fosite.Requester) (err error) {
|
|
return s.memstore.CreateAccessTokenSession(ctx, signature, request)
|
|
}
|
|
|
|
func (s *OAuth2ServiceImpl) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) {
|
|
return s.memstore.GetAccessTokenSession(ctx, signature, session)
|
|
}
|
|
|
|
func (s *OAuth2ServiceImpl) DeleteAccessTokenSession(ctx context.Context, signature string) (err error) {
|
|
return s.memstore.DeleteAccessTokenSession(ctx, signature)
|
|
}
|
|
|
|
func (s *OAuth2ServiceImpl) CreateRefreshTokenSession(ctx context.Context, signature string, request fosite.Requester) (err error) {
|
|
return s.memstore.CreateRefreshTokenSession(ctx, signature, request)
|
|
}
|
|
|
|
func (s *OAuth2ServiceImpl) GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) {
|
|
return s.memstore.GetRefreshTokenSession(ctx, signature, session)
|
|
}
|
|
|
|
func (s *OAuth2ServiceImpl) DeleteRefreshTokenSession(ctx context.Context, signature string) (err error) {
|
|
return s.memstore.DeleteRefreshTokenSession(ctx, signature)
|
|
}
|
|
|
|
// RevokeRefreshToken revokes a refresh token as specified in:
|
|
// https://tools.ietf.org/html/rfc7009#section-2.1
|
|
// If the particular
|
|
// token is a refresh token and the authorization server supports the
|
|
// revocation of access tokens, then the authorization server SHOULD
|
|
// also invalidate all access tokens based on the same authorization
|
|
// grant (see Implementation Note).
|
|
func (s *OAuth2ServiceImpl) RevokeRefreshToken(ctx context.Context, requestID string) error {
|
|
return s.memstore.RevokeRefreshToken(ctx, requestID)
|
|
}
|
|
|
|
// RevokeRefreshTokenMaybeGracePeriod revokes a refresh token as specified in:
|
|
// https://tools.ietf.org/html/rfc7009#section-2.1
|
|
// If the particular
|
|
// token is a refresh token and the authorization server supports the
|
|
// revocation of access tokens, then the authorization server SHOULD
|
|
// also invalidate all access tokens based on the same authorization
|
|
// grant (see Implementation Note).
|
|
//
|
|
// If the Refresh Token grace period is greater than zero in configuration the token
|
|
// will have its expiration time set as UTCNow + GracePeriod.
|
|
func (s *OAuth2ServiceImpl) RevokeRefreshTokenMaybeGracePeriod(ctx context.Context, requestID string, signature string) error {
|
|
return s.memstore.RevokeRefreshTokenMaybeGracePeriod(ctx, requestID, signature)
|
|
}
|
|
|
|
// RevokeAccessToken revokes an access token as specified in:
|
|
// https://tools.ietf.org/html/rfc7009#section-2.1
|
|
// If the token passed to the request
|
|
// is an access token, the server MAY revoke the respective refresh
|
|
// token as well.
|
|
func (s *OAuth2ServiceImpl) RevokeAccessToken(ctx context.Context, requestID string) error {
|
|
return s.memstore.RevokeAccessToken(ctx, requestID)
|
|
}
|
|
|
|
// GetPublicKey returns public key, issued by 'issuer', and assigned for subject. Public key is used to check
|
|
// signature of jwt assertion in authorization grants.
|
|
func (s *OAuth2ServiceImpl) GetPublicKey(ctx context.Context, issuer string, subject string, kid string) (*jose.JSONWebKey, error) {
|
|
return s.sqlstore.GetExternalServicePublicKey(ctx, issuer)
|
|
}
|
|
|
|
// GetPublicKeys returns public key, set issued by 'issuer', and assigned for subject.
|
|
func (s *OAuth2ServiceImpl) GetPublicKeys(ctx context.Context, issuer string, subject string) (*jose.JSONWebKeySet, error) {
|
|
jwk, err := s.sqlstore.GetExternalServicePublicKey(ctx, issuer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &jose.JSONWebKeySet{
|
|
Keys: []jose.JSONWebKey{*jwk},
|
|
}, nil
|
|
}
|
|
|
|
// GetPublicKeyScopes returns assigned scope for assertion, identified by public key, issued by 'issuer'.
|
|
func (s *OAuth2ServiceImpl) GetPublicKeyScopes(ctx context.Context, issuer string, subject string, kid string) ([]string, error) {
|
|
client, err := s.GetExternalService(ctx, issuer)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
userID, err := utils.ParseUserIDFromSubject(subject)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return client.GetScopesOnUser(ctx, s.accessControl, userID), nil
|
|
}
|
|
|
|
// IsJWTUsed returns true, if JWT is not known yet or it can not be considered valid, because it must be already
|
|
// expired.
|
|
func (s *OAuth2ServiceImpl) IsJWTUsed(ctx context.Context, jti string) (bool, error) {
|
|
return s.memstore.IsJWTUsed(ctx, jti)
|
|
}
|
|
|
|
// MarkJWTUsedForTime marks JWT as used for a time passed in exp parameter. This helps ensure that JWTs are not
|
|
// replayed by maintaining the set of used "jti" values for the length of time for which the JWT would be
|
|
// considered valid based on the applicable "exp" instant. (https://tools.ietf.org/html/rfc7523#section-3)
|
|
func (s *OAuth2ServiceImpl) MarkJWTUsedForTime(ctx context.Context, jti string, exp time.Time) error {
|
|
return s.memstore.MarkJWTUsedForTime(ctx, jti, exp)
|
|
}
|