Skip to content

Commit

Permalink
Remove dependency on github.com/microsoftgraph/msgraph-sdk-go
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Christopher Swenson committed Nov 2, 2023
1 parent 9df3be7 commit 77eddba
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 66 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ bootstrap:
fi

.PHONY: test
test: fmtcheck
test:
CGO_ENABLED=0 go test ./... $(TESTARGS) -timeout=20m

.PHONY: fmtcheck
Expand Down
210 changes: 170 additions & 40 deletions client/msgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
11 changes: 1 addition & 10 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
)

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
)
15 changes: 0 additions & 15 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand All @@ -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=
Expand All @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down

0 comments on commit 77eddba

Please sign in to comment.