diff --git a/go.mod b/go.mod index b78507934..fe15c4632 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/google/uuid v1.3.0 github.com/gorhill/cronexpr v0.0.0-20180427100037-88b0669f7d75 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 - github.com/lestrrat-go/jwx v1.2.26 + github.com/lestrrat-go/jwx/v2 v2.0.12 github.com/opentracing/opentracing-go v1.2.0 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 github.com/sirupsen/logrus v1.9.3 @@ -27,7 +27,7 @@ require ( github.com/tidwall/gjson v1.14.0 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 golang.org/x/net v0.10.0 - golang.org/x/text v0.9.0 + golang.org/x/text v0.12.0 google.golang.org/grpc v1.48.0 google.golang.org/protobuf v1.28.0 gopkg.in/h2non/gock.v1 v1.1.2 @@ -50,7 +50,6 @@ require ( github.com/go-openapi/swag v0.19.5 // indirect github.com/goccy/go-json v0.10.2 // indirect github.com/gofrs/uuid v4.2.0+incompatible // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -59,9 +58,9 @@ require ( github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/jcchavezs/porto v0.4.0 // indirect github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect - github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect github.com/lestrrat-go/blackmagic v1.0.1 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/httprc v1.0.4 // indirect github.com/lestrrat-go/iter v1.0.2 // indirect github.com/lestrrat-go/option v1.0.1 // indirect github.com/magefile/mage v1.13.0 // indirect @@ -77,6 +76,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/procfs v0.7.3 // indirect github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect + github.com/segmentio/asm v1.2.0 // indirect github.com/spf13/afero v1.8.2 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect @@ -88,10 +88,10 @@ require ( go.uber.org/atomic v1.9.0 // indirect go.uber.org/multierr v1.8.0 // indirect go.uber.org/zap v1.21.0 // indirect - golang.org/x/crypto v0.9.0 // indirect + golang.org/x/crypto v0.12.0 // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/mod v0.8.0 // indirect - golang.org/x/sys v0.9.0 // indirect + golang.org/x/sys v0.11.0 // indirect golang.org/x/tools v0.6.0 // indirect google.golang.org/genproto v0.0.0-20220714211235-042d03aeabc9 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect diff --git a/go.sum b/go.sum index 0afa77e70..66f185968 100644 --- a/go.sum +++ b/go.sum @@ -138,8 +138,6 @@ github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -253,16 +251,16 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= -github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/httprc v1.0.4 h1:bAZymwoZQb+Oq8MEbyipag7iSq6YIga8Wj6GOiJGdI8= +github.com/lestrrat-go/httprc v1.0.4/go.mod h1:mwwz3JMTPBjHUkkDv/IGJ39aALInZLrhBp0X7KGUZlo= github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= -github.com/lestrrat-go/jwx v1.2.26 h1:4iFo8FPRZGDYe1t19mQP0zTRqA7n8HnJ5lkIiDvJcB0= -github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDuIkx8ftpQ= +github.com/lestrrat-go/jwx/v2 v2.0.12 h1:3d589+5w/b9b7S3DneICPW16AqTyYXB7VRjgluSDWeA= +github.com/lestrrat-go/jwx/v2 v2.0.12/go.mod h1:Mq4KN1mM7bp+5z/W5HS8aCNs5RKZ911G/0y2qUjAQuQ= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= @@ -330,11 +328,9 @@ github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBO github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= +github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= +github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.3 h1:DBBfY8eMYazKEJHb3JKpSPfpgd2mBCoNFlQx6C5fftU= -github.com/sirupsen/logrus v1.8.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/snowzach/rotatefilehook v0.0.0-20220211133110-53752135082d h1:4660u5vJtsyrn3QwJNfESwCws+TM1CMhRn123xjVyQ8= @@ -419,8 +415,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -542,7 +538,6 @@ golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -584,14 +579,14 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -601,8 +596,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/agent/handler/credential.go b/pkg/agent/handler/credential.go index 96eb870b9..f8eeeccc5 100644 --- a/pkg/agent/handler/credential.go +++ b/pkg/agent/handler/credential.go @@ -13,6 +13,7 @@ import ( defs "github.com/Axway/agent-sdk/pkg/apic/definitions" prov "github.com/Axway/agent-sdk/pkg/apic/provisioning" "github.com/Axway/agent-sdk/pkg/authz/oauth" + "github.com/Axway/agent-sdk/pkg/config" "github.com/Axway/agent-sdk/pkg/util" "github.com/Axway/agent-sdk/pkg/util/log" "github.com/Axway/agent-sdk/pkg/watchmanager/proto" @@ -445,24 +446,39 @@ func (h *credentials) getCRD(ctx context.Context, cred *management.Credential) ( return crd, err } +func formattedJWKS(jwks string) string { + formattedJWKS := strings.ReplaceAll(jwks, "----- ", "-----\n") + return strings.ReplaceAll(formattedJWKS, " -----", "\n-----") +} + func (h *credentials) registerIDPClientCredential(cr *provCreds) error { p := cr.GetIDPProvider() idpCredData := cr.GetIDPCredentialData() - formattedJWKS := strings.ReplaceAll(idpCredData.GetPublicKey(), "----- ", "-----\n") - formattedJWKS = strings.ReplaceAll(formattedJWKS, " -----", "\n-----") - // prepare external client metadata from CRD data - clientMetadata, err := oauth.NewClientMetadataBuilder(). + builder := oauth.NewClientMetadataBuilder(). SetClientName(cr.GetName()). SetScopes(idpCredData.GetScopes()). SetGrantTypes(idpCredData.GetGrantTypes()). SetTokenEndpointAuthMethod(idpCredData.GetTokenEndpointAuthMethod()). SetResponseType(idpCredData.GetResponseTypes()). - SetRedirectURIs(idpCredData.GetRedirectURIs()). - SetJWKS([]byte(formattedJWKS)). - SetJWKSURI(idpCredData.GetJwksURI()). - Build() + SetRedirectURIs(idpCredData.GetRedirectURIs()) + + if idpCredData.GetTokenEndpointAuthMethod() == config.PrivateKeyJWT { + builder.SetJWKS([]byte(formattedJWKS(idpCredData.GetPublicKey()))). + SetJWKSURI(idpCredData.GetJwksURI()) + } + + if idpCredData.GetTokenEndpointAuthMethod() == config.TLSClientAuth || idpCredData.GetTokenEndpointAuthMethod() == config.SelfSignedTLSClientAuth { + builder.SetJWKS([]byte(formattedJWKS(idpCredData.GetCertificate()))). + SetCertificateMetadata(idpCredData.GetCertificateMetadata()). + SetTLSClientAuthSanDNS(idpCredData.GetTLSClientAuthSanDNS()). + SetTLSClientAuthSanEmail(idpCredData.GetTLSClientAuthSanEmail()). + SetTLSClientAuthSanIP(idpCredData.GetTLSClientAuthSanIP()). + SetTLSClientAuthSanURI(idpCredData.GetTLSClientAuthSanURI()) + } + + clientMetadata, err := builder.Build() if err != nil { return err } @@ -535,15 +551,21 @@ type provCreds struct { } type idpCredData struct { - clientID string - clientSecret string - scopes []string - grantTypes []string - tokenAuthMethod string - responseTypes []string - redirectURLs []string - jwksURI string - publicKey string + clientID string + clientSecret string + scopes []string + grantTypes []string + tokenAuthMethod string + responseTypes []string + redirectURLs []string + jwksURI string + publicKey string + certificate string + certificateMetadata string + tlsClientAuthSanDNS string + tlsClientAuthSanEmail string + tlsClientAuthSanIP string + tlsClientAuthSanURI string } func (h *credentials) newProvCreds(cr *management.Credential, appDetails map[string]interface{}, provData map[string]interface{}, action prov.CredentialAction, crd *management.CredentialRequestDefinition) (*provCreds, error) { @@ -601,6 +623,12 @@ func newIDPCredData(p oauth.Provider, credData, provData map[string]interface{}) cd.tokenAuthMethod = util.GetStringFromMapInterface(prov.OauthTokenAuthMethod, credData) cd.publicKey = util.GetStringFromMapInterface(prov.OauthJwks, credData) cd.jwksURI = util.GetStringFromMapInterface(prov.OauthJwksURI, credData) + cd.certificate = util.GetStringFromMapInterface(prov.OauthCertificate, credData) + cd.certificateMetadata = util.GetStringFromMapInterface(prov.OauthCertificateMetadata, credData) + cd.tlsClientAuthSanDNS = util.GetStringFromMapInterface(prov.OauthTLSAuthSANDNS, credData) + cd.tlsClientAuthSanEmail = util.GetStringFromMapInterface(prov.OauthTLSAuthSANEmail, credData) + cd.tlsClientAuthSanIP = util.GetStringFromMapInterface(prov.OauthTLSAuthSANIP, credData) + cd.tlsClientAuthSanURI = util.GetStringFromMapInterface(prov.OauthTLSAuthSANURI, credData) return cd } @@ -737,6 +765,36 @@ func (c *idpCredData) GetPublicKey() string { return c.publicKey } +// GetCertificate - returns the certificate +func (c *idpCredData) GetCertificate() string { + return c.certificate +} + +// GetCertificateMetadata - returns the certificate metadata property +func (c *idpCredData) GetCertificateMetadata() string { + return c.certificateMetadata +} + +// GetTLSClientAuthSanDNS - returns the value for tls_client_auth_san_dns +func (c *idpCredData) GetTLSClientAuthSanDNS() string { + return c.tlsClientAuthSanDNS +} + +// GetTLSClientAuthSanDNS - returns the value for tls_client_auth_san_dns +func (c *idpCredData) GetTLSClientAuthSanEmail() string { + return c.tlsClientAuthSanEmail +} + +// GetTLSClientAuthSanIP - returns the value for tls_client_auth_san_ip +func (c *idpCredData) GetTLSClientAuthSanIP() string { + return c.tlsClientAuthSanIP +} + +// GetTLSClientAuthSanURI - returns the value for tls_client_auth_san_uri +func (c *idpCredData) GetTLSClientAuthSanURI() string { + return c.tlsClientAuthSanURI +} + // encryptSchema schema is the json schema. credData is the data that contains data to encrypt based on the key, alg and hash. func encryptSchema( schema, credData map[string]interface{}, key, alg, hash string, diff --git a/pkg/agent/handler/credential_test.go b/pkg/agent/handler/credential_test.go index 263e279e8..5f7e2f50f 100644 --- a/pkg/agent/handler/credential_test.go +++ b/pkg/agent/handler/credential_test.go @@ -11,6 +11,7 @@ import ( "encoding/pem" "fmt" "net/http" + "os" "strings" "testing" "time" @@ -445,6 +446,11 @@ func TestIDPCredentialProvisioning(t *testing.T) { s := oauth.NewMockIDPServer() defer s.Close() + publicKey, err := os.ReadFile("../../authz/oauth/testdata/publickey") + assert.Nil(t, err) + + certificate, err := os.ReadFile("../../authz/oauth/testdata/client_cert.pem") + assert.Nil(t, err) tests := []struct { name string metadataURL string @@ -454,6 +460,8 @@ func TestIDPCredentialProvisioning(t *testing.T) { registrationStatus int handlerInvoked bool hasError bool + authMethod string + jwks []byte }{ { name: "should provision IDP credential with no error", @@ -462,13 +470,71 @@ func TestIDPCredentialProvisioning(t *testing.T) { expectedProvType: provision, outboundStatus: prov.Success, registrationStatus: http.StatusCreated, + authMethod: config.ClientSecretBasic, }, { name: "should fail to provision and set the status to error", metadataURL: s.GetMetadataURL(), tokenURL: "test", outboundStatus: prov.Error, - hasError: true, + authMethod: config.ClientSecretBasic, + }, + { + name: "should fail to provision with no jwks for private_kwy_jwt", + metadataURL: s.GetMetadataURL(), + tokenURL: s.GetTokenURL(), + outboundStatus: prov.Error, + authMethod: config.PrivateKeyJWT, + }, + { + name: "should fail to provision with no jwks for tls_client_auth", + metadataURL: s.GetMetadataURL(), + tokenURL: s.GetTokenURL(), + outboundStatus: prov.Error, + authMethod: config.TLSClientAuth, + }, + { + name: "should fail to provision with no jwks for self_signed_tls_client_auth", + metadataURL: s.GetMetadataURL(), + tokenURL: s.GetTokenURL(), + outboundStatus: prov.Error, + authMethod: config.SelfSignedTLSClientAuth, + }, + { + name: "should fail to provision with invalid jwks for private_kwy_jwt", + metadataURL: s.GetMetadataURL(), + tokenURL: s.GetTokenURL(), + outboundStatus: prov.Error, + authMethod: config.PrivateKeyJWT, + jwks: []byte("invalid-private-key"), + }, + { + name: "should fail to provision with invalid jwks for tls_client_auth", + metadataURL: s.GetMetadataURL(), + tokenURL: s.GetTokenURL(), + outboundStatus: prov.Error, + authMethod: config.TLSClientAuth, + jwks: []byte("invalid-certificate"), + }, + { + name: "should fail to provision with invalid jwks for private_kwy_jwt", + metadataURL: s.GetMetadataURL(), + tokenURL: s.GetTokenURL(), + outboundStatus: prov.Success, + expectedProvType: provision, + authMethod: config.PrivateKeyJWT, + jwks: publicKey, + registrationStatus: http.StatusCreated, + }, + { + name: "should fail to provision with invalid jwks for tls_client_auth", + metadataURL: s.GetMetadataURL(), + tokenURL: s.GetTokenURL(), + outboundStatus: prov.Success, + expectedProvType: provision, + authMethod: config.TLSClientAuth, + jwks: certificate, + registrationStatus: http.StatusCreated, }, } for _, tc := range tests { @@ -481,7 +547,11 @@ func TestIDPCredentialProvisioning(t *testing.T) { cred.Status.Level = prov.Pending.String() cred.Spec.Data = map[string]interface{}{ - "idpTokenURL": tc.tokenURL, + prov.IDPTokenURL: tc.tokenURL, + prov.OauthGrantType: "client_credentials", + prov.OauthTokenAuthMethod: tc.authMethod, + prov.OauthJwks: string(tc.jwks), + prov.OauthCertificate: string(tc.jwks), } p := &mockCredProv{ @@ -515,8 +585,12 @@ func TestIDPCredentialProvisioning(t *testing.T) { ri, _ := cred.AsInstance() s.SetRegistrationResponseCode(tc.registrationStatus) err := handler.Handle(NewEventContext(proto.Event_UPDATED, nil, ri.Kind, ri.Name), nil, ri) - assert.Equal(t, tc.expectedProvType, p.expectedProvType) assert.Nil(t, err) + if !tc.hasError { + assert.Equal(t, tc.expectedProvType, p.expectedProvType) + } else { + assert.NotNil(t, err) + } }) } } @@ -975,10 +1049,10 @@ func createIDPConfig(s oauth.MockIDPServer) *config.IDPConfiguration { ClientID: "test", ClientSecret: "test", }, - GrantType: "client_credentials", + GrantType: oauth.GrantTypeClientCredentials, ClientScopes: "read,write", - AuthMethod: "client_secret_basic", - AuthResponseType: "token", + AuthMethod: config.ClientSecretBasic, + AuthResponseType: oauth.AuthResponseToken, ExtraProperties: config.ExtraProperties{"key": "value"}, } } diff --git a/pkg/agent/provisioning.go b/pkg/agent/provisioning.go index 9aa92d95d..89223461c 100644 --- a/pkg/agent/provisioning.go +++ b/pkg/agent/provisioning.go @@ -16,14 +16,25 @@ import ( ) var supportedIDPGrantTypes = map[string]bool{ - "client_credentials": true, - "authorization_code": true} + oauth.GrantTypeClientCredentials: true, + oauth.GrantTypeAuthorizationCode: true} var supportedIDPTokenAuthMethods = map[string]bool{ - "client_secret_basic": true, - "client_secret_post": true, - "client_secret_jwt": true, - "private_key_jwt": true} + config.ClientSecretBasic: true, + config.ClientSecretPost: true, + config.ClientSecretJWT: true, + config.PrivateKeyJWT: true, + config.TLSClientAuth: true, + config.SelfSignedTLSClientAuth: true, +} + +var tlsAuthCertificateMetadata = []string{ + oauth.TLSClientAuthSubjectDN, + oauth.TLSClientAuthSanDNS, + oauth.TLSClientAuthSanEmail, + oauth.TLSClientAuthSanIP, + oauth.TLSClientAuthSanURI, +} // credential request definitions // createOrUpdateDefinition - @@ -216,6 +227,24 @@ func WithCRDRequestSchemaProperty(prop provisioning.PropertyBuilder) func(c *crd } } +func idpUsesPrivateKeyJWTAuth(tokenAuthMethods []string) bool { + for _, s := range tokenAuthMethods { + if s == config.PrivateKeyJWT { + return true + } + } + return false +} + +func idpUsesTLSClientAuth(tokenAuthMethods []string) bool { + for _, s := range tokenAuthMethods { + if s == config.TLSClientAuth || s == config.SelfSignedTLSClientAuth { + return true + } + } + return false +} + // WithCRDForIDP - set the schema properties using the provider metadata func WithCRDForIDP(p oauth.Provider, scopes []string) func(c *crdBuilderOptions) { return func(c *crdBuilderOptions) { @@ -229,10 +258,22 @@ func WithCRDForIDP(p oauth.Provider, scopes []string) func(c *crdBuilderOptions) setIDPTokenURLSchemaProperty(p, c) setIDPScopesSchemaProperty(p, scopes, c) setIDPGrantTypesSchemaProperty(p, c) - setIDPTokenAuthMethodSchemaProperty(p, c) + tokenAuthMethods := setIDPTokenAuthMethodSchemaProperty(p, c) setIDPRedirectURIsSchemaProperty(p, c) - setIDPJWKSURISchemaProperty(p, c) - setIDPJWKSSchemaProperty(p, c) + + usePrivateKeyJWTAuth := idpUsesPrivateKeyJWTAuth(tokenAuthMethods) + useTLSClientAuth := idpUsesTLSClientAuth(tokenAuthMethods) + if usePrivateKeyJWTAuth || useTLSClientAuth { + setIDPJWKSURISchemaProperty(p, c) + } + + if usePrivateKeyJWTAuth { + setIDPJWKSSchemaProperty(p, c) + } + + if useTLSClientAuth { + setIDPTLSClientAuthSchemaProperty(p, c) + } } } @@ -269,39 +310,52 @@ func setIDPScopesSchemaProperty(p oauth.Provider, scopes []string, c *crdBuilder } func setIDPGrantTypesSchemaProperty(p oauth.Provider, c *crdBuilderOptions) { - grantType := removeUnsupportedTypes( - p.GetSupportedGrantTypes(), supportedIDPGrantTypes) + grantType, defaultGrantType := removeUnsupportedTypes( + p.GetSupportedGrantTypes(), supportedIDPGrantTypes, oauth.GrantTypeClientCredentials) c.reqProps = append(c.reqProps, provisioning.NewSchemaPropertyBuilder(). SetName(provisioning.OauthGrantType). SetLabel("Grant Type"). IsString(). - SetDefaultValue("client_credentials"). + SetDefaultValue(defaultGrantType). SetEnumValues(grantType)) } -func removeUnsupportedTypes(values []string, supportedTypes map[string]bool) []string { +func removeUnsupportedTypes(values []string, supportedTypes map[string]bool, defaultType string) ([]string, string) { var result []string + defaultSupportedType := "" + defaultExists := false for _, s := range values { if ok := supportedTypes[s]; ok { + if s == defaultType { + defaultExists = true + } + if defaultSupportedType == "" { + defaultSupportedType = s + } result = append(result, s) } } - return result + + if !defaultExists { + defaultType = defaultSupportedType + } + return result, defaultType } -func setIDPTokenAuthMethodSchemaProperty(p oauth.Provider, c *crdBuilderOptions) { - tokenAuthMethod := removeUnsupportedTypes( - p.GetSupportedTokenAuthMethods(), supportedIDPTokenAuthMethods) +func setIDPTokenAuthMethodSchemaProperty(p oauth.Provider, c *crdBuilderOptions) []string { + tokenAuthMethods, defaultTokenMethod := removeUnsupportedTypes( + p.GetSupportedTokenAuthMethods(), supportedIDPTokenAuthMethods, config.ClientSecretBasic) c.reqProps = append(c.reqProps, provisioning.NewSchemaPropertyBuilder(). SetName(provisioning.OauthTokenAuthMethod). SetLabel("Token Auth Method"). IsString(). - SetDefaultValue("client_secret_basic"). - SetEnumValues(tokenAuthMethod)) + SetDefaultValue(defaultTokenMethod). + SetEnumValues(tokenAuthMethods)) + return tokenAuthMethods } func setIDPRedirectURIsSchemaProperty(p oauth.Provider, c *crdBuilderOptions) { @@ -333,6 +387,41 @@ func setIDPJWKSSchemaProperty(p oauth.Provider, c *crdBuilderOptions) { } +func setIDPTLSClientAuthSchemaProperty(p oauth.Provider, c *crdBuilderOptions) { + c.reqProps = append(c.reqProps, + provisioning.NewSchemaPropertyBuilder(). + SetName(provisioning.OauthCertificate). + SetLabel("Public Certificate"). + IsString()) + c.reqProps = append(c.reqProps, + provisioning.NewSchemaPropertyBuilder(). + SetName(provisioning.OauthCertificateMetadata). + SetLabel("Certificate Metadata"). + IsString(). + SetDefaultValue(oauth.TLSClientAuthSubjectDN). + SetEnumValues(tlsAuthCertificateMetadata)) + c.reqProps = append(c.reqProps, + provisioning.NewSchemaPropertyBuilder(). + SetName(provisioning.OauthTLSAuthSANDNS). + SetLabel("Certificate Subject Alternative Name, DNS"). + IsString()) + c.reqProps = append(c.reqProps, + provisioning.NewSchemaPropertyBuilder(). + SetName(provisioning.OauthTLSAuthSANEmail). + SetLabel("Certificate Subject Alternative Name, Email"). + IsString()) + c.reqProps = append(c.reqProps, + provisioning.NewSchemaPropertyBuilder(). + SetName(provisioning.OauthTLSAuthSANIP). + SetLabel("Certificate Subject Alternative Name, IP address"). + IsString()) + c.reqProps = append(c.reqProps, + provisioning.NewSchemaPropertyBuilder(). + SetName(provisioning.OauthTLSAuthSANURI). + SetLabel("Certificate Subject Alternative Name, URI"). + IsString()) +} + // WithCRDOAuthSecret - set that the Oauth cred is secret based func WithCRDOAuthSecret() func(c *crdBuilderOptions) { return func(c *crdBuilderOptions) { diff --git a/pkg/agent/provisioning_test.go b/pkg/agent/provisioning_test.go index 4055dc1c1..915022bad 100644 --- a/pkg/agent/provisioning_test.go +++ b/pkg/agent/provisioning_test.go @@ -77,9 +77,9 @@ func TestNewCredentialRequestBuilder(t *testing.T) { ClientID: "test", ClientSecret: "test", }, - GrantType: "client_credentials", + GrantType: oauth.GrantTypeClientCredentials, ClientScopes: "read,write", - AuthMethod: "client_secret_basic", + AuthMethod: config.ClientSecretBasic, AuthResponseType: "token", ExtraProperties: config.ExtraProperties{"key": "value"}, } diff --git a/pkg/apic/auth/apicauth.go b/pkg/apic/auth/apicauth.go index 8e6f547f0..e0f03a117 100644 --- a/pkg/apic/auth/apicauth.go +++ b/pkg/apic/auth/apicauth.go @@ -147,7 +147,7 @@ func (ptp *platformTokenGetter) initAxwayIDPClient() error { "", ptp.cfg.GetAuthConfig().GetAudience(), privateKey, - publicKey, "")) + publicKey, "", oauth.SigningMethodRS256)) return err } diff --git a/pkg/apic/provisioning/definitions.go b/pkg/apic/provisioning/definitions.go index c7b3f3729..cd495c925 100644 --- a/pkg/apic/provisioning/definitions.go +++ b/pkg/apic/provisioning/definitions.go @@ -10,15 +10,21 @@ const ( OAuthPublicKeyCRD = "oauth-public-key" OAuthIDPCRD = "oauth-idp" - OauthClientID = "clientId" - OauthClientSecret = "clientSecret" - OauthPublicKey = "publicKey" - OauthGrantType = "grantType" - OauthTokenAuthMethod = "tokenAuthMethod" - OauthScopes = "scopes" - OauthRedirectURIs = "redirectURLs" - OauthJwksURI = "jwksURI" - OauthJwks = "jwks" + OauthClientID = "clientId" + OauthClientSecret = "clientSecret" + OauthPublicKey = "publicKey" + OauthGrantType = "grantType" + OauthTokenAuthMethod = "tokenAuthMethod" + OauthScopes = "scopes" + OauthRedirectURIs = "redirectURLs" + OauthJwksURI = "jwksURI" + OauthJwks = "jwks" + OauthCertificate = "certificate" + OauthCertificateMetadata = "certificateMetadata" + OauthTLSAuthSANDNS = "tlsClientAuthSanDNS" + OauthTLSAuthSANEmail = "tlsClientAuthSanEmail" + OauthTLSAuthSANIP = "tlsClientAuthSanIP" + OauthTLSAuthSANURI = "tlsClientAuthSanURI" IDPTokenURL = "idpTokenURL" diff --git a/pkg/apic/provisioning/idpcredentialdata.go b/pkg/apic/provisioning/idpcredentialdata.go index 77adf2e53..a49aab844 100644 --- a/pkg/apic/provisioning/idpcredentialdata.go +++ b/pkg/apic/provisioning/idpcredentialdata.go @@ -20,4 +20,16 @@ type IDPCredentialData interface { GetJwksURI() string // GetPublicKey - returns the public key GetPublicKey() string + // GetCertificate - returns the public certificate + GetCertificate() string + // GetCertificateMetadata - returns the certificate metadata property + GetCertificateMetadata() string + // GetTLSClientAuthSanDNS - returns the value for tls_client_auth_san_dns + GetTLSClientAuthSanDNS() string + // GetTLSClientAuthSanDNS - returns the value for tls_client_auth_san_dns + GetTLSClientAuthSanEmail() string + // GetTLSClientAuthSanIP - returns the value for tls_client_auth_san_ip + GetTLSClientAuthSanIP() string + // GetTLSClientAuthSanURI - returns the value for tls_client_auth_san_uri + GetTLSClientAuthSanURI() string } diff --git a/pkg/authz/oauth/authclient.go b/pkg/authz/oauth/authclient.go index fe94fec14..5d59caeff 100644 --- a/pkg/authz/oauth/authclient.go +++ b/pkg/authz/oauth/authclient.go @@ -102,7 +102,7 @@ func WithClientSecretPostAuth(clientID, clientSecret, scope string) AuthClientOp } // WithClientSecretJwtAuth - sets up to use client secret authenticator -func WithClientSecretJwtAuth(clientID, clientSecret, scope, issuer, aud string) AuthClientOption { +func WithClientSecretJwtAuth(clientID, clientSecret, scope, issuer, aud, signingMethod string) AuthClientOption { return func(opt *authClientOptions) { opt.authenticator = &clientSecretJwtAuthenticator{ clientID, @@ -110,12 +110,13 @@ func WithClientSecretJwtAuth(clientID, clientSecret, scope, issuer, aud string) scope, issuer, aud, + signingMethod, } } } // WithKeyPairAuth - sets up to use public/private key pair authenticator -func WithKeyPairAuth(clientID, issuer, audience string, privKey *rsa.PrivateKey, publicKey []byte, scope string) AuthClientOption { +func WithKeyPairAuth(clientID, issuer, audience string, privKey *rsa.PrivateKey, publicKey []byte, scope, signingMethod string) AuthClientOption { return func(opt *authClientOptions) { opt.authenticator = &keyPairAuthenticator{ clientID, @@ -124,6 +125,7 @@ func WithKeyPairAuth(clientID, issuer, audience string, privKey *rsa.PrivateKey, privKey, publicKey, scope, + signingMethod, } } } diff --git a/pkg/authz/oauth/authclient_test.go b/pkg/authz/oauth/authclient_test.go index fd414a2c4..7bb3b0481 100644 --- a/pkg/authz/oauth/authclient_test.go +++ b/pkg/authz/oauth/authclient_test.go @@ -78,7 +78,7 @@ func TestGetPlatformTokensHttpError(t *testing.T) { s.SetTokenResponse("", 0, http.StatusBadRequest) ac, err = NewAuthClient(s.GetTokenURL(), apiClient, WithServerName("testServer"), - WithKeyPairAuth("invalid_client", "", "", privateKey, publicKey, "")) + WithKeyPairAuth("invalid_client", "", "", privateKey, publicKey, "", "")) assert.Nil(t, err) assert.NotNil(t, ac) @@ -88,7 +88,7 @@ func TestGetPlatformTokensHttpError(t *testing.T) { s.SetTokenResponse("token", 3*time.Second, http.StatusOK) ac, err = NewAuthClient(s.GetTokenURL(), apiClient, WithServerName("testServer"), - WithKeyPairAuth("invalid_client", "", "", privateKey, publicKey, "")) + WithKeyPairAuth("invalid_client", "", "", privateKey, publicKey, "", "")) assert.Nil(t, err) assert.NotNil(t, ac) @@ -114,3 +114,96 @@ func TestGetPlatformTokensTimeout(t *testing.T) { _, err = ac.GetToken() assert.NotNil(t, err) } + +func TestAuthClientTypes(t *testing.T) { + s := NewMockIDPServer() + defer s.Close() + keyReader := NewKeyReader( + "testdata/private_key.pem", + "testdata/publickey", + "", + ) + privateKey, keyErr := keyReader.GetPrivateKey() + assert.Nil(t, keyErr) + + publicKey, keyErr := keyReader.GetPublicKey() + assert.Nil(t, keyErr) + + cases := []struct { + name string + tokenReqWithAuthorization bool + typedAuthOpt AuthClientOption + expectedTokenReqClientID string + expectedTokenReqClientSecret string + expectedTokenReqClientAssertType string + expectedTokenReqScope string + }{ + { + name: "test", + typedAuthOpt: WithClientSecretBasicAuth("test-id", "test-secret", "test-scope"), + tokenReqWithAuthorization: true, + expectedTokenReqScope: "test-scope", + }, + { + name: "test", + typedAuthOpt: WithClientSecretPostAuth("test-id", "test-secret", "test-scope"), + expectedTokenReqClientID: "test-id", + expectedTokenReqClientSecret: "test-secret", + expectedTokenReqScope: "test-scope", + }, + { + name: "test", + typedAuthOpt: WithClientSecretJwtAuth("test-id", "test-secret", "test-scope", "", "aud", ""), + expectedTokenReqClientID: "test-id", + expectedTokenReqScope: "test-scope", + expectedTokenReqClientAssertType: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + }, + { + name: "test", + typedAuthOpt: WithKeyPairAuth("test-id", "", "aud", privateKey, publicKey, "test-scope", ""), + expectedTokenReqScope: "test-scope", + expectedTokenReqClientAssertType: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + }, + { + name: "test", + typedAuthOpt: WithTLSClientAuth("test-id", "test-scope"), + expectedTokenReqClientID: "test-id", + expectedTokenReqScope: "test-scope", + }, + } + for _, tc := range cases { + s.SetTokenResponse("token", 3*time.Second, http.StatusOK) + apiClient := api.NewClientWithTimeout(config.NewTLSConfig(), "", time.Second) + opts := []AuthClientOption{WithServerName("testServer"), tc.typedAuthOpt} + ac, err := NewAuthClient(s.GetTokenURL(), apiClient, opts...) + + assert.Nil(t, err) + assert.NotNil(t, ac) + + token, err := ac.GetToken() + assert.Nil(t, err) + assert.Equal(t, "token", token) + if tc.tokenReqWithAuthorization { + headers := s.GetTokenRequestHeaders() + authHeaderVal := headers.Get("Authorization") + assert.NotEmpty(t, authHeaderVal) + } + tokenReqValues := s.GetTokenRequestValues() + + grantType := tokenReqValues.Get("grant_type") + assert.Equal(t, "client_credentials", grantType) + + clientID := tokenReqValues.Get("client_id") + assert.Equal(t, tc.expectedTokenReqClientID, clientID) + + clientSecret := tokenReqValues.Get("client_secret") + assert.Equal(t, tc.expectedTokenReqClientSecret, clientSecret) + + clientAssertType := tokenReqValues.Get("client_assertion_type") + assert.Equal(t, tc.expectedTokenReqClientAssertType, clientAssertType) + + tokenScope := tokenReqValues.Get("scope") + assert.Equal(t, tc.expectedTokenReqScope, tokenScope) + + } +} diff --git a/pkg/authz/oauth/clientmetadata.go b/pkg/authz/oauth/clientmetadata.go index f06e39c3b..198551946 100644 --- a/pkg/authz/oauth/clientmetadata.go +++ b/pkg/authz/oauth/clientmetadata.go @@ -41,6 +41,10 @@ type ClientMetadata interface { GetJwksURI() string GetJwks() map[string]interface{} GetExtraProperties() map[string]string + GetTLSClientAuthSanDNS() string + GetTLSClientAuthSanEmail() string + GetTLSClientAuthSanIP() string + GetTLSClientAuthSanURI() string } type clientMetadata struct { @@ -56,12 +60,18 @@ type clientMetadata struct { ResponseTypes []string `json:"response_types,omitempty"` TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty"` - ClientURI string `json:"client_uri,omitempty"` - RedirectURIs []string `json:"redirect_uris,omitempty"` - JwksURI string `json:"jwks_uri,omitempty"` - Jwks map[string]interface{} `json:"jwks,omitempty"` - LogoURI string `json:"logo_uri,omitempty"` - extraProperties map[string]string `json:"-"` + ClientURI string `json:"client_uri,omitempty"` + RedirectURIs []string `json:"redirect_uris,omitempty"` + JwksURI string `json:"jwks_uri,omitempty"` + Jwks map[string]interface{} `json:"jwks,omitempty"` + LogoURI string `json:"logo_uri,omitempty"` + TLSClientAuthSubjectDN string `json:"tls_client_auth_subject_dn,omitempty"` + TLSClientAuthSanDNS string `json:"tls_client_auth_san_dns,omitempty"` + TLSClientAuthSanEmail string `json:"tls_client_auth_san_email,omitempty"` + TLSClientAuthSanIP string `json:"tls_client_auth_san_ip,omitempty"` + TLSClientAuthSanURI string `json:"tls_client_auth_san_uri,omitempty"` + + extraProperties map[string]string `json:"-"` } var clientFields map[string]bool @@ -152,6 +162,22 @@ func (c *clientMetadata) GetExtraProperties() map[string]string { return c.extraProperties } +func (c *clientMetadata) GetTLSClientAuthSanDNS() string { + return c.TLSClientAuthSanDNS +} + +func (c *clientMetadata) GetTLSClientAuthSanEmail() string { + return c.TLSClientAuthSanEmail +} + +func (c *clientMetadata) GetTLSClientAuthSanIP() string { + return c.TLSClientAuthSanIP +} + +func (c *clientMetadata) GetTLSClientAuthSanURI() string { + return c.TLSClientAuthSanURI +} + // MarshalJSON serialize the client metadata with provider metadata func (c *clientMetadata) MarshalJSON() ([]byte, error) { type alias clientMetadata diff --git a/pkg/authz/oauth/clientmetadata_test.go b/pkg/authz/oauth/clientmetadata_test.go index 1b60a8009..f3e99c015 100644 --- a/pkg/authz/oauth/clientmetadata_test.go +++ b/pkg/authz/oauth/clientmetadata_test.go @@ -5,15 +5,16 @@ import ( "strings" "testing" + "github.com/Axway/agent-sdk/pkg/config" "github.com/stretchr/testify/assert" ) func TestClientMetadataSerialization(t *testing.T) { c, err := NewClientMetadataBuilder(). SetClientName("test"). - SetGrantTypes([]string{"client_credentials", "authorization_code"}). - SetTokenEndpointAuthMethod("client_secret_jwt"). - SetResponseType([]string{"token"}). + SetGrantTypes([]string{GrantTypeClientCredentials, GrantTypeAuthorizationCode}). + SetTokenEndpointAuthMethod(config.ClientSecretJWT). + SetResponseType([]string{AuthResponseToken}). SetRedirectURIs([]string{"http://localhost"}). SetScopes([]string{"scope1", "scope2"}). SetLogoURI("http://localhost"). diff --git a/pkg/authz/oauth/clientmetadatabuilder.go b/pkg/authz/oauth/clientmetadatabuilder.go index fc0300dbf..6d525152c 100644 --- a/pkg/authz/oauth/clientmetadatabuilder.go +++ b/pkg/authz/oauth/clientmetadatabuilder.go @@ -1,14 +1,19 @@ package oauth import ( + "crypto/x509" + "encoding/base64" "encoding/json" + "encoding/pem" "fmt" + "github.com/Axway/agent-sdk/pkg/config" "github.com/Axway/agent-sdk/pkg/util" - "github.com/lestrrat-go/jwx/jwk" + jwkcert "github.com/lestrrat-go/jwx/v2/cert" + "github.com/lestrrat-go/jwx/v2/jwk" ) -var grantTypeWithRedirects = map[string]bool{grantAuthorizationCode: true, grantImplicit: true} +var grantTypeWithRedirects = map[string]bool{GrantTypeAuthorizationCode: true, GrantTypeImplicit: true} // ClientBuilder - Builder for IdP client representation type ClientBuilder interface { @@ -24,14 +29,26 @@ type ClientBuilder interface { SetJWKSURI(string) ClientBuilder SetJWKS([]byte) ClientBuilder + + SetCertificateMetadata(certificateMetaddata string) ClientBuilder + SetTLSClientAuthSanDNS(tlsClientAuthSanDNS string) ClientBuilder + SetTLSClientAuthSanEmail(tlsClientAuthSanEmail string) ClientBuilder + SetTLSClientAuthSanIP(tlsClientAuthSanIP string) ClientBuilder + SetTLSClientAuthSanURI(tlsClientAuthSanURI string) ClientBuilder SetExtraProperties(map[string]string) ClientBuilder Build() (ClientMetadata, error) } type clientBuilder struct { - publicKey []byte - idpClientMetadata *clientMetadata + jwks []byte + jwksURI string + idpClientMetadata *clientMetadata + certificateMetadata string + tlsClientAuthSanDNS string + tlsClientAuthSanEmail string + tlsClientAuthSanIP string + tlsClientAuthSanURI string } // NewClientMetadataBuilder - create a new instance of builder to construct client metadata @@ -77,12 +94,37 @@ func (b *clientBuilder) SetLogoURI(logoURI string) ClientBuilder { } func (b *clientBuilder) SetJWKSURI(jwksURI string) ClientBuilder { - b.idpClientMetadata.JwksURI = jwksURI + b.jwksURI = jwksURI + return b +} + +func (b *clientBuilder) SetJWKS(jwks []byte) ClientBuilder { + b.jwks = jwks + return b +} + +func (b *clientBuilder) SetCertificateMetadata(certificateMetadata string) ClientBuilder { + b.certificateMetadata = certificateMetadata + return b +} + +func (b *clientBuilder) SetTLSClientAuthSanDNS(tlsClientAuthSanDNS string) ClientBuilder { + b.tlsClientAuthSanDNS = tlsClientAuthSanDNS + return b +} + +func (b *clientBuilder) SetTLSClientAuthSanEmail(tlsClientAuthSanEmail string) ClientBuilder { + b.tlsClientAuthSanEmail = tlsClientAuthSanEmail return b } -func (b *clientBuilder) SetJWKS(publicKey []byte) ClientBuilder { - b.publicKey = publicKey +func (b *clientBuilder) SetTLSClientAuthSanIP(tlsClientAuthSanIP string) ClientBuilder { + b.tlsClientAuthSanIP = tlsClientAuthSanIP + return b +} + +func (b *clientBuilder) SetTLSClientAuthSanURI(tlsClientAuthSanURI string) ClientBuilder { + b.tlsClientAuthSanURI = tlsClientAuthSanURI return b } @@ -91,43 +133,135 @@ func (b *clientBuilder) SetExtraProperties(extraProperties map[string]string) Cl return b } -func (b *clientBuilder) decodeJWKS() ([]byte, error) { - p, err := util.ParsePublicKey(b.publicKey) +func (b *clientBuilder) decodePublicKeyJWKS() (jwk.Key, error) { + p, err := util.ParsePublicKey(b.jwks) if err != nil { return nil, err } - key, err := jwk.New(p) + key, err := jwk.FromRaw(p) if err != nil { return nil, fmt.Errorf("failed to parse public key: %s", err) } - kid, _ := util.ComputeKIDFromDER(b.publicKey) + kid, _ := util.ComputeKIDFromDER(b.jwks) key.Set(jwk.KeyIDKey, kid) key.Set(jwk.KeyUsageKey, jwk.ForSignature) - buf, err := json.MarshalIndent(key, "", " ") + return key, nil +} + +func (b *clientBuilder) decodeCertificateJWKS() (string, jwk.Key, error) { + pemBlock, _ := pem.Decode(b.jwks) + if pemBlock == nil { + return "", nil, fmt.Errorf("failed to decode certificate") + } + + cert, err := x509.ParseCertificate(pemBlock.Bytes) if err != nil { - return nil, fmt.Errorf("failed to marshal jwks: %s", err) + return "", nil, fmt.Errorf("failed to parse certificate: %s", err) } - return buf, nil + + subjectDN := cert.Subject.String() + key, err := jwk.FromRaw(cert.PublicKey) + if err != nil { + return "", nil, fmt.Errorf("failed to parse client certificate: %s", err) + } + + c := &jwkcert.Chain{} + c.Add([]byte(base64.StdEncoding.EncodeToString(pemBlock.Bytes))) + key.Set(jwk.X509CertChainKey, c) + key.Set(jwk.KeyUsageKey, jwk.ForSignature) + + return subjectDN, key, nil } -func (b *clientBuilder) Build() (ClientMetadata, error) { - if b.publicKey != nil && len(b.publicKey) > 0 { - jwksBuf, err := b.decodeJWKS() +func (b *clientBuilder) setClientMetadataJWKS(key jwk.Key) error { + jwksBuf, err := json.Marshal(key) + if err != nil { + return err + } + b.idpClientMetadata.Jwks = map[string]interface{}{ + "keys": []json.RawMessage{json.RawMessage(jwksBuf)}, + } + + return nil +} + +func (b *clientBuilder) setPrivateKeyJWTProperties() error { + if len(b.jwks) == 0 && len(b.jwksURI) == 0 { + return fmt.Errorf("public key is required for private_key_jwt token authentication method") + } + if len(b.jwks) != 0 { + key, err := b.decodePublicKeyJWKS() if err != nil { - return nil, err + return err } + b.setClientMetadataJWKS(key) + } + b.idpClientMetadata.JwksURI = b.jwksURI + return nil +} - b.idpClientMetadata.Jwks = map[string]interface{}{ - "keys": []json.RawMessage{json.RawMessage(jwksBuf)}, +func (b *clientBuilder) setTLSClientAuthProperties() error { + if len(b.jwks) == 0 && len(b.jwksURI) == 0 { + return fmt.Errorf("client certificate is required for tls_client_auth/self_signed_tls_client_auth token authentication method") + } + if len(b.jwks) != 0 { + subjectDN, jwks, err := b.decodeCertificateJWKS() + if err != nil { + return err + } + b.setClientMetadataJWKS(jwks) + + switch b.certificateMetadata { + case TLSClientAuthSanDNS: + if b.tlsClientAuthSanDNS == "" { + return fmt.Errorf("no value provided for tls_client_auth_san_dns") + } + b.idpClientMetadata.TLSClientAuthSanDNS = b.tlsClientAuthSanDNS + case TLSClientAuthSanEmail: + if b.tlsClientAuthSanEmail == "" { + return fmt.Errorf("no value provided for tls_client_auth_san_email") + } + b.idpClientMetadata.TLSClientAuthSanEmail = b.tlsClientAuthSanEmail + case TLSClientAuthSanIP: + if b.tlsClientAuthSanIP == "" { + return fmt.Errorf("no value provided for tls_client_auth_san_ip") + } + b.idpClientMetadata.TLSClientAuthSanIP = b.tlsClientAuthSanIP + case TLSClientAuthSanURI: + if b.tlsClientAuthSanURI == "" { + return fmt.Errorf("no value provided for tls_client_auth_san_uri") + } + b.idpClientMetadata.TLSClientAuthSanURI = b.tlsClientAuthSanURI + default: + b.idpClientMetadata.TLSClientAuthSubjectDN = subjectDN } } + b.idpClientMetadata.JwksURI = b.jwksURI + return nil +} +func (b *clientBuilder) Build() (ClientMetadata, error) { for _, grantType := range b.idpClientMetadata.GrantTypes { if _, ok := grantTypeWithRedirects[grantType]; ok && len(b.idpClientMetadata.RedirectURIs) == 0 { return nil, fmt.Errorf("invalid client metadata redirect uri should be set for %s grant type", grantType) } } + + switch b.idpClientMetadata.GetTokenEndpointAuthMethod() { + case config.PrivateKeyJWT: + err := b.setPrivateKeyJWTProperties() + if err != nil { + return nil, err + } + case config.TLSClientAuth: + fallthrough + case config.SelfSignedTLSClientAuth: + err := b.setTLSClientAuthProperties() + if err != nil { + return nil, err + } + } return b.idpClientMetadata, nil } diff --git a/pkg/authz/oauth/clientmetadatabuilder_test.go b/pkg/authz/oauth/clientmetadatabuilder_test.go index 869c00d81..2f48bba88 100644 --- a/pkg/authz/oauth/clientmetadatabuilder_test.go +++ b/pkg/authz/oauth/clientmetadatabuilder_test.go @@ -3,78 +3,248 @@ package oauth import ( "testing" + "github.com/Axway/agent-sdk/pkg/config" "github.com/Axway/agent-sdk/pkg/util" "github.com/stretchr/testify/assert" ) func TestClientBuilder(t *testing.T) { - cm, err := NewClientMetadataBuilder().Build() - assert.Nil(t, err) - assert.NotNil(t, cm) - assert.Equal(t, "", cm.GetClientName()) - assert.Equal(t, 0, len(cm.GetGrantTypes())) // Provider will set default - assert.Equal(t, "", cm.GetTokenEndpointAuthMethod()) // Provider will set default - assert.Equal(t, 0, len(cm.GetRedirectURIs())) - assert.Equal(t, 0, len(cm.GetScopes())) - assert.Equal(t, "", cm.GetLogoURI()) - assert.Nil(t, cm.GetJwks()) - - cm, err = NewClientMetadataBuilder(). - SetClientName("test"). - SetGrantTypes([]string{"client_credentials", "authorization_code"}). - SetTokenEndpointAuthMethod("client_secret_post"). - SetResponseType([]string{"token"}). - SetRedirectURIs([]string{"http://localhost"}). - SetScopes([]string{"scope1", "scope2"}). - SetLogoURI("http://localhost"). - Build() - - assert.Nil(t, err) - assert.NotNil(t, cm) - assert.Equal(t, "test", cm.GetClientName()) - assert.Equal(t, 2, len(cm.GetGrantTypes())) // Provider will set default - assert.Equal(t, "client_secret_post", cm.GetTokenEndpointAuthMethod()) // Provider will set default - assert.Equal(t, 1, len(cm.GetResponseTypes())) - assert.Equal(t, 1, len(cm.GetRedirectURIs())) - assert.Equal(t, 2, len(cm.GetScopes())) - assert.Equal(t, "http://localhost", cm.GetLogoURI()) - assert.Nil(t, cm.GetJwks()) - publicKey, err := util.ReadPublicKeyBytes("testdata/publickey") assert.Nil(t, err) - cm, err = NewClientMetadataBuilder(). - SetClientName("test"). - SetGrantTypes([]string{"client_credentials"}). - SetTokenEndpointAuthMethod("private_key_jwt"). - SetJWKS(publicKey). - Build() - + certificate, err := util.ReadPublicKeyBytes("testdata/client_cert.pem") assert.Nil(t, err) - assert.NotNil(t, cm) - assert.NotNil(t, cm.GetJwks()) -} - -func TestBuildValidations(t *testing.T) { - client, err := NewClientMetadataBuilder(). - SetClientName("test"). - SetGrantTypes([]string{"client_credentials"}). - SetTokenEndpointAuthMethod("private_key_jwt"). - SetJWKS([]byte("invalid-public-key")). - Build() - assert.NotNil(t, err) - assert.Nil(t, client) + cases := []struct { + name string + grantTypes []string + tokenAuthMethod string + responseType []string + redirectURIs []string + scopes []string + logoURI string + publicKey []byte + certificate []byte + certificateMetadata string + tlsClientAuthSanDNS string + tlsClientAuthSanEmail string + tlsClientAuthSanIP string + tlsClientAuthSanURI string + expectErr bool + }{ + { + name: "test_build_with_authorization_code_no_redirect", + grantTypes: []string{GrantTypeAuthorizationCode}, + tokenAuthMethod: config.ClientSecretBasic, + expectErr: true, + }, + { + name: "test_build_client_secret", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.ClientSecretPost, + responseType: []string{AuthResponseToken}, + redirectURIs: []string{"http://localhost"}, + scopes: []string{"scope1", "scope2"}, + logoURI: "http://localhost", + }, + { + name: "test_build_with_private_key_jwt_no_jwks", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.PrivateKeyJWT, + responseType: []string{AuthResponseToken}, + expectErr: true, + }, + { + name: "test_build_with_private_key_jwt_invalid_jwks", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.PrivateKeyJWT, + responseType: []string{AuthResponseToken}, + publicKey: []byte("invalid-public-key"), + expectErr: true, + }, + { + name: "test_build_with_private_key_jwt_valid_jwks", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.PrivateKeyJWT, + responseType: []string{AuthResponseToken}, + publicKey: publicKey, + }, + { + name: "test_build_with_tls_client_auth_no_jwks", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + expectErr: true, + }, + { + name: "test_build_with_tls_client_auth_invalid_jwks", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: []byte("invalid-client-cert"), + expectErr: true, + }, + { + name: "test_build_with_tls_client_auth_valid_jwks_with_subject_dn", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: certificate, + tlsClientAuthSanDNS: "san-dns", + tlsClientAuthSanEmail: "san-email", + tlsClientAuthSanIP: "san-ip", + tlsClientAuthSanURI: "san-uri", + }, + { + name: "test_build_with_tls_client_auth_valid_jwks_with_san_dns", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: certificate, + certificateMetadata: TLSClientAuthSanDNS, + tlsClientAuthSanDNS: "san-dns", + tlsClientAuthSanEmail: "san-email", + tlsClientAuthSanIP: "san-ip", + tlsClientAuthSanURI: "san-uri", + }, + { + name: "test_build_with_tls_client_auth_valid_jwks_with_san_email", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: certificate, + certificateMetadata: TLSClientAuthSanEmail, + tlsClientAuthSanDNS: "san-dns", + tlsClientAuthSanEmail: "san-email", + tlsClientAuthSanIP: "san-ip", + tlsClientAuthSanURI: "san-uri", + }, + { + name: "test_build_with_tls_client_auth_valid_jwks_with_san_ip", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: certificate, + certificateMetadata: TLSClientAuthSanIP, + tlsClientAuthSanDNS: "san-dns", + tlsClientAuthSanEmail: "san-email", + tlsClientAuthSanIP: "san-ip", + tlsClientAuthSanURI: "san-uri", + }, + { + name: "test_build_with_tls_client_auth_valid_jwks_with_san_uri", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: certificate, + certificateMetadata: TLSClientAuthSanURI, + tlsClientAuthSanDNS: "san-dns", + tlsClientAuthSanEmail: "san-email", + tlsClientAuthSanIP: "san-ip", + tlsClientAuthSanURI: "san-uri", + }, + { + name: "test_build_with_tls_client_auth_valid_jwks_with_no_san_dns", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: certificate, + certificateMetadata: TLSClientAuthSanDNS, + expectErr: true, + }, + { + name: "test_build_with_tls_client_auth_valid_jwks_with_no_san_email", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: certificate, + certificateMetadata: TLSClientAuthSanEmail, + expectErr: true, + }, + { + name: "test_build_with_tls_client_auth_valid_jwks_with_no_san_ip", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: certificate, + certificateMetadata: TLSClientAuthSanIP, + expectErr: true, + }, + { + name: "test_build_with_tls_client_auth_valid_jwks_with_no_san_uri", + grantTypes: []string{GrantTypeClientCredentials}, + tokenAuthMethod: config.TLSClientAuth, + responseType: []string{AuthResponseToken}, + certificate: certificate, + certificateMetadata: TLSClientAuthSanURI, + expectErr: true, + }, + } + for _, tc := range cases { + builder := NewClientMetadataBuilder(). + SetClientName(tc.name). + SetGrantTypes(tc.grantTypes). + SetTokenEndpointAuthMethod(tc.tokenAuthMethod). + SetResponseType(tc.responseType). + SetRedirectURIs(tc.redirectURIs). + SetScopes(tc.scopes). + SetLogoURI(tc.logoURI) + if tc.publicKey != nil { + builder.SetJWKS(tc.publicKey) + } + if tc.certificate != nil { + builder.SetJWKS(tc.certificate). + SetCertificateMetadata(tc.certificateMetadata). + SetTLSClientAuthSanDNS(tc.tlsClientAuthSanDNS). + SetTLSClientAuthSanEmail(tc.tlsClientAuthSanEmail). + SetTLSClientAuthSanIP(tc.tlsClientAuthSanIP). + SetTLSClientAuthSanURI(tc.tlsClientAuthSanURI) + } - publicKey, err := util.ReadPublicKeyBytes("testdata/publickey") - assert.Nil(t, err) + client, err := builder.Build() + if tc.expectErr { + assert.NotNil(t, err) + } else { + assert.Nil(t, err) + assert.NotNil(t, client) + assert.Equal(t, tc.name, client.GetClientName()) + assert.Equal(t, tc.grantTypes, client.GetGrantTypes()) + assert.Equal(t, tc.tokenAuthMethod, client.GetTokenEndpointAuthMethod()) + assert.Equal(t, tc.responseType, client.GetResponseTypes()) + assert.Equal(t, tc.redirectURIs, client.GetRedirectURIs()) + assert.Equal(t, tc.scopes, client.GetScopes()) + assert.Equal(t, tc.logoURI, client.GetLogoURI()) - client, err = NewClientMetadataBuilder(). - SetClientName("test"). - SetGrantTypes([]string{"authorization_code"}). - SetJWKS(publicKey). - Build() + // assert client metadata + if tc.publicKey != nil { + assert.NotEmpty(t, client.GetJwks()) + } + if tc.certificate != nil { + assert.NotEmpty(t, client.GetJwks()) + switch tc.certificateMetadata { + case TLSClientAuthSanDNS: + assert.Equal(t, tc.tlsClientAuthSanDNS, client.GetTLSClientAuthSanDNS()) + assert.Equal(t, "", client.GetTLSClientAuthSanEmail()) + assert.Equal(t, "", client.GetTLSClientAuthSanIP()) + assert.Equal(t, "", client.GetTLSClientAuthSanURI()) + case TLSClientAuthSanEmail: + assert.Equal(t, tc.tlsClientAuthSanEmail, client.GetTLSClientAuthSanEmail()) + assert.Equal(t, "", client.GetTLSClientAuthSanDNS()) + assert.Equal(t, "", client.GetTLSClientAuthSanIP()) + assert.Equal(t, "", client.GetTLSClientAuthSanURI()) + case TLSClientAuthSanIP: + assert.Equal(t, tc.tlsClientAuthSanIP, client.GetTLSClientAuthSanIP()) + assert.Equal(t, "", client.GetTLSClientAuthSanDNS()) + assert.Equal(t, "", client.GetTLSClientAuthSanEmail()) + assert.Equal(t, "", client.GetTLSClientAuthSanURI()) + case TLSClientAuthSanURI: + assert.Equal(t, tc.tlsClientAuthSanURI, client.GetTLSClientAuthSanURI()) + assert.Equal(t, "", client.GetTLSClientAuthSanDNS()) + assert.Equal(t, "", client.GetTLSClientAuthSanEmail()) + assert.Equal(t, "", client.GetTLSClientAuthSanIP()) + } - assert.NotNil(t, err) - assert.Nil(t, client) + } + } + } } diff --git a/pkg/authz/oauth/clientsecretbasicauthenticator.go b/pkg/authz/oauth/clientsecretbasicauthenticator.go index 60e77d6f9..befbc5eae 100644 --- a/pkg/authz/oauth/clientsecretbasicauthenticator.go +++ b/pkg/authz/oauth/clientsecretbasicauthenticator.go @@ -2,9 +2,14 @@ package oauth import ( "encoding/base64" + "fmt" "net/url" ) +const ( + basicAuthHeaderTemplate = "Basic %s" +) + type clientSecretBasicAuthenticator struct { clientID string clientSecret string @@ -13,7 +18,7 @@ type clientSecretBasicAuthenticator struct { func (p *clientSecretBasicAuthenticator) prepareRequest() (url.Values, map[string]string, error) { v := url.Values{ - metaGrantType: []string{grantClientCredentials}, + metaGrantType: []string{GrantTypeClientCredentials}, } if p.scope != "" { @@ -22,7 +27,7 @@ func (p *clientSecretBasicAuthenticator) prepareRequest() (url.Values, map[strin token := base64.StdEncoding.EncodeToString([]byte(p.clientID + ":" + p.clientSecret)) headers := map[string]string{ - "Authorization": "Basic " + token, + hdrAuthorization: fmt.Sprintf(basicAuthHeaderTemplate, token), } return v, headers, nil } diff --git a/pkg/authz/oauth/clientsecretjwtauthenticator.go b/pkg/authz/oauth/clientsecretjwtauthenticator.go index 6d9057678..8a44a5b8b 100644 --- a/pkg/authz/oauth/clientsecretjwtauthenticator.go +++ b/pkg/authz/oauth/clientsecretjwtauthenticator.go @@ -9,17 +9,18 @@ import ( ) type clientSecretJwtAuthenticator struct { - clientID string - clientSecret string - scope string - issuer string - aud string + clientID string + clientSecret string + scope string + issuer string + aud string + signingMethod string } // prepareInitialToken prepares a token for an access request func (p *clientSecretJwtAuthenticator) prepareInitialToken() (string, error) { now := time.Now() - token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{ + token := jwt.NewWithClaims(getSigningMethod(p.signingMethod, jwt.SigningMethodHS256), jwt.StandardClaims{ Issuer: p.issuer, Subject: p.clientID, Audience: p.aud, @@ -43,7 +44,7 @@ func (p *clientSecretJwtAuthenticator) prepareRequest() (url.Values, map[string] } v := url.Values{ - metaGrantType: []string{grantClientCredentials}, + metaGrantType: []string{GrantTypeClientCredentials}, metaClientID: []string{p.clientID}, metaClientAssertionType: []string{assertionTypeJWT}, metaClientAssertion: []string{requestToken}, diff --git a/pkg/authz/oauth/clientsecretpostauthenticator.go b/pkg/authz/oauth/clientsecretpostauthenticator.go index bc68d2a82..e2a85d821 100644 --- a/pkg/authz/oauth/clientsecretpostauthenticator.go +++ b/pkg/authz/oauth/clientsecretpostauthenticator.go @@ -12,7 +12,7 @@ type clientSecretPostAuthenticator struct { func (p *clientSecretPostAuthenticator) prepareRequest() (url.Values, map[string]string, error) { v := url.Values{ - metaGrantType: []string{grantClientCredentials}, + metaGrantType: []string{GrantTypeClientCredentials}, metaClientID: []string{p.clientID}, } diff --git a/pkg/authz/oauth/constants.go b/pkg/authz/oauth/constants.go index 28f84a566..7100c86cc 100644 --- a/pkg/authz/oauth/constants.go +++ b/pkg/authz/oauth/constants.go @@ -23,12 +23,12 @@ const ( mimeApplicationFormURLEncoded = "application/x-www-form-urlencoded" mimeApplicationJSON = "application/json" - grantAuthorizationCode = "authorization_code" - grantImplicit = "implicit" - grantClientCredentials = "client_credentials" + GrantTypeAuthorizationCode = "authorization_code" + GrantTypeImplicit = "implicit" + GrantTypeClientCredentials = "client_credentials" - authResponseToken = "token" - authResponseCode = "code" + AuthResponseToken = "token" + AuthResponseCode = "code" assertionTypeJWT = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" @@ -38,4 +38,10 @@ const ( metaScope = "scope" metaClientAssertionType = "client_assertion_type" metaClientAssertion = "client_assertion" + + TLSClientAuthSubjectDN = "tls_client_auth_subject_dn" + TLSClientAuthSanDNS = "tls_client_auth_san_dns" + TLSClientAuthSanEmail = "tls_client_auth_san_email" + TLSClientAuthSanIP = "tls_client_auth_san_ip" + TLSClientAuthSanURI = "tls_client_auth_san_uri" ) diff --git a/pkg/authz/oauth/keypairauthenticator.go b/pkg/authz/oauth/keypairauthenticator.go index b675bc747..6e279acca 100644 --- a/pkg/authz/oauth/keypairauthenticator.go +++ b/pkg/authz/oauth/keypairauthenticator.go @@ -11,13 +11,55 @@ import ( "github.com/google/uuid" ) +const ( + SigningMethodRS256 = "RS256" + SigningMethodRS384 = "RS384" + SigningMethodRS512 = "RS512" + + SigningMethodES256 = "ES256" + SigningMethodES384 = "ES384" + SigningMethodES512 = "ES512" + + SigningMethodPS256 = "PS256" + SigningMethodPS384 = "PS384" + SigningMethodPS512 = "PS512" + + SigningMethodHS256 = "HS256" + SigningMethodHS384 = "HS384" + SigningMethodHS512 = "HS512" +) + +var signingMethodMap = map[string]jwt.SigningMethod{ + SigningMethodRS256: jwt.SigningMethodRS256, + SigningMethodRS384: jwt.SigningMethodRS384, + SigningMethodRS512: jwt.SigningMethodRS512, + SigningMethodES256: jwt.SigningMethodES256, + SigningMethodES384: jwt.SigningMethodES384, + SigningMethodES512: jwt.SigningMethodES512, + SigningMethodPS256: jwt.SigningMethodPS256, + SigningMethodPS384: jwt.SigningMethodPS384, + SigningMethodPS512: jwt.SigningMethodPS512, + SigningMethodHS256: jwt.SigningMethodHS256, + SigningMethodHS384: jwt.SigningMethodHS384, + SigningMethodHS512: jwt.SigningMethodHS512, +} + type keyPairAuthenticator struct { - clientID string - issuer string - aud string - privateKey *rsa.PrivateKey - publicKey []byte - scope string + clientID string + issuer string + aud string + privateKey *rsa.PrivateKey + publicKey []byte + scope string + signingMethod string +} + +func getSigningMethod(signingMethod string, defaultSigningMethod jwt.SigningMethod) jwt.SigningMethod { + sm, ok := signingMethodMap[signingMethod] + if !ok { + return defaultSigningMethod + } + return sm } // prepareInitialToken prepares a token for an access request @@ -26,7 +68,7 @@ func (p *keyPairAuthenticator) prepareInitialToken(kid string) (string, error) { if p.issuer == "" { p.issuer = fmt.Sprintf("%s:%s", assertionTypeJWT, p.clientID) } - token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.StandardClaims{ + token := jwt.NewWithClaims(getSigningMethod(p.signingMethod, jwt.SigningMethodRS256), jwt.StandardClaims{ Issuer: p.issuer, Subject: p.clientID, Audience: p.aud, @@ -57,7 +99,7 @@ func (p *keyPairAuthenticator) prepareRequest() (url.Values, map[string]string, } v := url.Values{ - metaGrantType: []string{grantClientCredentials}, + metaGrantType: []string{GrantTypeClientCredentials}, metaClientAssertionType: []string{assertionTypeJWT}, metaClientAssertion: []string{requestToken}, } diff --git a/pkg/authz/oauth/mockidpserver.go b/pkg/authz/oauth/mockidpserver.go index f757fd8ab..4dee839a5 100644 --- a/pkg/authz/oauth/mockidpserver.go +++ b/pkg/authz/oauth/mockidpserver.go @@ -2,9 +2,11 @@ package oauth import ( "encoding/json" - "io/ioutil" + "fmt" + "io" "net/http" "net/http/httptest" + "net/url" "strings" "time" @@ -20,6 +22,8 @@ type MockIDPServer interface { SetMetadataResponseCode(statusCode int) SetTokenResponse(accessToken string, expiry time.Duration, statusCode int) SetRegistrationResponseCode(statusCode int) + GetTokenRequestHeaders() http.Header + GetTokenRequestValues() url.Values Close() } @@ -31,6 +35,8 @@ type mockIDPServer struct { tokenExpiry time.Duration serverMetadata *AuthorizationServerMetadata server *httptest.Server + tokenReqHeaders http.Header + tokenReqValues url.Values } // NewMockIDPServer - creates a new mock IDP server for tests @@ -65,6 +71,16 @@ func (m *mockIDPServer) handleRequest(resp http.ResponseWriter, req *http.Reques resp.Write(buf) } if strings.Contains(req.RequestURI, "/token") { + m.tokenReqHeaders = req.Header + m.tokenReqValues = nil + reqBuf, _ := io.ReadAll(req.Body) + if len(reqBuf) != 0 { + fmt.Printf("%s\n", string(reqBuf)) + val, err := url.ParseQuery(string(reqBuf)) + if err == nil { + m.tokenReqValues = val + } + } defer func() { m.tokenResponseCode = http.StatusOK m.accessToken = "" @@ -93,7 +109,7 @@ func (m *mockIDPServer) handleRequest(resp http.ResponseWriter, req *http.Reques return } resp.WriteHeader(http.StatusCreated) - clientBuf, _ := ioutil.ReadAll(req.Body) + clientBuf, _ := io.ReadAll(req.Body) cl := &clientMetadata{} json.Unmarshal(clientBuf, cl) cl.ClientID = uuid.New().String() @@ -145,6 +161,14 @@ func (m *mockIDPServer) SetRegistrationResponseCode(statusCode int) { m.registerResponseCode = statusCode } +func (m *mockIDPServer) GetTokenRequestHeaders() http.Header { + return m.tokenReqHeaders +} + +func (m *mockIDPServer) GetTokenRequestValues() url.Values { + return m.tokenReqValues +} + func (m *mockIDPServer) Close() { m.server.Close() } diff --git a/pkg/authz/oauth/oktaprovider.go b/pkg/authz/oauth/oktaprovider.go index 6b1e57415..2490113cd 100644 --- a/pkg/authz/oauth/oktaprovider.go +++ b/pkg/authz/oauth/oktaprovider.go @@ -24,7 +24,7 @@ func (i *okta) preProcessClientRequest(clientRequest *clientMetadata) { } for _, grantTypes := range clientRequest.GrantTypes { - if grantTypes != grantClientCredentials { + if grantTypes != GrantTypeClientCredentials { appType = oktaAppTypeWeb } } diff --git a/pkg/authz/oauth/provider.go b/pkg/authz/oauth/provider.go index 30f1fcea7..6c4d386b1 100644 --- a/pkg/authz/oauth/provider.go +++ b/pkg/authz/oauth/provider.go @@ -21,6 +21,7 @@ type Provider interface { GetTitle() string GetIssuer() string GetTokenEndpoint() string + GetMTLSTokenEndpoint() string GetAuthorizationEndpoint() string GetSupportedScopes() []string GetSupportedGrantTypes() []string @@ -82,7 +83,6 @@ func NewProvider(idp corecfg.IDPConfig, tlsCfg corecfg.TLSConfig, proxyURL strin } p.authServerMetadata = metadata - // No OAuth client is needed to request token for access token based authentication to IdP if p.cfg.GetAuthConfig() != nil && p.cfg.GetAuthConfig().GetType() != corecfg.AccessToken { p.authClient, err = p.createAuthClient() @@ -155,6 +155,7 @@ func (p *provider) createClientSecretJWTAuthClient() (AuthClient, error) { p.cfg.GetAuthConfig().GetClientScope(), p.cfg.GetAuthConfig().GetClientID(), p.authServerMetadata.Issuer, + p.cfg.GetAuthConfig().GetTokenSigningMethod(), )) } @@ -182,12 +183,13 @@ func (p *provider) createPrivateKeyJWTAuthClient() (AuthClient, error) { privateKey, publicKey, p.cfg.GetAuthConfig().GetClientScope(), + p.cfg.GetAuthConfig().GetTokenSigningMethod(), ), ) } func (p *provider) createTLSAuthClient() (AuthClient, error) { - return NewAuthClient(p.GetTokenEndpoint(), p.apiClient, + return NewAuthClient(p.GetMTLSTokenEndpoint(), p.apiClient, WithServerName(p.cfg.GetIDPName()), WithTLSClientAuth(p.cfg.GetAuthConfig().GetClientID(), p.cfg.GetAuthConfig().GetClientScope())) } @@ -219,8 +221,12 @@ func (p *provider) useTLSAuth() bool { // GetTokenEndpoint - return the token endpoint URL func (p *provider) GetTokenEndpoint() string { + return p.authServerMetadata.TokenEndpoint +} + +func (p *provider) GetMTLSTokenEndpoint() string { if p.authServerMetadata != nil { - if p.useTLSAuth() && p.authServerMetadata.MTLSEndPointAlias != nil && p.authServerMetadata.MTLSEndPointAlias.TokenEndpoint != "" { + if p.authServerMetadata.MTLSEndPointAlias != nil && p.authServerMetadata.MTLSEndPointAlias.TokenEndpoint != "" { return p.authServerMetadata.MTLSEndPointAlias.TokenEndpoint } return p.authServerMetadata.TokenEndpoint @@ -269,6 +275,15 @@ func (p *provider) GetSupportedResponseMethod() []string { return []string{""} } +func (p *provider) getClientRegistraionEndpoint() string { + registrationEndpoint := p.authServerMetadata.RegistrationEndpoint + if p.useTLSAuth() && + p.authServerMetadata.MTLSEndPointAlias != nil && p.authServerMetadata.MTLSEndPointAlias.RegistrationEndpoint != "" { + registrationEndpoint = p.authServerMetadata.MTLSEndPointAlias.RegistrationEndpoint + } + return registrationEndpoint +} + // RegisterClient - register the OAuth client with IDP func (p *provider) RegisterClient(clientReq ClientMetadata) (ClientMetadata, error) { authPrefix := p.idpType.getAuthorizationHeaderPrefix() @@ -294,7 +309,7 @@ func (p *provider) RegisterClient(clientReq ClientMetadata) (ClientMetadata, err request := coreapi.Request{ Method: coreapi.POST, - URL: p.authServerMetadata.RegistrationEndpoint, + URL: p.getClientRegistraionEndpoint(), Headers: header, Body: clientBuffer, } @@ -362,7 +377,7 @@ func (p *provider) applyClientDefaults(clientRequest *clientMetadata) { if len(clientRequest.ResponseTypes) == 0 { defaultAuthResponseType := p.cfg.GetAuthResponseType() if defaultAuthResponseType == "" { - defaultAuthResponseType = authResponseToken + defaultAuthResponseType = AuthResponseToken } clientRequest.ResponseTypes = []string{defaultAuthResponseType} } @@ -370,9 +385,9 @@ func (p *provider) applyClientDefaults(clientRequest *clientMetadata) { func (p *provider) preProcessResponseType(clientRequest *clientMetadata) { for _, grantTypes := range clientRequest.GrantTypes { - if grantTypes == grantAuthorizationCode { + if grantTypes == GrantTypeAuthorizationCode { if !p.hasCodeResponseMethod(clientRequest) { - clientRequest.ResponseTypes = []string{authResponseCode} + clientRequest.ResponseTypes = []string{AuthResponseCode} } } } @@ -380,7 +395,7 @@ func (p *provider) preProcessResponseType(clientRequest *clientMetadata) { func (p *provider) hasCodeResponseMethod(clientRequest *clientMetadata) bool { for _, authResponseMethod := range clientRequest.ResponseTypes { - if authResponseMethod == authResponseCode { + if authResponseMethod == AuthResponseCode { return true } } @@ -401,7 +416,7 @@ func (p *provider) UnregisterClient(clientID string) error { request := coreapi.Request{ Method: coreapi.DELETE, - URL: p.authServerMetadata.RegistrationEndpoint + "/" + clientID, + URL: p.getClientRegistraionEndpoint() + "/" + clientID, Headers: header, } diff --git a/pkg/authz/oauth/provider_test.go b/pkg/authz/oauth/provider_test.go index 34974c544..36b5d8df4 100644 --- a/pkg/authz/oauth/provider_test.go +++ b/pkg/authz/oauth/provider_test.go @@ -19,13 +19,13 @@ func TestRegistration(t *testing.T) { Type: "okta", MetadataURL: s.GetMetadataURL(), AuthConfig: &config.IDPAuthConfiguration{ - Type: "client", + Type: config.Client, ClientID: "test", ClientSecret: "test", }, - GrantType: "client_credentials", + GrantType: GrantTypeClientCredentials, ClientScopes: "read,write", - AuthMethod: "client_secret_basic", + AuthMethod: config.ClientSecretBasic, AuthResponseType: "", ExtraProperties: config.ExtraProperties{"key": "value"}, } diff --git a/pkg/authz/oauth/providerregistry.go b/pkg/authz/oauth/providerregistry.go index 2cbd1b417..548ecab35 100644 --- a/pkg/authz/oauth/providerregistry.go +++ b/pkg/authz/oauth/providerregistry.go @@ -10,9 +10,10 @@ import ( ) const ( - issuerKeyPrefix = "issuer:" - tokenEpKeyPrefix = "tokenEp:" - authEpKeyPrefix = "authEp:" + issuerKeyPrefix = "issuer:" + tokenEpKeyPrefix = "tokenEp:" + mtlsTokenEpKeyPrefix = "mtlsTokenEp:" + authEpKeyPrefix = "authEp:" ) // ProviderRegistry - interface for provider registry @@ -55,6 +56,7 @@ func (r *providerRegistry) RegisterProvider(idp corecfg.IDPConfig, tlsCfg corecf name := p.GetName() issuer := p.GetIssuer() tokenEndpoint := p.GetTokenEndpoint() + mtlsTokenEndpoint := p.GetMTLSTokenEndpoint() authEndPoint := p.GetAuthorizationEndpoint() r.logger. @@ -67,6 +69,9 @@ func (r *providerRegistry) RegisterProvider(idp corecfg.IDPConfig, tlsCfg corecf r.providerMap.Set(name, p) r.providerMap.SetSecondaryKey(name, issuerKeyPrefix+issuer) r.providerMap.SetSecondaryKey(name, tokenEpKeyPrefix+tokenEndpoint) + if mtlsTokenEndpoint != "" { + r.providerMap.SetSecondaryKey(name, mtlsTokenEpKeyPrefix+mtlsTokenEndpoint) + } r.providerMap.SetSecondaryKey(name, authEpKeyPrefix+authEndPoint) return nil @@ -93,7 +98,11 @@ func (r *providerRegistry) GetProviderByIssuer(issuer string) (Provider, error) // GetProviderByTokenEndpoint - returns the provider from registry based on the IDP token endpoint func (r *providerRegistry) GetProviderByTokenEndpoint(tokenEndpoint string) (Provider, error) { - return r.getProviderBySecondaryKey(tokenEpKeyPrefix + tokenEndpoint) + p, err := r.getProviderBySecondaryKey(mtlsTokenEpKeyPrefix + tokenEndpoint) + if err != nil { + p, err = r.getProviderBySecondaryKey(tokenEpKeyPrefix + tokenEndpoint) + } + return p, err } // GetProviderByAuthorizationEndpoint - returns the provider from registry based on the IDP authorization endpoint diff --git a/pkg/authz/oauth/testdata/client_cert.pem b/pkg/authz/oauth/testdata/client_cert.pem new file mode 100644 index 000000000..97af5092d --- /dev/null +++ b/pkg/authz/oauth/testdata/client_cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDQTCCAikCFBTdXwdbrWLRWO2Fn5YXOL6qqkkWMA0GCSqGSIb3DQEBCwUAMF0x +CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJBWjEMMAoGA1UEBwwDUEhYMQ4wDAYDVQQK +DAVBeHdheTELMAkGA1UECwwCUkQxFjAUBgNVBAMMDWF4d2F5dGVzdC5uZXQwHhcN +MjMwODE1MDAwMTExWhcNMjQwODE0MDAwMTExWjBdMQswCQYDVQQGEwJVUzELMAkG +A1UECAwCQVoxDDAKBgNVBAcMA1BIWDEOMAwGA1UECgwFQXh3YXkxCzAJBgNVBAsM +AlJEMRYwFAYDVQQDDA1heHdheXRlc3QubmV0MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEApGtiWolBpdydWaYRGuzVFpmxpONUnnsO3WjTuZ1/3UkYUynF +uE68YrWfFCa+AzeuRHgSCdkGX/QVqEZaFVolk0JCFs+AvuFmMl6JZhejwpt2h/pb +nfVaFAi8GXlPkE2l3ANRi+kzssaSqaXduR2RlVLJ8+lPlV91naTnfd8zXl4Z5amQ +5m6ZAP8vIiuk9MIpYAG88HzissDES3fKnHHn9v3pxe0zS0IZX0hvGBjBGU561UpC +56sdxbfnxCm/NuQLtPEeQfYj9pd8YZoC40h9TefKVDQCD8Fimo3n3xZ26KZYTVcy +DY205PC7/IMR39L29pqUyS3rlLzbaFbDm21MwwIDAQABMA0GCSqGSIb3DQEBCwUA +A4IBAQASi73LdEfBDnk+n4UFdiBWFgiGHiZQX/2Sqf6HeFSyFWybkFxbz5s8JZ2y +YqfWk0q4r8V+AL7Kp8Stc532+GADFvCde3Bkx1L0ai8MsalGru2RQX5kogZ/p3Zi +8MXtGbIQh+DIDLgmn5gwAswtIcHAaH3GxfGiKNOR3MKWnenTvGAQIb/1PCJjclzG +DrAO1dkP6m37D2CqJANz2Q2HcZk699NgfQvTvF3KHZ+xnQINAT0v8UmmKYyv6NDo +ZjBobjPEKlgOczELcuSK7eUqnSrv/f6xOUW0OnqCgZjeHxiQyPahwO/a066Z3rNS +4ZXLLJ2BMOV29qL3sfujLYxlWcb+ +-----END CERTIFICATE----- diff --git a/pkg/authz/oauth/tlsclientauthenticator.go b/pkg/authz/oauth/tlsclientauthenticator.go index 68384313c..c980bea91 100644 --- a/pkg/authz/oauth/tlsclientauthenticator.go +++ b/pkg/authz/oauth/tlsclientauthenticator.go @@ -9,7 +9,7 @@ type tlsClientAuthenticator struct { func (p *tlsClientAuthenticator) prepareRequest() (url.Values, map[string]string, error) { v := url.Values{ - metaGrantType: []string{grantClientCredentials}, + metaGrantType: []string{GrantTypeClientCredentials}, metaClientID: []string{p.clientID}, } diff --git a/pkg/config/externalidpconfig.go b/pkg/config/externalidpconfig.go index 9d03694d7..d3c221b0e 100644 --- a/pkg/config/externalidpconfig.go +++ b/pkg/config/externalidpconfig.go @@ -18,29 +18,30 @@ const ( TLSClientAuth = "tls_client_auth" SelfSignedTLSClientAuth = "self_signed_tls_client_auth" - propInsecureSkipVerify = "insecureSkipVerify" - pathExternalIDP = "agentFeatures.idp" - fldName = "name" - fldTitle = "title" - fldType = "type" - fldMetadataURL = "metadataUrl" - fldExtraProperties = "extraProperties" - fldScope = "scope" - fldGrantType = "grantType" - fldAuthMethod = "authMethod" - fldAuthResponseType = "authResponseType" - fldAuthType = "auth.type" - fldAuthAccessToken = "auth.accessToken" - fldAuthClientID = "auth.clientId" - fldAuthClientSecret = "auth.clientSecret" - fldAuthClientScope = "auth.clientScope" - fldAuthPrivateKey = "auth.privateKey" - fldAuthPublicKey = "auth.publicKey" - fldAuthKeyPassword = "auth.keyPassword" - fldSSLInsecureSkipVerify = "ssl." + propInsecureSkipVerify - fldSSLRootCACertPath = "ssl.rootCACertPath" - fldSSLClientCertPath = "ssl.clientCertPath" - fldSSLClientKeyPath = "ssl.clientKeyPath" + propInsecureSkipVerify = "insecureSkipVerify" + pathExternalIDP = "agentFeatures.idp" + fldName = "name" + fldTitle = "title" + fldType = "type" + fldMetadataURL = "metadataUrl" + fldExtraProperties = "extraProperties" + fldScope = "scope" + fldGrantType = "grantType" + fldAuthMethod = "authMethod" + fldAuthResponseType = "authResponseType" + fldAuthType = "auth.type" + fldAuthAccessToken = "auth.accessToken" + fldAuthClientID = "auth.clientId" + fldAuthClientSecret = "auth.clientSecret" + fldAuthClientScope = "auth.clientScope" + fldAuthPrivateKey = "auth.privateKey" + fldAuthPublicKey = "auth.publicKey" + fldAuthKeyPassword = "auth.keyPassword" + fldAuthTokenSigningMethod = "auth.tokenSigningMethod" + fldSSLInsecureSkipVerify = "ssl." + propInsecureSkipVerify + fldSSLRootCACertPath = "ssl.rootCACertPath" + fldSSLClientCertPath = "ssl.clientCertPath" + fldSSLClientKeyPath = "ssl.clientKeyPath" ) var configProperties = []string{ @@ -65,6 +66,7 @@ var configProperties = []string{ fldAuthPrivateKey, fldAuthPublicKey, fldAuthKeyPassword, + fldAuthTokenSigningMethod, } var validIDPAuthType = map[string]bool{ @@ -147,6 +149,8 @@ type IDPAuthConfig interface { GetPublicKey() string // GetKeyPassword() - public key to be used for private_key_jwt authentication GetKeyPassword() string + // GetSigningMethod() - the token signing method for private_key_jwt authentication + GetTokenSigningMethod() string } // IDPConfig - interface for IdP provider config @@ -179,14 +183,15 @@ type IDPConfig interface { // IDPAuthConfiguration - Structure to hold the IdP provider auth config type IDPAuthConfiguration struct { - Type string `json:"type,omitempty"` - AccessToken string `json:"accessToken,omitempty"` - ClientID string `json:"clientId,omitempty"` - ClientSecret string `json:"clientSecret,omitempty"` - ClientScope string `json:"clientScope,omitempty"` - PrivateKey string `json:"privateKey,omitempty"` - PublicKey string `json:"publicKey,omitempty"` - KeyPwd string `json:"keyPassword,omitempty"` + Type string `json:"type,omitempty"` + AccessToken string `json:"accessToken,omitempty"` + ClientID string `json:"clientId,omitempty"` + ClientSecret string `json:"clientSecret,omitempty"` + ClientScope string `json:"clientScope,omitempty"` + PrivateKey string `json:"privateKey,omitempty"` + PublicKey string `json:"publicKey,omitempty"` + KeyPwd string `json:"keyPassword,omitempty"` + TokenSigningMethod string `json:"tokenSigningMethod,omitempty"` } // IDPConfiguration - Structure to hold the IdP provider config @@ -315,6 +320,11 @@ func (i *IDPAuthConfiguration) GetKeyPassword() string { return i.KeyPwd } +// GetTokenSigningMethod - +func (i *IDPAuthConfiguration) GetTokenSigningMethod() string { + return i.TokenSigningMethod +} + // validate - Validates the IDP auth configuration func (i *IDPAuthConfiguration) validate(tlsCfg TLSConfig) { if ok := validIDPAuthType[i.GetType()]; !ok {