Skip to content

Commit

Permalink
feat: Add generic oidc account (#288)
Browse files Browse the repository at this point in the history
* feat: Add generic oidc account

* chore: Add generic oidc account to account type

* chore: remove subject keys which are not required

* fix: add AccountTypeGenericOIDCAccount to account resource creation
  • Loading branch information
grace-rehn authored Dec 4, 2024
1 parent d53c52f commit 94ae598
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 2 deletions.
2 changes: 1 addition & 1 deletion pkg/accounts/account.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type IAccount interface {

// account is the embedded struct used for all accounts.
type account struct {
AccountType AccountType `json:"AccountType" validate:"required,oneof=None UsernamePassword SshKeyPair AzureSubscription AzureServicePrincipal AzureOidc AmazonWebServicesAccount AmazonWebServicesOidcAccount AmazonWebServicesRoleAccount GoogleCloudAccount Token"`
AccountType AccountType `json:"AccountType" validate:"required,oneof=None UsernamePassword SshKeyPair AzureSubscription AzureServicePrincipal AzureOidc AmazonWebServicesAccount AmazonWebServicesOidcAccount AmazonWebServicesRoleAccount GoogleCloudAccount GenericOidcAccount Token"`
Description string `json:"Description,omitempty"`
EnvironmentIDs []string `json:"EnvironmentIds,omitempty"`
Name string `json:"Name" validate:"required,notblank,notall"`
Expand Down
2 changes: 1 addition & 1 deletion pkg/accounts/account_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
// username/password, tokens, Azure and AWS credentials, and SSH key pairs.
type AccountResource struct {
AccessKey string `json:"AccessKey,omitempty"`
AccountType AccountType `json:"AccountType" validate:"required,oneof=None UsernamePassword SshKeyPair AzureSubscription AzureServicePrincipal AzureOidc AmazonWebServicesAccount AmazonWebServicesRoleAccount AmazonWebServicesOidcAccount GoogleCloudAccount Token"`
AccountType AccountType `json:"AccountType" validate:"required,oneof=None UsernamePassword SshKeyPair AzureSubscription AzureServicePrincipal AzureOidc AmazonWebServicesAccount AmazonWebServicesRoleAccount AmazonWebServicesOidcAccount GoogleCloudAccount GenericOidcAccount Token"`
ApplicationID *uuid.UUID `json:"ClientId,omitempty"`
ApplicationPassword *core.SensitiveValue `json:"Password,omitempty"`
AuthenticationEndpoint string `json:"ActiveDirectoryEndpointBaseUri,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions pkg/accounts/account_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const (
AccountTypeAzureOIDC = AccountType("AzureOidc")
AccountTypeAwsOIDC = AccountType("AmazonWebServicesOidcAccount")
AccountTypeAzureSubscription = AccountType("AzureSubscription")
AccountTypeGenericOIDCAccount = AccountType("GenericOidcAccount")
AccountTypeGoogleCloudPlatformAccount = AccountType("GoogleCloudAccount")
AccountTypeSSHKeyPair = AccountType("SshKeyPair")
AccountTypeToken = AccountType("Token")
Expand Down
12 changes: 12 additions & 0 deletions pkg/accounts/account_utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ func ToAccount(accountResource *AccountResource) (IAccount, error) {
azureSubscriptionAccount.ManagementEndpoint = accountResource.ManagementEndpoint
azureSubscriptionAccount.StorageEndpointSuffix = accountResource.StorageEndpointSuffix
account = azureSubscriptionAccount
case AccountTypeGenericOIDCAccount:
genericOIDCAccount, err := NewGenericOIDCAccount(accountResource.GetName())
if err != nil {
return nil, err
}
genericOIDCAccount.Audience = accountResource.Audience
genericOIDCAccount.DeploymentSubjectKeys = accountResource.DeploymentSubjectKeys
account = genericOIDCAccount
case AccountTypeGoogleCloudPlatformAccount:
googleCloudPlatformAccount, err := NewGoogleCloudPlatformAccount(accountResource.GetName(), accountResource.JsonKey)
if err != nil {
Expand Down Expand Up @@ -175,6 +183,10 @@ func ToAccountResource(account IAccount) (*AccountResource, error) {
accountResource.ManagementEndpoint = azureSubscriptionAccount.ManagementEndpoint
accountResource.StorageEndpointSuffix = azureSubscriptionAccount.StorageEndpointSuffix
accountResource.SubscriptionID = azureSubscriptionAccount.SubscriptionID
case AccountTypeGenericOIDCAccount:
genericOidcAccount := account.(*GenericOIDCAccount)
accountResource.DeploymentSubjectKeys = genericOidcAccount.DeploymentSubjectKeys
accountResource.Audience = genericOidcAccount.Audience
case AccountTypeGoogleCloudPlatformAccount:
googleCloudPlatformAccount := account.(*GoogleCloudPlatformAccount)
accountResource.JsonKey = googleCloudPlatformAccount.JsonKey
Expand Down
7 changes: 7 additions & 0 deletions pkg/accounts/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,13 @@ func (a *Accounts) UnmarshalJSON(b []byte) error {
return err
}
a.Items = append(a.Items, azureSubscriptionAccount)
case AccountTypeGenericOIDCAccount:
var genericOIDCAccount *GenericOIDCAccount
err := json.Unmarshal(*account, &genericOIDCAccount)
if err != nil {
return err
}
a.Items = append(a.Items, genericOIDCAccount)
case AccountTypeGoogleCloudPlatformAccount:
var googleCloudAccount *GoogleCloudPlatformAccount
err := json.Unmarshal(*account, &googleCloudAccount)
Expand Down
49 changes: 49 additions & 0 deletions pkg/accounts/generic_oidc_account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package accounts

import (
"github.com/OctopusDeploy/go-octopusdeploy/v2/internal"
"github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/validation"
"github.com/go-playground/validator/v10"
"github.com/go-playground/validator/v10/non-standard/validators"
)

// GenericOIDCAccount represents a Generic OIDC account.
type GenericOIDCAccount struct {
Audience string `json:"Audience,omitempty"`
DeploymentSubjectKeys []string `json:"DeploymentSubjectKeys,omitempty" validate:"omitempty,dive,oneof=space environment project tenant runbook account type'"`

account
}

// NewGenericOIDCAccount creates and initializes a Generic OIDC account.
func NewGenericOIDCAccount(name string) (*GenericOIDCAccount, error) {
if internal.IsEmpty(name) {
return nil, internal.CreateRequiredParameterIsEmptyOrNilError("name")
}

account := GenericOIDCAccount{
account: *newAccount(name, AccountTypeGenericOIDCAccount),
}

// validate to ensure that all expectations are met
err := account.Validate()
if err != nil {
return nil, err
}

return &account, nil
}

// Validate checks the state of this account and returns an error if invalid.
func (a *GenericOIDCAccount) Validate() error {
v := validator.New()
err := v.RegisterValidation("notblank", validators.NotBlank)
if err != nil {
return err
}
err = v.RegisterValidation("notall", validation.NotAll)
if err != nil {
return err
}
return v.Struct(a)
}
63 changes: 63 additions & 0 deletions pkg/accounts/generic_oidc_account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package accounts

import (
"github.com/OctopusDeploy/go-octopusdeploy/v2/internal"
"github.com/stretchr/testify/require"
"testing"
)

func TestGenericOIDCAccount(t *testing.T) {
name := internal.GetRandomName()
audience := "api://default"
deploymentSubjectKeys := []string{"space", "project", "tenant", "environment"}
invalidDeploymentSubjectKeys := []string{"space", "target"}

testCases := []struct {
TestName string
IsError bool
Name string
Audience string
DeploymentSubjectKeys []string
}{
{"Valid", false, name, audience, deploymentSubjectKeys},
{"EmptyName", true, "", audience, deploymentSubjectKeys},
{"NilSubjectKeys", false, name, "", nil},
{"InvalidDeploymentSubjectKeys", true, name, "", invalidDeploymentSubjectKeys},
}

for _, tc := range testCases {
t.Run(tc.TestName, func(t *testing.T) {
genericOIDCAccount := &GenericOIDCAccount{
Audience: tc.Audience,
DeploymentSubjectKeys: tc.DeploymentSubjectKeys,
}
genericOIDCAccount.AccountType = AccountTypeGenericOIDCAccount
genericOIDCAccount.Name = tc.Name
if tc.IsError {
require.Error(t, genericOIDCAccount.Validate())
} else {
require.NoError(t, genericOIDCAccount.Validate())

require.Equal(t, AccountTypeGenericOIDCAccount, genericOIDCAccount.GetAccountType())
require.Equal(t, tc.Name, genericOIDCAccount.GetName())
}
genericOIDCAccount.SetName(tc.Name)
if tc.IsError {
require.Error(t, genericOIDCAccount.Validate())
} else {
require.NoError(t, genericOIDCAccount.Validate())
require.Equal(t, tc.Name, genericOIDCAccount.GetName())
}
})
}
}

func TestGenericOIDCAccountNew(t *testing.T) {
name := internal.GetRandomName()

account, err := NewGenericOIDCAccount(name)

require.NotNil(t, account)
require.NoError(t, err)
require.NoError(t, account.Validate())
}

0 comments on commit 94ae598

Please sign in to comment.