mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Authn: resolve issues with setting up a nil identity (#92620)
This commit is contained in:
parent
692280cd32
commit
4f024d94d8
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
@ -115,7 +115,7 @@
|
|||||||
/pkg/services/annotations/ @grafana/grafana-search-and-storage
|
/pkg/services/annotations/ @grafana/grafana-search-and-storage
|
||||||
/pkg/services/apikey/ @grafana/identity-squad
|
/pkg/services/apikey/ @grafana/identity-squad
|
||||||
/pkg/services/cleanup/ @grafana/grafana-backend-group
|
/pkg/services/cleanup/ @grafana/grafana-backend-group
|
||||||
/pkg/services/contexthandler/ @grafana/grafana-backend-group
|
/pkg/services/contexthandler/ @grafana/grafana-backend-group @grafana/grafana-app-platform-squad
|
||||||
/pkg/services/correlations/ @grafana/explore-squad
|
/pkg/services/correlations/ @grafana/explore-squad
|
||||||
/pkg/services/dashboardimport/ @grafana/grafana-backend-group
|
/pkg/services/dashboardimport/ @grafana/grafana-backend-group
|
||||||
/pkg/services/dashboards/ @grafana/grafana-app-platform-squad
|
/pkg/services/dashboards/ @grafana/grafana-app-platform-squad
|
||||||
@ -320,7 +320,7 @@
|
|||||||
/e2e/ @grafana/grafana-frontend-platform
|
/e2e/ @grafana/grafana-frontend-platform
|
||||||
/e2e/cloud-plugins-suite/ @grafana/partner-datasources
|
/e2e/cloud-plugins-suite/ @grafana/partner-datasources
|
||||||
/e2e/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend
|
/e2e/plugin-e2e/plugin-e2e-api-tests/ @grafana/plugins-platform-frontend
|
||||||
/e2e/test-plugins/grafana-extensionstest-app/ @grafana/plugins-platform-frontend
|
/e2e/test-plugins/grafana-extensionstest-app/ @grafana/plugins-platform-frontend
|
||||||
|
|
||||||
# Packages
|
# Packages
|
||||||
/packages/ @grafana/grafana-frontend-platform @grafana/plugins-platform-frontend
|
/packages/ @grafana/grafana-frontend-platform @grafana/plugins-platform-frontend
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/go-jose/go-jose/v3/jwt"
|
"github.com/go-jose/go-jose/v3/jwt"
|
||||||
authnlib "github.com/grafana/authlib/authn"
|
authnlib "github.com/grafana/authlib/authn"
|
||||||
authnlibclaims "github.com/grafana/authlib/claims"
|
"github.com/grafana/authlib/claims"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"golang.org/x/sync/singleflight"
|
"golang.org/x/sync/singleflight"
|
||||||
|
|
||||||
@ -85,7 +85,7 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
|
|||||||
s.logger.FromContext(ctx).Debug("Sign new id token", "id", id.GetID())
|
s.logger.FromContext(ctx).Debug("Sign new id token", "id", id.GetID())
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
claims := &auth.IDClaims{
|
idClaims := &auth.IDClaims{
|
||||||
Claims: &jwt.Claims{
|
Claims: &jwt.Claims{
|
||||||
Issuer: s.cfg.AppURL,
|
Issuer: s.cfg.AppURL,
|
||||||
Audience: getAudience(id.GetOrgID()),
|
Audience: getAudience(id.GetOrgID()),
|
||||||
@ -100,15 +100,15 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
if id.IsIdentityType(authnlibclaims.TypeUser) {
|
if id.IsIdentityType(claims.TypeUser) {
|
||||||
claims.Rest.Email = id.GetEmail()
|
idClaims.Rest.Email = id.GetEmail()
|
||||||
claims.Rest.EmailVerified = id.IsEmailVerified()
|
idClaims.Rest.EmailVerified = id.IsEmailVerified()
|
||||||
claims.Rest.AuthenticatedBy = id.GetAuthenticatedBy()
|
idClaims.Rest.AuthenticatedBy = id.GetAuthenticatedBy()
|
||||||
claims.Rest.Username = id.GetLogin()
|
idClaims.Rest.Username = id.GetLogin()
|
||||||
claims.Rest.DisplayName = id.GetDisplayName()
|
idClaims.Rest.DisplayName = id.GetDisplayName()
|
||||||
}
|
}
|
||||||
|
|
||||||
token, err := s.signer.SignIDToken(ctx, claims)
|
token, err := s.signer.SignIDToken(ctx, idClaims)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.metrics.failedTokenSigningCounter.Inc()
|
s.metrics.failedTokenSigningCounter.Inc()
|
||||||
return resultType{}, nil
|
return resultType{}, nil
|
||||||
@ -124,7 +124,7 @@ func (s *Service) SignIdentity(ctx context.Context, id identity.Requester) (stri
|
|||||||
s.logger.FromContext(ctx).Error("Failed to add id token to cache", "error", err)
|
s.logger.FromContext(ctx).Error("Failed to add id token to cache", "error", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultType{token: token, idClaims: claims}, nil
|
return resultType{token: token, idClaims: idClaims}, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -140,7 +140,7 @@ func (s *Service) RemoveIDToken(ctx context.Context, id identity.Requester) erro
|
|||||||
|
|
||||||
func (s *Service) hook(ctx context.Context, identity *authn.Identity, _ *authn.Request) error {
|
func (s *Service) hook(ctx context.Context, identity *authn.Identity, _ *authn.Request) error {
|
||||||
// FIXME(kalleep): we should probably lazy load this
|
// FIXME(kalleep): we should probably lazy load this
|
||||||
token, claims, err := s.SignIdentity(ctx, identity)
|
token, idClaims, err := s.SignIdentity(ctx, identity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if shouldLogErr(err) {
|
if shouldLogErr(err) {
|
||||||
s.logger.FromContext(ctx).Error("Failed to sign id token", "err", err, "id", identity.GetID())
|
s.logger.FromContext(ctx).Error("Failed to sign id token", "err", err, "id", identity.GetID())
|
||||||
@ -150,7 +150,7 @@ func (s *Service) hook(ctx context.Context, identity *authn.Identity, _ *authn.R
|
|||||||
}
|
}
|
||||||
|
|
||||||
identity.IDToken = token
|
identity.IDToken = token
|
||||||
identity.IDTokenClaims = claims
|
identity.IDTokenClaims = idClaims
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,13 +74,11 @@ type ExtendedJWT struct {
|
|||||||
func (s *ExtendedJWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identity, error) {
|
func (s *ExtendedJWT) Authenticate(ctx context.Context, r *authn.Request) (*authn.Identity, error) {
|
||||||
jwtToken := s.retrieveAuthenticationToken(r.HTTPRequest)
|
jwtToken := s.retrieveAuthenticationToken(r.HTTPRequest)
|
||||||
|
|
||||||
accessToken, err := s.accessTokenVerifier.Verify(ctx, jwtToken)
|
accessTokenClaims, err := s.accessTokenVerifier.Verify(ctx, jwtToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errExtJWTInvalid.Errorf("failed to verify access token: %w", err)
|
return nil, errExtJWTInvalid.Errorf("failed to verify access token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
accessTokenClaims := authlib.NewAccessClaims(*accessToken)
|
|
||||||
|
|
||||||
idToken := s.retrieveAuthorizationToken(r.HTTPRequest)
|
idToken := s.retrieveAuthorizationToken(r.HTTPRequest)
|
||||||
if idToken != "" {
|
if idToken != "" {
|
||||||
idTokenClaims, err := s.idTokenVerifier.Verify(ctx, idToken)
|
idTokenClaims, err := s.idTokenVerifier.Verify(ctx, idToken)
|
||||||
@ -88,10 +86,10 @@ func (s *ExtendedJWT) Authenticate(ctx context.Context, r *authn.Request) (*auth
|
|||||||
return nil, errExtJWTInvalid.Errorf("failed to verify id token: %w", err)
|
return nil, errExtJWTInvalid.Errorf("failed to verify id token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.authenticateAsUser(authlib.NewIdentityClaims(*idTokenClaims), accessTokenClaims)
|
return s.authenticateAsUser(*idTokenClaims, *accessTokenClaims)
|
||||||
}
|
}
|
||||||
|
|
||||||
return s.authenticateAsService(accessTokenClaims)
|
return s.authenticateAsService(*accessTokenClaims)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ExtendedJWT) IsEnabled() bool {
|
func (s *ExtendedJWT) IsEnabled() bool {
|
||||||
@ -99,73 +97,75 @@ func (s *ExtendedJWT) IsEnabled() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *ExtendedJWT) authenticateAsUser(
|
func (s *ExtendedJWT) authenticateAsUser(
|
||||||
idTokenClaims claims.IdentityClaims,
|
idTokenClaims authlib.Claims[authlib.IDTokenClaims],
|
||||||
accessTokenClaims claims.AccessClaims,
|
accessTokenClaims authlib.Claims[authlib.AccessTokenClaims],
|
||||||
) (*authn.Identity, error) {
|
) (*authn.Identity, error) {
|
||||||
// Only allow id tokens signed for namespace configured for this instance.
|
// Only allow id tokens signed for namespace configured for this instance.
|
||||||
if allowedNamespace := s.namespaceMapper(s.getDefaultOrgID()); !claims.NamespaceMatches(idTokenClaims, allowedNamespace) {
|
if allowedNamespace := s.namespaceMapper(s.getDefaultOrgID()); !claims.NamespaceMatches(authlib.NewIdentityClaims(idTokenClaims), allowedNamespace) {
|
||||||
return nil, errExtJWTDisallowedNamespaceClaim.Errorf("unexpected id token namespace: %s", idTokenClaims.Namespace())
|
return nil, errExtJWTDisallowedNamespaceClaim.Errorf("unexpected id token namespace: %s", idTokenClaims.Rest.Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow access tokens with either the same namespace as the validated id token namespace or wildcard (`*`).
|
// Allow access tokens with either the same namespace as the validated id token namespace or wildcard (`*`).
|
||||||
if !claims.NamespaceMatches(accessTokenClaims, idTokenClaims.Namespace()) {
|
if !claims.NamespaceMatches(authlib.NewAccessClaims(accessTokenClaims), idTokenClaims.Rest.Namespace) {
|
||||||
return nil, errExtJWTMisMatchedNamespaceClaims.Errorf("unexpected access token namespace: %s", accessTokenClaims.Namespace())
|
return nil, errExtJWTMisMatchedNamespaceClaims.Errorf("unexpected access token namespace: %s", accessTokenClaims.Rest.Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
accessType, _, err := identity.ParseTypeAndID(accessTokenClaims.Subject())
|
accessType, _, err := identity.ParseTypeAndID(accessTokenClaims.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", accessTokenClaims.Subject())
|
return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", accessTokenClaims.Subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !claims.IsIdentityType(accessType, claims.TypeAccessPolicy) {
|
if !claims.IsIdentityType(accessType, claims.TypeAccessPolicy) {
|
||||||
return nil, errExtJWTInvalid.Errorf("unexpected identity: %s", accessTokenClaims.Subject())
|
return nil, errExtJWTInvalid.Errorf("unexpected identity: %s", accessTokenClaims.Subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
t, id, err := identity.ParseTypeAndID(idTokenClaims.Subject())
|
t, id, err := identity.ParseTypeAndID(idTokenClaims.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errExtJWTInvalid.Errorf("failed to parse id token subject: %w", err)
|
return nil, errExtJWTInvalid.Errorf("failed to parse id token subject: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !claims.IsIdentityType(t, claims.TypeUser) {
|
if !claims.IsIdentityType(t, claims.TypeUser) {
|
||||||
return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", idTokenClaims.Subject())
|
return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", idTokenClaims.Subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
// For use in service layer, allow higher privilege
|
// For use in service layer, allow higher privilege
|
||||||
allowedKubernetesNamespace := accessTokenClaims.Namespace()
|
allowedKubernetesNamespace := accessTokenClaims.Rest.Namespace
|
||||||
if len(s.cfg.StackID) > 0 {
|
if len(s.cfg.StackID) > 0 {
|
||||||
// For single-tenant cloud use, choose the lower of the two (id token will always have the specific namespace)
|
// For single-tenant cloud use, choose the lower of the two (id token will always have the specific namespace)
|
||||||
allowedKubernetesNamespace = idTokenClaims.Namespace()
|
allowedKubernetesNamespace = idTokenClaims.Rest.Namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
return &authn.Identity{
|
return &authn.Identity{
|
||||||
ID: id,
|
ID: id,
|
||||||
Type: t,
|
Type: t,
|
||||||
OrgID: s.getDefaultOrgID(),
|
OrgID: s.getDefaultOrgID(),
|
||||||
|
AccessTokenClaims: &accessTokenClaims,
|
||||||
|
IDTokenClaims: &idTokenClaims,
|
||||||
AuthenticatedBy: login.ExtendedJWTModule,
|
AuthenticatedBy: login.ExtendedJWTModule,
|
||||||
AuthID: accessTokenClaims.Subject(),
|
AuthID: accessTokenClaims.Subject,
|
||||||
AllowedKubernetesNamespace: allowedKubernetesNamespace,
|
AllowedKubernetesNamespace: allowedKubernetesNamespace,
|
||||||
ClientParams: authn.ClientParams{
|
ClientParams: authn.ClientParams{
|
||||||
SyncPermissions: true,
|
SyncPermissions: true,
|
||||||
FetchPermissionsParams: authn.FetchPermissionsParams{
|
FetchPermissionsParams: authn.FetchPermissionsParams{
|
||||||
ActionsLookup: accessTokenClaims.DelegatedPermissions(),
|
ActionsLookup: accessTokenClaims.Rest.DelegatedPermissions,
|
||||||
},
|
},
|
||||||
FetchSyncedUser: true,
|
FetchSyncedUser: true,
|
||||||
}}, nil
|
}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ExtendedJWT) authenticateAsService(accessTokenClaims claims.AccessClaims) (*authn.Identity, error) {
|
func (s *ExtendedJWT) authenticateAsService(accessTokenClaims authlib.Claims[authlib.AccessTokenClaims]) (*authn.Identity, error) {
|
||||||
// Allow access tokens with that has a wildcard namespace or a namespace matching this instance.
|
// Allow access tokens with that has a wildcard namespace or a namespace matching this instance.
|
||||||
if allowedNamespace := s.namespaceMapper(s.getDefaultOrgID()); !claims.NamespaceMatches(accessTokenClaims, allowedNamespace) {
|
if allowedNamespace := s.namespaceMapper(s.getDefaultOrgID()); !claims.NamespaceMatches(authlib.NewAccessClaims(accessTokenClaims), allowedNamespace) {
|
||||||
return nil, errExtJWTDisallowedNamespaceClaim.Errorf("unexpected access token namespace: %s", accessTokenClaims.Namespace())
|
return nil, errExtJWTDisallowedNamespaceClaim.Errorf("unexpected access token namespace: %s", accessTokenClaims.Rest.Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
t, id, err := identity.ParseTypeAndID(accessTokenClaims.Subject())
|
t, id, err := identity.ParseTypeAndID(accessTokenClaims.Subject)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("failed to parse access token subject: %w", err)
|
return nil, fmt.Errorf("failed to parse access token subject: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !claims.IsIdentityType(t, claims.TypeAccessPolicy) {
|
if !claims.IsIdentityType(t, claims.TypeAccessPolicy) {
|
||||||
return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", accessTokenClaims.Subject())
|
return nil, errExtJWTInvalidSubject.Errorf("unexpected identity: %s", accessTokenClaims.Subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &authn.Identity{
|
return &authn.Identity{
|
||||||
@ -173,13 +173,15 @@ func (s *ExtendedJWT) authenticateAsService(accessTokenClaims claims.AccessClaim
|
|||||||
UID: id,
|
UID: id,
|
||||||
Type: t,
|
Type: t,
|
||||||
OrgID: s.getDefaultOrgID(),
|
OrgID: s.getDefaultOrgID(),
|
||||||
|
AccessTokenClaims: &accessTokenClaims,
|
||||||
|
IDTokenClaims: nil,
|
||||||
AuthenticatedBy: login.ExtendedJWTModule,
|
AuthenticatedBy: login.ExtendedJWTModule,
|
||||||
AuthID: accessTokenClaims.Subject(),
|
AuthID: accessTokenClaims.Subject,
|
||||||
AllowedKubernetesNamespace: accessTokenClaims.Namespace(),
|
AllowedKubernetesNamespace: accessTokenClaims.Rest.Namespace,
|
||||||
ClientParams: authn.ClientParams{
|
ClientParams: authn.ClientParams{
|
||||||
SyncPermissions: true,
|
SyncPermissions: true,
|
||||||
FetchPermissionsParams: authn.FetchPermissionsParams{
|
FetchPermissionsParams: authn.FetchPermissionsParams{
|
||||||
Roles: accessTokenClaims.Permissions(),
|
Roles: accessTokenClaims.Rest.Permissions,
|
||||||
},
|
},
|
||||||
FetchSyncedUser: false,
|
FetchSyncedUser: false,
|
||||||
},
|
},
|
||||||
|
@ -230,6 +230,7 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
UID: "this-uid",
|
UID: "this-uid",
|
||||||
Type: claims.TypeAccessPolicy,
|
Type: claims.TypeAccessPolicy,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
|
AccessTokenClaims: &validAccessTokenClaims,
|
||||||
AllowedKubernetesNamespace: "default",
|
AllowedKubernetesNamespace: "default",
|
||||||
AuthenticatedBy: "extendedjwt",
|
AuthenticatedBy: "extendedjwt",
|
||||||
AuthID: "access-policy:this-uid",
|
AuthID: "access-policy:this-uid",
|
||||||
@ -247,6 +248,7 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
UID: "this-uid",
|
UID: "this-uid",
|
||||||
Type: claims.TypeAccessPolicy,
|
Type: claims.TypeAccessPolicy,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
|
AccessTokenClaims: &validAccessTokenClaimsWildcard,
|
||||||
AllowedKubernetesNamespace: "*",
|
AllowedKubernetesNamespace: "*",
|
||||||
AuthenticatedBy: "extendedjwt",
|
AuthenticatedBy: "extendedjwt",
|
||||||
AuthID: "access-policy:this-uid",
|
AuthID: "access-policy:this-uid",
|
||||||
@ -264,6 +266,8 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
ID: "2",
|
ID: "2",
|
||||||
Type: claims.TypeUser,
|
Type: claims.TypeUser,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
|
AccessTokenClaims: &validAccessTokenClaims,
|
||||||
|
IDTokenClaims: &validIDTokenClaims,
|
||||||
AllowedKubernetesNamespace: "default",
|
AllowedKubernetesNamespace: "default",
|
||||||
AuthenticatedBy: "extendedjwt",
|
AuthenticatedBy: "extendedjwt",
|
||||||
AuthID: "access-policy:this-uid",
|
AuthID: "access-policy:this-uid",
|
||||||
@ -285,6 +289,8 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
ID: "2",
|
ID: "2",
|
||||||
Type: claims.TypeUser,
|
Type: claims.TypeUser,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
|
AccessTokenClaims: &validAccessTokenClaimsWildcard,
|
||||||
|
IDTokenClaims: &validIDTokenClaims,
|
||||||
AllowedKubernetesNamespace: "*",
|
AllowedKubernetesNamespace: "*",
|
||||||
AuthenticatedBy: "extendedjwt",
|
AuthenticatedBy: "extendedjwt",
|
||||||
AuthID: "access-policy:this-uid",
|
AuthID: "access-policy:this-uid",
|
||||||
@ -311,6 +317,8 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
ID: "2",
|
ID: "2",
|
||||||
Type: claims.TypeUser,
|
Type: claims.TypeUser,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
|
AccessTokenClaims: &validAccessTokenClaimsWildcard,
|
||||||
|
IDTokenClaims: &validIDTokenClaimsWithStackSet,
|
||||||
AllowedKubernetesNamespace: "stacks-1234",
|
AllowedKubernetesNamespace: "stacks-1234",
|
||||||
AuthenticatedBy: "extendedjwt",
|
AuthenticatedBy: "extendedjwt",
|
||||||
AuthID: "access-policy:this-uid",
|
AuthID: "access-policy:this-uid",
|
||||||
@ -337,6 +345,7 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
UID: "this-uid",
|
UID: "this-uid",
|
||||||
Type: claims.TypeAccessPolicy,
|
Type: claims.TypeAccessPolicy,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
|
AccessTokenClaims: &validAccessTokenClaimsWithStackSet,
|
||||||
AllowedKubernetesNamespace: "stacks-1234",
|
AllowedKubernetesNamespace: "stacks-1234",
|
||||||
AuthenticatedBy: "extendedjwt",
|
AuthenticatedBy: "extendedjwt",
|
||||||
AuthID: "access-policy:this-uid",
|
AuthID: "access-policy:this-uid",
|
||||||
@ -362,6 +371,7 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
UID: "this-uid",
|
UID: "this-uid",
|
||||||
Type: claims.TypeAccessPolicy,
|
Type: claims.TypeAccessPolicy,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
|
AccessTokenClaims: &validAccessTokenClaimsWithDeprecatedStackClaimSet,
|
||||||
AllowedKubernetesNamespace: "stack-1234",
|
AllowedKubernetesNamespace: "stack-1234",
|
||||||
AuthenticatedBy: "extendedjwt",
|
AuthenticatedBy: "extendedjwt",
|
||||||
AuthID: "access-policy:this-uid",
|
AuthID: "access-policy:this-uid",
|
||||||
@ -387,6 +397,8 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
ID: "2",
|
ID: "2",
|
||||||
Type: claims.TypeUser,
|
Type: claims.TypeUser,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
|
AccessTokenClaims: &validAccessTokenClaimsWithDeprecatedStackClaimSet,
|
||||||
|
IDTokenClaims: &validIDTokenClaimsWithDeprecatedStackClaimSet,
|
||||||
AllowedKubernetesNamespace: "stack-1234",
|
AllowedKubernetesNamespace: "stack-1234",
|
||||||
AuthenticatedBy: "extendedjwt",
|
AuthenticatedBy: "extendedjwt",
|
||||||
AuthID: "access-policy:this-uid",
|
AuthID: "access-policy:this-uid",
|
||||||
@ -413,6 +425,8 @@ func TestExtendedJWT_Authenticate(t *testing.T) {
|
|||||||
ID: "2",
|
ID: "2",
|
||||||
Type: claims.TypeUser,
|
Type: claims.TypeUser,
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
|
AccessTokenClaims: &validAccessTokenClaimsWildcard,
|
||||||
|
IDTokenClaims: &validIDTokenClaimsWithStackSet,
|
||||||
AllowedKubernetesNamespace: "stacks-1234",
|
AllowedKubernetesNamespace: "stacks-1234",
|
||||||
AuthenticatedBy: "extendedjwt",
|
AuthenticatedBy: "extendedjwt",
|
||||||
AuthID: "access-policy:this-uid",
|
AuthID: "access-policy:this-uid",
|
||||||
|
@ -74,10 +74,15 @@ type Identity struct {
|
|||||||
// IDToken is a signed token representing the identity that can be forwarded to plugins and external services.
|
// IDToken is a signed token representing the identity that can be forwarded to plugins and external services.
|
||||||
IDToken string
|
IDToken string
|
||||||
IDTokenClaims *authn.Claims[authn.IDTokenClaims]
|
IDTokenClaims *authn.Claims[authn.IDTokenClaims]
|
||||||
|
|
||||||
|
AccessTokenClaims *authn.Claims[authn.AccessTokenClaims]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access implements claims.AuthInfo.
|
// Access implements claims.AuthInfo.
|
||||||
func (i *Identity) GetAccess() claims.AccessClaims {
|
func (i *Identity) GetAccess() claims.AccessClaims {
|
||||||
|
if i.AccessTokenClaims != nil {
|
||||||
|
return authn.NewAccessClaims(*i.AccessTokenClaims)
|
||||||
|
}
|
||||||
return &identity.IDClaimsWrapper{Source: i}
|
return &identity.IDClaimsWrapper{Source: i}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,6 +122,7 @@ func (h *ContextHandler) Middleware(next http.Handler) http.Handler {
|
|||||||
reqContext.IsSignedIn = !reqContext.SignedInUser.IsAnonymous
|
reqContext.IsSignedIn = !reqContext.SignedInUser.IsAnonymous
|
||||||
reqContext.AllowAnonymous = reqContext.SignedInUser.IsAnonymous
|
reqContext.AllowAnonymous = reqContext.SignedInUser.IsAnonymous
|
||||||
reqContext.IsRenderCall = id.IsAuthenticatedBy(login.RenderModule)
|
reqContext.IsRenderCall = id.IsAuthenticatedBy(login.RenderModule)
|
||||||
|
ctx = identity.WithRequester(ctx, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
h.excludeSensitiveHeadersFromRequest(reqContext.Req)
|
h.excludeSensitiveHeadersFromRequest(reqContext.Req)
|
||||||
@ -139,8 +140,7 @@ func (h *ContextHandler) Middleware(next http.Handler) http.Handler {
|
|||||||
|
|
||||||
// End the span to make next handlers not wrapped within middleware span
|
// End the span to make next handlers not wrapped within middleware span
|
||||||
span.End()
|
span.End()
|
||||||
|
next.ServeHTTP(w, r.WithContext(ctx))
|
||||||
next.ServeHTTP(w, r.WithContext(identity.WithRequester(ctx, id)))
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9841,6 +9841,12 @@
|
|||||||
"$ref": "#/definitions/SnapshotListResponseDTO"
|
"$ref": "#/definitions/SnapshotListResponseDTO"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"statusMovedPermanently": {
|
||||||
|
"description": "StatusMovedPermanently",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ErrorResponseBody"
|
||||||
|
}
|
||||||
|
},
|
||||||
"unauthorisedError": {
|
"unauthorisedError": {
|
||||||
"description": "UnauthorizedError is returned when the request is not authenticated.",
|
"description": "UnauthorizedError is returned when the request is not authenticated.",
|
||||||
"schema": {
|
"schema": {
|
||||||
|
Loading…
Reference in New Issue
Block a user