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

Provider secret special chars #53

Merged
merged 8 commits into from
Dec 18, 2024
8 changes: 5 additions & 3 deletions btp/cisclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ import (
)

const (
errInstanceDoesNotExist = "cannot delete instance does not exist"
errCouldNotParseCISSecret = "CIS Secret seems malformed"
errInstanceDoesNotExist = "cannot delete instance does not exist"
errCouldNotParseCISSecret = "CIS Secret seems malformed"
errCouldNotParseUserCredential = "error while parsing sa-provider-secret JSON"
)

type InstanceParameters = map[string]interface{}
Expand Down Expand Up @@ -242,7 +243,8 @@ func ServiceClientFromSecret(cisSecret []byte, userSecret []byte) (Client, error
var userCredential UserCredential

if err := json.Unmarshal(userSecret, &userCredential); err != nil {
return Client{}, err
return Client{}, errors.Wrap(err, errCouldNotParseUserCredential)

}

credential := &Credentials{
Expand Down
44 changes: 44 additions & 0 deletions btp/client_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package btp

import (
"strings"
"testing"

"github.com/sap/crossplane-provider-btp/internal"
)

func TestNewBTPClient(t *testing.T) {

tests := []struct {
name string
cisSecretData []byte
serviceAccountSecretData []byte
wantErr *string
}{
{
name: "sucessfully create new btp client",
cisSecretData: []byte("{\"endpoints\": {\"accounts_service_url\": \"xxx\", \"cloud_automation_url\": \"xxx\", \"entitlements_service_url\": \"xxx\", \"events_service_url\": \"xxx\", \"external_provider_registry_url\": \"xxx\", \"metadata_service_url\": \"xxx\", \"order_processing_url\": \"xxx\", \"provisioning_service_url\": \"xxx\", \"saas_registry_service_url\": \"xxx\" }, \"grant_type\": \"client_credentials\", \"sap.cloud.service\": \"xxx\", \"uaa\": { \"apiurl\": \"xxx\", \"clientid\": \"xxx\", \"clientsecret\": \"xxx\", \"credential-type\": \"binding-secret\", \"identityzone\": \"xxx\", \"identityzoneid\": \"xxx\", \"sburl\": \"xxx\", \"subaccountid\": \"xxx\", \"tenantid\": \"xxx\", \"tenantmode\": \"shared\", \"uaadomain\": \"xxx\", \"url\": \"xxx\", \"verificationkey\": \"xxx\", \"xsappname\": \"xxx\", \"xsmasterappname\": \"xxx\", \"zoneid\": \"xxx\"}}"),
serviceAccountSecretData: []byte("{\"email\": \"[email protected]\",\"username\": \"xxx\",\"password\": \"xxx\"}"),
wantErr: nil,
},
{
name: "fail on invalid json",
cisSecretData: []byte("{\"endpoints\": {\"accounts_service_url\": \"xxx\", \"cloud_automation_url\": \"xxx\", \"entitlements_service_url\": \"xxx\", \"events_service_url\": \"xxx\", \"external_provider_registry_url\": \"xxx\", \"metadata_service_url\": \"xxx\", \"order_processing_url\": \"xxx\", \"provisioning_service_url\": \"xxx\", \"saas_registry_service_url\": \"xxx\" }, \"grant_type\": \"client_credentials\", \"sap.cloud.service\": \"xxx\", \"uaa\": { \"apiurl\": \"xxx\", \"clientid\": \"xxx\", \"clientsecret\": \"xxx\", \"credential-type\": \"binding-secret\", \"identityzone\": \"xxx\", \"identityzoneid\": \"xxx\", \"sburl\": \"xxx\", \"subaccountid\": \"xxx\", \"tenantid\": \"xxx\", \"tenantmode\": \"shared\", \"uaadomain\": \"xxx\", \"url\": \"xxx\", \"verificationkey\": \"xxx\", \"xsappname\": \"xxx\", \"xsmasterappname\": \"xxx\", \"zoneid\": \"xxx\"}}"),
serviceAccountSecretData: []byte("{\"email\": \"[email protected]\",\"username\": \"xxx\",\"password\": \"xx\"x\"}"),
wantErr: internal.Ptr(errCouldNotParseUserCredential),
},
}
for _, tt := range tests {
t.Run(
tt.name, func(t *testing.T) {
_, err := NewBTPClient(tt.cisSecretData, tt.serviceAccountSecretData)
if err != nil && tt.wantErr == nil {
t.Errorf("unexpected error output: %s", err)
}
if err != nil && !strings.Contains(err.Error(), internal.Val(tt.wantErr)) {
t.Errorf("error does not contain wanted error message: %s", err)
}
},
)
}
}
33 changes: 27 additions & 6 deletions internal/clients/servicemanager/api_plan_resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ import (
"sigs.k8s.io/controller-runtime/pkg/log"
)

const ErrInvalidSecretData = "BindingCredentials can't be created from invalid secret data"
const ErrUnmarshalToBindingCredentials = "JSON can not be unmarshalled to BindingCredentials"
const ErrJsonMarshal = "Error marshalling secret data"
const ErrMissingClientId = "Client ID (clientid) is missing"
const ErrMissingClientSecret = "Client Secret (clientsecret) is missing"
const ErrMissingSmUrl = "Service Manager URL (sm_url) is missing"
const ErrMissingUrl = "Token URL (tokenurl) is missing"
const ErrMissingXsappname = "Xsappname (xsappname) is missing"

// PlanIdResolver used as its own resolval implementation downstream
type PlanIdResolver interface {
Expand All @@ -31,19 +37,34 @@ func NewCredsFromOperatorSecret(secretData map[string][]byte) (BindingCredential
plain[k] = string(v)
}

var binding BindingCredentials
bytes, err := json.Marshal(plain)
if err != nil {
return BindingCredentials{}, errors.New(ErrInvalidSecretData)
return BindingCredentials{}, errors.New(ErrJsonMarshal)
}

var binding BindingCredentials
err = json.Unmarshal(bytes, &binding)
if err != nil {
return BindingCredentials{}, errors.New(ErrInvalidSecretData)
return BindingCredentials{}, errors.New(ErrUnmarshalToBindingCredentials)
}

if plain[apisv1alpha1.ResourceCredentialsXsuaaUrl] == "" {
return BindingCredentials{}, errors.New(ErrMissingUrl)
}

binding.Url = internal.Ptr(plain[apisv1alpha1.ResourceCredentialsXsuaaUrl])

if binding.Clientid == nil || binding.Clientsecret == nil || binding.SmUrl == nil || binding.Url == nil || binding.Xsappname == nil {
return BindingCredentials{}, errors.New(ErrInvalidSecretData)
if binding.Clientid == nil {
return BindingCredentials{}, errors.New(ErrMissingClientId)
}
if binding.Clientsecret == nil {
return BindingCredentials{}, errors.New(ErrMissingClientSecret)
}
if binding.SmUrl == nil {
return BindingCredentials{}, errors.New(ErrMissingSmUrl)
}
if binding.Xsappname == nil {
return BindingCredentials{}, errors.New(ErrMissingXsappname)
}

return binding, nil
Expand Down
57 changes: 47 additions & 10 deletions internal/clients/servicemanager/api_plan_resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,10 @@ import (
"net/http"
"testing"

"github.com/crossplane/crossplane-runtime/pkg/test"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
"github.com/sap/crossplane-provider-btp/internal"
servicemanager "github.com/sap/crossplane-provider-btp/internal/openapi_clients/btp-service-manager-api-go/pkg"
"github.com/stretchr/testify/assert"
)

func TestNewServiceManagerClient(t *testing.T) {
Expand Down Expand Up @@ -174,17 +173,57 @@ func TestNewCredsFromOperatorSecret(t *testing.T) {
err error
}{
{
name: "MissingAttributeError",
name: "Missing Attribute Error Client ID",
secret: map[string][]byte{
"clientsecret": []byte("someSecret"),
"sm_url": []byte("https://valid.url"),
"tokenurl": []byte("https://valid.url"),
"xsappname": []byte("someXsAppName"),
},
err: errors.New(ErrMissingClientId),
},
{
name: "Missing Attribute Error Client Secret",
secret: map[string][]byte{
"clientid": []byte("someClientId"),
"sm_url": []byte("https://valid.url"),
"tokenurl": []byte("https://valid.url"),
"xsappname": []byte("someXsAppName"),
},
err: errors.New(ErrMissingClientSecret),
},
{
name: "Missing Attribute Error token URL",
secret: map[string][]byte{
"clientid": []byte("someClientId"),
"clientsecret": []byte("someSecret"),
"sm_url": []byte("https://valid.url"),
"xsappname": []byte("someXsAppName"),
},
err: errors.New(ErrMissingUrl),
},
{
name: "Missing Attribute Error SmUrl",
secret: map[string][]byte{
"clientid": []byte("someClientId"),
"clientsecret": []byte("someSecret"),
"tokenurl": []byte("https://valid.url"),
"xsappname": []byte("someXsAppName"),
},
err: errors.New(ErrInvalidSecretData),
err: errors.New(ErrMissingSmUrl),
},
{
name: "Missing Attribute Error Xsappname",
secret: map[string][]byte{
"clientid": []byte("someClientId"),
"clientsecret": []byte("someSecret"),
"sm_url": []byte("https://valid.url"),
"tokenurl": []byte("https://valid.url"),
},
err: errors.New(ErrMissingXsappname),
},
{
name: "SuccessfulMapping",
name: "Successful Mapping",
secret: map[string][]byte{
"clientid": []byte("someClientId"),
"clientsecret": []byte("someSecret"),
Expand All @@ -204,11 +243,9 @@ func TestNewCredsFromOperatorSecret(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
o, err := NewCredsFromOperatorSecret(tc.secret)
if diff := cmp.Diff(tc.o, o); diff != "" {
t.Errorf("\nNewBindingCredentialsFromSecretData(): -want, +got:\n%s\n", diff)
}
if diff := cmp.Diff(tc.err, err, test.EquateErrors()); diff != "" {
t.Errorf("\nNewBindingCredentialsFromSecretData(): -want error, +got error:\n%s\n", diff)
assert.Equal(t, tc.o, o)
if tc.err != nil {
assert.EqualError(t, err, tc.err.Error())
}

})
Expand Down
17 changes: 9 additions & 8 deletions internal/clients/tfclient/tfclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ import (
)

const (
errNoProviderConfig = "no providerConfigRef provided"
errGetProviderConfig = "cannot get referenced ProviderConfig"
errTrackUsage = "cannot track ProviderConfig usage"
errExtractCredentials = "cannot extract credentials"
errUnmarshalCredentials = "cannot unmarshal btp-account-tf credentials as JSON"
errTrackRUsage = "cannot track ResourceUsage"
errGetServiceAccountCreds = "cannot get Service Account credentials"
errNoProviderConfig = "no providerConfigRef provided"
errGetProviderConfig = "cannot get referenced ProviderConfig"
errTrackUsage = "cannot track ProviderConfig usage"
errExtractCredentials = "cannot extract credentials"
errUnmarshalCredentials = "cannot unmarshal btp-account-tf credentials as JSON"
errTrackRUsage = "cannot track ResourceUsage"
errGetServiceAccountCreds = "cannot get Service Account credentials"
errCouldNotParseUserCredential = "error while parsing sa-provider-secret JSON"
)

var (
Expand Down Expand Up @@ -135,7 +136,7 @@ func TerraformSetupBuilderNoTracking(version, providerSource, providerVersion st

var userCredential btp.UserCredential
if err := json.Unmarshal(ServiceAccountSecretData, &userCredential); err != nil {
return ps, err
return ps, errors.Wrap(err, errCouldNotParseUserCredential)
MarlenKoch marked this conversation as resolved.
Show resolved Hide resolved
}

ps.Configuration = map[string]any{
Expand Down
Loading