From bafab32d9aa4bf70a89bb1052d967255c1b8a654 Mon Sep 17 00:00:00 2001 From: Jason Collins Date: Wed, 19 Oct 2022 13:20:26 -0700 Subject: [PATCH] APIGOV-23815 - add basic auth support in sdk --- pkg/agent/agent.go | 9 +++--- pkg/agent/provisioning.go | 34 +++++++++++++++++++++-- pkg/agent/provisioning_test.go | 6 ++++ pkg/apic/client.go | 3 +- pkg/apic/provisioning/credentials.go | 18 +++++++++--- pkg/apic/provisioning/credentials_test.go | 19 +++++++++---- pkg/apic/provisioning/definitions.go | 5 ++++ pkg/apic/servicebody.go | 7 +++-- pkg/apic/servicebuilder.go | 26 +++++++++++------ pkg/apic/specoas2processor.go | 4 +++ pkg/apic/specoas3processor.go | 4 +++ 11 files changed, 107 insertions(+), 28 deletions(-) diff --git a/pkg/agent/agent.go b/pkg/agent/agent.go index e5e377604..2d6726aec 100644 --- a/pkg/agent/agent.go +++ b/pkg/agent/agent.go @@ -65,11 +65,10 @@ type agentData struct { proxyResourceHandler *handler.StreamWatchProxyHandler isInitialized bool - instanceValidatorJobID string - provisioner provisioning.Provisioning - marketplaceMigration migrate.Migrator - streamer *stream.StreamerClient - authProviderRegistry oauth.ProviderRegistry + provisioner provisioning.Provisioning + marketplaceMigration migrate.Migrator + streamer *stream.StreamerClient + authProviderRegistry oauth.ProviderRegistry // profiling profileDone chan struct{} diff --git a/pkg/agent/provisioning.go b/pkg/agent/provisioning.go index 4e64132ac..68a609d50 100644 --- a/pkg/agent/provisioning.go +++ b/pkg/agent/provisioning.go @@ -2,7 +2,6 @@ package agent import ( "github.com/Axway/agent-sdk/pkg/agent/handler" - apiv1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1" v1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1" management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1" "github.com/Axway/agent-sdk/pkg/apic/definitions" @@ -45,7 +44,7 @@ func createOrUpdateDefinition(data v1.Interface, marketplaceMigration migrate.Mi func runMarketplaceMigration(ri *v1.ResourceInstance, marketplaceMigration migrate.Migrator) bool { // check if the KIND and ID combo have an item in the cache - var existingRI *apiv1.ResourceInstance + var existingRI *v1.ResourceInstance switch ri.Kind { case management.AccessRequestDefinitionGVK().Kind: @@ -385,6 +384,32 @@ func NewAPIKeyCredentialRequestBuilder(options ...func(*crdBuilderOptions)) prov return NewCredentialRequestBuilder(apiKeyOptions...) } +// NewBasicAuthCredentialRequestBuilder - add basic auth base properties for provisioning schema +func NewBasicAuthCredentialRequestBuilder(options ...func(*crdBuilderOptions)) provisioning.CredentialRequestBuilder { + apiKeyOptions := []func(*crdBuilderOptions){ + WithCRDName(provisioning.BasicAuthCRD), + WithCRDTitle("Basic Auth"), + WithCRDProvisionSchemaProperty( + provisioning.NewSchemaPropertyBuilder(). + SetName(provisioning.BasicAuthUsername). + SetLabel("Username"). + SetRequired(). + IsString(). + IsEncrypted()), + WithCRDProvisionSchemaProperty( + provisioning.NewSchemaPropertyBuilder(). + SetName(provisioning.BasicAuthPassword). + SetLabel("Password"). + SetRequired(). + IsString(). + IsEncrypted()), + } + + apiKeyOptions = append(apiKeyOptions, options...) + + return NewCredentialRequestBuilder(apiKeyOptions...) +} + // NewOAuthCredentialRequestBuilder - add oauth base properties for provisioning schema func NewOAuthCredentialRequestBuilder(options ...func(*crdBuilderOptions)) provisioning.CredentialRequestBuilder { oauthOptions := []func(*crdBuilderOptions){ @@ -419,6 +444,11 @@ func NewAccessRequestBuilder() provisioning.AccessRequestBuilder { return provisioning.NewAccessRequestBuilder(createOrUpdateAccessRequestDefinition) } +// NewBasicAuthAccessRequestBuilder - called by the agents +func NewBasicAuthAccessRequestBuilder() provisioning.AccessRequestBuilder { + return NewAccessRequestBuilder().SetName(provisioning.BasicAuthARD) +} + // NewAPIKeyAccessRequestBuilder - called by the agents func NewAPIKeyAccessRequestBuilder() provisioning.AccessRequestBuilder { return NewAccessRequestBuilder().SetName(provisioning.APIKeyARD) diff --git a/pkg/agent/provisioning_test.go b/pkg/agent/provisioning_test.go index 50ca0ef97..4055dc1c1 100644 --- a/pkg/agent/provisioning_test.go +++ b/pkg/agent/provisioning_test.go @@ -38,6 +38,10 @@ func TestNewCredentialRequestBuilder(t *testing.T) { name string expectedName string }{ + { + name: "Test Basic Auth Helper", + expectedName: "http-basic", + }, { name: "Test APIKey Helper", expectedName: "api-key", @@ -57,6 +61,8 @@ func TestNewCredentialRequestBuilder(t *testing.T) { var err error var crd *management.CredentialRequestDefinition switch test.expectedName { + case "http-basic": + crd, err = NewBasicAuthCredentialRequestBuilder().Register() case "api-key": crd, err = NewAPIKeyCredentialRequestBuilder().Register() case "oauth": diff --git a/pkg/apic/client.go b/pkg/apic/client.go index 94ede9e78..24c1d2986 100644 --- a/pkg/apic/client.go +++ b/pkg/apic/client.go @@ -30,6 +30,7 @@ const ( Apikey = "verify-api-key" Passthrough = "pass-through" Oauth = "verify-oauth-token" + Basic = "http-basic" ) // other consts @@ -38,7 +39,7 @@ const ( ) // ValidPolicies - list of valid auth policies supported by Central. Add to this list as more policies are supported. -var ValidPolicies = []string{Apikey, Passthrough, Oauth} +var ValidPolicies = []string{Apikey, Passthrough, Oauth, Basic} // SubscriptionProcessor - callback method type to process subscriptions type SubscriptionProcessor func(subscription Subscription) diff --git a/pkg/apic/provisioning/credentials.go b/pkg/apic/provisioning/credentials.go index b335c70b5..0be68269b 100644 --- a/pkg/apic/provisioning/credentials.go +++ b/pkg/apic/provisioning/credentials.go @@ -3,9 +3,8 @@ package provisioning import "time" const ( - apiKey = "api-key" - oauth = "oauth" - other = "other" + oauth = "oauth" + other = "other" ) // Credential - holds the details about the credential to send to encrypt and send to platform @@ -35,6 +34,7 @@ type CredentialBuilder interface { SetOAuthID(id string) Credential SetOAuthIDAndSecret(id, secret string) Credential SetAPIKey(key string) Credential + SetHTTPBasic(username, password string) Credential SetCredential(data map[string]interface{}) Credential } @@ -70,13 +70,23 @@ func (c *credentialBuilder) SetOAuthIDAndSecret(id, secret string) Credential { // SetAPIKey - set the credential as an API Key type func (c *credentialBuilder) SetAPIKey(key string) Credential { - c.credential.credentialType = apiKey + c.credential.credentialType = APIKeyCRD c.credential.data = map[string]interface{}{ APIKey: key, } return c.credential } +// SetHTTPBasic - set the credential as an API Key type +func (c *credentialBuilder) SetHTTPBasic(username, password string) Credential { + c.credential.credentialType = BasicAuthCRD + c.credential.data = map[string]interface{}{ + BasicAuthUsername: username, + BasicAuthPassword: password, + } + return c.credential +} + // SetExpirationTime - set the credential expiration time func (c *credentialBuilder) SetExpirationTime(expTime time.Time) CredentialBuilder { c.credential.expTime = expTime diff --git a/pkg/apic/provisioning/credentials_test.go b/pkg/apic/provisioning/credentials_test.go index 64d2f30ad..9d6af8f61 100644 --- a/pkg/apic/provisioning/credentials_test.go +++ b/pkg/apic/provisioning/credentials_test.go @@ -9,12 +9,19 @@ import ( func TestCredentialBuilder(t *testing.T) { tests := []struct { - name string - key string - id string - secret string - other map[string]interface{} + name string + username string + password string + key string + id string + secret string + other map[string]interface{} }{ + { + name: "Build Basic Auth Credential", + username: "basic-user", + password: "basic-pass", + }, { name: "Build API Key Credential", key: "api-key-data", @@ -44,6 +51,8 @@ func TestCredentialBuilder(t *testing.T) { switch { case tt.key != "": cred = builder.SetAPIKey(tt.key) + case tt.username != "": + cred = builder.SetHTTPBasic(tt.username, tt.password) case tt.id != "" && tt.secret != "": cred = builder.SetOAuthIDAndSecret(tt.key, tt.secret) case tt.id != "": diff --git a/pkg/apic/provisioning/definitions.go b/pkg/apic/provisioning/definitions.go index 4d7a812f1..4df8be814 100644 --- a/pkg/apic/provisioning/definitions.go +++ b/pkg/apic/provisioning/definitions.go @@ -3,7 +3,9 @@ package provisioning // default names of ARD and CRDs const ( APIKeyARD = "api-key" + BasicAuthARD = "http-basic" APIKeyCRD = "api-key" + BasicAuthCRD = "http-basic" OAuthSecretCRD = "oauth-secret" OAuthPublicKeyCRD = "oauth-public-key" OAuthIDPCRD = "oauth-idp" @@ -22,6 +24,9 @@ const ( APIKey = "apiKey" + BasicAuthUsername = "username" + BasicAuthPassword = "password" + CredExpDetail = "Agent: CredentialExpired" ) diff --git a/pkg/apic/servicebody.go b/pkg/apic/servicebody.go index b1f385187..70c2cb309 100644 --- a/pkg/apic/servicebody.go +++ b/pkg/apic/servicebody.go @@ -57,7 +57,7 @@ type ServiceBody struct { accessRequestDefinition *management.AccessRequestDefinition } -//SetAccessRequestDefinitionName - set the name of the access request definition for this service body +// SetAccessRequestDefinitionName - set the name of the access request definition for this service body func (s *ServiceBody) SetAccessRequestDefinitionName(ardName string, isUnique bool) { s.ardName = ardName s.uniqueARD = isUnique @@ -73,7 +73,7 @@ func (s *ServiceBody) GetAPIKeyInfo() []APIKeyInfo { return s.apiKeyInfo } -//GetScopes - returns the array of scopes for this service instance +// GetScopes - returns the array of scopes for this service instance func (s *ServiceBody) GetScopes() map[string]string { return s.scopes } @@ -84,6 +84,9 @@ func (s *ServiceBody) GetCredentialRequestDefinitions() []string { return s.credentialRequestPolicies } for _, policy := range s.authPolicies { + if policy == Basic { + s.credentialRequestPolicies = append(s.credentialRequestPolicies, provisioning.BasicAuthCRD) + } if policy == Apikey { s.credentialRequestPolicies = append(s.credentialRequestPolicies, provisioning.APIKeyCRD) } diff --git a/pkg/apic/servicebuilder.go b/pkg/apic/servicebuilder.go index 282d67454..062252232 100644 --- a/pkg/apic/servicebuilder.go +++ b/pkg/apic/servicebuilder.go @@ -3,6 +3,7 @@ package apic import ( "fmt" + "github.com/Axway/agent-sdk/pkg/apic/provisioning" "github.com/Axway/agent-sdk/pkg/config" ) @@ -311,16 +312,23 @@ func (b *serviceBodyBuilder) Build() (ServiceBody, error) { // get oauth scopes b.serviceBody.scopes = val.GetOAuthScopes() - // only set ard name based on spec if not already set - if b.serviceBody.ardName == "" { - if len(b.serviceBody.apiKeyInfo) > 0 { - b.serviceBody.ardName = "api-key" - } + // if the spec has multiple then use the oauth ard + err := b.serviceBody.createAccessRequestDefinition() + if err != nil { + return b.serviceBody, err + } - // if the spec has api key and oauth use the oauth ard - err := b.serviceBody.createAccessRequestDefinition() - if err != nil { - return b.serviceBody, err + // only set ard name based on spec if not already set, use first auth we find + if b.serviceBody.ardName == "" { + for _, p := range b.serviceBody.authPolicies { + if p == Basic { + b.serviceBody.ardName = provisioning.BasicAuthARD + break + } + if p == Apikey { + b.serviceBody.ardName = provisioning.APIKeyARD + break + } } } } diff --git a/pkg/apic/specoas2processor.go b/pkg/apic/specoas2processor.go index f65729c59..18d3e3828 100644 --- a/pkg/apic/specoas2processor.go +++ b/pkg/apic/specoas2processor.go @@ -15,6 +15,8 @@ var validOA2Schemes = map[string]bool{"http": true, "https": true, "ws": true, " const ( oasSecurityAPIKey = "apiKey" oasSecurityOauth = "oauth2" + oasSecurityBasic = "basic" + oasSecurityHttp = "http" ) // oas2SpecProcessor parses and validates an OAS2 spec, and exposes methods to modify the content of the spec. @@ -75,6 +77,8 @@ func (p *oas2SpecProcessor) ParseAuthInfo() { scopes := make(map[string]string) for _, scheme := range p.spec.SecurityDefinitions { switch scheme.Type { + case oasSecurityBasic: + authPolicies = append(authPolicies, Basic) case oasSecurityAPIKey: authPolicies = append(authPolicies, Apikey) keyInfo = append(keyInfo, APIKeyInfo{ diff --git a/pkg/apic/specoas3processor.go b/pkg/apic/specoas3processor.go index 84ffb9be7..9d36f29c9 100644 --- a/pkg/apic/specoas3processor.go +++ b/pkg/apic/specoas3processor.go @@ -152,6 +152,10 @@ func (p *oas3SpecProcessor) ParseAuthInfo() { scopes := make(map[string]string) for _, scheme := range p.spec.Components.SecuritySchemes { switch scheme.Value.Type { + case oasSecurityHttp: + if scheme.Value.Scheme == oasSecurityBasic { + authPolicies = append(authPolicies, Basic) + } case oasSecurityAPIKey: authPolicies = append(authPolicies, Apikey) keyInfo = append(keyInfo, APIKeyInfo{