diff --git a/go.mod b/go.mod index c8977cc..c4993e1 100644 --- a/go.mod +++ b/go.mod @@ -7,11 +7,14 @@ require ( github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 github.com/stretchr/testify v1.9.0 golang.org/x/oauth2 v0.23.0 + sigs.k8s.io/yaml v1.4.0 ) require ( github.com/davecgh/go-spew v1.1.1 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/crypto v0.22.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index e4f1bdb..9ec60fb 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -5,8 +6,18 @@ github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7 github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +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/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466 h1:17JxqqJY66GmZVHkmAsGEkcIu0oCe3AM420QDgGwZx0= github.com/shurcooL/graphql v0.0.0-20230722043721-ed46e5a46466/go.mod h1:9dIRpgIY7hVhoqfe0/FcYp0bpInZaT7dc3BYOprrIUE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -55,8 +66,11 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/internal/signer/signer.go b/internal/signer/signer.go index 18480de..d896022 100644 --- a/internal/signer/signer.go +++ b/internal/signer/signer.go @@ -6,7 +6,6 @@ package signer import ( "crypto/ecdsa" "crypto/x509" - "encoding/json" "encoding/pem" "errors" "time" @@ -14,6 +13,7 @@ import ( jose "github.com/go-jose/go-jose/v3" jwt "github.com/go-jose/go-jose/v3/jwt" "golang.org/x/oauth2" + "sigs.k8s.io/yaml" ) const serviceAccountIssuer = "mondoo/ams" @@ -54,7 +54,7 @@ func privateKeyFromBytes(bytes []byte) (*ecdsa.PrivateKey, error) { func NewServiceAccountTokenSource(data []byte) (*serviceAccountTokenSource, *serviceAccountCredentials, error) { var credentials *serviceAccountCredentials - err := json.Unmarshal(data, &credentials) + err := yaml.Unmarshal(data, &credentials) if credentials == nil || err != nil { return nil, nil, errors.New("valid service account needs to be provided") } diff --git a/internal/signer/signer_internal_test.go b/internal/signer/signer_internal_test.go new file mode 100644 index 0000000..3419b24 --- /dev/null +++ b/internal/signer/signer_internal_test.go @@ -0,0 +1,42 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package signer + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "crypto/x509" + "encoding/pem" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPrivateKeyFromBytes(t *testing.T) { + t.Run("Valid ECDSA Private Key", func(t *testing.T) { + privKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + privKeyBytes, _ := x509.MarshalPKCS8PrivateKey(privKey) + pemBlock := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privKeyBytes}) + + key, err := privateKeyFromBytes(pemBlock) + assert.NoError(t, err) + assert.NotNil(t, key) + assert.IsType(t, &ecdsa.PrivateKey{}, key) + }) + + t.Run("Invalid PEM Format", func(t *testing.T) { + _, err := privateKeyFromBytes([]byte("invalid-pem")) + assert.ErrorIs(t, err, ErrAuthKeyNotPem) + }) + + t.Run("Invalid Private Key Type", func(t *testing.T) { + // Generate an RSA private key (unsupported for this function) + rsaKey, _ := x509.MarshalPKCS8PrivateKey(&struct{}{}) + pemBlock := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: rsaKey}) + + _, err := privateKeyFromBytes(pemBlock) + assert.ErrorContains(t, err, "syntax error: sequence truncated") + }) +} diff --git a/internal/signer/signer_test.go b/internal/signer/signer_test.go new file mode 100644 index 0000000..37b1394 --- /dev/null +++ b/internal/signer/signer_test.go @@ -0,0 +1,59 @@ +// Copyright (c) Mondoo, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package signer_test + +import ( + "testing" + + "github.com/stretchr/testify/assert" + + subject "go.mondoo.com/mondoo-go/internal/signer" +) + +func TestNewServiceAccountTokenSource(t *testing.T) { + t.Run("Invalid Data", func(t *testing.T) { + data := []byte("invalid-yaml-data") + + tokenSource, creds, err := subject.NewServiceAccountTokenSource(data) + + assert.Nil(t, tokenSource) + assert.Nil(t, creds) + assert.Error(t, err) + assert.Equal(t, "valid service account needs to be provided", err.Error()) + }) + + t.Run("Invalid Private Key", func(t *testing.T) { + credentials := []byte(` +certificate: | + -----BEGIN CERTIFICATE----- + foo + -----END CERTIFICATE----- +force: false +mrn: //test.api.mondoo.app/spaces/test-796596/serviceaccounts/abc +private_key: | + invalid-pem-key +space_mrn: //captain.api.mondoo.app/spaces/test-796596 +`) + + tokenSource, creds, err := subject.NewServiceAccountTokenSource(credentials) + + assert.Nil(t, tokenSource) + assert.Nil(t, creds) + assert.Error(t, err) + assert.Contains(t, err.Error(), "valid service account needs to be provided") + }) + + t.Run("Missing Private Key in Credentials in YAML format", func(t *testing.T) { + credentials := []byte(` +mrn: //test.api.mondoo.app/spaces/test-796596/serviceaccounts/abc +space_mrn: //captain.api.mondoo.app/spaces/test-796596 +`) + + tokenSource, creds, err := subject.NewServiceAccountTokenSource(credentials) + assert.Nil(t, tokenSource) + assert.Nil(t, creds) + assert.Error(t, err) + assert.Contains(t, err.Error(), "cannot load retrieved key") + }) +}