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 }