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

     1  package agent
     2  
     3  import (
     4  	"github.com/Axway/agent-sdk/pkg/agent/handler"
     5  	v1 "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/api/v1"
     6  	management "github.com/Axway/agent-sdk/pkg/apic/apiserver/models/management/v1alpha1"
     7  	"github.com/Axway/agent-sdk/pkg/apic/provisioning"
     8  	"github.com/Axway/agent-sdk/pkg/authz/oauth"
     9  	"github.com/Axway/agent-sdk/pkg/config"
    10  	"github.com/Axway/agent-sdk/pkg/util"
    11  )
    12  
    13  var supportedIDPGrantTypes = map[string]bool{
    14  	oauth.GrantTypeClientCredentials: true,
    15  	oauth.GrantTypeAuthorizationCode: true}
    16  
    17  var supportedIDPTokenAuthMethods = map[string]bool{
    18  	config.ClientSecretBasic:       true,
    19  	config.ClientSecretPost:        true,
    20  	config.ClientSecretJWT:         true,
    21  	config.PrivateKeyJWT:           true,
    22  	config.TLSClientAuth:           true,
    23  	config.SelfSignedTLSClientAuth: true,
    24  }
    25  
    26  var tlsAuthCertificateMetadata = []string{
    27  	oauth.TLSClientAuthSubjectDN,
    28  	oauth.TLSClientAuthSanDNS,
    29  	oauth.TLSClientAuthSanEmail,
    30  	oauth.TLSClientAuthSanIP,
    31  	oauth.TLSClientAuthSanURI,
    32  }
    33  
    34  // createOrUpdateCredentialRequestDefinition -
    35  func createOrUpdateCredentialRequestDefinition(data *management.CredentialRequestDefinition) (*management.CredentialRequestDefinition, error) {
    36  	ri, err := createOrUpdateDefinition(data)
    37  	if ri == nil || err != nil {
    38  		return nil, err
    39  	}
    40  	err = data.FromInstance(ri)
    41  	return data, err
    42  }
    43  
    44  // createOrUpdateDefinition -
    45  func createOrUpdateDefinition(data v1.Interface) (*v1.ResourceInstance, error) {
    46  
    47  	ri, err := agent.apicClient.CreateOrUpdateResource(data)
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	var existingRI *v1.ResourceInstance
    53  
    54  	switch ri.Kind {
    55  	case management.AccessRequestDefinitionGVK().Kind:
    56  		existingRI, _ = agent.cacheManager.GetAccessRequestDefinitionByName(ri.Name)
    57  	case management.CredentialRequestDefinitionGVK().Kind:
    58  		existingRI, _ = agent.cacheManager.GetCredentialRequestDefinitionByName(ri.Name)
    59  	}
    60  
    61  	// if not existing, go ahead and add the request definition
    62  	if existingRI == nil {
    63  		switch ri.Kind {
    64  		case management.AccessRequestDefinitionGVK().Kind:
    65  			agent.cacheManager.AddAccessRequestDefinition(ri)
    66  		case management.CredentialRequestDefinitionGVK().Kind:
    67  			agent.cacheManager.AddCredentialRequestDefinition(ri)
    68  		}
    69  	}
    70  
    71  	return ri, nil
    72  }
    73  
    74  type crdBuilderOptions struct {
    75  	name               string
    76  	title              string
    77  	renewable          bool
    78  	suspendable        bool
    79  	deprovisionExpired bool
    80  	expirationDays     int
    81  	provProps          []provisioning.PropertyBuilder
    82  	reqProps           []provisioning.PropertyBuilder
    83  	registerFunc       provisioning.RegisterCredentialRequestDefinition
    84  }
    85  
    86  // NewCredentialRequestBuilder - called by the agents to build and register a new credential request definition
    87  func NewCredentialRequestBuilder(options ...func(*crdBuilderOptions)) provisioning.CredentialRequestBuilder {
    88  	thisCred := &crdBuilderOptions{
    89  		renewable:    false,
    90  		provProps:    make([]provisioning.PropertyBuilder, 0),
    91  		reqProps:     make([]provisioning.PropertyBuilder, 0),
    92  		registerFunc: createOrUpdateCredentialRequestDefinition,
    93  	}
    94  
    95  	if agent.cfg != nil {
    96  		thisCred.expirationDays = agent.cfg.GetCredentialConfig().GetExpirationDays()
    97  		thisCred.deprovisionExpired = agent.cfg.GetCredentialConfig().ShouldDeprovisionExpired()
    98  	}
    99  
   100  	for _, o := range options {
   101  		o(thisCred)
   102  	}
   103  
   104  	provSchema := provisioning.NewSchemaBuilder()
   105  	for _, provProp := range thisCred.provProps {
   106  		provSchema.AddProperty(provProp)
   107  	}
   108  
   109  	reqSchema := provisioning.NewSchemaBuilder()
   110  	for _, props := range thisCred.reqProps {
   111  		reqSchema.AddProperty(props)
   112  	}
   113  
   114  	builder := provisioning.NewCRDBuilder(thisCred.registerFunc).
   115  		SetName(thisCred.name).
   116  		SetTitle(thisCred.title).
   117  		SetProvisionSchema(provSchema).
   118  		SetRequestSchema(reqSchema).
   119  		SetExpirationDays(thisCred.expirationDays)
   120  
   121  	if thisCred.renewable {
   122  		builder.IsRenewable()
   123  	}
   124  
   125  	if thisCred.suspendable {
   126  		builder.IsSuspendable()
   127  	}
   128  
   129  	if thisCred.deprovisionExpired {
   130  		builder.SetDeprovisionExpired()
   131  	}
   132  
   133  	return builder
   134  }
   135  
   136  // WithCRDName - set another name for the CRD
   137  func WithCRDName(name string) func(c *crdBuilderOptions) {
   138  	return func(c *crdBuilderOptions) {
   139  		c.name = name
   140  	}
   141  }
   142  
   143  // WithCRDTitle - set the title for the CRD
   144  func WithCRDTitle(title string) func(c *crdBuilderOptions) {
   145  	return func(c *crdBuilderOptions) {
   146  		c.title = title
   147  	}
   148  }
   149  
   150  // WithCRDIsRenewable - set the flag for renewable credential
   151  func WithCRDIsRenewable() func(c *crdBuilderOptions) {
   152  	return func(c *crdBuilderOptions) {
   153  		c.renewable = true
   154  	}
   155  }
   156  
   157  // WithCRDIsSuspendable - set the flag for suspendable credential
   158  func WithCRDIsSuspendable() func(c *crdBuilderOptions) {
   159  	return func(c *crdBuilderOptions) {
   160  		c.suspendable = true
   161  	}
   162  }
   163  
   164  // WithCRDExpirationDays - set the expiration days
   165  func WithCRDExpirationDays(expirationDays int) func(c *crdBuilderOptions) {
   166  	return func(c *crdBuilderOptions) {
   167  		c.expirationDays = expirationDays
   168  	}
   169  }
   170  
   171  // WithCRDDeprovisionExpired - set the flag for deprovisioning expired credential
   172  func WithCRDDeprovisionExpired() func(c *crdBuilderOptions) {
   173  	return func(c *crdBuilderOptions) {
   174  		c.deprovisionExpired = true
   175  	}
   176  }
   177  
   178  // WithCRDProvisionSchemaProperty - add more provisioning properties
   179  func WithCRDProvisionSchemaProperty(prop provisioning.PropertyBuilder) func(c *crdBuilderOptions) {
   180  	return func(c *crdBuilderOptions) {
   181  		c.provProps = append(c.provProps, prop)
   182  	}
   183  }
   184  
   185  // WithCRDRequestSchemaProperty - add more request properties
   186  func WithCRDRequestSchemaProperty(prop provisioning.PropertyBuilder) func(c *crdBuilderOptions) {
   187  	return func(c *crdBuilderOptions) {
   188  		c.reqProps = append(c.reqProps, prop)
   189  	}
   190  }
   191  
   192  // WithCRDRegisterFunc - use the provided registration function for creating CRD
   193  func WithCRDRegisterFunc(registerFunc provisioning.RegisterCredentialRequestDefinition) func(c *crdBuilderOptions) {
   194  	return func(c *crdBuilderOptions) {
   195  		c.registerFunc = registerFunc
   196  	}
   197  }
   198  
   199  func idpUsesPrivateKeyJWTAuth(tokenAuthMethods []string) bool {
   200  	for _, s := range tokenAuthMethods {
   201  		if s == config.PrivateKeyJWT {
   202  			return true
   203  		}
   204  	}
   205  	return false
   206  }
   207  
   208  func idpUsesTLSClientAuth(tokenAuthMethods []string) bool {
   209  	for _, s := range tokenAuthMethods {
   210  		if s == config.TLSClientAuth || s == config.SelfSignedTLSClientAuth {
   211  			return true
   212  		}
   213  	}
   214  	return false
   215  }
   216  
   217  // WithCRDForIDP - set the schema properties using the provider metadata
   218  func WithCRDForIDP(p oauth.Provider, scopes []string) func(c *crdBuilderOptions) {
   219  	return func(c *crdBuilderOptions) {
   220  		if c.name == "" {
   221  			name := util.ConvertToDomainNameCompliant(p.GetName())
   222  			c.name = name + "-" + provisioning.OAuthIDPCRD
   223  			c.title = "OAuth" + p.GetName()
   224  		}
   225  
   226  		setIDPClientSecretSchemaProperty(c)
   227  		setIDPTokenURLSchemaProperty(p, c)
   228  		setIDPScopesSchemaProperty(scopes, c)
   229  		setIDPGrantTypesSchemaProperty(p, c)
   230  		setIDPTokenAuthMethodSchemaProperty(p, c)
   231  		setIDPRedirectURIsSchemaProperty(c)
   232  	}
   233  }
   234  
   235  func setIDPClientSecretSchemaProperty(c *crdBuilderOptions) {
   236  	c.provProps = append(c.provProps,
   237  		provisioning.NewSchemaPropertyBuilder().
   238  			SetName(provisioning.OauthClientSecret).
   239  			SetLabel("Client Secret").
   240  			IsString().
   241  			IsEncrypted())
   242  }
   243  
   244  func setIDPTokenURLSchemaProperty(p oauth.Provider, c *crdBuilderOptions) {
   245  	c.reqProps = append(c.reqProps,
   246  		provisioning.NewSchemaPropertyBuilder().
   247  			SetName(provisioning.IDPTokenURL).
   248  			SetRequired().
   249  			SetLabel("Token URL").
   250  			SetReadOnly().
   251  			IsString().
   252  			SetDefaultValue(p.GetTokenEndpoint()))
   253  }
   254  
   255  func setIDPScopesSchemaProperty(scopes []string, c *crdBuilderOptions) {
   256  	c.reqProps = append(c.reqProps,
   257  		provisioning.NewSchemaPropertyBuilder().
   258  			SetName(provisioning.OauthScopes).
   259  			SetLabel("Scopes").
   260  			IsArray().
   261  			AddItem(
   262  				provisioning.NewSchemaPropertyBuilder().
   263  					SetName("scope").
   264  					IsString().SetEnumValues(scopes).SetSortEnumValues()))
   265  }
   266  
   267  func setIDPGrantTypesSchemaProperty(p oauth.Provider, c *crdBuilderOptions) {
   268  	grantType, defaultGrantType := removeUnsupportedTypes(
   269  		p.GetSupportedGrantTypes(), supportedIDPGrantTypes, oauth.GrantTypeClientCredentials)
   270  
   271  	c.reqProps = append(c.reqProps,
   272  		provisioning.NewSchemaPropertyBuilder().
   273  			SetName(provisioning.OauthGrantType).
   274  			SetLabel("Grant Type").
   275  			IsString().
   276  			SetDefaultValue(defaultGrantType).
   277  			SetEnumValues(grantType))
   278  }
   279  
   280  func removeUnsupportedTypes(values []string, supportedTypes map[string]bool, defaultType string) ([]string, string) {
   281  	var result []string
   282  	defaultSupportedType := ""
   283  	defaultExists := false
   284  	for _, s := range values {
   285  		if ok := supportedTypes[s]; ok {
   286  			if s == defaultType {
   287  				defaultExists = true
   288  			}
   289  			if defaultSupportedType == "" {
   290  				defaultSupportedType = s
   291  			}
   292  			result = append(result, s)
   293  		}
   294  	}
   295  
   296  	if !defaultExists {
   297  		defaultType = defaultSupportedType
   298  	}
   299  	return result, defaultType
   300  }
   301  
   302  func setIDPTokenAuthMethodSchemaProperty(p oauth.Provider, c *crdBuilderOptions) []string {
   303  	tokenAuthMethods, defaultTokenMethod := removeUnsupportedTypes(
   304  		p.GetSupportedTokenAuthMethods(), supportedIDPTokenAuthMethods, config.ClientSecretBasic)
   305  
   306  	tmBuilder := provisioning.NewSchemaPropertyBuilder().
   307  		SetName(provisioning.OauthTokenAuthMethod).
   308  		SetLabel("Token Auth Method").
   309  		IsString().
   310  		SetDefaultValue(defaultTokenMethod).
   311  		SetEnumValues(tokenAuthMethods)
   312  
   313  	if idpUsesPrivateKeyJWTAuth(tokenAuthMethods) {
   314  		setIDPJWKSURISchemaProperty(config.PrivateKeyJWT, tmBuilder)
   315  		setIDPJWKSSchemaProperty(config.PrivateKeyJWT, tmBuilder)
   316  	}
   317  
   318  	if idpUsesTLSClientAuth(tokenAuthMethods) {
   319  		setIDPJWKSURISchemaProperty(config.TLSClientAuth, tmBuilder)
   320  		setIDPTLSClientAuthSchemaProperty(tmBuilder)
   321  	}
   322  
   323  	c.reqProps = append(c.reqProps, tmBuilder)
   324  	return tokenAuthMethods
   325  }
   326  
   327  func setIDPRedirectURIsSchemaProperty(c *crdBuilderOptions) {
   328  	c.reqProps = append(c.reqProps,
   329  		provisioning.NewSchemaPropertyBuilder().
   330  			SetName(provisioning.OauthRedirectURIs).
   331  			SetLabel("Redirect URLs").
   332  			IsArray().
   333  			AddItem(
   334  				provisioning.NewSchemaPropertyBuilder().
   335  					SetName("URL").
   336  					IsString()))
   337  }
   338  
   339  func setIDPJWKSURISchemaProperty(depValue string, propBuilder provisioning.StringPropertyBuilder) {
   340  	propBuilder.AddDependency(
   341  		depValue,
   342  		provisioning.NewSchemaPropertyBuilder().
   343  			SetName(provisioning.OauthJwksURI).
   344  			SetLabel("JWKS URI").
   345  			IsString())
   346  }
   347  
   348  func setIDPJWKSSchemaProperty(depValue string, propBuilder provisioning.StringPropertyBuilder) {
   349  	propBuilder.AddDependency(
   350  		depValue,
   351  		provisioning.NewSchemaPropertyBuilder().
   352  			SetName(provisioning.OauthJwks).
   353  			SetLabel("Public Key").
   354  			IsString())
   355  }
   356  
   357  func setIDPTLSClientAuthSchemaProperty(propBuilder provisioning.StringPropertyBuilder) {
   358  	propBuilder.AddDependency(
   359  		config.TLSClientAuth,
   360  		provisioning.NewSchemaPropertyBuilder().
   361  			SetName(provisioning.OauthCertificate).
   362  			SetLabel("Public Certificate").
   363  			IsString())
   364  
   365  	certMetadataBuilder := provisioning.NewSchemaPropertyBuilder().
   366  		SetName(provisioning.OauthCertificateMetadata).
   367  		SetLabel("Certificate Metadata").
   368  		IsString().
   369  		SetDefaultValue(oauth.TLSClientAuthSubjectDN).
   370  		SetEnumValues(tlsAuthCertificateMetadata)
   371  
   372  	propBuilder.AddDependency(
   373  		config.TLSClientAuth,
   374  		certMetadataBuilder,
   375  	)
   376  	certMetadataBuilder.AddDependency(
   377  		oauth.TLSClientAuthSanDNS,
   378  		provisioning.NewSchemaPropertyBuilder().
   379  			SetName(provisioning.OauthTLSAuthSANDNS).
   380  			SetLabel("Certificate Subject Alternative Name, DNS").
   381  			IsString())
   382  
   383  	certMetadataBuilder.AddDependency(
   384  		oauth.TLSClientAuthSanEmail,
   385  		provisioning.NewSchemaPropertyBuilder().
   386  			SetName(provisioning.OauthTLSAuthSANEmail).
   387  			SetLabel("Certificate Subject Alternative Name, Email").
   388  			IsString())
   389  
   390  	certMetadataBuilder.AddDependency(
   391  		oauth.TLSClientAuthSanIP,
   392  		provisioning.NewSchemaPropertyBuilder().
   393  			SetName(provisioning.OauthTLSAuthSANIP).
   394  			SetLabel("Certificate Subject Alternative Name, IP address").
   395  			IsString())
   396  
   397  	certMetadataBuilder.AddDependency(
   398  		oauth.TLSClientAuthSanURI,
   399  		provisioning.NewSchemaPropertyBuilder().
   400  			SetName(provisioning.OauthTLSAuthSANURI).
   401  			SetLabel("Certificate Subject Alternative Name, URI").
   402  			IsString())
   403  }
   404  
   405  // WithCRDOAuthSecret - set that the Oauth cred is secret based
   406  func WithCRDOAuthSecret() func(c *crdBuilderOptions) {
   407  	return func(c *crdBuilderOptions) {
   408  		if c.name == "" {
   409  			c.name = provisioning.OAuthSecretCRD
   410  			c.title = "OAuth Client ID & Secret"
   411  		}
   412  		c.provProps = append(c.provProps,
   413  			provisioning.NewSchemaPropertyBuilder().
   414  				SetName(provisioning.OauthClientSecret).
   415  				SetLabel("Client Secret").
   416  				SetRequired().
   417  				IsString().
   418  				IsEncrypted())
   419  	}
   420  }
   421  
   422  // WithCRDOAuthPublicKey - set that the Oauth cred is key based
   423  func WithCRDOAuthPublicKey() func(c *crdBuilderOptions) {
   424  	return func(c *crdBuilderOptions) {
   425  		if c.name == "" {
   426  			c.name = provisioning.OAuthPublicKeyCRD
   427  			c.title = "OAuth Client ID & Private Key"
   428  		}
   429  
   430  		c.reqProps = append(c.reqProps,
   431  			provisioning.NewSchemaPropertyBuilder().
   432  				SetName(provisioning.OauthPublicKey).
   433  				SetLabel("Public Key").
   434  				SetRequired().
   435  				IsString())
   436  	}
   437  }
   438  
   439  // NewAPIKeyCredentialRequestBuilder - add api key base properties for provisioning schema
   440  func NewAPIKeyCredentialRequestBuilder(options ...func(*crdBuilderOptions)) provisioning.CredentialRequestBuilder {
   441  	apiKeyOptions := []func(*crdBuilderOptions){
   442  		WithCRDName(provisioning.APIKeyCRD),
   443  		WithCRDTitle("API Key"),
   444  		WithCRDProvisionSchemaProperty(
   445  			provisioning.NewSchemaPropertyBuilder().
   446  				SetName(provisioning.APIKey).
   447  				SetLabel("API Key").
   448  				SetRequired().
   449  				IsString().
   450  				IsEncrypted()),
   451  	}
   452  
   453  	apiKeyOptions = append(apiKeyOptions, options...)
   454  
   455  	return NewCredentialRequestBuilder(apiKeyOptions...)
   456  }
   457  
   458  // NewBasicAuthCredentialRequestBuilder - add basic auth base properties for provisioning schema
   459  func NewBasicAuthCredentialRequestBuilder(options ...func(*crdBuilderOptions)) provisioning.CredentialRequestBuilder {
   460  	basicAuthOptions := []func(*crdBuilderOptions){
   461  		WithCRDName(provisioning.BasicAuthCRD),
   462  		WithCRDTitle("Basic Auth"),
   463  		WithCRDProvisionSchemaProperty(
   464  			provisioning.NewSchemaPropertyBuilder().
   465  				SetName(provisioning.BasicAuthUsername).
   466  				SetLabel("Username").
   467  				SetRequired().
   468  				IsString().
   469  				IsEncrypted()),
   470  		WithCRDProvisionSchemaProperty(
   471  			provisioning.NewSchemaPropertyBuilder().
   472  				SetName(provisioning.BasicAuthPassword).
   473  				SetLabel("Password").
   474  				SetRequired().
   475  				IsString().
   476  				IsEncrypted()),
   477  	}
   478  
   479  	basicAuthOptions = append(basicAuthOptions, options...)
   480  
   481  	return NewCredentialRequestBuilder(basicAuthOptions...)
   482  }
   483  
   484  // NewOAuthCredentialRequestBuilder - add oauth base properties for provisioning schema
   485  func NewOAuthCredentialRequestBuilder(options ...func(*crdBuilderOptions)) provisioning.CredentialRequestBuilder {
   486  	oauthOptions := []func(*crdBuilderOptions){
   487  		WithCRDProvisionSchemaProperty(
   488  			provisioning.NewSchemaPropertyBuilder().
   489  				SetName(provisioning.OauthClientID).
   490  				SetLabel("Client ID").
   491  				SetRequired().
   492  				IsString().
   493  				IsCopyable()),
   494  	}
   495  
   496  	oauthOptions = append(oauthOptions, options...)
   497  
   498  	return NewCredentialRequestBuilder(oauthOptions...)
   499  }
   500  
   501  // access request definitions
   502  
   503  // createOrUpdateAccessRequestDefinition -
   504  func createOrUpdateAccessRequestDefinition(data *management.AccessRequestDefinition) (*management.AccessRequestDefinition, error) {
   505  	ri, err := createOrUpdateDefinition(data)
   506  	if ri == nil || err != nil {
   507  		return nil, err
   508  	}
   509  	err = data.FromInstance(ri)
   510  	return data, err
   511  }
   512  
   513  // NewAccessRequestBuilder - called by the agents to build and register a new access request definition
   514  func NewAccessRequestBuilder() provisioning.AccessRequestBuilder {
   515  	return provisioning.NewAccessRequestBuilder(createOrUpdateAccessRequestDefinition)
   516  }
   517  
   518  // NewBasicAuthAccessRequestBuilder - called by the agents
   519  func NewBasicAuthAccessRequestBuilder() provisioning.AccessRequestBuilder {
   520  	return NewAccessRequestBuilder().SetName(provisioning.BasicAuthARD)
   521  }
   522  
   523  // NewAPIKeyAccessRequestBuilder - called by the agents
   524  func NewAPIKeyAccessRequestBuilder() provisioning.AccessRequestBuilder {
   525  	return NewAccessRequestBuilder().SetName(provisioning.APIKeyARD)
   526  }
   527  
   528  // provisioner
   529  
   530  // RegisterProvisioner - allow the agent to register a provisioner
   531  func RegisterProvisioner(provisioner provisioning.Provisioning) {
   532  	if agent.agentFeaturesCfg == nil {
   533  		return
   534  	}
   535  	agent.provisioner = provisioner
   536  
   537  	if agent.cfg.GetAgentType() == config.DiscoveryAgent || agent.cfg.GetAgentType() == config.GovernanceAgent {
   538  		agent.proxyResourceHandler.RegisterTargetHandler(
   539  			"accessrequesthandler",
   540  			handler.NewAccessRequestHandler(agent.provisioner, agent.cacheManager, agent.apicClient),
   541  		)
   542  		agent.proxyResourceHandler.RegisterTargetHandler(
   543  			"managedappHandler",
   544  			handler.NewManagedApplicationHandler(agent.provisioner, agent.cacheManager, agent.apicClient),
   545  		)
   546  		registry := oauth.NewIdpRegistry(oauth.WithProviderRegistry(GetAuthProviderRegistry()))
   547  		agent.proxyResourceHandler.RegisterTargetHandler(
   548  			"credentialHandler",
   549  			handler.NewCredentialHandler(agent.provisioner, agent.apicClient, registry),
   550  		)
   551  	}
   552  }