Skip to content

Commit

Permalink
PDI-1813: Export block HCL generation for PingFederate (#132)
Browse files Browse the repository at this point in the history
* Add PF resource export pingfederate_oauth_issuer

* Add PF resource export pingfederate_server_settings

* Add PF resource export pingfederate_open_id_connect_settings

* Add PF resource export pingfederate_password_credential_validator

* Add PF resource export pingfederate_redirect_validation
  • Loading branch information
erikostien-pingidentity authored Aug 21, 2024
1 parent 137beb9 commit de58e24
Show file tree
Hide file tree
Showing 13 changed files with 514 additions and 0 deletions.
5 changes: 5 additions & 0 deletions internal/connector/pingfederate/pingfederate_connector.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ func (c *PingfederateConnector) Export(format, outputDir string, overwriteExport
resources.OAuthAccessTokenMapping(&c.clientInfo),
resources.OAuthCIBAServerPolicySettings(&c.clientInfo),
resources.OAuthClient(&c.clientInfo),
resources.OAuthIssuer(&c.clientInfo),
resources.OpenIDConnectSettings(&c.clientInfo),
resources.PasswordCredentialValidator(&c.clientInfo),
resources.RedirectValidation(&c.clientInfo),
resources.ServerSettings(&c.clientInfo),
}

return common.WriteFiles(exportableResources, format, outputDir, overwriteExport)
Expand Down
32 changes: 32 additions & 0 deletions internal/connector/pingfederate/pingfederate_connector_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,38 @@ func TestPingFederateTerraformPlan(t *testing.T) {
"Error: Invalid Attribute Value",
},
},
{
name: "PingFederateOAuthIssuer",
resource: resources.OAuthIssuer(PingFederateClientInfo),
ignoredErrors: nil,
},
{
name: "PingFederateOpenIDConnectSettings",
resource: resources.OpenIDConnectSettings(PingFederateClientInfo),
ignoredErrors: []string{
"Error: Plugin did not respond",
"Error: Request cancelled",
},
},
{
name: "PingFederatePasswordCredentialValidator",
resource: resources.PasswordCredentialValidator(PingFederateClientInfo),
ignoredErrors: []string{
"Error: The \"LDAP Datastore\" field is required for the LDAP Username Password Credential Validator",
"Error: The \"Search Base\" field is required for the LDAP Username Password Credential Validator",
"Error: The \"Search Filter\" field is required for the LDAP Username Password Credential Validator",
},
},
{
name: "PingFederateRedirectValidation",
resource: resources.RedirectValidation(PingFederateClientInfo),
ignoredErrors: nil,
},
{
name: "PingFederateServerSettings",
resource: resources.ServerSettings(PingFederateClientInfo),
ignoredErrors: nil,
},
}

for _, tc := range testCases {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package resources

import (
"fmt"

"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/common"
"github.com/pingidentity/pingctl/internal/logger"
)

// Verify that the resource satisfies the exportable resource interface
var (
_ connector.ExportableResource = &PingFederateOAuthIssuerResource{}
)

type PingFederateOAuthIssuerResource struct {
clientInfo *connector.PingFederateClientInfo
}

// Utility method for creating a PingFederateOAuthIssuerResource
func OAuthIssuer(clientInfo *connector.PingFederateClientInfo) *PingFederateOAuthIssuerResource {
return &PingFederateOAuthIssuerResource{
clientInfo: clientInfo,
}
}

func (r *PingFederateOAuthIssuerResource) ExportAll() (*[]connector.ImportBlock, error) {
l := logger.Get()

l.Debug().Msgf("Fetching all %s resources...", r.ResourceType())

apiExecuteFunc := r.clientInfo.ApiClient.OauthIssuersAPI.GetOauthIssuers(r.clientInfo.Context).Execute
apiFunctionName := "GetOauthIssuers"

issuers, response, err := apiExecuteFunc()

err = common.HandleClientResponse(response, err, apiFunctionName, r.ResourceType())
if err != nil {
return nil, err
}

if issuers == nil {
l.Error().Msgf("Returned %s() issuers is nil.", apiFunctionName)
l.Error().Msgf("%s Response Code: %s\nResponse Body: %s", apiFunctionName, response.Status, response.Body)
return nil, fmt.Errorf("failed to fetch %s resources via %s()", r.ResourceType(), apiFunctionName)
}

issuersItems, ok := issuers.GetItemsOk()
if !ok {
l.Error().Msgf("Failed to get %s() issuers items.", apiFunctionName)
l.Error().Msgf("%s Response Code: %s\nResponse Body: %s", apiFunctionName, response.Status, response.Body)
return nil, fmt.Errorf("failed to fetch %s resources via %s()", r.ResourceType(), apiFunctionName)
}

importBlocks := []connector.ImportBlock{}

l.Debug().Msgf("Generating Import Blocks for all %s resources...", r.ResourceType())

for _, issuer := range issuersItems {
issuerId, issuerIdOk := issuer.GetIdOk()
issuerName, issuerNameOk := issuer.GetNameOk()

if issuerIdOk && issuerNameOk {
commentData := map[string]string{
"Resource Type": r.ResourceType(),
"OAuth Issuer Resource ID": *issuerId,
"OAuth Issuer Resource Name": *issuerName,
}

importBlocks = append(importBlocks, connector.ImportBlock{
ResourceType: r.ResourceType(),
ResourceName: *issuerName,
ResourceID: *issuerId,
CommentInformation: common.GenerateCommentInformation(commentData),
})
}
}

return &importBlocks, nil
}

func (r *PingFederateOAuthIssuerResource) ResourceType() string {
return "pingfederate_oauth_issuer"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package resources_test

import (
"testing"

"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/pingfederate/resources"
"github.com/pingidentity/pingctl/internal/testing/testutils"
)

func TestPingFederateOAuthIssuerExport(t *testing.T) {
// Get initialized apiClient and resource
PingFederateClientInfo := testutils.GetPingFederateClientInfo(t)
resource := resources.OAuthIssuer(PingFederateClientInfo)

// Defined the expected ImportBlocks for the resource
expectedImportBlocks := []connector.ImportBlock{
{
ResourceType: "pingfederate_oauth_issuer",
ResourceName: "Test Issuer",
ResourceID: "BmoJwEmyzs4RSNMzVUlCs8qTPC",
},
}

testutils.ValidateImportBlocks(t, resource, &expectedImportBlocks)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package resources

import (
"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/common"
"github.com/pingidentity/pingctl/internal/logger"
)

// Verify that the resource satisfies the exportable resource interface
var (
_ connector.ExportableResource = &PingFederateOpenIDConnectSettingsResource{}
)

type PingFederateOpenIDConnectSettingsResource struct {
clientInfo *connector.PingFederateClientInfo
}

// Utility method for creating a PingFederateOpenIDConnectSettingsResource
func OpenIDConnectSettings(clientInfo *connector.PingFederateClientInfo) *PingFederateOpenIDConnectSettingsResource {
return &PingFederateOpenIDConnectSettingsResource{
clientInfo: clientInfo,
}
}

func (r *PingFederateOpenIDConnectSettingsResource) ExportAll() (*[]connector.ImportBlock, error) {
l := logger.Get()

importBlocks := []connector.ImportBlock{}

l.Debug().Msgf("Generating Import Blocks for all %s resources...", r.ResourceType())

openIDConnectSettingsId := "open_id_connect_settings_singleton_id"
openIDConnectSettingsName := "Open ID Connect Settings"

commentData := map[string]string{
"Resource Type": r.ResourceType(),
"Singleton ID": common.SINGLETON_ID_COMMENT_DATA,
}

importBlocks = append(importBlocks, connector.ImportBlock{
ResourceType: r.ResourceType(),
ResourceName: openIDConnectSettingsName,
ResourceID: openIDConnectSettingsId,
CommentInformation: common.GenerateCommentInformation(commentData),
})

return &importBlocks, nil
}

func (r *PingFederateOpenIDConnectSettingsResource) ResourceType() string {
return "pingfederate_open_id_connect_settings"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package resources_test

import (
"testing"

"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/pingfederate/resources"
"github.com/pingidentity/pingctl/internal/testing/testutils"
)

func TestPingFederateOpenIDConnectSettingsExport(t *testing.T) {
// Get initialized apiClient and resource
PingFederateClientInfo := testutils.GetPingFederateClientInfo(t)
resource := resources.OpenIDConnectSettings(PingFederateClientInfo)

// Defined the expected ImportBlocks for the resource
expectedImportBlocks := []connector.ImportBlock{
{
ResourceType: "pingfederate_open_id_connect_settings",
ResourceName: "Open ID Connect Settings",
ResourceID: "open_id_connect_settings_singleton_id",
},
}

testutils.ValidateImportBlocks(t, resource, &expectedImportBlocks)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package resources

import (
"fmt"

"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/common"
"github.com/pingidentity/pingctl/internal/logger"
)

// Verify that the resource satisfies the exportable resource interface
var (
_ connector.ExportableResource = &PingFederatePasswordCredentialValidatorResource{}
)

type PingFederatePasswordCredentialValidatorResource struct {
clientInfo *connector.PingFederateClientInfo
}

// Utility method for creating a PingFederatePasswordCredentialValidatorResource
func PasswordCredentialValidator(clientInfo *connector.PingFederateClientInfo) *PingFederatePasswordCredentialValidatorResource {
return &PingFederatePasswordCredentialValidatorResource{
clientInfo: clientInfo,
}
}

func (r *PingFederatePasswordCredentialValidatorResource) ExportAll() (*[]connector.ImportBlock, error) {
l := logger.Get()

l.Debug().Msgf("Fetching all %s resources...", r.ResourceType())

apiExecuteFunc := r.clientInfo.ApiClient.PasswordCredentialValidatorsAPI.GetPasswordCredentialValidators(r.clientInfo.Context).Execute
apiFunctionName := "GetPasswordCredentialValidators"

passwordCredentialValidators, response, err := apiExecuteFunc()

err = common.HandleClientResponse(response, err, apiFunctionName, r.ResourceType())
if err != nil {
return nil, err
}

if passwordCredentialValidators == nil {
l.Error().Msgf("Returned %s() passwordCredentialValidators is nil.", apiFunctionName)
l.Error().Msgf("%s Response Code: %s\nResponse Body: %s", apiFunctionName, response.Status, response.Body)
return nil, fmt.Errorf("failed to fetch %s resources via %s()", r.ResourceType(), apiFunctionName)
}

passwordCredentialValidatorsItems, ok := passwordCredentialValidators.GetItemsOk()
if !ok {
l.Error().Msgf("Failed to get %s() passwordCredentialValidators items.", apiFunctionName)
l.Error().Msgf("%s Response Code: %s\nResponse Body: %s", apiFunctionName, response.Status, response.Body)
return nil, fmt.Errorf("failed to fetch %s resources via %s()", r.ResourceType(), apiFunctionName)
}

importBlocks := []connector.ImportBlock{}

l.Debug().Msgf("Generating Import Blocks for all %s resources...", r.ResourceType())

for _, passwordCredentialValidator := range passwordCredentialValidatorsItems {
passwordCredentialValidatorId, passwordCredentialValidatorIdOk := passwordCredentialValidator.GetIdOk()
passwordCredentialValidatorName, passwordCredentialValidatorNameOk := passwordCredentialValidator.GetNameOk()

if passwordCredentialValidatorIdOk && passwordCredentialValidatorNameOk {
commentData := map[string]string{
"Resource Type": r.ResourceType(),
"Password Credential Validator Resource ID": *passwordCredentialValidatorId,
"Password Credential Validator Resource Name": *passwordCredentialValidatorName,
}

importBlocks = append(importBlocks, connector.ImportBlock{
ResourceType: r.ResourceType(),
ResourceName: *passwordCredentialValidatorName,
ResourceID: *passwordCredentialValidatorId,
CommentInformation: common.GenerateCommentInformation(commentData),
})
}
}

return &importBlocks, nil
}

func (r *PingFederatePasswordCredentialValidatorResource) ResourceType() string {
return "pingfederate_password_credential_validator"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package resources_test

import (
"testing"

"github.com/pingidentity/pingctl/internal/connector"
"github.com/pingidentity/pingctl/internal/connector/pingfederate/resources"
"github.com/pingidentity/pingctl/internal/testing/testutils"
)

func TestPingFederatePasswordCredentialValidatorExport(t *testing.T) {
// Get initialized apiClient and resource
PingFederateClientInfo := testutils.GetPingFederateClientInfo(t)
resource := resources.PasswordCredentialValidator(PingFederateClientInfo)

// Defined the expected ImportBlocks for the resource
expectedImportBlocks := []connector.ImportBlock{
{
ResourceType: "pingfederate_password_credential_validator",
ResourceName: "pingdirectory",
ResourceID: "pingdirectory",
},
{
ResourceType: "pingfederate_password_credential_validator",
ResourceName: "simple",
ResourceID: "simple",
},
{
ResourceType: "pingfederate_password_credential_validator",
ResourceName: "PD PCV",
ResourceID: "PDPCV",
},
}

testutils.ValidateImportBlocks(t, resource, &expectedImportBlocks)
}
Loading

0 comments on commit de58e24

Please sign in to comment.