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:
Karl Persson
2023-09-28 09:22:05 +02:00
committed by GitHub
parent 3a1c3be057
commit b9b4246432
8 changed files with 264 additions and 170 deletions

View File

@@ -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.

View File

@@ -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)
}

View 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)
})
}