Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

APIGOV-23815 - add basic auth support in sdk #580

Merged
merged 2 commits into from
Oct 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions pkg/agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{}
Expand Down
34 changes: 32 additions & 2 deletions pkg/agent/provisioning.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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 {
basicAuthOptions := []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()),
}

basicAuthOptions = append(basicAuthOptions, options...)

return NewCredentialRequestBuilder(basicAuthOptions...)
}

// NewOAuthCredentialRequestBuilder - add oauth base properties for provisioning schema
func NewOAuthCredentialRequestBuilder(options ...func(*crdBuilderOptions)) provisioning.CredentialRequestBuilder {
oauthOptions := []func(*crdBuilderOptions){
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 6 additions & 0 deletions pkg/agent/provisioning_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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":
Expand Down
3 changes: 2 additions & 1 deletion pkg/apic/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
Apikey = "verify-api-key"
Passthrough = "pass-through"
Oauth = "verify-oauth-token"
Basic = "http-basic"
)

// other consts
Expand All @@ -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)
Expand Down
18 changes: 14 additions & 4 deletions pkg/apic/provisioning/credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
Expand Down
19 changes: 14 additions & 5 deletions pkg/apic/provisioning/credentials_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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 != "":
Expand Down
5 changes: 5 additions & 0 deletions pkg/apic/provisioning/definitions.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -22,6 +24,9 @@ const (

APIKey = "apiKey"

BasicAuthUsername = "username"
BasicAuthPassword = "password"

CredExpDetail = "Agent: CredentialExpired"
)

Expand Down
7 changes: 5 additions & 2 deletions pkg/apic/servicebody.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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)
}
Expand Down
26 changes: 17 additions & 9 deletions pkg/apic/servicebuilder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package apic
import (
"fmt"

"github.com/Axway/agent-sdk/pkg/apic/provisioning"
"github.com/Axway/agent-sdk/pkg/config"
)

Expand Down Expand Up @@ -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
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/apic/specoas2processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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{
Expand Down
4 changes: 4 additions & 0 deletions pkg/apic/specoas3processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down