mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
IDForwarding: Add auth hook to generate id token (#75555)
* AuthN: Move identity struct to its own file * IDForwarding: Add IDToken property to usr and identity structs and add GetIDToken to requester interface * Inject IDService into background services * IDForwarding: Register post auth hook when feature toggle is enabled
This commit is contained in:
@@ -62,6 +62,9 @@ type Requester interface {
|
||||
HasUniqueId() bool
|
||||
// AuthenticatedBy returns the authentication method used to authenticate the entity.
|
||||
GetAuthenticatedBy() string
|
||||
// GetIDToken returns a signed token representing the identity that can be forwarded to plugins and external services.
|
||||
// Will only be set when featuremgmt.FlagIdForwarding is enabled.
|
||||
GetIDToken() string
|
||||
}
|
||||
|
||||
// IntIdentifier converts a string identifier to an int64.
|
||||
|
||||
@@ -11,6 +11,8 @@ import (
|
||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||
"github.com/grafana/grafana/pkg/services/auth"
|
||||
"github.com/grafana/grafana/pkg/services/auth/identity"
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
)
|
||||
|
||||
@@ -22,8 +24,17 @@ const (
|
||||
|
||||
var _ auth.IDService = (*Service)(nil)
|
||||
|
||||
func ProvideService(cfg *setting.Cfg, signer auth.IDSigner, cache remotecache.CacheStorage) *Service {
|
||||
return &Service{cfg, log.New("id-service"), signer, cache}
|
||||
func ProvideService(
|
||||
cfg *setting.Cfg, signer auth.IDSigner, cache remotecache.CacheStorage,
|
||||
features featuremgmt.FeatureToggles, authnService authn.Service,
|
||||
) *Service {
|
||||
s := &Service{cfg, log.New("id-service"), signer, cache}
|
||||
|
||||
if features.IsEnabled(featuremgmt.FlagIdForwarding) {
|
||||
authnService.RegisterPostAuthHook(s.hook, 140)
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
@@ -46,7 +57,6 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
|
||||
s.logger.Debug("Sign new id token", "namespace", namespace, "id", identifier)
|
||||
|
||||
now := time.Now()
|
||||
|
||||
token, err := s.signer.SignIDToken(ctx, &auth.IDClaims{
|
||||
Claims: jwt.Claims{
|
||||
ID: identifier,
|
||||
@@ -69,6 +79,21 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
|
||||
return token, nil
|
||||
}
|
||||
|
||||
func (s *Service) hook(ctx context.Context, identity *authn.Identity, _ *authn.Request) error {
|
||||
// FIXME(kalleep): implement identity.Requester for authn.Identity
|
||||
// FIXME(kalleep): we should probably lazy load this
|
||||
token, err := s.SignIdentity(ctx, identity.SignedInUser())
|
||||
if err != nil {
|
||||
namespace, id := identity.NamespacedID()
|
||||
s.logger.Error("Failed to sign id token", "err", err, "namespace", namespace, "id", id)
|
||||
// for now don't return error so we don't break authentication from this hook
|
||||
return nil
|
||||
}
|
||||
|
||||
identity.IDToken = token
|
||||
return nil
|
||||
}
|
||||
|
||||
func prefixCacheKey(key string) string {
|
||||
return fmt.Sprintf("%s-%s", cachePrefix, key)
|
||||
}
|
||||
|
||||
41
pkg/services/auth/idimpl/service_test.go
Normal file
41
pkg/services/auth/idimpl/service_test.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package idimpl
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/authn"
|
||||
"github.com/grafana/grafana/pkg/services/authn/authntest"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func Test_ProvideService(t *testing.T) {
|
||||
t.Run("should register post auth hook when feature flag is enabled", func(t *testing.T) {
|
||||
features := featuremgmt.WithFeatures(featuremgmt.FlagIdForwarding)
|
||||
|
||||
var hookRegistered bool
|
||||
authnService := &authntest.MockService{
|
||||
RegisterPostAuthHookFunc: func(_ authn.PostAuthHookFn, _ uint) {
|
||||
hookRegistered = true
|
||||
},
|
||||
}
|
||||
|
||||
_ = ProvideService(setting.NewCfg(), nil, nil, features, authnService)
|
||||
assert.True(t, hookRegistered)
|
||||
})
|
||||
|
||||
t.Run("should not register post auth hook when feature flag is disabled", func(t *testing.T) {
|
||||
features := featuremgmt.WithFeatures()
|
||||
|
||||
var hookRegistered bool
|
||||
authnService := &authntest.MockService{
|
||||
RegisterPostAuthHookFunc: func(_ authn.PostAuthHookFn, _ uint) {
|
||||
hookRegistered = true
|
||||
},
|
||||
}
|
||||
|
||||
_ = ProvideService(setting.NewCfg(), nil, nil, features, authnService)
|
||||
assert.False(t, hookRegistered)
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user