From 77eddbaf1e4db5b70cc54c34f46b878134b8ae6a Mon Sep 17 00:00:00 2001 From: Christopher Swenson Date: Thu, 2 Nov 2023 12:27:30 -0700 Subject: [PATCH] Remove dependency on github.com/microsoftgraph/msgraph-sdk-go We only use msgraph-sdk-go for a handful of calls, and they are relatively straightforward HTTP calls. This code still uses the Microsoft packages for authentication, which is the trickier part. I'm having trouble getting the tests to pass consistently, but I always have trouble with these tests. I compiled the Vault binary with this change only, and it reduces the size of the Vault binary from 360 MB to 264 MB. --- Makefile | 2 +- client/msgraph.go | 210 +++++++++++++++++++++++++++++++++++++--------- go.mod | 11 +-- go.sum | 15 ---- 4 files changed, 172 insertions(+), 66 deletions(-) diff --git a/Makefile b/Makefile index cb962f50..67176845 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ bootstrap: fi .PHONY: test -test: fmtcheck +test: CGO_ENABLED=0 go test ./... $(TESTARGS) -timeout=20m .PHONY: fmtcheck diff --git a/client/msgraph.go b/client/msgraph.go index 5109c593..62b2702e 100644 --- a/client/msgraph.go +++ b/client/msgraph.go @@ -4,28 +4,83 @@ package client import ( + "bytes" "context" + "encoding/json" "fmt" + "io" + "net/http" + "net/url" "time" "github.com/Azure/azure-sdk-for-go/sdk/azcore" "github.com/google/uuid" - msgraphsdkgo "github.com/microsoftgraph/msgraph-sdk-go" + abs "github.com/microsoft/kiota-abstractions-go" auth "github.com/microsoftgraph/msgraph-sdk-go-core/authentication" - "github.com/microsoftgraph/msgraph-sdk-go/applications" - "github.com/microsoftgraph/msgraph-sdk-go/models" ) +type MSGraphApplication interface { + GetId() *string + GetPasswordCredentials() []Credentials // []Credentials +} + +type Credentials interface { + GetKeyId() *uuid.UUID + GetSecretText() *string + GetEndDateTime() *time.Time +} + +type APIApplicationValues struct { + Value []*APIApplication `json:"value"` +} + +type APIApplication struct { + ID string `json:"id"` + PasswordCredentials []APICredentials `json:"passwordCredentials"` +} + +func (a *APIApplication) GetId() *string { + return &a.ID +} + +func (a *APIApplication) GetPasswordCredentials() []Credentials { + x := a.PasswordCredentials + y := []Credentials{} + for _, z := range x { + y = append(y, &z) + } + return y +} + +type APICredentials struct { + KeyID *uuid.UUID `json:"keyId"` + SecretText *string `json:"secretText"` + EndDateTime *time.Time `json:"endDateTime"` +} + +func (a *APICredentials) GetKeyId() *uuid.UUID { + return a.KeyID +} + +func (a *APICredentials) GetSecretText() *string { + return a.SecretText +} + +func (a *APICredentials) GetEndDateTime() *time.Time { + return a.EndDateTime +} + type MSGraphClient interface { - GetApplication(ctx context.Context, clientID string) (models.Applicationable, error) - AddApplicationPassword(ctx context.Context, applicationObjectID string, displayName string, endDateTime time.Time) (models.PasswordCredentialable, error) + GetApplication(ctx context.Context, clientID string) (MSGraphApplication, error) + AddApplicationPassword(ctx context.Context, applicationObjectID string, displayName string, endDateTime time.Time) (Credentials, error) RemoveApplicationPassword(ctx context.Context, applicationObjectID string, keyID *uuid.UUID) error } var _ MSGraphClient = (*AppClient)(nil) type AppClient struct { - client *msgraphsdkgo.GraphServiceClient + baseUrl string + authProvider *auth.AzureIdentityAuthenticationProvider } // NewMSGraphApplicationClient returns a new AppClient configured to interact with @@ -41,63 +96,138 @@ func NewMSGraphApplicationClient(graphURI string, creds azcore.TokenCredential) if err != nil { return nil, err } - - adapter, err := msgraphsdkgo.NewGraphRequestAdapter(authProvider) - if err != nil { - return nil, err - } - - adapter.SetBaseUrl(fmt.Sprintf("%s/v1.0", graphURI)) - client := msgraphsdkgo.NewGraphServiceClient(adapter) - ac := &AppClient{ - client: client, + baseUrl: fmt.Sprintf("%s/v1.0", graphURI), + authProvider: authProvider, } + return ac, nil } -func (c *AppClient) GetApplication(ctx context.Context, clientID string) (models.Applicationable, error) { +func (c *AppClient) GetApplication(ctx context.Context, clientID string) (MSGraphApplication, error) { filter := fmt.Sprintf("appId eq '%s'", clientID) - req := applications.ApplicationsRequestBuilderGetRequestConfiguration{ - QueryParameters: &applications.ApplicationsRequestBuilderGetQueryParameters{ - Filter: &filter, - }, + query := "$filter=" + url.QueryEscape(filter) + u, err := url.Parse(fmt.Sprintf("%s/applications?%s", c.baseUrl, query)) + if err != nil { + return nil, err } - - resp, err := c.client.Applications().Get(ctx, &req) + req := abs.NewRequestInformation() + req.SetUri(*u) + err = c.authProvider.AuthenticateRequest(ctx, req, nil) if err != nil { return nil, err } + headers := map[string][]string{ + "accept": {"application/json"}, + "authorization": req.Headers.Get("Authorization"), + } + request := &http.Request{ + Method: "GET", + URL: u, + Header: headers, + } - apps := resp.GetValue() - if len(apps) == 0 { + resp, err := http.DefaultClient.Do(request) + if resp != nil && resp.Body != nil { + defer resp.Body.Close() + } + if resp.StatusCode != 200 { + return nil, fmt.Errorf("error from msgraph: %v", resp.StatusCode) + } + all, err := io.ReadAll(resp.Body) + apps := APIApplicationValues{} + err = json.Unmarshal(all, &apps) + if err != nil { + return nil, err + } + if len(apps.Value) == 0 { return nil, fmt.Errorf("no application found") } - if len(apps) > 1 { + if len(apps.Value) > 1 { return nil, fmt.Errorf("multiple applications found - double check your client_id") } - - return apps[0], nil + return apps.Value[0], nil } -func (c *AppClient) AddApplicationPassword(ctx context.Context, applicationObjectID string, displayName string, endDateTime time.Time) (models.PasswordCredentialable, error) { - requestBody := applications.NewItemAddPasswordPostRequestBody() - passwordCredential := models.NewPasswordCredential() - passwordCredential.SetDisplayName(&displayName) - passwordCredential.SetEndDateTime(&endDateTime) - requestBody.SetPasswordCredential(passwordCredential) - - resp, err := c.client.Applications().ByApplicationId(applicationObjectID).AddPassword().Post(ctx, requestBody, nil) +func (c *AppClient) AddApplicationPassword(ctx context.Context, applicationObjectID string, displayName string, endDateTime time.Time) (Credentials, error) { + bodyBytes, err := json.Marshal(map[string]interface{}{ + "passwordCredential": map[string]interface{}{ + "displayName": displayName, + "endDateTime": endDateTime, + }, + }) + if err != nil { + return nil, err + } + u, err := url.Parse(fmt.Sprintf("%s/applications/%s/addPassword", c.baseUrl, applicationObjectID)) if err != nil { return nil, err } + req := abs.NewRequestInformation() + req.SetUri(*u) + err = c.authProvider.AuthenticateRequest(ctx, req, nil) + if err != nil { + return nil, err + } + headers := map[string][]string{ + "content-type": {"application/json"}, + "authorization": req.Headers.Get("Authorization"), + } + request := &http.Request{ + Method: "POST", + URL: u, + Header: headers, + Body: io.NopCloser(bytes.NewBuffer(bodyBytes)), + } - return resp, nil + resp, err := http.DefaultClient.Do(request) + if resp != nil && resp.Body != nil { + defer resp.Body.Close() + } + if resp.StatusCode != 200 { + return nil, fmt.Errorf("error from msgraph: %v", resp.StatusCode) + } + all, err := io.ReadAll(resp.Body) + m := APICredentials{} + err = json.Unmarshal(all, &m) + if err != nil { + return nil, err + } + return &m, nil } func (c *AppClient) RemoveApplicationPassword(ctx context.Context, applicationObjectID string, keyID *uuid.UUID) error { - requestBody := applications.NewItemRemovePasswordPostRequestBody() - requestBody.SetKeyId(keyID) + bodyBytes, err := json.Marshal(map[string]interface{}{"keyId": keyID.String()}) + if err != nil { + return err + } + u, err := url.Parse(fmt.Sprintf("%s/applications/%s/removePassword", c.baseUrl, applicationObjectID)) + if err != nil { + return err + } + req := abs.NewRequestInformation() + req.SetUri(*u) + err = c.authProvider.AuthenticateRequest(ctx, req, nil) + if err != nil { + return err + } + headers := map[string][]string{ + "content-type": {"application/json"}, + "authorization": req.Headers.Get("Authorization"), + } + request := &http.Request{ + Method: "POST", + URL: u, + Header: headers, + Body: io.NopCloser(bytes.NewBuffer(bodyBytes)), + } - return c.client.Applications().ByApplicationId(applicationObjectID).RemovePassword().Post(ctx, requestBody, nil) + resp, err := http.DefaultClient.Do(request) + if resp != nil && resp.Body != nil { + defer resp.Body.Close() + } + if resp.StatusCode < 200 || resp.StatusCode >= 300 { + return fmt.Errorf("error from msgraph: %v", resp.StatusCode) + } + return nil } diff --git a/go.mod b/go.mod index 890d41f4..bc1e7184 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/vault/api v1.9.2 github.com/hashicorp/vault/sdk v0.9.2 - github.com/microsoftgraph/msgraph-sdk-go v1.13.0 golang.org/x/oauth2 v0.11.0 ) @@ -25,7 +24,6 @@ require ( github.com/armon/go-radix v1.0.0 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cjlapao/common-go v0.0.39 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fatih/color v1.13.0 // indirect github.com/go-jose/go-jose/v3 v3.0.0 // indirect @@ -54,12 +52,8 @@ require ( github.com/kylelemons/godebug v1.1.0 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.17 // indirect - github.com/microsoft/kiota-abstractions-go v1.2.0 // indirect + github.com/microsoft/kiota-abstractions-go v1.2.0 github.com/microsoft/kiota-authentication-azure-go v1.0.0 // indirect - github.com/microsoft/kiota-http-go v1.1.0 // indirect - github.com/microsoft/kiota-serialization-form-go v1.0.0 // indirect - github.com/microsoft/kiota-serialization-json-go v1.0.4 // indirect - github.com/microsoft/kiota-serialization-text-go v1.0.0 // indirect github.com/microsoftgraph/msgraph-sdk-go-core v1.0.0 github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/go-homedir v1.1.0 // indirect @@ -70,10 +64,8 @@ require ( github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pquerna/cachecontrol v0.1.0 // indirect github.com/ryanuber/go-glob v1.0.0 // indirect - github.com/stretchr/testify v1.8.4 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect go.opentelemetry.io/otel v1.16.0 // indirect go.opentelemetry.io/otel/metric v1.16.0 // indirect @@ -89,5 +81,4 @@ require ( google.golang.org/grpc v1.53.0 // indirect google.golang.org/protobuf v1.31.0 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 4f2ebd87..5e151b4e 100644 --- a/go.sum +++ b/go.sum @@ -41,7 +41,6 @@ github.com/coreos/go-oidc v2.2.1+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHo github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= @@ -164,16 +163,6 @@ github.com/microsoft/kiota-abstractions-go v1.2.0 h1:lUriJgqdCY/QajwWQOgTCQE9Aty github.com/microsoft/kiota-abstractions-go v1.2.0/go.mod h1:RkxyZ5x87Njik7iVeQY9M2wtrrL1MJZcXiI/BxD/82g= github.com/microsoft/kiota-authentication-azure-go v1.0.0 h1:29FNZZ/4nnCOwFcGWlB/sxPvWz487HA2bXH8jR5k2Rk= github.com/microsoft/kiota-authentication-azure-go v1.0.0/go.mod h1:rnx3PRlkGdXDcA/0lZQTbBwyYGmc+3POt7HpE/e4jGw= -github.com/microsoft/kiota-http-go v1.1.0 h1:L5I93EiNtlP/X6YzeTlhjWt7Q1DxzC9CmWSVtX3b0tE= -github.com/microsoft/kiota-http-go v1.1.0/go.mod h1:zESUM6ovki9LEupqziCbxJ+FAYoF0dFDYZVpOkAfSLc= -github.com/microsoft/kiota-serialization-form-go v1.0.0 h1:UNdrkMnLFqUCccQZerKjblsyVgifS11b3WCx+eFEsAI= -github.com/microsoft/kiota-serialization-form-go v1.0.0/go.mod h1:h4mQOO6KVTNciMF6azi1J9QB19ujSw3ULKcSNyXXOMA= -github.com/microsoft/kiota-serialization-json-go v1.0.4 h1:5TaISWwd2Me8clrK7SqNATo0tv9seOq59y4I5953egQ= -github.com/microsoft/kiota-serialization-json-go v1.0.4/go.mod h1:rM4+FsAY+9AEpBsBzkFFis+b/LZLlNKKewuLwK9Q6Mg= -github.com/microsoft/kiota-serialization-text-go v1.0.0 h1:XOaRhAXy+g8ZVpcq7x7a0jlETWnWrEum0RhmbYrTFnA= -github.com/microsoft/kiota-serialization-text-go v1.0.0/go.mod h1:sM1/C6ecnQ7IquQOGUrUldaO5wj+9+v7G2W3sQ3fy6M= -github.com/microsoftgraph/msgraph-sdk-go v1.13.0 h1:k+3FJJYCSBcnIueefLrO4Ofsd4UP4NzOQ9k3La8I2oU= -github.com/microsoftgraph/msgraph-sdk-go v1.13.0/go.mod h1:ccLv84FJFtwdSzYWM/HlTes5FLzkzzBsYh9kg93/WS8= github.com/microsoftgraph/msgraph-sdk-go-core v1.0.0 h1:7NWTfyXvOjoizW7PmxNp3+8wCKPgpODs/D1cUZ3fkAY= github.com/microsoftgraph/msgraph-sdk-go-core v1.0.0/go.mod h1:tQb4q3YMIj2dWhhXhQSJ4ELpol931ANKzHSYK5kX1qE= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -194,7 +183,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= @@ -209,7 +197,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= github.com/pquerna/cachecontrol v0.1.0 h1:yJMy84ti9h/+OEWa752kBTKv4XC30OtVVHYv/8cTqKc= github.com/pquerna/cachecontrol v0.1.0/go.mod h1:NrUG3Z7Rdu85UNR3vm7SOsl1nFIeSiQnrHV5K9mBcUI= @@ -240,7 +227,6 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= @@ -305,7 +291,6 @@ google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=