github.com/Axway/agent-sdk@v1.1.101/pkg/agent/handler/credential.go (about)

     1  package handler
     2  
     3  import (
     4  	"context"
     5  	"encoding/base64"
     6  	"fmt"
     7  	"reflect"
     8  	"strings"
     9  	"time"
    10  
    11  	v1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
    12  	management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1"
    13  	defs "github.com/Axway/agent-sdk/pkg/apic/definitions"
    14  	prov "github.com/Axway/agent-sdk/pkg/apic/provisioning"
    15  	"github.com/Axway/agent-sdk/pkg/apic/provisioning/idp"
    16  	"github.com/Axway/agent-sdk/pkg/authz/oauth"
    17  	"github.com/Axway/agent-sdk/pkg/util"
    18  	"github.com/Axway/agent-sdk/pkg/util/log"
    19  	"github.com/Axway/agent-sdk/pkg/watchmanager/proto"
    20  )
    21  
    22  const (
    23  	update          = "update"
    24  	xAxwayEncrypted = "x-axway-encrypted"
    25  	crFinalizer     = "agent.credential.provisioned"
    26  )
    27  
    28  type credProv interface {
    29  	CredentialProvision(credentialRequest prov.CredentialRequest) (status prov.RequestStatus, credentials prov.Credential)
    30  	CredentialDeprovision(credentialRequest prov.CredentialRequest) (status prov.RequestStatus)
    31  	CredentialUpdate(credentialRequest prov.CredentialRequest) (status prov.RequestStatus, credentials prov.Credential)
    32  }
    33  
    34  type credentials struct {
    35  	marketplaceHandler
    36  	prov                credProv
    37  	client              client
    38  	encryptSchema       encryptSchemaFunc
    39  	idpProviderRegistry oauth.IdPRegistry
    40  }
    41  
    42  // encryptSchemaFunc func signature for encryptSchema
    43  type encryptSchemaFunc func(schema, credData map[string]interface{}, key, alg, hash string) (map[string]interface{}, error)
    44  
    45  // NewCredentialHandler creates a Handler for Credentials
    46  func NewCredentialHandler(prov credProv, client client, providerRegistry oauth.IdPRegistry) Handler {
    47  	return &credentials{
    48  		prov:                prov,
    49  		client:              client,
    50  		encryptSchema:       encryptSchema,
    51  		idpProviderRegistry: providerRegistry,
    52  	}
    53  }
    54  
    55  // Handle processes grpc events triggered for Credentials
    56  func (h *credentials) Handle(ctx context.Context, meta *proto.EventMeta, resource *v1.ResourceInstance) error {
    57  	action := GetActionFromContext(ctx)
    58  	if resource.Kind != management.CredentialGVK().Kind || h.prov == nil || h.shouldIgnoreSubResourceUpdate(action, meta) {
    59  		return nil
    60  	}
    61  
    62  	logger := getLoggerFromContext(ctx).WithComponent("credentialHandler")
    63  	ctx = setLoggerInContext(ctx, logger)
    64  
    65  	cr := &management.Credential{}
    66  	err := cr.FromInstance(resource)
    67  	if err != nil {
    68  		logger.WithError(err).Error("could not handle credential request")
    69  		return nil
    70  	}
    71  
    72  	if ok := isStatusFound(cr.Status); !ok {
    73  		logger.Debugf("could not handle credential request as it did not have a status subresource")
    74  		return nil
    75  	}
    76  
    77  	if ok := h.shouldProcessDeleting(cr); ok {
    78  		logger.Trace("processing resource in deleting state")
    79  		h.onDeleting(ctx, cr)
    80  		return nil
    81  	}
    82  
    83  	var credential *management.Credential
    84  	if ok := h.shouldProcessPending(cr); ok {
    85  		log.Trace("processing resource in pending status")
    86  		credential = h.onPending(ctx, cr)
    87  	} else if actions := h.shouldProcessUpdating(cr); len(actions) != 0 {
    88  		log.Trace("processing resource in updating status")
    89  		credential = h.onUpdates(ctx, cr, actions)
    90  	}
    91  
    92  	if credential != nil {
    93  		err = h.client.CreateSubResource(cr.ResourceMeta, cr.SubResources)
    94  		if err != nil {
    95  			logger.WithError(err).Error("error creating subresources")
    96  		}
    97  
    98  		// update the status resource regardless of errors updating the other subresources
    99  		statusErr := h.client.CreateSubResource(credential.ResourceMeta, map[string]interface{}{"status": credential.Status})
   100  		if statusErr != nil {
   101  			logger.WithError(statusErr).Error("error creating status subresources")
   102  			return statusErr
   103  		}
   104  	}
   105  
   106  	return err
   107  }
   108  
   109  // shouldProcessDeleting
   110  // Finalizers = has agent finalizer and
   111  //  (Spec.State.Name = Inactive, StateReason = Credential Expired, Status.Level = Pending) or
   112  //  (Metadata.State = Deleting)
   113  
   114  func (h *credentials) shouldProcessDeleting(cr *management.Credential) bool {
   115  	if !hasAgentCredentialFinalizer(cr.Finalizers) {
   116  		return false
   117  	}
   118  
   119  	if cr.Spec.State.Name == v1.Inactive && cr.Spec.State.Reason == prov.CredExpDetail && cr.Status.Level == prov.Pending.String() {
   120  		// expired credential
   121  		return true
   122  	}
   123  
   124  	if cr.Metadata.State == v1.ResourceDeleting {
   125  		// don't process delete when error from agent
   126  		return !hasAgentCredentialError(cr.Status)
   127  	}
   128  
   129  	return false
   130  }
   131  
   132  // shouldProvision
   133  // Status.Level = Pending and
   134  // Metadata.State = !Deleting and
   135  // Spec.State.Name = Active and
   136  // Spec.State.Rotate = false and
   137  // Finalizers = no agent finalizer
   138  func (h *credentials) shouldProcessPending(cr *management.Credential) bool {
   139  	if h.marketplaceHandler.shouldProcessPending(cr.Status, cr.Metadata.State) {
   140  		return cr.Spec.State.Name == v1.Active && !cr.Spec.State.Rotate && !hasAgentCredentialFinalizer(cr.Finalizers)
   141  	}
   142  	return false
   143  }
   144  
   145  // shouldProcessUpdating
   146  func (h *credentials) shouldProcessUpdating(cr *management.Credential) []prov.CredentialAction {
   147  	actions := []prov.CredentialAction{}
   148  	inter := reflect.TypeOf((*credProv)(nil)).Elem()
   149  	if !reflect.TypeOf(h.prov).Implements(inter) {
   150  		log.Debugf("credential updates not supported by agent")
   151  		return actions
   152  	}
   153  
   154  	if !hasAgentCredentialFinalizer(cr.Finalizers) || cr.Status.Level != prov.Pending.String() {
   155  		return actions
   156  	}
   157  
   158  	// suspend
   159  	if cr.Spec.State.Name == v1.Inactive && (cr.State.Name == v1.Active || cr.State.Name == "") {
   160  		actions = append(actions, prov.Suspend)
   161  	}
   162  
   163  	// rotate
   164  	if cr.Spec.State.Rotate {
   165  		actions = append(actions, prov.Rotate)
   166  	}
   167  
   168  	// enable
   169  	if cr.Spec.State.Name == v1.Active && cr.State.Name == v1.Inactive {
   170  		actions = append(actions, prov.Enable)
   171  	}
   172  	return actions
   173  }
   174  
   175  func (h *credentials) onDeleting(ctx context.Context, cred *management.Credential) {
   176  	logger := getLoggerFromContext(ctx)
   177  	provData := h.deprovisionPreProcess(ctx, cred)
   178  	crd, err := h.getCRD(ctx, cred)
   179  	if err != nil {
   180  		logger.WithError(err).Error("error getting credential request definition")
   181  		h.onError(ctx, cred, err)
   182  		return
   183  	}
   184  	app, err := h.getManagedApp(ctx, cred)
   185  	if err != nil {
   186  		logger.WithError(err).Error("error getting managed app")
   187  		h.onError(ctx, cred, err)
   188  		return
   189  	}
   190  
   191  	provCreds, err := h.newProvCreds(cred, app, provData, 0, crd)
   192  
   193  	if err != nil {
   194  		logger.WithError(err).Error("error preparing credential request")
   195  		h.onError(ctx, cred, err)
   196  		return
   197  	}
   198  
   199  	status := h.prov.CredentialDeprovision(provCreds)
   200  
   201  	h.deprovisionPostProcess(status, provCreds, logger, ctx, cred)
   202  }
   203  
   204  func (*credentials) deprovisionPreProcess(_ context.Context, cred *management.Credential) map[string]interface{} {
   205  	var provData map[string]interface{}
   206  	if cred.Data != nil {
   207  		if m, ok := cred.Data.(map[string]interface{}); ok {
   208  			provData = m
   209  		}
   210  	}
   211  	return provData
   212  }
   213  
   214  func (h *credentials) deprovisionPostProcess(status prov.RequestStatus, provCreds *provCreds, logger log.FieldLogger, ctx context.Context, cred *management.Credential) {
   215  	if status.GetStatus() == prov.Success {
   216  		if provCreds.IsIDPCredential() {
   217  			err := provCreds.idpProvisioner.UnregisterClient()
   218  			if err != nil {
   219  				logger.
   220  					WithError(err).
   221  					WithField("client_id", provCreds.idpProvisioner.GetIDPCredentialData().GetClientID()).
   222  					WithField("provider", provCreds.GetIDPProvider().GetName()).
   223  					Warn("error deprovisioning credential request from IDP, please ask administrator to remove the client from IdP")
   224  			}
   225  		}
   226  
   227  		ri, _ := cred.AsInstance()
   228  		h.client.UpdateResourceFinalizer(ri, crFinalizer, "", false)
   229  
   230  		// update sub resources when expire
   231  		if cred.Metadata.State != v1.ResourceDeleting {
   232  			cred.State.Name = v1.Inactive
   233  			cred.Status.Level = prov.Success.String()
   234  			cred.Status.Reasons = []v1.ResourceStatusReason{}
   235  			h.client.CreateSubResource(cred.ResourceMeta, map[string]interface{}{
   236  				"state": cred.State,
   237  			})
   238  			h.client.CreateSubResource(cred.ResourceMeta, map[string]interface{}{
   239  				"status": cred.Status,
   240  			})
   241  		}
   242  	} else {
   243  		err := fmt.Errorf(status.GetMessage())
   244  		logger.WithError(err).Error("request status was not Success, skipping")
   245  		h.onError(ctx, cred, err)
   246  		h.client.CreateSubResource(cred.ResourceMeta, cred.SubResources)
   247  	}
   248  }
   249  
   250  func (h *credentials) onPending(ctx context.Context, cred *management.Credential) *management.Credential {
   251  	// check the application status
   252  	logger := getLoggerFromContext(ctx)
   253  	app, crd, shouldReturn := h.provisionPreProcess(ctx, cred)
   254  	if shouldReturn {
   255  		return cred
   256  	}
   257  
   258  	provCreds, err := h.newProvCreds(cred, app, nil, 0, crd)
   259  	if err != nil {
   260  		logger.WithError(err).Error("error preparing credential request")
   261  		h.onError(ctx, cred, err)
   262  		return cred
   263  	}
   264  
   265  	if provCreds.IsIDPCredential() {
   266  		err := provCreds.idpProvisioner.RegisterClient()
   267  		if err != nil {
   268  			logger.WithError(err).Error("error provisioning credential request with IDP")
   269  			h.onError(ctx, cred, err)
   270  			return cred
   271  		}
   272  	}
   273  
   274  	status, credentialData := h.prov.CredentialProvision(provCreds)
   275  
   276  	h.provisionPostProcess(status, credentialData, app, crd, provCreds, cred)
   277  
   278  	return cred
   279  }
   280  
   281  func (h *credentials) provisionPreProcess(ctx context.Context, cred *management.Credential) (*management.ManagedApplication, *management.CredentialRequestDefinition, bool) {
   282  	logger := getLoggerFromContext(ctx)
   283  	app, err := h.getManagedApp(ctx, cred)
   284  	if err != nil {
   285  		logger.WithError(err).Error("error getting managed app")
   286  		h.onError(ctx, cred, err)
   287  		return nil, nil, true
   288  	}
   289  
   290  	if app.Status.Level != prov.Success.String() {
   291  		err = fmt.Errorf("cannot handle credential when application is not yet successful")
   292  		h.onError(ctx, cred, err)
   293  		return nil, nil, true
   294  	}
   295  
   296  	crd, err := h.getCRD(ctx, cred)
   297  	if err != nil {
   298  		logger.WithError(err).Error("error getting credential request definition")
   299  		h.onError(ctx, cred, err)
   300  		return nil, nil, true
   301  	}
   302  
   303  	return app, crd, false
   304  }
   305  
   306  func (h *credentials) provisionPostProcess(status prov.RequestStatus, credentialData prov.Credential, app *management.ManagedApplication, crd *management.CredentialRequestDefinition, provCreds *provCreds, cred *management.Credential) {
   307  	var err error
   308  	data := map[string]interface{}{}
   309  	idpAgentDetails := make(map[string]string)
   310  	if status.GetStatus() == prov.Success {
   311  		credentialData := h.getProvisionedCredentialData(provCreds, credentialData)
   312  		if credentialData != nil {
   313  			sec := app.Spec.Security
   314  			d := credentialData.GetData()
   315  			if crd.Spec.Provision == nil {
   316  				data = d
   317  			} else if d != nil {
   318  				data, err = h.encryptSchema(
   319  					crd.Spec.Provision.Schema,
   320  					d,
   321  					sec.EncryptionKey, sec.EncryptionAlgorithm, sec.EncryptionHash,
   322  				)
   323  			}
   324  			if provCreds.IsIDPCredential() {
   325  				idpAgentDetails, err = provCreds.idpProvisioner.GetAgentDetails()
   326  			}
   327  			if err != nil {
   328  				status = prov.NewRequestStatusBuilder().
   329  					SetMessage(fmt.Sprintf("error encrypting credential: %s", err.Error())).
   330  					SetCurrentStatusReasons(cred.Status.Reasons).
   331  					Failed()
   332  			}
   333  		}
   334  	}
   335  
   336  	cred.Data = data
   337  	cred.Status = prov.NewStatusReason(status)
   338  
   339  	// use the expiration time sent back with the data
   340  	if credentialData != nil && !credentialData.GetExpirationTime().IsZero() {
   341  		cred.Policies.Expiry = &management.CredentialPoliciesExpiry{
   342  			Timestamp: v1.Time(credentialData.GetExpirationTime()),
   343  		}
   344  	} else if provCreds.days != 0 {
   345  		// update the expiration timestamp
   346  		expTS := time.Now().AddDate(0, 0, provCreds.days)
   347  
   348  		cred.Policies.Expiry = &management.CredentialPoliciesExpiry{
   349  			Timestamp: v1.Time(expTS),
   350  		}
   351  	}
   352  
   353  	details := util.MergeMapStringString(util.GetAgentDetailStrings(cred), status.GetProperties(), idpAgentDetails)
   354  	util.SetAgentDetails(cred, util.MapStringStringToMapStringInterface(details))
   355  
   356  	h.processCredentialLevelSuccess(provCreds, cred)
   357  
   358  	cred.SubResources = map[string]interface{}{
   359  		defs.XAgentDetails: util.GetAgentDetails(cred),
   360  		"data":             cred.Data,
   361  		"policies":         cred.Policies,
   362  		"state":            cred.State,
   363  	}
   364  }
   365  
   366  func (h *credentials) processCredentialLevelSuccess(provCreds *provCreds, cred *management.Credential) {
   367  	if cred.Status.Level == prov.Success.String() {
   368  		if !hasAgentCredentialFinalizer(cred.Finalizers) {
   369  			ri, _ := cred.AsInstance()
   370  			// only add finalizer on success
   371  			h.client.UpdateResourceFinalizer(ri, crFinalizer, "", true)
   372  		}
   373  
   374  		if provCreds.GetCredentialAction() != prov.Rotate {
   375  			// if this is not a rotate action update the state to the desired state
   376  			cred.State.Name = cred.Spec.State.Name
   377  		} else {
   378  			// if the action was rotate lets remove the rotate flag from spec
   379  			cred.Spec.State.Rotate = false
   380  			h.client.UpdateResourceInstance(cred)
   381  		}
   382  	} else if cred.State.Name == "" {
   383  		cred.State.Name = v1.Inactive
   384  	}
   385  }
   386  
   387  func (h *credentials) onUpdates(ctx context.Context, cred *management.Credential, actions []prov.CredentialAction) *management.Credential {
   388  	logger := getLoggerFromContext(ctx)
   389  	app, crd, shouldReturn := h.provisionPreProcess(ctx, cred)
   390  	provData := h.deprovisionPreProcess(ctx, cred)
   391  	if shouldReturn {
   392  		return cred
   393  	}
   394  
   395  	for _, action := range actions {
   396  		provCreds, err := h.newProvCreds(cred, app, provData, action, crd)
   397  		if err != nil {
   398  			logger.WithError(err).Error("error preparing credential request")
   399  			h.onError(ctx, cred, err)
   400  			return cred
   401  		}
   402  
   403  		if action != prov.Suspend && provCreds.IsIDPCredential() {
   404  			err := provCreds.idpProvisioner.RegisterClient()
   405  			if err != nil {
   406  				logger.WithError(err).Error("error provisioning credential request with IDP")
   407  				h.onError(ctx, cred, err)
   408  				return cred
   409  			}
   410  		}
   411  
   412  		status, credentialData := h.prov.CredentialUpdate(provCreds)
   413  		h.provisionPostProcess(status, credentialData, app, crd, provCreds, cred)
   414  	}
   415  
   416  	return cred
   417  }
   418  
   419  // onError updates the AccessRequest with an error status
   420  func (h *credentials) onError(_ context.Context, cred *management.Credential, err error) {
   421  	ps := prov.NewRequestStatusBuilder()
   422  	status := ps.SetMessage(fmt.Sprintf("Agent: %s", err.Error())).SetCurrentStatusReasons(cred.Status.Reasons).Failed()
   423  	cred.Status = prov.NewStatusReason(status)
   424  	cred.SubResources = map[string]interface{}{
   425  		"status": cred.Status,
   426  	}
   427  }
   428  
   429  func (h *credentials) getManagedApp(_ context.Context, cred *management.Credential) (*management.ManagedApplication, error) {
   430  	app := management.NewManagedApplication(cred.Spec.ManagedApplication, cred.Metadata.Scope.Name)
   431  	ri, err := h.client.GetResource(app.GetSelfLink())
   432  	if err != nil {
   433  		return nil, err
   434  	}
   435  
   436  	app = &management.ManagedApplication{}
   437  	err = app.FromInstance(ri)
   438  	return app, err
   439  }
   440  
   441  func (h *credentials) getCRD(_ context.Context, cred *management.Credential) (*management.CredentialRequestDefinition, error) {
   442  	crd := management.NewCredentialRequestDefinition(cred.Spec.CredentialRequestDefinition, cred.Metadata.Scope.Name)
   443  	ri, err := h.client.GetResource(crd.GetSelfLink())
   444  	if err != nil {
   445  		return nil, err
   446  	}
   447  
   448  	crd = &management.CredentialRequestDefinition{}
   449  	err = crd.FromInstance(ri)
   450  	return crd, err
   451  }
   452  
   453  func (h *credentials) getProvisionedCredentialData(provCreds *provCreds, credentialData prov.Credential) prov.Credential {
   454  	if provCreds.IsIDPCredential() {
   455  		return prov.NewCredentialBuilder().SetOAuthIDAndSecret(
   456  			provCreds.GetIDPCredentialData().GetClientID(),
   457  			provCreds.GetIDPCredentialData().GetClientSecret(),
   458  		)
   459  	}
   460  	return credentialData
   461  }
   462  
   463  func hasAgentCredentialError(status *v1.ResourceStatus) bool {
   464  	for _, r := range status.Reasons {
   465  		if strings.HasPrefix(r.Detail, "Agent:") {
   466  			return true
   467  		}
   468  	}
   469  	return false
   470  }
   471  
   472  func hasAgentCredentialFinalizer(finalizers []v1.Finalizer) bool {
   473  	for _, f := range finalizers {
   474  		if f.Name == crFinalizer {
   475  			return true
   476  		}
   477  	}
   478  	return false
   479  }
   480  
   481  type provCreds struct {
   482  	managedApp        string
   483  	credType          string
   484  	id                string
   485  	name              string
   486  	days              int
   487  	credAction        prov.CredentialAction
   488  	credData          map[string]interface{}
   489  	credDetails       map[string]interface{}
   490  	appDetails        map[string]interface{}
   491  	idpProvisioner    idp.Provisioner
   492  	credSchema        map[string]interface{}
   493  	credProvSchema    map[string]interface{}
   494  	credSchemaDetails map[string]interface{}
   495  }
   496  
   497  func (h *credentials) newProvCreds(cr *management.Credential, app *management.ManagedApplication, provData map[string]interface{}, action prov.CredentialAction, crd *management.CredentialRequestDefinition) (*provCreds, error) {
   498  	credDetails := util.GetAgentDetails(cr)
   499  
   500  	provCred := &provCreds{
   501  		appDetails:  util.GetAgentDetails(app),
   502  		credDetails: credDetails,
   503  		credType:    cr.Spec.CredentialRequestDefinition,
   504  		credData:    cr.Spec.Data,
   505  		managedApp:  cr.Spec.ManagedApplication,
   506  		id:          cr.Metadata.ID,
   507  		name:        cr.Name,
   508  		credAction:  action,
   509  		days:        0,
   510  	}
   511  
   512  	if crd != nil {
   513  		if crd.Spec.Provision != nil &&
   514  			crd.Spec.Provision.Policies.Expiry != nil {
   515  			provCred.days = int(crd.Spec.Provision.Policies.Expiry.Period)
   516  		}
   517  
   518  		credSchemaDetails := util.GetAgentDetails(crd)
   519  		provCred.credSchema = crd.Spec.Schema
   520  		if crd.Spec.Provision != nil {
   521  			provCred.credProvSchema = crd.Spec.Provision.Schema
   522  		}
   523  		provCred.credSchemaDetails = credSchemaDetails
   524  	}
   525  	idpProvisioner, err := idp.NewProvisioner(context.Background(), h.idpProviderRegistry, app, cr)
   526  	if err != nil {
   527  		return nil, fmt.Errorf("IDP provider not found for credential request")
   528  	}
   529  	provCred.idpProvisioner = idpProvisioner
   530  	return provCred, nil
   531  }
   532  
   533  // GetApplicationName gets the name of the managed application
   534  func (c provCreds) GetApplicationName() string {
   535  	return c.managedApp
   536  }
   537  
   538  // GetID gets the id of the credential resource
   539  func (c provCreds) GetID() string {
   540  	return c.id
   541  }
   542  
   543  // GetName gets the name of the credential resource
   544  func (c provCreds) GetName() string {
   545  	return c.name
   546  }
   547  
   548  // GetCredentialType gets the type of the credential
   549  func (c provCreds) GetCredentialType() string {
   550  	return c.credType
   551  }
   552  
   553  // GetCredentialData gets the data of the credential
   554  func (c provCreds) GetCredentialData() map[string]interface{} {
   555  	return c.credData
   556  }
   557  
   558  // GetCredentialAction gets the data of the credential
   559  func (c provCreds) GetCredentialAction() prov.CredentialAction {
   560  	return c.credAction
   561  }
   562  
   563  // GetID gets the id of the credential resource
   564  func (c provCreds) GetCredentialExpirationDays() int {
   565  	return c.days
   566  }
   567  
   568  // GetCredentialSchema returns the schema for the credential request.
   569  func (c provCreds) GetCredentialSchema() map[string]interface{} {
   570  	return c.credSchema
   571  }
   572  
   573  // GetCredentialProvisionSchema returns the provisioning schema for the credential request.
   574  func (c provCreds) GetCredentialProvisionSchema() map[string]interface{} {
   575  	return c.credProvSchema
   576  }
   577  
   578  // GetCredentialSchemaDetailsValue returns a value found on the 'x-agent-details' sub resource of the crd.
   579  func (c provCreds) GetCredentialSchemaDetailsValue(key string) interface{} {
   580  	if c.credSchemaDetails == nil {
   581  		return nil
   582  	}
   583  
   584  	return c.credSchemaDetails[key]
   585  }
   586  
   587  // IsIDPCredential returns boolean indicating if the credential request is for IDP provider
   588  func (c provCreds) IsIDPCredential() bool {
   589  	return c.idpProvisioner.IsIDPCredential()
   590  }
   591  
   592  // GetIDPProvider returns the interface for IDP provider if the credential request is for IDP provider
   593  func (c provCreds) GetIDPProvider() oauth.Provider {
   594  	return c.idpProvisioner.GetIDPProvider()
   595  }
   596  
   597  // GetIDPCredentialData returns the credential data for IDP from the request
   598  func (c provCreds) GetIDPCredentialData() prov.IDPCredentialData {
   599  	return c.idpProvisioner.GetIDPCredentialData()
   600  }
   601  
   602  // GetCredentialDetailsValue returns a value found on the 'x-agent-details' sub resource of the Credentials.
   603  func (c provCreds) GetCredentialDetailsValue(key string) string {
   604  	if c.credDetails == nil {
   605  		return ""
   606  	}
   607  
   608  	return util.ToString(c.credDetails[key])
   609  }
   610  
   611  // GetApplicationDetailsValue returns a value found on the 'x-agent-details' sub resource of the ManagedApplication.
   612  func (c provCreds) GetApplicationDetailsValue(key string) string {
   613  	if c.appDetails == nil {
   614  		return ""
   615  	}
   616  
   617  	return util.ToString(c.appDetails[key])
   618  }
   619  
   620  // encryptSchema schema is the json schema. credData is the data that contains data to encrypt based on the key, alg and hash.
   621  func encryptSchema(
   622  	schema, credData map[string]interface{}, key, alg, hash string,
   623  ) (map[string]interface{}, error) {
   624  	data := make(map[string]interface{})
   625  	enc, err := util.NewEncryptor(key, alg, hash)
   626  	if err != nil {
   627  		return data, err
   628  	}
   629  
   630  	schemaProps, ok := schema["properties"]
   631  	if !ok {
   632  		return data, fmt.Errorf("properties field not found on schema")
   633  	}
   634  
   635  	props, ok := schemaProps.(map[string]interface{})
   636  	if !ok {
   637  		props = make(map[string]interface{})
   638  	}
   639  
   640  	return encryptMap(enc, props, credData), nil
   641  }
   642  
   643  // encryptMap loops through all data and checks the value against the provisioning schema to see if it should be encrypted.
   644  func encryptMap(enc util.Encryptor, schema, data map[string]interface{}) map[string]interface{} {
   645  	for key, value := range data {
   646  		schemaValue := schema[key]
   647  		v, ok := schemaValue.(map[string]interface{})
   648  		if !ok {
   649  			continue
   650  		}
   651  
   652  		if _, ok := v[xAxwayEncrypted]; ok {
   653  			v, ok := value.(string)
   654  			if !ok {
   655  				continue
   656  			}
   657  
   658  			str, err := enc.Encrypt(v)
   659  			if err != nil {
   660  
   661  				log.Error(err)
   662  				continue
   663  			}
   664  
   665  			data[key] = base64.StdEncoding.EncodeToString([]byte(str))
   666  		}
   667  	}
   668  
   669  	return data
   670  }