Massive cleanup. Tests are passing.

This commit is contained in:
Jeff Mitchell committed 2021-11-10 13:59:21 -05:00
1 parent 073c3e1904
commit 933fc23905
6 files changed
+208 -248

No files matched your search

+1
View File
@@ -12,6 +12,7 @@ require (
github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1 github.com/hashicorp/go-secure-stdlib/parseutil v0.1.1
github.com/kr/pretty v0.3.0 github.com/kr/pretty v0.3.0
github.com/manicminer/hamilton v0.32.0 github.com/manicminer/hamilton v0.32.0
github.com/mitchellh/mapstructure v1.4.1
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
google.golang.org/protobuf v1.27.1 google.golang.org/protobuf v1.27.1
) )
+140 -165
View File
@@ -9,196 +9,167 @@ import (
"github.com/Azure/go-autorest/autorest" "github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure/auth" "github.com/Azure/go-autorest/autorest/azure/auth"
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs"
pb "github.com/hashicorp/boundary/sdk/pbs/plugin"
hauth "github.com/manicminer/hamilton/auth" hauth "github.com/manicminer/hamilton/auth"
"github.com/manicminer/hamilton/environments" "github.com/manicminer/hamilton/environments"
"github.com/manicminer/hamilton/msgraph" "github.com/manicminer/hamilton/msgraph"
"github.com/manicminer/hamilton/odata" "github.com/manicminer/hamilton/odata"
"google.golang.org/protobuf/types/known/structpb" "github.com/mitchellh/mapstructure"
) )
type WrappedHamiltonConfig struct { type AuthorizationInfo struct {
hauth.Config HamiltonConfig hauth.Config
SecretId string AuthParams AuthParams
} }
func authParams(hc *hostcatalogs.HostCatalog, secrets *structpb.Struct) (map[string]string, error) { type Attributes struct {
SubscriptionId string `mapstructure:"subscription_id"`
ClientId string `mapstructure:"client_id"`
TenantId string `mapstructure:"tenant_id"`
DisableCredentialRotation bool `mapstructure:"disable_credential_rotation"`
}
type SecretData struct {
SecretValue string `mapstructure:"secret_value"`
SecretId string `mapstructure:"secret_id"`
CredsLastRotatedTime string `mapstructure:"creds_last_rotated_time"`
}
type AuthParams struct {
SubscriptionId string
ClientId string
ClientObjectId string
TenantId string
SecretValue string
SecretId string
CredsLastRotatedTime time.Time
}
func getAuthorizationInfo(hc *hostcatalogs.HostCatalog) (*AuthorizationInfo, error) {
if hc == nil { if hc == nil {
return nil, errors.New("host catalog is nil") return nil, errors.New("host catalog is nil")
} }
if hc.GetAttributes() == nil { if hc.GetAttributes() == nil {
return nil, errors.New("host catalog attributes is nil") return nil, errors.New("host catalog attributes is nil")
} }
hcFields := hc.GetAttributes().GetFields() if hc.GetSecrets() == nil {
if hcFields == nil { return nil, errors.New("host catalog secret data is nil")
return nil, errors.New("host catalog attributes fields is nil")
} }
if secrets == nil { hcFields := hc.GetAttributes().AsMap()
return nil, errors.New("secrets is nil") var attrs Attributes
if err := mapstructure.Decode(hcFields, &attrs); err != nil {
return nil, fmt.Errorf("error decoding host catalog attribute fields: %w", err)
} }
pdFields := secrets.GetFields() if attrs.SubscriptionId == "" {
if pdFields == nil { return nil, errors.New("subscription id is empty")
return nil, errors.New("secrets data fields is nil") }
if attrs.TenantId == "" {
return nil, errors.New("tenant id is empty")
} }
var subscriptionId string pdFields := hc.GetSecrets().AsMap()
if hcFields[constSubscriptionId] == nil { var secrets SecretData
return nil, errors.New("subscription id not provided in incoming data") if err := mapstructure.Decode(pdFields, &secrets); err != nil {
return nil, fmt.Errorf("error decoding host catalog persisted data fields: %w", err)
} }
if subscriptionId = hcFields[constSubscriptionId].GetStringValue(); subscriptionId == "" { if secrets.SecretValue == "" {
return nil, errors.New("subscription id could not be read as a string value") return nil, errors.New("secret value is empty")
} }
var lastRotatedTime time.Time
ret := map[string]string{ var err error
constSubscriptionId: subscriptionId, if secrets.CredsLastRotatedTime != "" {
} lastRotatedTime, err = time.Parse(time.RFC3339Nano, secrets.CredsLastRotatedTime)
clientId := hcFields[constClientId]
secretValue := pdFields[constSecretValue]
secretId := pdFields[constSecretId]
tenantId := hcFields[constTenantId]
switch {
case clientId != nil && clientId.GetStringValue() != "" &&
secretValue != nil && secretValue.GetStringValue() != "" &&
tenantId != nil && tenantId.GetStringValue() != "":
ret[constClientId] = clientId.GetStringValue()
ret[constSecretValue] = secretValue.GetStringValue()
ret[constTenantId] = tenantId.GetStringValue()
if secretId != nil {
ret[constSecretId] = secretId.GetStringValue()
}
}
return ret, nil
}
func fetchAuthorizer(hc *hostcatalogs.HostCatalog, secrets *structpb.Struct) (string, autorest.Authorizer, error) {
aParams, err := authParams(hc, secrets)
if err != nil {
return "", nil, fmt.Errorf("error finding authentication params: %w", err)
}
var authorizer autorest.Authorizer
// Switch between currently-understood authorization types
{
switch {
case aParams[constClientId] != "" &&
aParams[constSecretValue] != "" &&
aParams[constTenantId] != "":
credsConfig := auth.NewClientCredentialsConfig(
aParams[constClientId],
aParams[constSecretValue],
aParams[constTenantId],
)
authorizer, err = credsConfig.Authorizer()
if err != nil {
return "", nil, fmt.Errorf("error authorizing to Azure: %w", err)
}
default:
return "", nil, errors.New("no or incomplete authentication information available")
}
if authorizer == nil {
return "", nil, fmt.Errorf("authorizer after authorizing to Azure is nil")
}
}
return aParams[constSubscriptionId], authorizer, nil
}
func getWrappedHamiltonConfig(hc *hostcatalogs.HostCatalog, persisted *pb.HostCatalogPersisted) (*WrappedHamiltonConfig, error) {
secrets := hc.GetSecrets()
if secrets == nil && persisted != nil {
secrets = persisted.GetSecrets()
}
aParams, err := authParams(hc, secrets)
if err != nil {
return nil, fmt.Errorf("error fetching authentication params when fetching: %w", err)
}
authConfig := &WrappedHamiltonConfig{}
authConfig.Environment = environments.Global
switch {
case aParams[constClientId] != "" &&
aParams[constSecretValue] != "" &&
aParams[constTenantId] != "":
authConfig.TenantID = aParams[constTenantId]
authConfig.ClientID = aParams[constClientId]
authConfig.ClientSecret = aParams[constSecretValue]
if aParams[constSecretId] != "" {
authConfig.SecretId = aParams[constSecretId]
}
authConfig.EnableClientSecretAuth = true
default:
return nil, errors.New("no or incomplete authentication information available")
}
return authConfig, nil
}
func getObjectId(ctx context.Context, hConfig *WrappedHamiltonConfig, opt ...Option) (string, error) {
opts, err := getOpts(opt...)
if err != nil {
return "", fmt.Errorf("error parsing ops: %w", err)
}
objId := opts.withObjectId
if objId == "" {
clientId := opts.withClientId
if clientId == "" && hConfig != nil {
clientId = hConfig.ClientID
}
if clientId == "" {
return "", fmt.Errorf("neither client id nor object id passed in, cannot continue")
}
// First, find the appId
aClient, err := getApplicationsClient(ctx, hConfig)
if err != nil { if err != nil {
return "", fmt.Errorf("error getting application client: %w", err) return nil, fmt.Errorf("error parsing last rotated time: %w", err)
} }
if aClient == nil {
return "", errors.New("applications client is nil when getting object id")
}
apps, _, err := aClient.List(ctx, odata.Query{
Filter: fmt.Sprintf("appId eq '%s'", clientId),
})
if err != nil {
return "", fmt.Errorf("error listing applications to find objId: %w", err)
}
if apps == nil {
return "", errors.New("nil apps returned when listing to find objId")
}
if len(*apps) != 1 {
return "", fmt.Errorf("unexpected number of apps found, expected 1, found %d", len(*apps))
}
objId = *(*apps)[0].DirectoryObject.ID
} }
return objId, nil
return &AuthorizationInfo{
HamiltonConfig: hauth.Config{
Environment: environments.Global,
TenantID: attrs.TenantId,
ClientID: attrs.ClientId,
ClientSecret: secrets.SecretValue,
EnableClientSecretAuth: true,
},
AuthParams: AuthParams{
SubscriptionId: attrs.SubscriptionId,
ClientId: attrs.ClientId,
TenantId: attrs.TenantId,
SecretId: secrets.SecretId,
SecretValue: secrets.SecretValue,
CredsLastRotatedTime: lastRotatedTime,
},
}, nil
}
func (a *AuthorizationInfo) autorestAuthorizer() (autorest.Authorizer, error) {
credsConfig := auth.NewClientCredentialsConfig(
a.AuthParams.ClientId,
a.AuthParams.SecretValue,
a.AuthParams.TenantId,
)
authorizer, err := credsConfig.Authorizer()
if err != nil {
return nil, fmt.Errorf("error authorizing to Azure: %w", err)
}
if authorizer == nil {
return nil, errors.New("generated authorizer is nil")
}
return authorizer, nil
}
func (a *AuthorizationInfo) populateObjectId(ctx context.Context, opt ...Option) error {
if a.AuthParams.ClientObjectId != "" {
return nil
}
if a.AuthParams.ClientId == "" {
return errors.New("client id not known at object id lookup time")
}
// First, find the appId
aClient, err := getApplicationsClient(ctx, a)
if err != nil {
return fmt.Errorf("error getting application client: %w", err)
}
if aClient == nil {
return errors.New("applications client is nil when getting object id")
}
apps, _, err := aClient.List(ctx, odata.Query{
Filter: fmt.Sprintf("appId eq '%s'", a.AuthParams.ClientId),
})
if err != nil {
return fmt.Errorf("error listing applications to find objId: %w", err)
}
if apps == nil {
return errors.New("nil apps returned when listing to find objId")
}
if len(*apps) != 1 {
return fmt.Errorf("unexpected number of apps found, expected 1, found %d", len(*apps))
}
a.AuthParams.ClientObjectId = *(*apps)[0].DirectoryObject.ID
return nil
} }
// rotateCredentials creates a new password, then uses a client with that new // rotateCredentials creates a new password, then uses a client with that new
// password to revoke the old. // password to revoke the old.
// //
// NOTE: the underlying auth config will be modified to use the new credentials! // NOTE: the underlying auth config will be modified to use the new credentials!
func rotateCredential(ctx context.Context, hConfig *WrappedHamiltonConfig, opt ...Option) (*msgraph.PasswordCredential, error) { func rotateCredential(ctx context.Context, authzInfo *AuthorizationInfo, opt ...Option) (*msgraph.PasswordCredential, error) {
if hConfig == nil { if authzInfo == nil {
return nil, errors.New("empty auth config id") return nil, errors.New("empty authz info")
} }
if hConfig.SecretId == "" { if authzInfo.AuthParams.SecretId == "" {
return nil, errors.New("missing original secret id") return nil, errors.New("missing original secret id")
} }
// Get the object ID here so we don't have to look it up twice // Ensure the object ID is set
objId, err := getObjectId(ctx, hConfig) if err := authzInfo.populateObjectId(ctx); err != nil {
if err != nil {
return nil, fmt.Errorf("error fetching object id: %w", err) return nil, fmt.Errorf("error fetching object id: %w", err)
} }
newCred, err := addCredential(ctx, hConfig, WithObjectId(objId)) newCred, err := addCredential(ctx, authzInfo)
if err != nil { if err != nil {
return nil, fmt.Errorf("error adding password: %w", err) return nil, fmt.Errorf("error adding password: %w", err)
} }
@@ -209,19 +180,23 @@ func rotateCredential(ctx context.Context, hConfig *WrappedHamiltonConfig, opt .
return nil, errors.New("new credential secret text is nil after adding") return nil, errors.New("new credential secret text is nil after adding")
} }
if err := removeCredential(ctx, hConfig, WithObjectId(objId)); err != nil { if err := removeCredential(ctx, authzInfo); err != nil {
return nil, fmt.Errorf("error removing previous credential: %w", err) return nil, fmt.Errorf("error removing previous credential: %w", err)
} }
return newCred, nil return newCred, nil
} }
func addCredential(ctx context.Context, hConfig *WrappedHamiltonConfig, opt ...Option) (*msgraph.PasswordCredential, error) { func addCredential(ctx context.Context, authzInfo *AuthorizationInfo, opt ...Option) (*msgraph.PasswordCredential, error) {
objId, err := getObjectId(ctx, hConfig, opt...) if authzInfo == nil {
if err != nil { return nil, errors.New("empty authz info")
}
// Ensure the object ID is set
if err := authzInfo.populateObjectId(ctx); err != nil {
return nil, fmt.Errorf("error fetching object id: %w", err) return nil, fmt.Errorf("error fetching object id: %w", err)
} }
aClient, err := getApplicationsClient(ctx, hConfig) aClient, err := getApplicationsClient(ctx, authzInfo)
if err != nil { if err != nil {
return nil, fmt.Errorf("error getting application client: %w", err) return nil, fmt.Errorf("error getting application client: %w", err)
} }
@@ -231,7 +206,7 @@ func addCredential(ctx context.Context, hConfig *WrappedHamiltonConfig, opt ...O
// Create the new password // Create the new password
displayName := fmt.Sprintf("boundary-rotated-%s", time.Now().Format(time.RFC3339)) displayName := fmt.Sprintf("boundary-rotated-%s", time.Now().Format(time.RFC3339))
newPass, _, err := aClient.AddPassword(ctx, objId, msgraph.PasswordCredential{ newPass, _, err := aClient.AddPassword(ctx, authzInfo.AuthParams.ClientObjectId, msgraph.PasswordCredential{
DisplayName: &displayName, DisplayName: &displayName,
}) })
if err != nil { if err != nil {
@@ -250,9 +225,9 @@ func addCredential(ctx context.Context, hConfig *WrappedHamiltonConfig, opt ...O
return newPass, nil return newPass, nil
} }
func removeCredential(ctx context.Context, hConfig *WrappedHamiltonConfig, opt ...Option) error { func removeCredential(ctx context.Context, authzInfo *AuthorizationInfo, opt ...Option) error {
objId, err := getObjectId(ctx, hConfig, opt...) // Ensure the object ID is set
if err != nil { if err := authzInfo.populateObjectId(ctx); err != nil {
return fmt.Errorf("error fetching object id: %w", err) return fmt.Errorf("error fetching object id: %w", err)
} }
@@ -261,12 +236,12 @@ func removeCredential(ctx context.Context, hConfig *WrappedHamiltonConfig, opt .
return fmt.Errorf("error parsing ops: %w", err) return fmt.Errorf("error parsing ops: %w", err)
} }
secretId := hConfig.SecretId secretId := authzInfo.AuthParams.SecretId
if opts.withSecretId != "" { if opts.withSecretId != "" {
secretId = opts.withSecretId secretId = opts.withSecretId
} }
aClient, err := getApplicationsClient(ctx, hConfig) aClient, err := getApplicationsClient(ctx, authzInfo)
if err != nil { if err != nil {
return fmt.Errorf("error getting application client: %w", err) return fmt.Errorf("error getting application client: %w", err)
} }
@@ -274,7 +249,7 @@ func removeCredential(ctx context.Context, hConfig *WrappedHamiltonConfig, opt .
return errors.New("applications client is nil when removing credential") return errors.New("applications client is nil when removing credential")
} }
_, err = aClient.RemovePassword(ctx, objId, secretId) _, err = aClient.RemovePassword(ctx, authzInfo.AuthParams.ClientObjectId, secretId)
if err != nil { if err != nil {
return fmt.Errorf("error removing old password: %w", err) return fmt.Errorf("error removing old password: %w", err)
} }
+4 -7
View File
@@ -112,20 +112,17 @@ func getPublicIpAddressesClient(opt ...Option) (*network.PublicIPAddressesClient
return &client, nil return &client, nil
} }
func getApplicationsClient(ctx context.Context, authConfig *WrappedHamiltonConfig) (*msgraph.ApplicationsClient, error) { func getApplicationsClient(ctx context.Context, authzInfo *AuthorizationInfo) (*msgraph.ApplicationsClient, error) {
if authConfig == nil { if authzInfo == nil {
return nil, errors.New("empty auth config id when fetching service principals client") return nil, errors.New("empty auth config id when fetching service principals client")
} }
if authConfig.TenantID == "" {
return nil, errors.New("empty tenant id in auth config when fetching service principals client")
}
authorizer, err := authConfig.NewAuthorizer(ctx, hauth.MsGraph) authorizer, err := authzInfo.HamiltonConfig.NewAuthorizer(ctx, hauth.MsGraph)
if err != nil { if err != nil {
return nil, fmt.Errorf("error fetching hauth authorizer when fetching service principals client: %w", err) return nil, fmt.Errorf("error fetching hauth authorizer when fetching service principals client: %w", err)
} }
client := msgraph.NewApplicationsClient(authConfig.TenantID) client := msgraph.NewApplicationsClient(authzInfo.AuthParams.TenantId)
client.BaseClient.Authorizer = authorizer client.BaseClient.Authorizer = authorizer
return client, nil return client, nil
+12 -21
View File
@@ -26,16 +26,15 @@ type Option func(*options) error
// options = how options are represented // options = how options are represented
type options struct { type options struct {
withHostCatalogAttrs *structpb.Struct withHostCatalogAttrs *structpb.Struct
withPersistedData *structpb.Struct withPersistedData *structpb.Struct
withSubscriptionId string withSubscriptionId string
withAuthorizer autorest.Authorizer withAuthorizer autorest.Authorizer
withUserAgent string withUserAgent string
withBaseUrl string withBaseUrl string
withWrappedHamiltonConfig *WrappedHamiltonConfig withAuthorizationInfo *AuthorizationInfo
withClientId string withClientId string
withObjectId string withSecretId string
withSecretId string
} }
func getDefaultOptions() options { func getDefaultOptions() options {
@@ -100,10 +99,10 @@ func WithBaseUrl(with string) Option {
} }
} }
// WithWrappedHamiltonConfig contains the hamilton package authentication config to use // WithAuthorizationInfo contains the authorization information to use
func WithWrappedHamiltonConfig(with *WrappedHamiltonConfig) Option { func WithAuthorizationInfo(with *AuthorizationInfo) Option {
return func(o *options) error { return func(o *options) error {
o.withWrappedHamiltonConfig = with o.withAuthorizationInfo = with
return nil return nil
} }
} }
@@ -116,14 +115,6 @@ func WithClientId(with string) Option {
} }
} }
// WithObjectId contains the object ID to use
func WithObjectId(with string) Option {
return func(o *options) error {
o.withObjectId = with
return nil
}
}
// WithSecretId contains the secret ID to use // WithSecretId contains the secret ID to use
func WithSecretId(with string) Option { func WithSecretId(with string) Option {
return func(o *options) error { return func(o *options) error {
+31 -29
View File
@@ -9,7 +9,7 @@ import (
"github.com/Azure/azure-sdk-for-go/profiles/latest/network/mgmt/network" "github.com/Azure/azure-sdk-for-go/profiles/latest/network/mgmt/network"
"github.com/Azure/azure-sdk-for-go/profiles/latest/resources/mgmt/resources" "github.com/Azure/azure-sdk-for-go/profiles/latest/resources/mgmt/resources"
"github.com/kr/pretty" "github.com/mitchellh/mapstructure"
"google.golang.org/protobuf/types/known/structpb" "google.golang.org/protobuf/types/known/structpb"
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs" "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/hostcatalogs"
@@ -27,11 +27,11 @@ var (
) )
func rotateCredFromCallback(ctx context.Context, catalog *hostcatalogs.HostCatalog) (*pb.HostCatalogPersisted, error) { func rotateCredFromCallback(ctx context.Context, catalog *hostcatalogs.HostCatalog) (*pb.HostCatalogPersisted, error) {
authConfig, err := getWrappedHamiltonConfig(catalog, nil) authzInfo, err := getAuthorizationInfo(catalog)
if err != nil { if err != nil {
return nil, fmt.Errorf("error getting hauth config when creating catalog: %w", err) return nil, fmt.Errorf("error getting hauth config when creating catalog: %w", err)
} }
newPass, err := rotateCredential(ctx, authConfig) newPass, err := rotateCredential(ctx, authzInfo)
if err != nil { if err != nil {
return nil, fmt.Errorf("error rotating credentials when creating catalog: %w", err) return nil, fmt.Errorf("error rotating credentials when creating catalog: %w", err)
} }
@@ -67,14 +67,12 @@ func (p *AzurePlugin) OnCreateCatalog(ctx context.Context, req *pb.OnCreateCatal
// Check if rotation is skipped. Always prefer attempting rotation unless we // Check if rotation is skipped. Always prefer attempting rotation unless we
// explicitly are told not to // explicitly are told not to
var skipRotation bool var skipRotation bool
if attrs := catalog.GetAttributes(); attrs != nil { if catalog.GetAttributes() != nil {
if fields := attrs.GetFields(); fields != nil { var attrs Attributes
if field := fields[constDisableCredentialRotation]; field != nil { if err := mapstructure.Decode(catalog.GetAttributes().AsMap(), &attrs); err != nil {
if field.GetBoolValue() { return nil, fmt.Errorf("error decoding catalog attributes: %w", err)
skipRotation = true
}
}
} }
skipRotation = attrs.DisableCredentialRotation
} }
if skipRotation { if skipRotation {
return &pb.OnCreateCatalogResponse{ return &pb.OnCreateCatalogResponse{
@@ -117,13 +115,13 @@ func (p *AzurePlugin) OnUpdateCatalog(ctx context.Context, req *pb.OnUpdateCatal
sanitizeSecretsFields(secrets) sanitizeSecretsFields(secrets)
// If the old credential had been rotated, attempt to delete the old // If the old credential had been rotated, attempt to delete the old
// credential using itself; if it fails, proceed anyways, since in theory // credentials using the new ones; if it fails, proceed anyways, since in
// only Boundary knows this value so simply forgetting it is safe enough (if // theory only Boundary knows this value so simply forgetting it is safe
// not clean). // enough (if not clean).
var field *structpb.Value var field *structpb.Value
var pdFields map[string]*structpb.Value var pdFields map[string]*structpb.Value
var err error var err error
var authConfig *WrappedHamiltonConfig var authzInfo *AuthorizationInfo
persisted := req.GetPersisted() persisted := req.GetPersisted()
if persisted == nil { if persisted == nil {
@@ -141,12 +139,13 @@ func (p *AzurePlugin) OnUpdateCatalog(ctx context.Context, req *pb.OnUpdateCatal
goto after_revocation goto after_revocation
} }
// If the field exists, it is a timestamp here indicating last rotation time // If the field exists, it is a timestamp here indicating last rotation time
authConfig, err = getWrappedHamiltonConfig(currentCatalog, req.GetPersisted()) currentCatalog.Secrets = req.GetPersisted().Secrets
authzInfo, err = getAuthorizationInfo(currentCatalog)
if err != nil { if err != nil {
// TODO: warn in some way? // TODO: warn in some way?
goto after_revocation goto after_revocation
} }
if err := removeCredential(ctx, authConfig); err != nil { if err := removeCredential(ctx, authzInfo); err != nil {
// TODO: warn // TODO: warn
goto after_revocation goto after_revocation
} }
@@ -199,14 +198,16 @@ func (p *AzurePlugin) OnDeleteCatalog(ctx context.Context, req *pb.OnDeleteCatal
return nil, nil return nil, nil
} }
// The field existing means it is a string containing the last time it was // The field existing means it is a string containing the last time it was
// rotated. Delete the credential using itself. // rotated. Delete the credential using current creds.
authConfig, err := getWrappedHamiltonConfig(req.GetCatalog(), req.GetPersisted()) catalog := req.GetCatalog()
catalog.Secrets = req.GetPersisted().GetSecrets()
authzInfo, err := getAuthorizationInfo(catalog)
if err != nil { if err != nil {
return nil, fmt.Errorf("error getting auth config on catalog deletion: %w", err) return nil, fmt.Errorf("error getting auth config on catalog deletion: %w", err)
} }
if err := removeCredential(ctx, authConfig); err != nil { if err := removeCredential(ctx, authzInfo); err != nil {
if err != nil { if err != nil {
return nil, fmt.Errorf("error revoking credential on catalog deletion: %w, authConfig is %s", err, pretty.Sprint(authConfig)) return nil, fmt.Errorf("error revoking credential on catalog deletion: %w", err)
} }
} }
@@ -243,16 +244,17 @@ func (p *AzurePlugin) ListHosts(ctx context.Context, req *pb.ListHostsRequest) (
} }
// Create an authorizer // Create an authorizer
var secrets *structpb.Struct catalog.Secrets = req.GetPersisted().GetSecrets()
if req.GetPersisted() != nil { authzInfo, err := getAuthorizationInfo(catalog)
secrets = req.GetPersisted().GetSecrets()
}
subscriptionId, authorizer, err := fetchAuthorizer(catalog, secrets)
if err != nil { if err != nil {
return nil, fmt.Errorf("error fetching subscription id and authorizer: %w", err) return nil, fmt.Errorf("error fetching authorizationInfo: %w", err)
} }
if subscriptionId == "" { if authzInfo == nil {
return nil, errors.New("subscription id not discovered") return nil, errors.New("authorization info is nil")
}
authorizer, err := authzInfo.autorestAuthorizer()
if err != nil {
return nil, fmt.Errorf("error fetching autorest authorizer: %w", err)
} }
if authorizer == nil { if authorizer == nil {
return nil, errors.New("fetched authorizer is nil") return nil, errors.New("fetched authorizer is nil")
@@ -260,7 +262,7 @@ func (p *AzurePlugin) ListHosts(ctx context.Context, req *pb.ListHostsRequest) (
commonOpts := make([]Option, 0, 3) commonOpts := make([]Option, 0, 3)
commonOpts = append(commonOpts, commonOpts = append(commonOpts,
WithSubscriptionId(subscriptionId), WithSubscriptionId(authzInfo.AuthParams.SubscriptionId),
WithAuthorizer(authorizer), WithAuthorizer(authorizer),
) )
+20 -26
View File
@@ -51,7 +51,7 @@ func TestOnCreateOnDeleteCatalog(t *testing.T) {
ctx := context.Background() ctx := context.Background()
p := &AzurePlugin{} p := &AzurePlugin{}
hostCatalog, _ := testGetHostStructs(t) hostCatalog, _ := testGetHostStructs(t)
objId, initialAuthConfig, initialCred, cleanup := testCreateInitialSecret(t, hostCatalog) initialAuthConfig, initialCred, cleanup := testCreateInitialSecret(t, hostCatalog)
defer cleanup() defer cleanup()
// At this point, remove secrets corresponding to those read in by // At this point, remove secrets corresponding to those read in by
@@ -106,7 +106,6 @@ func TestOnCreateOnDeleteCatalog(t *testing.T) {
_ = removeCredential( _ = removeCredential(
ctx, ctx,
&deferAuthConfig, &deferAuthConfig,
WithObjectId(objId),
) )
}() }()
@@ -123,8 +122,9 @@ func TestOnCreateOnDeleteCatalog(t *testing.T) {
// waitForCreds(t, &waitForCredsAuthConfig, false) // waitForCreds(t, &waitForCredsAuthConfig, false)
// Make sure the new creds work, then sleep // Make sure the new creds work, then sleep
waitForCredsAuthConfig.SecretId = newPdFields[constSecretId].GetStringValue() waitForCredsAuthConfig.AuthParams.SecretId = newPdFields[constSecretId].GetStringValue()
waitForCredsAuthConfig.ClientSecret = newPdFields[constSecretValue].GetStringValue() waitForCredsAuthConfig.AuthParams.SecretValue = newPdFields[constSecretValue].GetStringValue()
waitForCredsAuthConfig.HamiltonConfig.ClientSecret = newPdFields[constSecretValue].GetStringValue()
waitForCreds(t, &waitForCredsAuthConfig, true) waitForCreds(t, &waitForCredsAuthConfig, true)
time.Sleep(10 * time.Minute) time.Sleep(10 * time.Minute)
@@ -139,8 +139,8 @@ func TestOnCreateOnDeleteCatalog(t *testing.T) {
// Now, use the credentials we got above to revoke this credential we got from OnCreate // Now, use the credentials we got above to revoke this credential we got from OnCreate
secrets = wrapMap(t, map[string]interface{}{ secrets = wrapMap(t, map[string]interface{}{
constSecretValue: waitForCredsAuthConfig.ClientSecret, constSecretValue: waitForCredsAuthConfig.HamiltonConfig.ClientSecret,
constSecretId: waitForCredsAuthConfig.SecretId, constSecretId: waitForCredsAuthConfig.AuthParams.SecretId,
}) })
cdResp, err = p.OnDeleteCatalog(ctx, &pb.OnDeleteCatalogRequest{ cdResp, err = p.OnDeleteCatalog(ctx, &pb.OnDeleteCatalogRequest{
Catalog: hostCatalog, Catalog: hostCatalog,
@@ -155,7 +155,7 @@ func TestOnCreateOnDeleteCatalog(t *testing.T) {
// waitForCreds(t, &waitForCredsAuthConfig, false) // waitForCreds(t, &waitForCredsAuthConfig, false)
} }
func waitForCreds(t *testing.T, hConfig *WrappedHamiltonConfig, shouldWork bool) auth.Authorizer { func waitForCreds(t *testing.T, authzInfo *AuthorizationInfo, shouldWork bool) auth.Authorizer {
t.Helper() t.Helper()
require := require.New(t) require := require.New(t)
ctx := context.Background() ctx := context.Background()
@@ -164,9 +164,9 @@ func waitForCreds(t *testing.T, hConfig *WrappedHamiltonConfig, shouldWork bool)
environments.Global, environments.Global,
auth.MsGraph, auth.MsGraph,
auth.TokenVersion2, auth.TokenVersion2,
hConfig.TenantID, authzInfo.AuthParams.TenantId,
hConfig.ClientID, authzInfo.AuthParams.ClientId,
hConfig.ClientSecret) authzInfo.AuthParams.SecretValue)
require.NoError(err) require.NoError(err)
for { for {
@@ -230,45 +230,39 @@ func testGetHostStructs(t *testing.T) (*hostcatalogs.HostCatalog, []*hostsets.Ho
// leading into a test. This will serve as our "initial secret" for a test. We // leading into a test. This will serve as our "initial secret" for a test. We
// also return a few cached items. It is expected that the host catalog contains // also return a few cached items. It is expected that the host catalog contains
// Secrets. // Secrets.
func testCreateInitialSecret(t *testing.T, hostCatalog *hostcatalogs.HostCatalog) (string, *WrappedHamiltonConfig, *msgraph.PasswordCredential, func()) { func testCreateInitialSecret(t *testing.T, hostCatalog *hostcatalogs.HostCatalog) (*AuthorizationInfo, *msgraph.PasswordCredential, func()) {
require := require.New(t) require := require.New(t)
ctx := context.Background() ctx := context.Background()
var initialCred *msgraph.PasswordCredential var initialCred *msgraph.PasswordCredential
var objId string // The object ID of the application
// Set up the data, get the config // Set up the data, get the config
persistedData := hostCatalog.GetSecrets() authzInfo, err := getAuthorizationInfo(hostCatalog)
authConfig, err := getWrappedHamiltonConfig(hostCatalog, &pb.HostCatalogPersisted{Secrets: persistedData})
require.NoError(err)
// Pre-cache the object ID
objId, err = getObjectId(ctx, authConfig, WithClientId(hostCatalog.GetAttributes().GetFields()[constClientId].GetStringValue()))
require.NoError(err) require.NoError(err)
// Get the credential // Get the credential
initialCred, err = addCredential(ctx, authConfig, WithObjectId(objId)) initialCred, err = addCredential(ctx, authzInfo)
require.NoError(err) require.NoError(err)
require.NotNil(initialCred) require.NotNil(initialCred)
require.NotNil(initialCred.KeyId) require.NotNil(initialCred.KeyId)
require.NotNil(initialCred.SecretText) require.NotNil(initialCred.SecretText)
origAuthConfig := *authConfig origAuthConfig := *authzInfo
origAuthConfig.AuthParams.SecretId = *initialCred.KeyId
cleanup := func() { cleanup := func() {
if err := removeCredential( if err := removeCredential(
ctx, ctx,
&origAuthConfig, &origAuthConfig,
WithObjectId(objId),
WithSecretId(*initialCred.KeyId),
); err != nil { ); err != nil {
// It may not exist because it's been rotated // It may not exist because it's been rotated
require.Contains(err.Error(), "No password credential found with keyId", err.Error()) require.Contains(err.Error(), "No password credential found with keyId", err.Error())
} }
} }
authConfig.SecretId = *initialCred.KeyId authzInfo.AuthParams.SecretId = *initialCred.KeyId
authConfig.ClientSecret = *initialCred.SecretText authzInfo.AuthParams.SecretValue = *initialCred.SecretText
waitForCreds(t, authConfig, true) authzInfo.HamiltonConfig.ClientSecret = *initialCred.SecretText
waitForCreds(t, authzInfo, true)
return objId, authConfig, initialCred, cleanup return authzInfo, initialCred, cleanup
} }