Merge pull request #961 from openziti/add.ext.jwt.aud.iss.checks

adds optional issuer and audience properties to ext jwt signers
This commit is contained in:
Andrew
2022-04-12 08:54:53 -04:00
committed by GitHub
13 changed files with 422 additions and 43 deletions
@@ -83,6 +83,8 @@ func MapExternalJwtSignerToRestModel(externalJwtSigner *model.ExternalJwtSigner)
NotBefore: &notBefore,
UseExternalID: &externalJwtSigner.UseExternalId,
Kid: &externalJwtSigner.Kid,
Issuer: externalJwtSigner.Issuer,
Audience: externalJwtSigner.Audience,
}
return ret
}
@@ -97,6 +99,8 @@ func MapCreateExternalJwtSignerToModel(signer *rest_model.ExternalJWTSignerCreat
ClaimsProperty: signer.ClaimsProperty,
UseExternalId: BoolOrDefault(signer.UseExternalID),
Kid: *signer.Kid,
Issuer: signer.Issuer,
Audience: signer.Audience,
}
}
@@ -119,6 +123,8 @@ func MapUpdateExternalJwtSignerToModel(id string, signer *rest_model.ExternalJWT
ClaimsProperty: signer.ClaimsProperty,
ExternalAuthUrl: signer.ExternalAuthURL,
Kid: *signer.Kid,
Issuer: signer.Issuer,
Audience: signer.Audience,
}
}
@@ -141,5 +147,7 @@ func MapPatchExternalJwtSignerToModel(id string, signer *rest_model.ExternalJWTS
UseExternalId: BoolOrDefault(signer.UseExternalID),
ClaimsProperty: signer.ClaimsProperty,
Kid: stringz.OrEmpty(signer.Kid),
Issuer: signer.Issuer,
Audience: signer.Audience,
}
}
+63 -12
View File
@@ -21,8 +21,8 @@ import (
"github.com/michaelquigley/pfxlog"
"github.com/openziti/edge/controller/apierror"
"github.com/openziti/edge/controller/persistence"
"github.com/openziti/storage/boltz"
nfPem "github.com/openziti/foundation/util/pem"
"github.com/openziti/storage/boltz"
cmap "github.com/orcaman/concurrent-map"
"go.etcd.io/bbolt"
"strings"
@@ -136,12 +136,11 @@ func (a *AuthModuleExtJwt) process(context AuthContext, isPrimary bool) (identit
jwtStr := strings.Replace(authHeader, "Bearer ", "", 1)
//pubKeyLookup also handles extJwtSigner.enabled checking
jwtToken, err := jwt.Parse(jwtStr, a.pubKeyLookup)
if err == nil && jwtToken.Valid {
claimsProperty := "sub"
mapClaims := jwtToken.Claims.(jwt.MapClaims)
extJwt := mapClaims[ExtJwtInternalClaim].(*persistence.ExternalJwtSigner)
if extJwt == nil {
@@ -151,13 +150,65 @@ func (a *AuthModuleExtJwt) process(context AuthContext, isPrimary bool) (identit
logger = logger.WithField("externalJwtSignerId", extJwt.Id)
if extJwt.ClaimsProperty != nil {
claimsProperty = *extJwt.ClaimsProperty
issuer := ""
if issuerVal, ok := mapClaims["iss"]; ok {
issuer, ok = issuerVal.(string)
if !ok {
logger.Error("issuer in claims was not a string")
return "", "", "", apierror.NewInvalidAuth()
}
}
logger = logger.WithField("claimsProperty", claimsProperty)
logger = logger.WithField("claimsIssuer", issuer)
identityIdInterface, ok := mapClaims[claimsProperty]
if extJwt.Issuer != nil && *extJwt.Issuer != issuer {
logger.WithField("expectedIssuer", *extJwt.Issuer).Error("invalid issuer")
return "", "", "", apierror.NewInvalidAuth()
}
if extJwt.Audience != nil {
audValues := mapClaims["aud"]
if audValues == nil {
logger.WithField("audience", audValues).Error("audience is missing")
return "", "", "", apierror.NewInvalidAuth()
}
audSlice, ok := audValues.([]string)
if !ok {
audString, ok := audValues.(string)
if !ok {
logger.WithField("audience", audValues).Error("audience is not a string or array of strings")
return "", "", "", apierror.NewInvalidAuth()
}
audSlice = []string{audString}
}
found := false
for _, validAud := range audSlice {
if validAud == *extJwt.Audience {
found = true
break
}
}
if !found {
logger.WithField("expectedAudience", *extJwt.Audience).WithField("claimsAudiences", audSlice).Error("invalid audience")
return "", "", "", apierror.NewInvalidAuth()
}
}
idClaimProperty := "sub"
if extJwt.ClaimsProperty != nil {
idClaimProperty = *extJwt.ClaimsProperty
}
logger = logger.WithField("idClaimProperty", idClaimProperty)
identityIdInterface, ok := mapClaims[idClaimProperty]
if !ok {
logger.Error("claims property on external jwt signer not found in claims")
@@ -189,7 +240,7 @@ func (a *AuthModuleExtJwt) process(context AuthContext, isPrimary bool) (identit
logger.WithError(err).Error("encountered unhandled nil auth policy during authentication")
return "", "", "", apierror.NewInvalidAuth()
}
externaJwtSignerId := ""
externalJwtSignerId := ""
if identity.Disabled {
logger.
WithField("disabledAt", identity.DisabledAt).
@@ -208,7 +259,7 @@ func (a *AuthModuleExtJwt) process(context AuthContext, isPrimary bool) (identit
found := false
for _, allowedId := range authPolicy.Primary.ExtJwt.AllowedExtJwtSigners {
if allowedId == extJwt.Id {
externaJwtSignerId = allowedId
externalJwtSignerId = allowedId
found = true
break
}
@@ -226,13 +277,13 @@ func (a *AuthModuleExtJwt) process(context AuthContext, isPrimary bool) (identit
return "", "", "", apierror.NewInvalidAuth()
}
externaJwtSignerId = extJwt.Id
externalJwtSignerId = extJwt.Id
}
if extJwt.UseExternalId {
return "", identityId, externaJwtSignerId, nil
return "", identityId, externalJwtSignerId, nil
}
return identityId, "", externaJwtSignerId, nil
return identityId, "", externalJwtSignerId, nil
}
logger.Error("authorization failed, jwt did not verify")
+10 -2
View File
@@ -20,8 +20,8 @@ import (
"github.com/openziti/edge/controller/apierror"
"github.com/openziti/edge/controller/persistence"
"github.com/openziti/fabric/controller/models"
"github.com/openziti/storage/boltz"
nfpem "github.com/openziti/foundation/util/pem"
"github.com/openziti/storage/boltz"
"github.com/pkg/errors"
"go.etcd.io/bbolt"
"reflect"
@@ -32,16 +32,18 @@ type ExternalJwtSigner struct {
models.BaseEntity
Name string
CertPem string
Kid string
Enabled bool
ExternalAuthUrl *string
UseExternalId bool
ClaimsProperty *string
Issuer *string
Audience *string
CommonName string
Fingerprint string
NotAfter time.Time
NotBefore time.Time
Kid string
}
func (entity *ExternalJwtSigner) toBoltEntity() (boltz.Entity, error) {
@@ -68,6 +70,8 @@ func (entity *ExternalJwtSigner) toBoltEntity() (boltz.Entity, error) {
UseExternalId: entity.UseExternalId,
ClaimsProperty: entity.ClaimsProperty,
Kid: entity.Kid,
Issuer: entity.Issuer,
Audience: entity.Audience,
}
return signer, nil
@@ -91,6 +95,8 @@ func (entity *ExternalJwtSigner) toBoltEntityForPatch(*bbolt.Tx, Handler, boltz.
UseExternalId: entity.UseExternalId,
ClaimsProperty: entity.ClaimsProperty,
Kid: entity.Kid,
Issuer: entity.Issuer,
Audience: entity.Issuer,
}
if entity.CertPem != "" {
@@ -129,5 +135,7 @@ func (entity *ExternalJwtSigner) fillFrom(_ Handler, _ *bbolt.Tx, boltEntity bol
entity.ClaimsProperty = boltExternalJwtSigner.ClaimsProperty
entity.UseExternalId = boltExternalJwtSigner.UseExternalId
entity.Kid = boltExternalJwtSigner.Kid
entity.Issuer = boltExternalJwtSigner.Issuer
entity.Audience = boltExternalJwtSigner.Audience
return nil
}
@@ -21,6 +21,7 @@ import (
"github.com/openziti/storage/ast"
"github.com/openziti/storage/boltz"
"go.etcd.io/bbolt"
"strings"
"time"
)
@@ -36,6 +37,8 @@ const (
FieldExternalJwtSignerClaimsProperty = "claimsProperty"
FieldExternalJwtSignerUseExternalId = "useExternalId"
FieldExternalJwtSignerKid = "kid"
FieldExternalJwtSignerIssuer = "issuer"
FieldExternalJwtSignerAudience = "audience"
DefaultClaimsProperty = "sub"
)
@@ -53,6 +56,8 @@ type ExternalJwtSigner struct {
ExternalAuthUrl *string
ClaimsProperty *string
UseExternalId bool
Issuer *string
Audience *string
}
func (entity *ExternalJwtSigner) GetName() string {
@@ -72,6 +77,8 @@ func (entity *ExternalJwtSigner) LoadValues(_ boltz.CrudStore, bucket *boltz.Typ
entity.ExternalAuthUrl = bucket.GetString(FieldExternalJwtSignerExternalAuthUrl)
entity.ClaimsProperty = bucket.GetString(FieldExternalJwtSignerClaimsProperty)
entity.UseExternalId = bucket.GetBoolWithDefault(FieldExternalJwtSignerUseExternalId, false)
entity.Issuer = bucket.GetString(FieldExternalJwtSignerIssuer)
entity.Audience = bucket.GetString(FieldExternalJwtSignerAudience)
}
func (entity *ExternalJwtSigner) SetValues(ctx *boltz.PersistContext) {
@@ -84,15 +91,28 @@ func (entity *ExternalJwtSigner) SetValues(ctx *boltz.PersistContext) {
ctx.SetTimeP(FieldExternalJwtSignerNotAfter, entity.NotAfter)
ctx.SetTimeP(FieldExternalJwtSignerNotBefore, entity.NotBefore)
ctx.SetBool(FieldExternalJwtSignerEnabled, entity.Enabled)
ctx.SetStringP(FieldExternalJwtSignerExternalAuthUrl, entity.ExternalAuthUrl)
ctx.SetBool(FieldExternalJwtSignerUseExternalId, entity.UseExternalId)
if entity.ClaimsProperty == nil || *entity.ClaimsProperty == "" {
if entity.ExternalAuthUrl != nil && strings.TrimSpace(*entity.ExternalAuthUrl) == "" {
entity.ExternalAuthUrl = nil
}
ctx.SetStringP(FieldExternalJwtSignerExternalAuthUrl, entity.ExternalAuthUrl)
if entity.Issuer != nil && strings.TrimSpace(*entity.Issuer) == "" {
entity.Issuer = nil
}
ctx.SetStringP(FieldExternalJwtSignerIssuer, entity.Issuer)
if entity.Audience != nil && strings.TrimSpace(*entity.Audience) == "" {
entity.Audience = nil
}
ctx.SetStringP(FieldExternalJwtSignerAudience, entity.Audience)
if entity.ClaimsProperty == nil || strings.TrimSpace(*entity.ClaimsProperty) == "" {
ctx.SetString(FieldExternalJwtSignerClaimsProperty, DefaultClaimsProperty)
} else {
ctx.SetStringP(FieldExternalJwtSignerClaimsProperty, entity.ClaimsProperty)
}
}
func (entity *ExternalJwtSigner) GetEntityType() string {
+66 -2
View File
@@ -19046,6 +19046,10 @@ func init() {
"kid"
],
"properties": {
"audience": {
"type": "string",
"x-nullable": true
},
"certPem": {
"type": "string"
},
@@ -19061,6 +19065,10 @@ func init() {
"format": "url",
"x-nullable": true
},
"issuer": {
"type": "string",
"x-nullable": true
},
"kid": {
"type": "string"
},
@@ -19097,9 +19105,14 @@ func init() {
"externalAuthUrl",
"claimsProperty",
"useExternalId",
"kid"
"kid",
"issuer",
"audience"
],
"properties": {
"audience": {
"type": "string"
},
"certPem": {
"type": "string"
},
@@ -19119,6 +19132,9 @@ func init() {
"fingerprint": {
"type": "string"
},
"issuer": {
"type": "string"
},
"kid": {
"type": "string"
},
@@ -19151,6 +19167,10 @@ func init() {
"externalJwtSignerPatch": {
"type": "object",
"properties": {
"audience": {
"type": "string",
"x-nullable": true
},
"certPem": {
"type": "string",
"x-nullable": true
@@ -19168,6 +19188,10 @@ func init() {
"format": "url",
"x-nullable": true
},
"issuer": {
"type": "string",
"x-nullable": true
},
"kid": {
"type": "string",
"x-nullable": true
@@ -19195,6 +19219,10 @@ func init() {
"kid"
],
"properties": {
"audience": {
"type": "string",
"x-nullable": true
},
"certPem": {
"type": "string"
},
@@ -19210,6 +19238,10 @@ func init() {
"format": "url",
"x-nullable": true
},
"issuer": {
"type": "string",
"x-nullable": true
},
"kid": {
"type": "string"
},
@@ -41860,6 +41892,10 @@ func init() {
"kid"
],
"properties": {
"audience": {
"type": "string",
"x-nullable": true
},
"certPem": {
"type": "string"
},
@@ -41875,6 +41911,10 @@ func init() {
"format": "url",
"x-nullable": true
},
"issuer": {
"type": "string",
"x-nullable": true
},
"kid": {
"type": "string"
},
@@ -41911,9 +41951,14 @@ func init() {
"externalAuthUrl",
"claimsProperty",
"useExternalId",
"kid"
"kid",
"issuer",
"audience"
],
"properties": {
"audience": {
"type": "string"
},
"certPem": {
"type": "string"
},
@@ -41933,6 +41978,9 @@ func init() {
"fingerprint": {
"type": "string"
},
"issuer": {
"type": "string"
},
"kid": {
"type": "string"
},
@@ -41965,6 +42013,10 @@ func init() {
"externalJwtSignerPatch": {
"type": "object",
"properties": {
"audience": {
"type": "string",
"x-nullable": true
},
"certPem": {
"type": "string",
"x-nullable": true
@@ -41982,6 +42034,10 @@ func init() {
"format": "url",
"x-nullable": true
},
"issuer": {
"type": "string",
"x-nullable": true
},
"kid": {
"type": "string",
"x-nullable": true
@@ -42009,6 +42065,10 @@ func init() {
"kid"
],
"properties": {
"audience": {
"type": "string",
"x-nullable": true
},
"certPem": {
"type": "string"
},
@@ -42024,6 +42084,10 @@ func init() {
"format": "url",
"x-nullable": true
},
"issuer": {
"type": "string",
"x-nullable": true
},
"kid": {
"type": "string"
},
+6
View File
@@ -43,6 +43,9 @@ import (
// swagger:model externalJwtSignerCreate
type ExternalJWTSignerCreate struct {
// audience
Audience *string `json:"audience,omitempty"`
// cert pem
// Required: true
CertPem *string `json:"certPem"`
@@ -57,6 +60,9 @@ type ExternalJWTSignerCreate struct {
// external auth Url
ExternalAuthURL *string `json:"externalAuthUrl,omitempty"`
// issuer
Issuer *string `json:"issuer,omitempty"`
// kid
// Required: true
Kid *string `json:"kid"`
+50
View File
@@ -44,6 +44,10 @@ import (
type ExternalJWTSignerDetail struct {
BaseEntity
// audience
// Required: true
Audience *string `json:"audience"`
// cert pem
// Required: true
CertPem *string `json:"certPem"`
@@ -68,6 +72,10 @@ type ExternalJWTSignerDetail struct {
// Required: true
Fingerprint *string `json:"fingerprint"`
// issuer
// Required: true
Issuer *string `json:"issuer"`
// kid
// Required: true
Kid *string `json:"kid"`
@@ -103,6 +111,8 @@ func (m *ExternalJWTSignerDetail) UnmarshalJSON(raw []byte) error {
// AO1
var dataAO1 struct {
Audience *string `json:"audience"`
CertPem *string `json:"certPem"`
ClaimsProperty *string `json:"claimsProperty"`
@@ -115,6 +125,8 @@ func (m *ExternalJWTSignerDetail) UnmarshalJSON(raw []byte) error {
Fingerprint *string `json:"fingerprint"`
Issuer *string `json:"issuer"`
Kid *string `json:"kid"`
Name *string `json:"name"`
@@ -129,6 +141,8 @@ func (m *ExternalJWTSignerDetail) UnmarshalJSON(raw []byte) error {
return err
}
m.Audience = dataAO1.Audience
m.CertPem = dataAO1.CertPem
m.ClaimsProperty = dataAO1.ClaimsProperty
@@ -141,6 +155,8 @@ func (m *ExternalJWTSignerDetail) UnmarshalJSON(raw []byte) error {
m.Fingerprint = dataAO1.Fingerprint
m.Issuer = dataAO1.Issuer
m.Kid = dataAO1.Kid
m.Name = dataAO1.Name
@@ -164,6 +180,8 @@ func (m ExternalJWTSignerDetail) MarshalJSON() ([]byte, error) {
}
_parts = append(_parts, aO0)
var dataAO1 struct {
Audience *string `json:"audience"`
CertPem *string `json:"certPem"`
ClaimsProperty *string `json:"claimsProperty"`
@@ -176,6 +194,8 @@ func (m ExternalJWTSignerDetail) MarshalJSON() ([]byte, error) {
Fingerprint *string `json:"fingerprint"`
Issuer *string `json:"issuer"`
Kid *string `json:"kid"`
Name *string `json:"name"`
@@ -187,6 +207,8 @@ func (m ExternalJWTSignerDetail) MarshalJSON() ([]byte, error) {
UseExternalID *bool `json:"useExternalId"`
}
dataAO1.Audience = m.Audience
dataAO1.CertPem = m.CertPem
dataAO1.ClaimsProperty = m.ClaimsProperty
@@ -199,6 +221,8 @@ func (m ExternalJWTSignerDetail) MarshalJSON() ([]byte, error) {
dataAO1.Fingerprint = m.Fingerprint
dataAO1.Issuer = m.Issuer
dataAO1.Kid = m.Kid
dataAO1.Name = m.Name
@@ -226,6 +250,10 @@ func (m *ExternalJWTSignerDetail) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateAudience(formats); err != nil {
res = append(res, err)
}
if err := m.validateCertPem(formats); err != nil {
res = append(res, err)
}
@@ -250,6 +278,10 @@ func (m *ExternalJWTSignerDetail) Validate(formats strfmt.Registry) error {
res = append(res, err)
}
if err := m.validateIssuer(formats); err != nil {
res = append(res, err)
}
if err := m.validateKid(formats); err != nil {
res = append(res, err)
}
@@ -276,6 +308,15 @@ func (m *ExternalJWTSignerDetail) Validate(formats strfmt.Registry) error {
return nil
}
func (m *ExternalJWTSignerDetail) validateAudience(formats strfmt.Registry) error {
if err := validate.Required("audience", "body", m.Audience); err != nil {
return err
}
return nil
}
func (m *ExternalJWTSignerDetail) validateCertPem(formats strfmt.Registry) error {
if err := validate.Required("certPem", "body", m.CertPem); err != nil {
@@ -330,6 +371,15 @@ func (m *ExternalJWTSignerDetail) validateFingerprint(formats strfmt.Registry) e
return nil
}
func (m *ExternalJWTSignerDetail) validateIssuer(formats strfmt.Registry) error {
if err := validate.Required("issuer", "body", m.Issuer); err != nil {
return err
}
return nil
}
func (m *ExternalJWTSignerDetail) validateKid(formats strfmt.Registry) error {
if err := validate.Required("kid", "body", m.Kid); err != nil {
+6
View File
@@ -42,6 +42,9 @@ import (
// swagger:model externalJwtSignerPatch
type ExternalJWTSignerPatch struct {
// audience
Audience *string `json:"audience,omitempty"`
// cert pem
CertPem *string `json:"certPem,omitempty"`
@@ -54,6 +57,9 @@ type ExternalJWTSignerPatch struct {
// external auth Url
ExternalAuthURL *string `json:"externalAuthUrl,omitempty"`
// issuer
Issuer *string `json:"issuer,omitempty"`
// kid
Kid *string `json:"kid,omitempty"`
+6
View File
@@ -43,6 +43,9 @@ import (
// swagger:model externalJwtSignerUpdate
type ExternalJWTSignerUpdate struct {
// audience
Audience *string `json:"audience,omitempty"`
// cert pem
// Required: true
CertPem *string `json:"certPem"`
@@ -57,6 +60,9 @@ type ExternalJWTSignerUpdate struct {
// external auth Url
ExternalAuthURL *string `json:"externalAuthUrl,omitempty"`
// issuer
Issuer *string `json:"issuer,omitempty"`
// kid
// Required: true
Kid *string `json:"kid"`
+24
View File
@@ -13735,6 +13735,9 @@ definitions:
- enabled
- kid
properties:
audience:
type: string
x-nullable: true
certPem:
type: string
claimsProperty:
@@ -13746,6 +13749,9 @@ definitions:
type: string
format: url
x-nullable: true
issuer:
type: string
x-nullable: true
kid:
type: string
name:
@@ -13774,7 +13780,11 @@ definitions:
- claimsProperty
- useExternalId
- kid
- issuer
- audience
properties:
audience:
type: string
certPem:
type: string
claimsProperty:
@@ -13788,6 +13798,8 @@ definitions:
format: url
fingerprint:
type: string
issuer:
type: string
kid:
type: string
name:
@@ -13809,6 +13821,9 @@ definitions:
externalJwtSignerPatch:
type: object
properties:
audience:
type: string
x-nullable: true
certPem:
type: string
x-nullable: true
@@ -13822,6 +13837,9 @@ definitions:
type: string
format: url
x-nullable: true
issuer:
type: string
x-nullable: true
kid:
type: string
x-nullable: true
@@ -13842,6 +13860,9 @@ definitions:
- enabled
- kid
properties:
audience:
type: string
x-nullable: true
certPem:
type: string
claimsProperty:
@@ -13853,6 +13874,9 @@ definitions:
type: string
format: url
x-nullable: true
issuer:
type: string
x-nullable: true
kid:
type: string
name:
@@ -178,6 +178,8 @@ definitions:
- claimsProperty
- useExternalId
- kid
- issuer
- audience
properties:
name:
type: string
@@ -205,6 +207,10 @@ definitions:
type: boolean
kid:
type: string
issuer:
type: string
audience:
type: string
externalJwtSignerCreate:
description: A create Certificate Authority (CA) object
type: object
@@ -233,6 +239,12 @@ definitions:
useExternalId:
type: boolean
x-nullable: true
issuer:
type: string
x-nullable: true
audience:
type: string
x-nullable: true
tags:
$ref: '../shared/base-entity.yml#/definitions/tags'
externalJwtSignerUpdate:
@@ -262,6 +274,12 @@ definitions:
useExternalId:
type: boolean
x-nullable: true
issuer:
type: string
x-nullable: true
audience:
type: string
x-nullable: true
tags:
$ref: '../shared/base-entity.yml#/definitions/tags'
externalJwtSignerPatch:
@@ -290,5 +308,11 @@ definitions:
useExternalId:
type: boolean
x-nullable: true
issuer:
type: string
x-nullable: true
audience:
type: string
x-nullable: true
tags:
$ref: '../shared/base-entity.yml#/definitions/tags'
+116 -16
View File
@@ -36,17 +36,18 @@ func Test_Authenticate_External_Jwt(t *testing.T) {
ctx.RequireAdminManagementApiLogin()
// create a bunch of signers to use
validJwtSignerCommonName := "valid signer"
validJwtSignerCert, validJwtSignerPrivateKey := newSelfSignedCert(validJwtSignerCommonName)
//valid signer with issuer and audience
validJwtSignerCert, validJwtSignerPrivateKey := newSelfSignedCert("valid signer")
validJwtSignerCertPem := nfpem.EncodeToString(validJwtSignerCert)
validJwtSignerName := "Test JWT Signer - Enabled"
validJwtSignerEnabled := true
validJwtSigner := &rest_model.ExternalJWTSignerCreate{
CertPem: &validJwtSignerCertPem,
Enabled: &validJwtSignerEnabled,
Name: &validJwtSignerName,
Kid: S(uuid.NewString()),
CertPem: &validJwtSignerCertPem,
Enabled: B(true),
Name: S("Test JWT Signer - Enabled"),
Kid: S(uuid.NewString()),
Issuer: S("the-very-best-iss"),
Audience: S("the-very-best-aud"),
}
createResponseEnv := &rest_model.CreateEnvelope{}
@@ -55,16 +56,30 @@ func Test_Authenticate_External_Jwt(t *testing.T) {
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
notEnabledJwtSignerCommonName := "not enabled signer"
notEnabledJwtSignerCert, notEnabledJwtSignerPrivateKey := newSelfSignedCert(notEnabledJwtSignerCommonName)
//valid signer no issuer no audienceS
validJwtSignerNoIssNoAudCert, validJwtSignerNoIssNoAudPrivateKey := newSelfSignedCert("valid signer")
validJwtSignerCertPemNoIssNoAud := nfpem.EncodeToString(validJwtSignerNoIssNoAudCert)
validJwtSignerNoIssNoAud := &rest_model.ExternalJWTSignerCreate{
CertPem: &validJwtSignerCertPemNoIssNoAud,
Enabled: B(true),
Name: S("Test JWT Signer - Enabled No Iss No Aud"),
Kid: S(uuid.NewString()),
}
resp, err = ctx.AdminManagementSession.newAuthenticatedRequest().SetBody(validJwtSignerNoIssNoAud).SetResult(createResponseEnv).Post("/external-jwt-signers")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
createResponseEnv = &rest_model.CreateEnvelope{}
notEnabledJwtSignerCert, notEnabledJwtSignerPrivateKey := newSelfSignedCert("not enabled signer")
notEnabledJwtSignerCertPem := nfpem.EncodeToString(notEnabledJwtSignerCert)
notEnabledJwtSignerName := "Test JWT Signer - Not Enabled"
notEnabledJwtSignerEnabled := false
notEnabledJwtSigner := &rest_model.ExternalJWTSignerCreate{
CertPem: &notEnabledJwtSignerCertPem,
Enabled: &notEnabledJwtSignerEnabled,
Name: &notEnabledJwtSignerName,
Enabled: B(false),
Name: S("Test JWT Signer - Not Enabled"),
Kid: S(uuid.NewString()),
}
@@ -81,11 +96,11 @@ func Test_Authenticate_External_Jwt(t *testing.T) {
jwtToken := jwt.New(jwt.SigningMethodES256)
jwtToken.Claims = jwt.StandardClaims{
Audience: "ziti.controller",
Audience: *validJwtSigner.Audience,
ExpiresAt: time.Now().Add(2 * time.Hour).Unix(),
Id: time.Now().String(),
IssuedAt: time.Now().Unix(),
Issuer: "fake.issuer",
Issuer: *validJwtSigner.Issuer,
NotBefore: time.Now().Unix(),
Subject: ctx.AdminManagementSession.identityId,
}
@@ -107,6 +122,37 @@ func Test_Authenticate_External_Jwt(t *testing.T) {
ctx.Req.NotNil(result.Data.Token)
})
t.Run("authenticating with a valid jwt succeeds and no iss no aud succeeds", func(t *testing.T) {
ctx.testContextChanged(t)
jwtToken := jwt.New(jwt.SigningMethodES256)
jwtToken.Claims = jwt.StandardClaims{
Audience: "i do not matter",
ExpiresAt: time.Now().Add(2 * time.Hour).Unix(),
Id: time.Now().String(),
IssuedAt: time.Now().Unix(),
Issuer: "i do not matter",
NotBefore: time.Now().Unix(),
Subject: ctx.AdminManagementSession.identityId,
}
jwtToken.Header["kid"] = *validJwtSignerNoIssNoAud.Kid
jwtStrSigned, err := jwtToken.SignedString(validJwtSignerNoIssNoAudPrivateKey)
ctx.Req.NoError(err)
ctx.Req.NotEmpty(jwtStrSigned)
result := &rest_model.CurrentAPISessionDetailEnvelope{}
resp, err := ctx.newAnonymousClientApiRequest().SetResult(result).SetHeader("Authorization", "Bearer "+jwtStrSigned).Post("/authenticate?method=ext-jwt")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusOK, resp.StatusCode())
ctx.Req.NotNil(result)
ctx.Req.NotNil(result.Data)
ctx.Req.NotNil(result.Data.Token)
})
t.Run("authenticating with a valid jwt but disabled signer fails", func(t *testing.T) {
ctx.testContextChanged(t)
@@ -134,6 +180,60 @@ func Test_Authenticate_External_Jwt(t *testing.T) {
ctx.Req.Equal(http.StatusUnauthorized, resp.StatusCode())
})
t.Run("authenticating with an invalid issuer jwt fails", func(t *testing.T) {
ctx.testContextChanged(t)
jwtToken := jwt.New(jwt.SigningMethodES256)
jwtToken.Claims = jwt.StandardClaims{
Audience: *validJwtSigner.Audience,
ExpiresAt: time.Now().Add(2 * time.Hour).Unix(),
Id: time.Now().String(),
IssuedAt: time.Now().Unix(),
Issuer: "i will cause this to fail",
NotBefore: time.Now().Unix(),
Subject: ctx.AdminManagementSession.identityId,
}
jwtToken.Header["kid"] = *validJwtSigner.Kid
jwtStrSigned, err := jwtToken.SignedString(validJwtSignerPrivateKey)
ctx.Req.NoError(err)
ctx.Req.NotEmpty(jwtStrSigned)
result := &rest_model.CurrentAPISessionDetailEnvelope{}
resp, err := ctx.newAnonymousClientApiRequest().SetResult(result).SetHeader("Authorization", "Bearer "+jwtStrSigned).Post("/authenticate?method=ext-jwt")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusUnauthorized, resp.StatusCode())
})
t.Run("authenticating with an invalid audience jwt fails", func(t *testing.T) {
ctx.testContextChanged(t)
jwtToken := jwt.New(jwt.SigningMethodES256)
jwtToken.Claims = jwt.StandardClaims{
Audience: "this test shall not succeed",
ExpiresAt: time.Now().Add(2 * time.Hour).Unix(),
Id: time.Now().String(),
IssuedAt: time.Now().Unix(),
Issuer: *validJwtSigner.Issuer,
NotBefore: time.Now().Unix(),
Subject: ctx.AdminManagementSession.identityId,
}
jwtToken.Header["kid"] = *validJwtSigner.Kid
jwtStrSigned, err := jwtToken.SignedString(validJwtSignerPrivateKey)
ctx.Req.NoError(err)
ctx.Req.NotEmpty(jwtStrSigned)
result := &rest_model.CurrentAPISessionDetailEnvelope{}
resp, err := ctx.newAnonymousClientApiRequest().SetResult(result).SetHeader("Authorization", "Bearer "+jwtStrSigned).Post("/authenticate?method=ext-jwt")
ctx.Req.NoError(err)
ctx.Req.Equal(http.StatusUnauthorized, resp.StatusCode())
})
t.Run("authenticating with a valid jwt but no kid fails", func(t *testing.T) {
ctx.testContextChanged(t)
+20 -8
View File
@@ -60,6 +60,8 @@ func Test_ExternalJWTSigner(t *testing.T) {
Tags: nil,
UseExternalID: B(true),
Kid: S(uuid.New().String()),
Issuer: S("i-am-the-issuer"),
Audience: S("you-are-the-audience"),
}
createResponseEnv := &rest_model.CreateEnvelope{}
@@ -95,6 +97,8 @@ func Test_ExternalJWTSigner(t *testing.T) {
ctx.Req.Equal(*jwtSigner.ClaimsProperty, *jwtSignerDetail.ClaimsProperty)
ctx.Req.Equal(*jwtSigner.ExternalAuthURL, *jwtSignerDetail.ExternalAuthURL)
ctx.Req.Equal(*jwtSigner.Kid, *jwtSignerDetail.Kid)
ctx.Req.Equal(*jwtSigner.Issuer, *jwtSignerDetail.Issuer)
ctx.Req.Equal(*jwtSigner.Audience, *jwtSignerDetail.Audience)
})
})
@@ -200,6 +204,8 @@ func Test_ExternalJWTSigner(t *testing.T) {
ctx.Req.False(*jwtSignerDetail.UseExternalID)
ctx.Req.Equal(persistence.DefaultClaimsProperty, *jwtSignerDetail.ClaimsProperty)
ctx.Req.Nil(jwtSignerDetail.ExternalAuthURL)
ctx.Req.Nil(jwtSignerDetail.Issuer)
ctx.Req.Nil(jwtSignerDetail.Audience)
})
})
})
@@ -377,10 +383,12 @@ func Test_ExternalJWTSigner(t *testing.T) {
jwtSignerEnabledUpdated := true
jwtSigner := &rest_model.ExternalJWTSignerCreate{
CertPem: &jwtSignerCertPem,
Enabled: &jwtSignerEnabled,
Name: &jwtSignerName,
Kid: S(uuid.New().String()),
CertPem: &jwtSignerCertPem,
Enabled: &jwtSignerEnabled,
Name: &jwtSignerName,
Kid: S(uuid.New().String()),
Issuer: S("origIssues"),
Audience: S("origAudience"),
}
createResponseEnv := &rest_model.CreateEnvelope{}
@@ -390,10 +398,12 @@ func Test_ExternalJWTSigner(t *testing.T) {
ctx.Req.Equal(http.StatusCreated, resp.StatusCode())
jwtSignerUpdate := &rest_model.ExternalJWTSignerUpdate{
CertPem: &jwtSignerCertPemUpdated,
Enabled: &jwtSignerEnabledUpdated,
Name: &jwtSignerNameUpdated,
Kid: S(uuid.New().String()),
CertPem: &jwtSignerCertPemUpdated,
Enabled: &jwtSignerEnabledUpdated,
Name: &jwtSignerNameUpdated,
Kid: S(uuid.New().String()),
Issuer: S(""),
Audience: S(""),
}
resp, err = ctx.AdminManagementSession.newAuthenticatedRequest().SetBody(jwtSignerUpdate).SetResult(createResponseEnv).Put("/external-jwt-signers/" + createResponseEnv.Data.ID)
@@ -424,6 +434,8 @@ func Test_ExternalJWTSigner(t *testing.T) {
ctx.Req.Equal(jwtSignerCertUpdated.NotAfter, time.Time(*jwtSignerDetail.NotAfter))
ctx.Req.Equal(fingerprint, *jwtSignerDetail.Fingerprint)
ctx.Req.Equal(*jwtSignerUpdate.Kid, *jwtSignerDetail.Kid)
ctx.Req.Nil(jwtSignerDetail.Issuer)
ctx.Req.Nil(jwtSignerDetail.Audience)
})
})
})