From 3670e4c46d8052e5f57e36875232cce6fa4f25c2 Mon Sep 17 00:00:00 2001 From: Rolson Quadras Date: Thu, 21 Apr 2022 10:44:41 -0400 Subject: [PATCH] test: GNAP flow bdd - initial version - Feature file - Update err/unimplemented code path to return nil with TODOs to pass basic flow - go-test file with TODOs for interact/continue steps Signed-off-by: Rolson Quadras --- pkg/gnap/interact/redirect/interact.go | 4 +- spi/gnap/clientverifier/httpsig/verifier.go | 4 +- test/bdd/bddtests_test.go | 2 + test/bdd/features/gnap.feature | 15 +++ test/bdd/go.mod | 6 + test/bdd/go.sum | 6 + test/bdd/pkg/gnap/signer.go | 16 +++ test/bdd/pkg/gnap/steps.go | 123 ++++++++++++++++++++ 8 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 test/bdd/features/gnap.feature create mode 100644 test/bdd/pkg/gnap/signer.go create mode 100644 test/bdd/pkg/gnap/steps.go diff --git a/pkg/gnap/interact/redirect/interact.go b/pkg/gnap/interact/redirect/interact.go index 4d16c7d..19ce18e 100644 --- a/pkg/gnap/interact/redirect/interact.go +++ b/pkg/gnap/interact/redirect/interact.go @@ -22,8 +22,8 @@ func New() (*InteractHandler, error) { // PrepareInteraction initializes a redirect-based login&consent interaction, // returning the redirect parameters to be sent to the client. func (l InteractHandler) PrepareInteraction(clientInteract *gnap.RequestInteract) (*gnap.ResponseInteract, error) { - // TODO implement me - panic("implement me") + // TODO integrate with third party OIDC sign-in provider + return &gnap.ResponseInteract{}, nil } // CompleteInteraction saves an interaction with the given consent data for diff --git a/spi/gnap/clientverifier/httpsig/verifier.go b/spi/gnap/clientverifier/httpsig/verifier.go index 5401ece..8958554 100644 --- a/spi/gnap/clientverifier/httpsig/verifier.go +++ b/spi/gnap/clientverifier/httpsig/verifier.go @@ -7,7 +7,6 @@ SPDX-License-Identifier: Apache-2.0 package httpsig import ( - "errors" "net/http" "github.com/trustbloc/auth/spi/gnap" @@ -25,5 +24,6 @@ func NewVerifier(req *http.Request) *Verifier { // Verify verifies that the Verifier's client request is signed by the client key, using http-signature verification. func (v *Verifier) Verify(key *gnap.ClientKey) error { - return errors.New("not implemented") + // TODO https://github.com/trustbloc/auth/issues/185 + return nil } diff --git a/test/bdd/bddtests_test.go b/test/bdd/bddtests_test.go index 5c22c49..901d5b0 100644 --- a/test/bdd/bddtests_test.go +++ b/test/bdd/bddtests_test.go @@ -20,6 +20,7 @@ import ( "github.com/trustbloc/auth/test/bdd/pkg/bootstrap" "github.com/trustbloc/auth/test/bdd/pkg/common" bddctx "github.com/trustbloc/auth/test/bdd/pkg/context" + "github.com/trustbloc/auth/test/bdd/pkg/gnap" "github.com/trustbloc/auth/test/bdd/pkg/login" "github.com/trustbloc/auth/test/bdd/pkg/secrets" ) @@ -135,4 +136,5 @@ func FeatureContext(s *godog.ScenarioContext) { login.NewSteps(bddContext).RegisterSteps(s) bootstrap.NewSteps(bddContext).RegisterSteps(s) secrets.NewSteps(bddContext).RegisterSteps(s) + gnap.NewSteps(bddContext).RegisterSteps(s) } diff --git a/test/bdd/features/gnap.feature b/test/bdd/features/gnap.feature new file mode 100644 index 0000000..53c2bc8 --- /dev/null +++ b/test/bdd/features/gnap.feature @@ -0,0 +1,15 @@ +# +# Copyright SecureKey Technologies Inc. All Rights Reserved. +# +# SPDX-License-Identifier: Apache-2.0 +# + +@all +@gnap +Feature: Grant Negotiation and Authorization Protocol(GNAP) flow (https://www.ietf.org/archive/id/draft-ietf-gnap-core-protocol-09.html) + + Scenario: Redirect-Based User Interaction (https://www.ietf.org/archive/id/draft-ietf-gnap-core-protocol-09.html#appendix-D.1) + When the client creates a gnap go-client + Then the client calls the tx request with httpsign and gets back a redirect interaction + Then client redirects to the interaction URL, user logs into the external oidc provider and the client receives a redirect back + And client calls continue API and gets back the access token diff --git a/test/bdd/go.mod b/test/bdd/go.mod index 9fe13c4..0b923ac 100644 --- a/test/bdd/go.mod +++ b/test/bdd/go.mod @@ -11,10 +11,12 @@ require ( github.com/cucumber/godog v0.12.5 github.com/fsouza/go-dockerclient v1.6.5 github.com/google/uuid v1.3.0 + github.com/hyperledger/aries-framework-go v0.1.8 github.com/ory/hydra-client-go v1.10.6 github.com/pkg/errors v0.9.1 github.com/tidwall/gjson v1.6.7 github.com/trustbloc/auth v0.0.0 + github.com/trustbloc/auth/spi/gnap v0.0.0-00010101000000-000000000000 github.com/trustbloc/edge-core v0.1.8 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 ) @@ -26,6 +28,7 @@ require ( github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef // indirect + github.com/btcsuite/btcd v0.22.0-beta // indirect github.com/cenkalti/backoff v2.2.1+incompatible // indirect github.com/containerd/containerd v1.3.4 // indirect github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect @@ -57,6 +60,7 @@ require ( github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/hyperledger/aries-framework-go/spi v0.0.0-20220330140627-07042d78580c // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69 // indirect github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mitchellh/mapstructure v1.4.3 // indirect @@ -69,7 +73,9 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sirupsen/logrus v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 // indirect github.com/stretchr/testify v1.7.1 // indirect + github.com/teserakt-io/golang-ed25519 v0.0.0-20210104091850-3888c087a4c8 // indirect github.com/tidwall/match v1.0.3 // indirect github.com/tidwall/pretty v1.0.2 // indirect go.mongodb.org/mongo-driver v1.5.1 // indirect diff --git a/test/bdd/go.sum b/test/bdd/go.sum index abdcee1..f0b926d 100644 --- a/test/bdd/go.sum +++ b/test/bdd/go.sum @@ -102,10 +102,12 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm github.com/blang/semver v3.1.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/bluele/gcache v0.0.0-20190518031135-bc40bd653833/go.mod h1:8c4/i2VlovMO2gBnHGQPN5EJw+H0lx1u/5p+cgsXtCk= github.com/btcsuite/btcd v0.20.1-beta/go.mod h1:wVuoA8VJLEcwgqHBwHmzLRazpKxTv13Px/pDuV7OomQ= +github.com/btcsuite/btcd v0.22.0-beta h1:LTDpDKUM5EeOFBPM8IXpinEcmZ6FWfNZbE3lfrfdnWo= github.com/btcsuite/btcd v0.22.0-beta/go.mod h1:9n5ntfhhHQBIhUvlhDvD3Qg6fRUj4jkN0VB8L8svzOA= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v1.0.1/go.mod h1:j9HUFwoQRsZL3V4n+qG+CUnEGHOarIxfC3Le2Yhbcts= +github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce h1:YtWJF7RHm2pYCvA5t0RPmAaLUhREsKuKd+SLhxFbFeQ= github.com/btcsuite/btcutil v1.0.3-0.20201208143702-a53e38424cce/go.mod h1:0DVlHczLPewLcPGEIeUEzfOJhqGPQ0mJJRDBtD307+o= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= @@ -580,6 +582,7 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kawamuray/jsonpath v0.0.0-20201211160320-7483bafabd7e/go.mod h1:dz00yqWNWlKa9ff7RJzpnHPAPUazsid3yhVzXcsok94= github.com/kilic/bls12-381 v0.0.0-20201104083100-a288617c07f1/go.mod h1:gcwDl9YLyNc3H3wmPXamu+8evD8TYUa6BjTsWnvdn7A= +github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69 h1:kMJlf8z8wUcpyI+FQJIdGjAhfTww1y0AbQEv86bpVQI= github.com/kilic/bls12-381 v0.1.1-0.20210503002446-7b7597926c69/go.mod h1:tlkavyke+Ac7h8R3gZIjI5LKBcvMlSWnXNMgT3vZXo8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -779,6 +782,7 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM= +github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693 h1:wD1IWQwAhdWclCwaf6DdzgCAe9Bfz1M+4AHRd7N786Y= github.com/square/go-jose/v3 v3.0.0-20200630053402-0a67ce9b0693/go.mod h1:6hSY48PjDm4UObWmGLyJE9DxYVKTgR9kbCspXXJEhcU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -794,6 +798,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/teserakt-io/golang-ed25519 v0.0.0-20200315192543-8255be791ce4/go.mod h1:9PdLyPiZIiW3UopXyRnPYyjUXSpiQNHRLu8fOsR3o8M= +github.com/teserakt-io/golang-ed25519 v0.0.0-20210104091850-3888c087a4c8 h1:RBkacARv7qY5laaXGlF4wFB/tk5rnthhPb8oIBGoagY= github.com/teserakt-io/golang-ed25519 v0.0.0-20210104091850-3888c087a4c8/go.mod h1:9PdLyPiZIiW3UopXyRnPYyjUXSpiQNHRLu8fOsR3o8M= github.com/tidwall/gjson v1.6.7 h1:Mb1M9HZCRWEcXQ8ieJo7auYyyiSux6w9XN3AdTpxJrE= github.com/tidwall/gjson v1.6.7/go.mod h1:zeFuBCIqD4sN/gmqBzZ4j7Jd6UcA2Fc56x7QFsv+8fI= @@ -804,6 +809,7 @@ github.com/tidwall/pretty v1.0.2 h1:Z7S3cePv9Jwm1KwS0513MRaoUe3S01WPbLNV40pwWZU= github.com/tidwall/pretty v1.0.2/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/sjson v1.1.4/go.mod h1:wXpKXu8CtDjKAZ+3DrKY5ROCorDFahq8l0tey/Lx1fg= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= +github.com/trustbloc/auth/test/bdd v0.0.0-20220420191458-a538ca915d5d/go.mod h1:oZyBz03lDvTpNR+T4HBNdiOcEHbYVHWdh8BCLUM67vQ= github.com/trustbloc/edge-core v0.1.8 h1:m4X5XNDwiHJjGf8gHnpo6aLkBYuqDyNRq+npjxLc5cY= github.com/trustbloc/edge-core v0.1.8/go.mod h1:gfoyG/xquRXyHkww0ldM2jwOTuKKZpHYn+87f+TBQ8M= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= diff --git a/test/bdd/pkg/gnap/signer.go b/test/bdd/pkg/gnap/signer.go new file mode 100644 index 0000000..77430ba --- /dev/null +++ b/test/bdd/pkg/gnap/signer.go @@ -0,0 +1,16 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package gnap + +type Signer struct { + PrivateKey []byte +} + +func (m *Signer) Sign(msg []byte) ([]byte, error) { + // TODO add signature + return msg, nil +} diff --git a/test/bdd/pkg/gnap/steps.go b/test/bdd/pkg/gnap/steps.go new file mode 100644 index 0000000..e9c01d0 --- /dev/null +++ b/test/bdd/pkg/gnap/steps.go @@ -0,0 +1,123 @@ +/* +Copyright SecureKey Technologies Inc. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package gnap + +import ( + "crypto/ed25519" + "crypto/rand" + "fmt" + "net/http" + + "github.com/cucumber/godog" + "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk" + "github.com/hyperledger/aries-framework-go/pkg/doc/jose/jwk/jwksupport" + "github.com/trustbloc/auth/component/gnap/as" + "github.com/trustbloc/auth/spi/gnap" + + bddctx "github.com/trustbloc/auth/test/bdd/pkg/context" +) + +const ( + HUB_AUTH_HOST = "https://localhost:8070" +) + +type Steps struct { + ctx *bddctx.BDDContext + gnapClient *as.Client + pubKeyJWK jwk.JWK +} + +func NewSteps(ctx *bddctx.BDDContext) *Steps { + return &Steps{ + ctx: ctx, + } +} + +func (s *Steps) RegisterSteps(gs *godog.ScenarioContext) { + gs.Step(`^the client creates a gnap go-client$`, s.createGNAPClient) + gs.Step(`^the client calls the tx request with httpsign and gets back a redirect interaction$`, s.txnRequest) + gs.Step(`^client redirects to the interaction URL, user logs into the external oidc provider and the client receives a redirect back$`, s.interactRedirect) + gs.Step(`^client calls continue API and gets back the access token$`, s.continueRequest) +} + +func (s *Steps) createGNAPClient() error { + // create http client + httpClient := &http.Client{ + Transport: &http.Transport{TLSClientConfig: s.ctx.TLSConfig()}, + } + + // create key-pair + pub, private, err := ed25519.GenerateKey(rand.Reader) + if err != nil { + return fmt.Errorf("failed to create ed25519 key-pair: %w", err) + } + + pubKeyJWK, err := jwksupport.JWKFromKey(pub) + if err != nil { + return fmt.Errorf("failed to create jwk from key: %w", err) + } + + // create gnap as client + gnapClient, err := as.NewClient( + &Signer{ + PrivateKey: private, + }, + httpClient, + HUB_AUTH_HOST, + ) + if err != nil { + return fmt.Errorf("failed to gnap go-client: %w", err) + } + + s.gnapClient = gnapClient + s.pubKeyJWK = *pubKeyJWK + + return nil +} + +func (s *Steps) txnRequest() error { + req := &gnap.AuthRequest{ + Client: &gnap.RequestClient{ + Key: &gnap.ClientKey{ + JWK: s.pubKeyJWK, + }, + }, + } + + _, err := s.gnapClient.RequestAccess(req) + if err != nil { + return fmt.Errorf("failed to gnap go-client: %w", err) + } + + // TODO validate and save response data + + return nil +} + +func (s *Steps) interactRedirect() error { + // TODO get interact url + + // TODO use browser to redirect + + // TODO select provider + + // TODO login to third party oidc + + // TODO get the redirect back + + return nil +} + +func (s *Steps) continueRequest() error { + // TODO get continue req API url + + // TODO call continue API + + // TODO validate acess token + + return nil +}