mirror of
https://github.com/openziti/ziti.git
synced 2026-09-23 11:03:46 +00:00
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:
@@ -83,6 +83,8 @@ func MapExternalJwtSignerToRestModel(externalJwtSigner *model.ExternalJwtSigner)
|
||||
NotBefore: ¬Before,
|
||||
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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"
|
||||
},
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"`
|
||||
|
||||
|
||||
@@ -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"`
|
||||
|
||||
@@ -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'
|
||||
@@ -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: ¬EnabledJwtSignerCertPem,
|
||||
Enabled: ¬EnabledJwtSignerEnabled,
|
||||
Name: ¬EnabledJwtSignerName,
|
||||
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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user