mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-21 14:35:22 +08:00
Support for joining Actions in un-reachable GitHub Enterprise Servers via Static JWKS (#48973)
* Add JWKS based validator for github tokens * Extend proto * Update auth srvr github join impl to support static jwks * Ignore govet * initialize with jwks validator * Update docs * Update terraform shizz * Regenerate various things
This commit is contained in:
@@ -1411,6 +1411,11 @@ message ProvisionTokenSpecV2GitHub {
|
||||
// See https://docs.github.com/en/enterprise-cloud@latest/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-issuer-value-for-an-enterprise
|
||||
// for more information about customized issuer values.
|
||||
string EnterpriseSlug = 3 [(gogoproto.jsontag) = "enterprise_slug,omitempty"];
|
||||
// StaticJWKS disables fetching of the GHES signing keys via the JWKS/OIDC
|
||||
// endpoints, and allows them to be directly specified. This allows joining
|
||||
// from GitHub Actions in GHES instances that are not reachable by the
|
||||
// Teleport Auth Service.
|
||||
string StaticJWKS = 4 [(gogoproto.jsontag) = "static_jwks,omitempty"];
|
||||
}
|
||||
|
||||
// ProvisionTokenSpecV2GitLab contains the GitLab-specific part of the
|
||||
|
||||
+1890
-1841
File diff suppressed because it is too large
Load Diff
@@ -100,6 +100,7 @@ resource, which you can apply after installing the Teleport Kubernetes operator.
|
||||
|allow|[][object](#specgithuballow-items)|Allow is a list of TokenRules, nodes using this token must match one allow rule to use this token.|
|
||||
|enterprise_server_host|string|EnterpriseServerHost allows joining from runners associated with a GitHub Enterprise Server instance. When unconfigured, tokens will be validated against github.com, but when configured to the host of a GHES instance, then the tokens will be validated against host. This value should be the hostname of the GHES instance, and should not include the scheme or a path. The instance must be accessible over HTTPS at this hostname and the certificate must be trusted by the Auth Service.|
|
||||
|enterprise_slug|string|EnterpriseSlug allows the slug of a GitHub Enterprise organisation to be included in the expected issuer of the OIDC tokens. This is for compatibility with the `include_enterprise_slug` option in GHE. This field should be set to the slug of your enterprise if this is enabled. If this is not enabled, then this field must be left empty. This field cannot be specified if `enterprise_server_host` is specified. See https://docs.github.com/en/enterprise-cloud@latest/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-issuer-value-for-an-enterprise for more information about customized issuer values.|
|
||||
|static_jwks|string|StaticJWKS disables fetching of the GHES signing keys via the JWKS/OIDC endpoints, and allows them to be directly specified. This allows joining from GitHub Actions in GHES instances that are not reachable by the Teleport Auth Service.|
|
||||
|
||||
### spec.github.allow items
|
||||
|
||||
|
||||
@@ -111,6 +111,7 @@ Optional:
|
||||
- `allow` (Attributes List) Allow is a list of TokenRules, nodes using this token must match one allow rule to use this token. (see [below for nested schema](#nested-schema-for-specgithuballow))
|
||||
- `enterprise_server_host` (String) EnterpriseServerHost allows joining from runners associated with a GitHub Enterprise Server instance. When unconfigured, tokens will be validated against github.com, but when configured to the host of a GHES instance, then the tokens will be validated against host. This value should be the hostname of the GHES instance, and should not include the scheme or a path. The instance must be accessible over HTTPS at this hostname and the certificate must be trusted by the Auth Service.
|
||||
- `enterprise_slug` (String) EnterpriseSlug allows the slug of a GitHub Enterprise organisation to be included in the expected issuer of the OIDC tokens. This is for compatibility with the `include_enterprise_slug` option in GHE. This field should be set to the slug of your enterprise if this is enabled. If this is not enabled, then this field must be left empty. This field cannot be specified if `enterprise_server_host` is specified. See https://docs.github.com/en/enterprise-cloud@latest/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-issuer-value-for-an-enterprise for more information about customized issuer values.
|
||||
- `static_jwks` (String) StaticJWKS disables fetching of the GHES signing keys via the JWKS/OIDC endpoints, and allows them to be directly specified. This allows joining from GitHub Actions in GHES instances that are not reachable by the Teleport Auth Service.
|
||||
|
||||
### Nested Schema for `spec.github.allow`
|
||||
|
||||
|
||||
@@ -145,6 +145,7 @@ Optional:
|
||||
- `allow` (Attributes List) Allow is a list of TokenRules, nodes using this token must match one allow rule to use this token. (see [below for nested schema](#nested-schema-for-specgithuballow))
|
||||
- `enterprise_server_host` (String) EnterpriseServerHost allows joining from runners associated with a GitHub Enterprise Server instance. When unconfigured, tokens will be validated against github.com, but when configured to the host of a GHES instance, then the tokens will be validated against host. This value should be the hostname of the GHES instance, and should not include the scheme or a path. The instance must be accessible over HTTPS at this hostname and the certificate must be trusted by the Auth Service.
|
||||
- `enterprise_slug` (String) EnterpriseSlug allows the slug of a GitHub Enterprise organisation to be included in the expected issuer of the OIDC tokens. This is for compatibility with the `include_enterprise_slug` option in GHE. This field should be set to the slug of your enterprise if this is enabled. If this is not enabled, then this field must be left empty. This field cannot be specified if `enterprise_server_host` is specified. See https://docs.github.com/en/enterprise-cloud@latest/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-issuer-value-for-an-enterprise for more information about customized issuer values.
|
||||
- `static_jwks` (String) StaticJWKS disables fetching of the GHES signing keys via the JWKS/OIDC endpoints, and allows them to be directly specified. This allows joining from GitHub Actions in GHES instances that are not reachable by the Teleport Auth Service.
|
||||
|
||||
### Nested Schema for `spec.github.allow`
|
||||
|
||||
|
||||
+6
@@ -204,6 +204,12 @@ spec:
|
||||
if `enterprise_server_host` is specified. See https://docs.github.com/en/enterprise-cloud@latest/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-issuer-value-for-an-enterprise
|
||||
for more information about customized issuer values.
|
||||
type: string
|
||||
static_jwks:
|
||||
description: StaticJWKS disables fetching of the GHES signing
|
||||
keys via the JWKS/OIDC endpoints, and allows them to be directly
|
||||
specified. This allows joining from GitHub Actions in GHES instances
|
||||
that are not reachable by the Teleport Auth Service.
|
||||
type: string
|
||||
type: object
|
||||
gitlab:
|
||||
description: GitLab allows the configuration of options specific to
|
||||
|
||||
@@ -204,6 +204,12 @@ spec:
|
||||
if `enterprise_server_host` is specified. See https://docs.github.com/en/enterprise-cloud@latest/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect#customizing-the-issuer-value-for-an-enterprise
|
||||
for more information about customized issuer values.
|
||||
type: string
|
||||
static_jwks:
|
||||
description: StaticJWKS disables fetching of the GHES signing
|
||||
keys via the JWKS/OIDC endpoints, and allows them to be directly
|
||||
specified. This allows joining from GitHub Actions in GHES instances
|
||||
that are not reachable by the Teleport Auth Service.
|
||||
type: string
|
||||
type: object
|
||||
gitlab:
|
||||
description: GitLab allows the configuration of options specific to
|
||||
|
||||
@@ -274,6 +274,11 @@ func GenSchemaProvisionTokenV2(ctx context.Context) (github_com_hashicorp_terraf
|
||||
Optional: true,
|
||||
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
|
||||
},
|
||||
"static_jwks": {
|
||||
Description: "StaticJWKS disables fetching of the GHES signing keys via the JWKS/OIDC endpoints, and allows them to be directly specified. This allows joining from GitHub Actions in GHES instances that are not reachable by the Teleport Auth Service.",
|
||||
Optional: true,
|
||||
Type: github_com_hashicorp_terraform_plugin_framework_types.StringType,
|
||||
},
|
||||
}),
|
||||
Description: "GitHub allows the configuration of options specific to the \"github\" join method.",
|
||||
Optional: true,
|
||||
@@ -1166,6 +1171,23 @@ func CopyProvisionTokenV2FromTerraform(_ context.Context, tf github_com_hashicor
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
a, ok := tf.Attrs["static_jwks"]
|
||||
if !ok {
|
||||
diags.Append(attrReadMissingDiag{"ProvisionTokenV2.Spec.GitHub.StaticJWKS"})
|
||||
} else {
|
||||
v, ok := a.(github_com_hashicorp_terraform_plugin_framework_types.String)
|
||||
if !ok {
|
||||
diags.Append(attrReadConversionFailureDiag{"ProvisionTokenV2.Spec.GitHub.StaticJWKS", "github.com/hashicorp/terraform-plugin-framework/types.String"})
|
||||
} else {
|
||||
var t string
|
||||
if !v.Null && !v.Unknown {
|
||||
t = string(v.Value)
|
||||
}
|
||||
obj.StaticJWKS = t
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3292,6 +3314,28 @@ func CopyProvisionTokenV2ToTerraform(ctx context.Context, obj *github_com_gravit
|
||||
tf.Attrs["enterprise_slug"] = v
|
||||
}
|
||||
}
|
||||
{
|
||||
t, ok := tf.AttrTypes["static_jwks"]
|
||||
if !ok {
|
||||
diags.Append(attrWriteMissingDiag{"ProvisionTokenV2.Spec.GitHub.StaticJWKS"})
|
||||
} else {
|
||||
v, ok := tf.Attrs["static_jwks"].(github_com_hashicorp_terraform_plugin_framework_types.String)
|
||||
if !ok {
|
||||
i, err := t.ValueFromTerraform(ctx, github_com_hashicorp_terraform_plugin_go_tftypes.NewValue(t.TerraformType(ctx), nil))
|
||||
if err != nil {
|
||||
diags.Append(attrWriteGeneralError{"ProvisionTokenV2.Spec.GitHub.StaticJWKS", err})
|
||||
}
|
||||
v, ok = i.(github_com_hashicorp_terraform_plugin_framework_types.String)
|
||||
if !ok {
|
||||
diags.Append(attrWriteConversionFailureDiag{"ProvisionTokenV2.Spec.GitHub.StaticJWKS", "github.com/hashicorp/terraform-plugin-framework/types.String"})
|
||||
}
|
||||
v.Null = string(obj.StaticJWKS) == ""
|
||||
}
|
||||
v.Value = string(obj.StaticJWKS)
|
||||
v.Unknown = false
|
||||
tf.Attrs["static_jwks"] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
v.Unknown = false
|
||||
tf.Attrs["github"] = v
|
||||
|
||||
@@ -568,6 +568,9 @@ func NewServer(cfg *InitConfig, opts ...ServerOption) (*Server, error) {
|
||||
},
|
||||
)
|
||||
}
|
||||
if as.ghaIDTokenJWKSValidator == nil {
|
||||
as.ghaIDTokenJWKSValidator = githubactions.ValidateTokenWithJWKS
|
||||
}
|
||||
if as.spaceliftIDTokenValidator == nil {
|
||||
as.spaceliftIDTokenValidator = spacelift.NewIDTokenValidator(
|
||||
spacelift.IDTokenValidatorConfig{
|
||||
@@ -985,6 +988,10 @@ type Server struct {
|
||||
// ghaIDTokenValidator allows ID tokens from GitHub Actions to be validated
|
||||
// by the auth server. It can be overridden for the purpose of tests.
|
||||
ghaIDTokenValidator ghaIDTokenValidator
|
||||
// ghaIDTokenJWKSValidator allows ID tokens from GitHub Actions to be
|
||||
// validated by the auth server using a known JWKS. It can be overridden for
|
||||
//the purpose of tests.
|
||||
ghaIDTokenJWKSValidator ghaIDTokenJWKSValidator
|
||||
|
||||
// spaceliftIDTokenValidator allows ID tokens from Spacelift to be validated
|
||||
// by the auth server. It can be overridden for the purpose of tests.
|
||||
|
||||
+22
-5
@@ -21,6 +21,7 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -36,6 +37,10 @@ type ghaIDTokenValidator interface {
|
||||
) (*githubactions.IDTokenClaims, error)
|
||||
}
|
||||
|
||||
type ghaIDTokenJWKSValidator func(
|
||||
now time.Time, jwksData []byte, token string,
|
||||
) (*githubactions.IDTokenClaims, error)
|
||||
|
||||
func (a *Server) checkGitHubJoinRequest(ctx context.Context, req *types.RegisterUsingTokenRequest) (*githubactions.IDTokenClaims, error) {
|
||||
if req.IDToken == "" {
|
||||
return nil, trace.BadParameter("IDToken not provided for Github join request")
|
||||
@@ -63,11 +68,23 @@ func (a *Server) checkGitHubJoinRequest(ctx context.Context, req *types.Register
|
||||
}
|
||||
}
|
||||
|
||||
claims, err := a.ghaIDTokenValidator.Validate(
|
||||
ctx, enterpriseOverride, enterpriseSlug, req.IDToken,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err)
|
||||
var claims *githubactions.IDTokenClaims
|
||||
if token.Spec.GitHub.StaticJWKS != "" {
|
||||
claims, err = a.ghaIDTokenJWKSValidator(
|
||||
a.clock.Now().UTC(),
|
||||
[]byte(token.Spec.GitHub.StaticJWKS),
|
||||
req.IDToken,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "validating with jwks")
|
||||
}
|
||||
} else {
|
||||
claims, err = a.ghaIDTokenValidator.Validate(
|
||||
ctx, enterpriseOverride, enterpriseSlug, req.IDToken,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "validating with oidc")
|
||||
}
|
||||
}
|
||||
|
||||
log.WithFields(logrus.Fields{
|
||||
|
||||
@@ -37,6 +37,7 @@ type mockIDTokenValidator struct {
|
||||
tokens map[string]githubactions.IDTokenClaims
|
||||
lastCalledGHESHost string
|
||||
lastCalledEnterpriseSlug string
|
||||
lastCalledJWKS string
|
||||
}
|
||||
|
||||
var errMockInvalidToken = errors.New("invalid token")
|
||||
@@ -57,6 +58,18 @@ func (m *mockIDTokenValidator) Validate(
|
||||
func (m *mockIDTokenValidator) reset() {
|
||||
m.lastCalledGHESHost = ""
|
||||
m.lastCalledEnterpriseSlug = ""
|
||||
m.lastCalledJWKS = ""
|
||||
}
|
||||
|
||||
func (m *mockIDTokenValidator) ValidateJWKS(
|
||||
_ time.Time, jwks []byte, token string,
|
||||
) (*githubactions.IDTokenClaims, error) {
|
||||
m.lastCalledJWKS = string(jwks)
|
||||
claims, ok := m.tokens[token]
|
||||
if !ok {
|
||||
return nil, errMockInvalidToken
|
||||
}
|
||||
return &claims, nil
|
||||
}
|
||||
|
||||
func TestAuth_RegisterUsingToken_GHA(t *testing.T) {
|
||||
@@ -77,6 +90,7 @@ func TestAuth_RegisterUsingToken_GHA(t *testing.T) {
|
||||
}
|
||||
var withTokenValidator ServerOption = func(server *Server) error {
|
||||
server.ghaIDTokenValidator = idTokenValidator
|
||||
server.ghaIDTokenJWKSValidator = idTokenValidator.ValidateJWKS
|
||||
return nil
|
||||
}
|
||||
ctx := context.Background()
|
||||
@@ -141,6 +155,36 @@ func TestAuth_RegisterUsingToken_GHA(t *testing.T) {
|
||||
request: newRequest(validIDToken),
|
||||
assertError: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "success with jwks",
|
||||
tokenSpec: types.ProvisionTokenSpecV2{
|
||||
JoinMethod: types.JoinMethodGitHub,
|
||||
Roles: []types.SystemRole{types.RoleNode},
|
||||
GitHub: &types.ProvisionTokenSpecV2GitHub{
|
||||
Allow: []*types.ProvisionTokenSpecV2GitHub_Rule{
|
||||
allowRule(nil),
|
||||
},
|
||||
StaticJWKS: "my-jwks",
|
||||
},
|
||||
},
|
||||
request: newRequest(validIDToken),
|
||||
assertError: require.NoError,
|
||||
},
|
||||
{
|
||||
name: "failure with jwks",
|
||||
tokenSpec: types.ProvisionTokenSpecV2{
|
||||
JoinMethod: types.JoinMethodGitHub,
|
||||
Roles: []types.SystemRole{types.RoleNode},
|
||||
GitHub: &types.ProvisionTokenSpecV2GitHub{
|
||||
Allow: []*types.ProvisionTokenSpecV2GitHub_Rule{
|
||||
allowRule(nil),
|
||||
},
|
||||
StaticJWKS: "my-jwks",
|
||||
},
|
||||
},
|
||||
request: newRequest("invalid"),
|
||||
assertError: require.Error,
|
||||
},
|
||||
{
|
||||
name: "ghes override",
|
||||
tokenSpec: types.ProvisionTokenSpecV2{
|
||||
@@ -385,6 +429,11 @@ func TestAuth_RegisterUsingToken_GHA(t *testing.T) {
|
||||
tt.tokenSpec.GitHub.EnterpriseSlug,
|
||||
idTokenValidator.lastCalledEnterpriseSlug,
|
||||
)
|
||||
require.Equal(
|
||||
t,
|
||||
tt.tokenSpec.GitHub.StaticJWKS,
|
||||
idTokenValidator.lastCalledJWKS,
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,10 +20,13 @@ package githubactions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc"
|
||||
"github.com/go-jose/go-jose/v3"
|
||||
josejwt "github.com/go-jose/go-jose/v3/jwt"
|
||||
"github.com/gravitational/trace"
|
||||
"github.com/jonboulle/clockwork"
|
||||
|
||||
@@ -113,3 +116,45 @@ func (id *IDTokenValidator) Validate(
|
||||
}
|
||||
return &claims, nil
|
||||
}
|
||||
|
||||
// ValidateTokenWithJWKS validates a GitHub Actions JWT using a configured
|
||||
// JWKS rather than fetching from well-known. This supports cases where GHES
|
||||
// is not accessible to the Teleport Auth Server.
|
||||
func ValidateTokenWithJWKS(
|
||||
now time.Time,
|
||||
jwksData []byte,
|
||||
token string,
|
||||
) (*IDTokenClaims, error) {
|
||||
parsed, err := josejwt.ParseSigned(token)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "parsing jwt")
|
||||
}
|
||||
|
||||
jwks := jose.JSONWebKeySet{}
|
||||
if err := json.Unmarshal(jwksData, &jwks); err != nil {
|
||||
return nil, trace.Wrap(err, "parsing provided jwks")
|
||||
}
|
||||
|
||||
stdClaims := josejwt.Claims{}
|
||||
if err := parsed.Claims(jwks, &stdClaims); err != nil {
|
||||
return nil, trace.Wrap(err, "validating jwt signature")
|
||||
}
|
||||
|
||||
leeway := time.Second * 10
|
||||
err = stdClaims.ValidateWithLeeway(josejwt.Expected{
|
||||
Audience: []string{
|
||||
"teleport.cluster.local",
|
||||
},
|
||||
Time: now,
|
||||
}, leeway)
|
||||
if err != nil {
|
||||
return nil, trace.Wrap(err, "validating standard claims")
|
||||
}
|
||||
|
||||
claims := IDTokenClaims{}
|
||||
if err := parsed.Claims(jwks, &claims); err != nil {
|
||||
return nil, trace.Wrap(err, "validating custom claims")
|
||||
}
|
||||
|
||||
return &claims, nil
|
||||
}
|
||||
|
||||
@@ -353,3 +353,144 @@ func TestIDTokenValidator_Validate(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func testSigner(t *testing.T) ([]byte, jose.Signer) {
|
||||
key, err := cryptosuites.GenerateKeyWithAlgorithm(cryptosuites.ECDSAP256)
|
||||
require.NoError(t, err)
|
||||
signer, err := jose.NewSigner(
|
||||
jose.SigningKey{Algorithm: jose.ES256, Key: key},
|
||||
(&jose.SignerOptions{}).
|
||||
WithType("JWT").
|
||||
WithHeader("kid", "foo"),
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
jwks := jose.JSONWebKeySet{Keys: []jose.JSONWebKey{
|
||||
{
|
||||
Key: key.Public(),
|
||||
Use: "sig",
|
||||
Algorithm: string(jose.ES256),
|
||||
KeyID: "foo",
|
||||
},
|
||||
}}
|
||||
jwksData, err := json.Marshal(jwks)
|
||||
require.NoError(t, err)
|
||||
return jwksData, signer
|
||||
}
|
||||
|
||||
//nolint:govet // there's some weird json struct tag overlap here
|
||||
type claims struct {
|
||||
jwt.Claims
|
||||
IDTokenClaims
|
||||
Subject string `json:"sub"`
|
||||
}
|
||||
|
||||
func TestValidateTokenWithJWKS(t *testing.T) {
|
||||
jwks, signer := testSigner(t)
|
||||
_, wrongSigner := testSigner(t)
|
||||
|
||||
now := time.Now()
|
||||
clusterName := "teleport.cluster.local"
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
signer jose.Signer
|
||||
claims claims
|
||||
|
||||
wantResult *IDTokenClaims
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "valid token",
|
||||
signer: signer,
|
||||
claims: claims{
|
||||
IDTokenClaims: IDTokenClaims{
|
||||
Repository: "123",
|
||||
},
|
||||
Subject: "foo",
|
||||
Claims: jwt.Claims{
|
||||
Audience: jwt.Audience{clusterName},
|
||||
IssuedAt: jwt.NewNumericDate(now.Add(-1 * time.Minute)),
|
||||
NotBefore: jwt.NewNumericDate(now.Add(-1 * time.Minute)),
|
||||
Expiry: jwt.NewNumericDate(now.Add(10 * time.Minute)),
|
||||
},
|
||||
},
|
||||
wantResult: &IDTokenClaims{
|
||||
Sub: "foo",
|
||||
Repository: "123",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "signed by wrong signer",
|
||||
signer: wrongSigner,
|
||||
claims: claims{
|
||||
IDTokenClaims: IDTokenClaims{
|
||||
Repository: "123",
|
||||
},
|
||||
Subject: "foo",
|
||||
Claims: jwt.Claims{
|
||||
Audience: jwt.Audience{clusterName},
|
||||
IssuedAt: jwt.NewNumericDate(now.Add(-1 * time.Minute)),
|
||||
NotBefore: jwt.NewNumericDate(now.Add(-1 * time.Minute)),
|
||||
Expiry: jwt.NewNumericDate(now.Add(10 * time.Minute)),
|
||||
},
|
||||
},
|
||||
wantResult: &IDTokenClaims{
|
||||
Sub: "foo",
|
||||
Repository: "123",
|
||||
},
|
||||
wantErr: "validating jwt signature",
|
||||
},
|
||||
{
|
||||
name: "expired",
|
||||
signer: signer,
|
||||
claims: claims{
|
||||
IDTokenClaims: IDTokenClaims{
|
||||
Repository: "123",
|
||||
},
|
||||
Subject: "foo",
|
||||
Claims: jwt.Claims{
|
||||
Audience: jwt.Audience{clusterName},
|
||||
IssuedAt: jwt.NewNumericDate(now.Add(-2 * time.Minute)),
|
||||
NotBefore: jwt.NewNumericDate(now.Add(-2 * time.Minute)),
|
||||
Expiry: jwt.NewNumericDate(now.Add(-1 * time.Minute)),
|
||||
},
|
||||
},
|
||||
wantErr: "token is expired",
|
||||
},
|
||||
{
|
||||
name: "not yet valid",
|
||||
signer: signer,
|
||||
claims: claims{
|
||||
IDTokenClaims: IDTokenClaims{
|
||||
Repository: "123",
|
||||
},
|
||||
Subject: "foo",
|
||||
Claims: jwt.Claims{
|
||||
Audience: jwt.Audience{clusterName},
|
||||
IssuedAt: jwt.NewNumericDate(now.Add(2 * time.Minute)),
|
||||
NotBefore: jwt.NewNumericDate(now.Add(2 * time.Minute)),
|
||||
Expiry: jwt.NewNumericDate(now.Add(4 * time.Minute)),
|
||||
},
|
||||
},
|
||||
wantErr: "token not valid yet",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
token, err := jwt.Signed(tt.signer).
|
||||
Claims(tt.claims).
|
||||
CompactSerialize()
|
||||
require.NoError(t, err)
|
||||
|
||||
result, err := ValidateTokenWithJWKS(now, jwks, token)
|
||||
if tt.wantErr != "" {
|
||||
require.ErrorContains(t, err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, tt.wantResult, result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user