1package api 2 3import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "io/ioutil" 8 "net/url" 9 "time" 10 11 "github.com/mitchellh/mapstructure" 12) 13 14const ( 15 // ACLClientType is the client type token 16 ACLClientType = "client" 17 18 // ACLManagementType is the management type token 19 ACLManagementType = "management" 20) 21 22type ACLLink struct { 23 ID string 24 Name string 25} 26 27type ACLTokenPolicyLink = ACLLink 28type ACLTokenRoleLink = ACLLink 29 30// ACLToken represents an ACL Token 31type ACLToken struct { 32 CreateIndex uint64 33 ModifyIndex uint64 34 AccessorID string 35 SecretID string 36 Description string 37 Policies []*ACLTokenPolicyLink `json:",omitempty"` 38 Roles []*ACLTokenRoleLink `json:",omitempty"` 39 ServiceIdentities []*ACLServiceIdentity `json:",omitempty"` 40 NodeIdentities []*ACLNodeIdentity `json:",omitempty"` 41 Local bool 42 AuthMethod string `json:",omitempty"` 43 ExpirationTTL time.Duration `json:",omitempty"` 44 ExpirationTime *time.Time `json:",omitempty"` 45 CreateTime time.Time `json:",omitempty"` 46 Hash []byte `json:",omitempty"` 47 48 // DEPRECATED (ACL-Legacy-Compat) 49 // Rules will only be present for legacy tokens returned via the new APIs 50 Rules string `json:",omitempty"` 51 52 // Namespace is the namespace the ACLToken is associated with. 53 // Namespaces are a Consul Enterprise feature. 54 Namespace string `json:",omitempty"` 55} 56 57type ACLTokenListEntry struct { 58 CreateIndex uint64 59 ModifyIndex uint64 60 AccessorID string 61 SecretID string 62 Description string 63 Policies []*ACLTokenPolicyLink `json:",omitempty"` 64 Roles []*ACLTokenRoleLink `json:",omitempty"` 65 ServiceIdentities []*ACLServiceIdentity `json:",omitempty"` 66 NodeIdentities []*ACLNodeIdentity `json:",omitempty"` 67 Local bool 68 AuthMethod string `json:",omitempty"` 69 ExpirationTime *time.Time `json:",omitempty"` 70 CreateTime time.Time 71 Hash []byte 72 Legacy bool 73 74 // Namespace is the namespace the ACLTokenListEntry is associated with. 75 // Namespacing is a Consul Enterprise feature. 76 Namespace string `json:",omitempty"` 77} 78 79// ACLEntry is used to represent a legacy ACL token 80// The legacy tokens are deprecated. 81type ACLEntry struct { 82 CreateIndex uint64 83 ModifyIndex uint64 84 ID string 85 Name string 86 Type string 87 Rules string 88} 89 90// ACLReplicationStatus is used to represent the status of ACL replication. 91type ACLReplicationStatus struct { 92 Enabled bool 93 Running bool 94 SourceDatacenter string 95 ReplicationType string 96 ReplicatedIndex uint64 97 ReplicatedRoleIndex uint64 98 ReplicatedTokenIndex uint64 99 LastSuccess time.Time 100 LastError time.Time 101} 102 103// ACLServiceIdentity represents a high-level grant of all necessary privileges 104// to assume the identity of the named Service in the Catalog and within 105// Connect. 106type ACLServiceIdentity struct { 107 ServiceName string 108 Datacenters []string `json:",omitempty"` 109} 110 111// ACLNodeIdentity represents a high-level grant of all necessary privileges 112// to assume the identity of the named Node in the Catalog and within Connect. 113type ACLNodeIdentity struct { 114 NodeName string 115 Datacenter string 116} 117 118// ACLPolicy represents an ACL Policy. 119type ACLPolicy struct { 120 ID string 121 Name string 122 Description string 123 Rules string 124 Datacenters []string 125 Hash []byte 126 CreateIndex uint64 127 ModifyIndex uint64 128 129 // Namespace is the namespace the ACLPolicy is associated with. 130 // Namespacing is a Consul Enterprise feature. 131 Namespace string `json:",omitempty"` 132} 133 134type ACLPolicyListEntry struct { 135 ID string 136 Name string 137 Description string 138 Datacenters []string 139 Hash []byte 140 CreateIndex uint64 141 ModifyIndex uint64 142 143 // Namespace is the namespace the ACLPolicyListEntry is associated with. 144 // Namespacing is a Consul Enterprise feature. 145 Namespace string `json:",omitempty"` 146} 147 148type ACLRolePolicyLink = ACLLink 149 150// ACLRole represents an ACL Role. 151type ACLRole struct { 152 ID string 153 Name string 154 Description string 155 Policies []*ACLRolePolicyLink `json:",omitempty"` 156 ServiceIdentities []*ACLServiceIdentity `json:",omitempty"` 157 NodeIdentities []*ACLNodeIdentity `json:",omitempty"` 158 Hash []byte 159 CreateIndex uint64 160 ModifyIndex uint64 161 162 // Namespace is the namespace the ACLRole is associated with. 163 // Namespacing is a Consul Enterprise feature. 164 Namespace string `json:",omitempty"` 165} 166 167// BindingRuleBindType is the type of binding rule mechanism used. 168type BindingRuleBindType string 169 170const ( 171 // BindingRuleBindTypeService binds to a service identity with the given name. 172 BindingRuleBindTypeService BindingRuleBindType = "service" 173 174 // BindingRuleBindTypeRole binds to pre-existing roles with the given name. 175 BindingRuleBindTypeRole BindingRuleBindType = "role" 176) 177 178type ACLBindingRule struct { 179 ID string 180 Description string 181 AuthMethod string 182 Selector string 183 BindType BindingRuleBindType 184 BindName string 185 186 CreateIndex uint64 187 ModifyIndex uint64 188 189 // Namespace is the namespace the ACLBindingRule is associated with. 190 // Namespacing is a Consul Enterprise feature. 191 Namespace string `json:",omitempty"` 192} 193 194type ACLAuthMethod struct { 195 Name string 196 Type string 197 DisplayName string `json:",omitempty"` 198 Description string `json:",omitempty"` 199 MaxTokenTTL time.Duration `json:",omitempty"` 200 201 // TokenLocality defines the kind of token that this auth method produces. 202 // This can be either 'local' or 'global'. If empty 'local' is assumed. 203 TokenLocality string `json:",omitempty"` 204 205 // Configuration is arbitrary configuration for the auth method. This 206 // should only contain primitive values and containers (such as lists and 207 // maps). 208 Config map[string]interface{} 209 210 CreateIndex uint64 211 ModifyIndex uint64 212 213 // NamespaceRules apply only on auth methods defined in the default namespace. 214 // Namespacing is a Consul Enterprise feature. 215 NamespaceRules []*ACLAuthMethodNamespaceRule `json:",omitempty"` 216 217 // Namespace is the namespace the ACLAuthMethod is associated with. 218 // Namespacing is a Consul Enterprise feature. 219 Namespace string `json:",omitempty"` 220} 221 222func (m *ACLAuthMethod) MarshalJSON() ([]byte, error) { 223 type Alias ACLAuthMethod 224 exported := &struct { 225 MaxTokenTTL string `json:",omitempty"` 226 *Alias 227 }{ 228 MaxTokenTTL: m.MaxTokenTTL.String(), 229 Alias: (*Alias)(m), 230 } 231 if m.MaxTokenTTL == 0 { 232 exported.MaxTokenTTL = "" 233 } 234 235 return json.Marshal(exported) 236} 237 238func (m *ACLAuthMethod) UnmarshalJSON(data []byte) error { 239 type Alias ACLAuthMethod 240 aux := &struct { 241 MaxTokenTTL string 242 *Alias 243 }{ 244 Alias: (*Alias)(m), 245 } 246 if err := json.Unmarshal(data, &aux); err != nil { 247 return err 248 } 249 var err error 250 if aux.MaxTokenTTL != "" { 251 if m.MaxTokenTTL, err = time.ParseDuration(aux.MaxTokenTTL); err != nil { 252 return err 253 } 254 } 255 256 return nil 257} 258 259type ACLAuthMethodNamespaceRule struct { 260 // Selector is an expression that matches against verified identity 261 // attributes returned from the auth method during login. 262 Selector string `json:",omitempty"` 263 264 // BindNamespace is the target namespace of the binding. Can be lightly 265 // templated using HIL ${foo} syntax from available field names. 266 // 267 // If empty it's created in the same namespace as the auth method. 268 BindNamespace string `json:",omitempty"` 269} 270 271type ACLAuthMethodListEntry struct { 272 Name string 273 Type string 274 DisplayName string `json:",omitempty"` 275 Description string `json:",omitempty"` 276 MaxTokenTTL time.Duration `json:",omitempty"` 277 278 // TokenLocality defines the kind of token that this auth method produces. 279 // This can be either 'local' or 'global'. If empty 'local' is assumed. 280 TokenLocality string `json:",omitempty"` 281 CreateIndex uint64 282 ModifyIndex uint64 283 284 // Namespace is the namespace the ACLAuthMethodListEntry is associated with. 285 // Namespacing is a Consul Enterprise feature. 286 Namespace string `json:",omitempty"` 287} 288 289// This is nearly identical to the ACLAuthMethod MarshalJSON 290func (m *ACLAuthMethodListEntry) MarshalJSON() ([]byte, error) { 291 type Alias ACLAuthMethodListEntry 292 exported := &struct { 293 MaxTokenTTL string `json:",omitempty"` 294 *Alias 295 }{ 296 MaxTokenTTL: m.MaxTokenTTL.String(), 297 Alias: (*Alias)(m), 298 } 299 if m.MaxTokenTTL == 0 { 300 exported.MaxTokenTTL = "" 301 } 302 303 return json.Marshal(exported) 304} 305 306// This is nearly identical to the ACLAuthMethod UnmarshalJSON 307func (m *ACLAuthMethodListEntry) UnmarshalJSON(data []byte) error { 308 type Alias ACLAuthMethodListEntry 309 aux := &struct { 310 MaxTokenTTL string 311 *Alias 312 }{ 313 Alias: (*Alias)(m), 314 } 315 316 if err := json.Unmarshal(data, &aux); err != nil { 317 return err 318 } 319 var err error 320 if aux.MaxTokenTTL != "" { 321 if m.MaxTokenTTL, err = time.ParseDuration(aux.MaxTokenTTL); err != nil { 322 return err 323 } 324 } 325 326 return nil 327} 328 329// ParseKubernetesAuthMethodConfig takes a raw config map and returns a parsed 330// KubernetesAuthMethodConfig. 331func ParseKubernetesAuthMethodConfig(raw map[string]interface{}) (*KubernetesAuthMethodConfig, error) { 332 var config KubernetesAuthMethodConfig 333 decodeConf := &mapstructure.DecoderConfig{ 334 Result: &config, 335 WeaklyTypedInput: true, 336 } 337 338 decoder, err := mapstructure.NewDecoder(decodeConf) 339 if err != nil { 340 return nil, err 341 } 342 343 if err := decoder.Decode(raw); err != nil { 344 return nil, fmt.Errorf("error decoding config: %s", err) 345 } 346 347 return &config, nil 348} 349 350// KubernetesAuthMethodConfig is the config for the built-in Consul auth method 351// for Kubernetes. 352type KubernetesAuthMethodConfig struct { 353 Host string `json:",omitempty"` 354 CACert string `json:",omitempty"` 355 ServiceAccountJWT string `json:",omitempty"` 356} 357 358// RenderToConfig converts this into a map[string]interface{} suitable for use 359// in the ACLAuthMethod.Config field. 360func (c *KubernetesAuthMethodConfig) RenderToConfig() map[string]interface{} { 361 return map[string]interface{}{ 362 "Host": c.Host, 363 "CACert": c.CACert, 364 "ServiceAccountJWT": c.ServiceAccountJWT, 365 } 366} 367 368// OIDCAuthMethodConfig is the config for the built-in Consul auth method for 369// OIDC and JWT. 370type OIDCAuthMethodConfig struct { 371 // common for type=oidc and type=jwt 372 JWTSupportedAlgs []string `json:",omitempty"` 373 BoundAudiences []string `json:",omitempty"` 374 ClaimMappings map[string]string `json:",omitempty"` 375 ListClaimMappings map[string]string `json:",omitempty"` 376 OIDCDiscoveryURL string `json:",omitempty"` 377 OIDCDiscoveryCACert string `json:",omitempty"` 378 // just for type=oidc 379 OIDCClientID string `json:",omitempty"` 380 OIDCClientSecret string `json:",omitempty"` 381 OIDCScopes []string `json:",omitempty"` 382 AllowedRedirectURIs []string `json:",omitempty"` 383 VerboseOIDCLogging bool `json:",omitempty"` 384 // just for type=jwt 385 JWKSURL string `json:",omitempty"` 386 JWKSCACert string `json:",omitempty"` 387 JWTValidationPubKeys []string `json:",omitempty"` 388 BoundIssuer string `json:",omitempty"` 389 ExpirationLeeway time.Duration `json:",omitempty"` 390 NotBeforeLeeway time.Duration `json:",omitempty"` 391 ClockSkewLeeway time.Duration `json:",omitempty"` 392} 393 394// RenderToConfig converts this into a map[string]interface{} suitable for use 395// in the ACLAuthMethod.Config field. 396func (c *OIDCAuthMethodConfig) RenderToConfig() map[string]interface{} { 397 return map[string]interface{}{ 398 // common for type=oidc and type=jwt 399 "JWTSupportedAlgs": c.JWTSupportedAlgs, 400 "BoundAudiences": c.BoundAudiences, 401 "ClaimMappings": c.ClaimMappings, 402 "ListClaimMappings": c.ListClaimMappings, 403 "OIDCDiscoveryURL": c.OIDCDiscoveryURL, 404 "OIDCDiscoveryCACert": c.OIDCDiscoveryCACert, 405 // just for type=oidc 406 "OIDCClientID": c.OIDCClientID, 407 "OIDCClientSecret": c.OIDCClientSecret, 408 "OIDCScopes": c.OIDCScopes, 409 "AllowedRedirectURIs": c.AllowedRedirectURIs, 410 "VerboseOIDCLogging": c.VerboseOIDCLogging, 411 // just for type=jwt 412 "JWKSURL": c.JWKSURL, 413 "JWKSCACert": c.JWKSCACert, 414 "JWTValidationPubKeys": c.JWTValidationPubKeys, 415 "BoundIssuer": c.BoundIssuer, 416 "ExpirationLeeway": c.ExpirationLeeway, 417 "NotBeforeLeeway": c.NotBeforeLeeway, 418 "ClockSkewLeeway": c.ClockSkewLeeway, 419 } 420} 421 422type ACLLoginParams struct { 423 AuthMethod string 424 BearerToken string 425 Meta map[string]string `json:",omitempty"` 426} 427 428type ACLOIDCAuthURLParams struct { 429 AuthMethod string 430 RedirectURI string 431 ClientNonce string 432 Meta map[string]string `json:",omitempty"` 433} 434 435// ACL can be used to query the ACL endpoints 436type ACL struct { 437 c *Client 438} 439 440// ACL returns a handle to the ACL endpoints 441func (c *Client) ACL() *ACL { 442 return &ACL{c} 443} 444 445// Bootstrap is used to perform a one-time ACL bootstrap operation on a cluster 446// to get the first management token. 447func (a *ACL) Bootstrap() (*ACLToken, *WriteMeta, error) { 448 r := a.c.newRequest("PUT", "/v1/acl/bootstrap") 449 rtt, resp, err := requireOK(a.c.doRequest(r)) 450 if err != nil { 451 return nil, nil, err 452 } 453 defer closeResponseBody(resp) 454 455 wm := &WriteMeta{RequestTime: rtt} 456 var out ACLToken 457 if err := decodeBody(resp, &out); err != nil { 458 return nil, nil, err 459 } 460 return &out, wm, nil 461} 462 463// Create is used to generate a new token with the given parameters 464// 465// Deprecated: Use TokenCreate instead. 466func (a *ACL) Create(acl *ACLEntry, q *WriteOptions) (string, *WriteMeta, error) { 467 r := a.c.newRequest("PUT", "/v1/acl/create") 468 r.setWriteOptions(q) 469 r.obj = acl 470 rtt, resp, err := requireOK(a.c.doRequest(r)) 471 if err != nil { 472 return "", nil, err 473 } 474 defer closeResponseBody(resp) 475 476 wm := &WriteMeta{RequestTime: rtt} 477 var out struct{ ID string } 478 if err := decodeBody(resp, &out); err != nil { 479 return "", nil, err 480 } 481 return out.ID, wm, nil 482} 483 484// Update is used to update the rules of an existing token 485// 486// Deprecated: Use TokenUpdate instead. 487func (a *ACL) Update(acl *ACLEntry, q *WriteOptions) (*WriteMeta, error) { 488 r := a.c.newRequest("PUT", "/v1/acl/update") 489 r.setWriteOptions(q) 490 r.obj = acl 491 rtt, resp, err := requireOK(a.c.doRequest(r)) 492 if err != nil { 493 return nil, err 494 } 495 defer closeResponseBody(resp) 496 497 wm := &WriteMeta{RequestTime: rtt} 498 return wm, nil 499} 500 501// Destroy is used to destroy a given ACL token ID 502// 503// Deprecated: Use TokenDelete instead. 504func (a *ACL) Destroy(id string, q *WriteOptions) (*WriteMeta, error) { 505 r := a.c.newRequest("PUT", "/v1/acl/destroy/"+id) 506 r.setWriteOptions(q) 507 rtt, resp, err := requireOK(a.c.doRequest(r)) 508 if err != nil { 509 return nil, err 510 } 511 closeResponseBody(resp) 512 513 wm := &WriteMeta{RequestTime: rtt} 514 return wm, nil 515} 516 517// Clone is used to return a new token cloned from an existing one 518// 519// Deprecated: Use TokenClone instead. 520func (a *ACL) Clone(id string, q *WriteOptions) (string, *WriteMeta, error) { 521 r := a.c.newRequest("PUT", "/v1/acl/clone/"+id) 522 r.setWriteOptions(q) 523 rtt, resp, err := requireOK(a.c.doRequest(r)) 524 if err != nil { 525 return "", nil, err 526 } 527 defer closeResponseBody(resp) 528 529 wm := &WriteMeta{RequestTime: rtt} 530 var out struct{ ID string } 531 if err := decodeBody(resp, &out); err != nil { 532 return "", nil, err 533 } 534 return out.ID, wm, nil 535} 536 537// Info is used to query for information about an ACL token 538// 539// Deprecated: Use TokenRead instead. 540func (a *ACL) Info(id string, q *QueryOptions) (*ACLEntry, *QueryMeta, error) { 541 r := a.c.newRequest("GET", "/v1/acl/info/"+id) 542 r.setQueryOptions(q) 543 rtt, resp, err := requireOK(a.c.doRequest(r)) 544 if err != nil { 545 return nil, nil, err 546 } 547 defer closeResponseBody(resp) 548 549 qm := &QueryMeta{} 550 parseQueryMeta(resp, qm) 551 qm.RequestTime = rtt 552 553 var entries []*ACLEntry 554 if err := decodeBody(resp, &entries); err != nil { 555 return nil, nil, err 556 } 557 if len(entries) > 0 { 558 return entries[0], qm, nil 559 } 560 return nil, qm, nil 561} 562 563// List is used to get all the ACL tokens 564// 565// Deprecated: Use TokenList instead. 566func (a *ACL) List(q *QueryOptions) ([]*ACLEntry, *QueryMeta, error) { 567 r := a.c.newRequest("GET", "/v1/acl/list") 568 r.setQueryOptions(q) 569 rtt, resp, err := requireOK(a.c.doRequest(r)) 570 if err != nil { 571 return nil, nil, err 572 } 573 defer closeResponseBody(resp) 574 575 qm := &QueryMeta{} 576 parseQueryMeta(resp, qm) 577 qm.RequestTime = rtt 578 579 var entries []*ACLEntry 580 if err := decodeBody(resp, &entries); err != nil { 581 return nil, nil, err 582 } 583 return entries, qm, nil 584} 585 586// Replication returns the status of the ACL replication process in the datacenter 587func (a *ACL) Replication(q *QueryOptions) (*ACLReplicationStatus, *QueryMeta, error) { 588 r := a.c.newRequest("GET", "/v1/acl/replication") 589 r.setQueryOptions(q) 590 rtt, resp, err := requireOK(a.c.doRequest(r)) 591 if err != nil { 592 return nil, nil, err 593 } 594 defer closeResponseBody(resp) 595 596 qm := &QueryMeta{} 597 parseQueryMeta(resp, qm) 598 qm.RequestTime = rtt 599 600 var entries *ACLReplicationStatus 601 if err := decodeBody(resp, &entries); err != nil { 602 return nil, nil, err 603 } 604 return entries, qm, nil 605} 606 607// TokenCreate creates a new ACL token. If either the AccessorID or SecretID fields 608// of the ACLToken structure are empty they will be filled in by Consul. 609func (a *ACL) TokenCreate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 610 r := a.c.newRequest("PUT", "/v1/acl/token") 611 r.setWriteOptions(q) 612 r.obj = token 613 rtt, resp, err := requireOK(a.c.doRequest(r)) 614 if err != nil { 615 return nil, nil, err 616 } 617 defer closeResponseBody(resp) 618 619 wm := &WriteMeta{RequestTime: rtt} 620 var out ACLToken 621 if err := decodeBody(resp, &out); err != nil { 622 return nil, nil, err 623 } 624 625 return &out, wm, nil 626} 627 628// TokenUpdate updates a token in place without modifying its AccessorID or SecretID. A valid 629// AccessorID must be set in the ACLToken structure passed to this function but the SecretID may 630// be omitted and will be filled in by Consul with its existing value. 631func (a *ACL) TokenUpdate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 632 if token.AccessorID == "" { 633 return nil, nil, fmt.Errorf("Must specify an AccessorID for Token Updating") 634 } 635 r := a.c.newRequest("PUT", "/v1/acl/token/"+token.AccessorID) 636 r.setWriteOptions(q) 637 r.obj = token 638 rtt, resp, err := requireOK(a.c.doRequest(r)) 639 if err != nil { 640 return nil, nil, err 641 } 642 defer closeResponseBody(resp) 643 644 wm := &WriteMeta{RequestTime: rtt} 645 var out ACLToken 646 if err := decodeBody(resp, &out); err != nil { 647 return nil, nil, err 648 } 649 650 return &out, wm, nil 651} 652 653// TokenClone will create a new token with the same policies and locality as the original 654// token but will have its own auto-generated AccessorID and SecretID as well having the 655// description passed to this function. The tokenID parameter must be a valid Accessor ID 656// of an existing token. 657func (a *ACL) TokenClone(tokenID string, description string, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 658 if tokenID == "" { 659 return nil, nil, fmt.Errorf("Must specify a tokenID for Token Cloning") 660 } 661 662 r := a.c.newRequest("PUT", "/v1/acl/token/"+tokenID+"/clone") 663 r.setWriteOptions(q) 664 r.obj = struct{ Description string }{description} 665 rtt, resp, err := requireOK(a.c.doRequest(r)) 666 if err != nil { 667 return nil, nil, err 668 } 669 defer closeResponseBody(resp) 670 671 wm := &WriteMeta{RequestTime: rtt} 672 var out ACLToken 673 if err := decodeBody(resp, &out); err != nil { 674 return nil, nil, err 675 } 676 677 return &out, wm, nil 678} 679 680// TokenDelete removes a single ACL token. The tokenID parameter must be a valid 681// Accessor ID of an existing token. 682func (a *ACL) TokenDelete(tokenID string, q *WriteOptions) (*WriteMeta, error) { 683 r := a.c.newRequest("DELETE", "/v1/acl/token/"+tokenID) 684 r.setWriteOptions(q) 685 rtt, resp, err := requireOK(a.c.doRequest(r)) 686 if err != nil { 687 return nil, err 688 } 689 closeResponseBody(resp) 690 691 wm := &WriteMeta{RequestTime: rtt} 692 return wm, nil 693} 694 695// TokenRead retrieves the full token details. The tokenID parameter must be a valid 696// Accessor ID of an existing token. 697func (a *ACL) TokenRead(tokenID string, q *QueryOptions) (*ACLToken, *QueryMeta, error) { 698 r := a.c.newRequest("GET", "/v1/acl/token/"+tokenID) 699 r.setQueryOptions(q) 700 rtt, resp, err := requireOK(a.c.doRequest(r)) 701 if err != nil { 702 return nil, nil, err 703 } 704 defer closeResponseBody(resp) 705 706 qm := &QueryMeta{} 707 parseQueryMeta(resp, qm) 708 qm.RequestTime = rtt 709 710 var out ACLToken 711 if err := decodeBody(resp, &out); err != nil { 712 return nil, nil, err 713 } 714 715 return &out, qm, nil 716} 717 718// TokenReadSelf retrieves the full token details of the token currently 719// assigned to the API Client. In this manner its possible to read a token 720// by its Secret ID. 721func (a *ACL) TokenReadSelf(q *QueryOptions) (*ACLToken, *QueryMeta, error) { 722 r := a.c.newRequest("GET", "/v1/acl/token/self") 723 r.setQueryOptions(q) 724 rtt, resp, err := requireOK(a.c.doRequest(r)) 725 if err != nil { 726 return nil, nil, err 727 } 728 defer closeResponseBody(resp) 729 730 qm := &QueryMeta{} 731 parseQueryMeta(resp, qm) 732 qm.RequestTime = rtt 733 734 var out ACLToken 735 if err := decodeBody(resp, &out); err != nil { 736 return nil, nil, err 737 } 738 739 return &out, qm, nil 740} 741 742// TokenList lists all tokens. The listing does not contain any SecretIDs as those 743// may only be retrieved by a call to TokenRead. 744func (a *ACL) TokenList(q *QueryOptions) ([]*ACLTokenListEntry, *QueryMeta, error) { 745 r := a.c.newRequest("GET", "/v1/acl/tokens") 746 r.setQueryOptions(q) 747 rtt, resp, err := requireOK(a.c.doRequest(r)) 748 if err != nil { 749 return nil, nil, err 750 } 751 defer closeResponseBody(resp) 752 753 qm := &QueryMeta{} 754 parseQueryMeta(resp, qm) 755 qm.RequestTime = rtt 756 757 var entries []*ACLTokenListEntry 758 if err := decodeBody(resp, &entries); err != nil { 759 return nil, nil, err 760 } 761 return entries, qm, nil 762} 763 764// PolicyCreate will create a new policy. It is not allowed for the policy parameters 765// ID field to be set as this will be generated by Consul while processing the request. 766func (a *ACL) PolicyCreate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) { 767 if policy.ID != "" { 768 return nil, nil, fmt.Errorf("Cannot specify an ID in Policy Creation") 769 } 770 r := a.c.newRequest("PUT", "/v1/acl/policy") 771 r.setWriteOptions(q) 772 r.obj = policy 773 rtt, resp, err := requireOK(a.c.doRequest(r)) 774 if err != nil { 775 return nil, nil, err 776 } 777 defer closeResponseBody(resp) 778 779 wm := &WriteMeta{RequestTime: rtt} 780 var out ACLPolicy 781 if err := decodeBody(resp, &out); err != nil { 782 return nil, nil, err 783 } 784 785 return &out, wm, nil 786} 787 788// PolicyUpdate updates a policy. The ID field of the policy parameter must be set to an 789// existing policy ID 790func (a *ACL) PolicyUpdate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) { 791 if policy.ID == "" { 792 return nil, nil, fmt.Errorf("Must specify an ID in Policy Update") 793 } 794 795 r := a.c.newRequest("PUT", "/v1/acl/policy/"+policy.ID) 796 r.setWriteOptions(q) 797 r.obj = policy 798 rtt, resp, err := requireOK(a.c.doRequest(r)) 799 if err != nil { 800 return nil, nil, err 801 } 802 defer closeResponseBody(resp) 803 804 wm := &WriteMeta{RequestTime: rtt} 805 var out ACLPolicy 806 if err := decodeBody(resp, &out); err != nil { 807 return nil, nil, err 808 } 809 810 return &out, wm, nil 811} 812 813// PolicyDelete deletes a policy given its ID. 814func (a *ACL) PolicyDelete(policyID string, q *WriteOptions) (*WriteMeta, error) { 815 r := a.c.newRequest("DELETE", "/v1/acl/policy/"+policyID) 816 r.setWriteOptions(q) 817 rtt, resp, err := requireOK(a.c.doRequest(r)) 818 if err != nil { 819 return nil, err 820 } 821 closeResponseBody(resp) 822 823 wm := &WriteMeta{RequestTime: rtt} 824 return wm, nil 825} 826 827// PolicyRead retrieves the policy details including the rule set. 828func (a *ACL) PolicyRead(policyID string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) { 829 r := a.c.newRequest("GET", "/v1/acl/policy/"+policyID) 830 r.setQueryOptions(q) 831 rtt, resp, err := requireOK(a.c.doRequest(r)) 832 if err != nil { 833 return nil, nil, err 834 } 835 defer closeResponseBody(resp) 836 837 qm := &QueryMeta{} 838 parseQueryMeta(resp, qm) 839 qm.RequestTime = rtt 840 841 var out ACLPolicy 842 if err := decodeBody(resp, &out); err != nil { 843 return nil, nil, err 844 } 845 846 return &out, qm, nil 847} 848 849// PolicyReadByName retrieves the policy details including the rule set with name. 850func (a *ACL) PolicyReadByName(policyName string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) { 851 r := a.c.newRequest("GET", "/v1/acl/policy/name/"+url.QueryEscape(policyName)) 852 r.setQueryOptions(q) 853 found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r)) 854 if err != nil { 855 return nil, nil, err 856 } 857 defer closeResponseBody(resp) 858 859 qm := &QueryMeta{} 860 parseQueryMeta(resp, qm) 861 qm.RequestTime = rtt 862 863 if !found { 864 return nil, qm, nil 865 } 866 867 var out ACLPolicy 868 if err := decodeBody(resp, &out); err != nil { 869 return nil, nil, err 870 } 871 872 return &out, qm, nil 873} 874 875// PolicyList retrieves a listing of all policies. The listing does not include the 876// rules for any policy as those should be retrieved by subsequent calls to PolicyRead. 877func (a *ACL) PolicyList(q *QueryOptions) ([]*ACLPolicyListEntry, *QueryMeta, error) { 878 r := a.c.newRequest("GET", "/v1/acl/policies") 879 r.setQueryOptions(q) 880 rtt, resp, err := requireOK(a.c.doRequest(r)) 881 if err != nil { 882 return nil, nil, err 883 } 884 defer closeResponseBody(resp) 885 886 qm := &QueryMeta{} 887 parseQueryMeta(resp, qm) 888 qm.RequestTime = rtt 889 890 var entries []*ACLPolicyListEntry 891 if err := decodeBody(resp, &entries); err != nil { 892 return nil, nil, err 893 } 894 return entries, qm, nil 895} 896 897// RulesTranslate translates the legacy rule syntax into the current syntax. 898// 899// Deprecated: Support for the legacy syntax translation will be removed 900// when legacy ACL support is removed. 901func (a *ACL) RulesTranslate(rules io.Reader) (string, error) { 902 r := a.c.newRequest("POST", "/v1/acl/rules/translate") 903 r.body = rules 904 r.header.Set("Content-Type", "text/plain") 905 rtt, resp, err := requireOK(a.c.doRequest(r)) 906 if err != nil { 907 return "", err 908 } 909 defer closeResponseBody(resp) 910 qm := &QueryMeta{} 911 parseQueryMeta(resp, qm) 912 qm.RequestTime = rtt 913 914 ruleBytes, err := ioutil.ReadAll(resp.Body) 915 if err != nil { 916 return "", fmt.Errorf("Failed to read translated rule body: %v", err) 917 } 918 919 return string(ruleBytes), nil 920} 921 922// RulesTranslateToken translates the rules associated with the legacy syntax 923// into the current syntax and returns the results. 924// 925// Deprecated: Support for the legacy syntax translation will be removed 926// when legacy ACL support is removed. 927func (a *ACL) RulesTranslateToken(tokenID string) (string, error) { 928 r := a.c.newRequest("GET", "/v1/acl/rules/translate/"+tokenID) 929 rtt, resp, err := requireOK(a.c.doRequest(r)) 930 if err != nil { 931 return "", err 932 } 933 defer closeResponseBody(resp) 934 qm := &QueryMeta{} 935 parseQueryMeta(resp, qm) 936 qm.RequestTime = rtt 937 938 ruleBytes, err := ioutil.ReadAll(resp.Body) 939 if err != nil { 940 return "", fmt.Errorf("Failed to read translated rule body: %v", err) 941 } 942 943 return string(ruleBytes), nil 944} 945 946// RoleCreate will create a new role. It is not allowed for the role parameters 947// ID field to be set as this will be generated by Consul while processing the request. 948func (a *ACL) RoleCreate(role *ACLRole, q *WriteOptions) (*ACLRole, *WriteMeta, error) { 949 if role.ID != "" { 950 return nil, nil, fmt.Errorf("Cannot specify an ID in Role Creation") 951 } 952 953 r := a.c.newRequest("PUT", "/v1/acl/role") 954 r.setWriteOptions(q) 955 r.obj = role 956 rtt, resp, err := requireOK(a.c.doRequest(r)) 957 if err != nil { 958 return nil, nil, err 959 } 960 defer closeResponseBody(resp) 961 962 wm := &WriteMeta{RequestTime: rtt} 963 var out ACLRole 964 if err := decodeBody(resp, &out); err != nil { 965 return nil, nil, err 966 } 967 968 return &out, wm, nil 969} 970 971// RoleUpdate updates a role. The ID field of the role parameter must be set to an 972// existing role ID 973func (a *ACL) RoleUpdate(role *ACLRole, q *WriteOptions) (*ACLRole, *WriteMeta, error) { 974 if role.ID == "" { 975 return nil, nil, fmt.Errorf("Must specify an ID in Role Update") 976 } 977 978 r := a.c.newRequest("PUT", "/v1/acl/role/"+role.ID) 979 r.setWriteOptions(q) 980 r.obj = role 981 rtt, resp, err := requireOK(a.c.doRequest(r)) 982 if err != nil { 983 return nil, nil, err 984 } 985 defer closeResponseBody(resp) 986 987 wm := &WriteMeta{RequestTime: rtt} 988 var out ACLRole 989 if err := decodeBody(resp, &out); err != nil { 990 return nil, nil, err 991 } 992 993 return &out, wm, nil 994} 995 996// RoleDelete deletes a role given its ID. 997func (a *ACL) RoleDelete(roleID string, q *WriteOptions) (*WriteMeta, error) { 998 r := a.c.newRequest("DELETE", "/v1/acl/role/"+roleID) 999 r.setWriteOptions(q) 1000 rtt, resp, err := requireOK(a.c.doRequest(r)) 1001 if err != nil { 1002 return nil, err 1003 } 1004 closeResponseBody(resp) 1005 1006 wm := &WriteMeta{RequestTime: rtt} 1007 return wm, nil 1008} 1009 1010// RoleRead retrieves the role details (by ID). Returns nil if not found. 1011func (a *ACL) RoleRead(roleID string, q *QueryOptions) (*ACLRole, *QueryMeta, error) { 1012 r := a.c.newRequest("GET", "/v1/acl/role/"+roleID) 1013 r.setQueryOptions(q) 1014 found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r)) 1015 if err != nil { 1016 return nil, nil, err 1017 } 1018 defer closeResponseBody(resp) 1019 1020 qm := &QueryMeta{} 1021 parseQueryMeta(resp, qm) 1022 qm.RequestTime = rtt 1023 1024 if !found { 1025 return nil, qm, nil 1026 } 1027 1028 var out ACLRole 1029 if err := decodeBody(resp, &out); err != nil { 1030 return nil, nil, err 1031 } 1032 1033 return &out, qm, nil 1034} 1035 1036// RoleReadByName retrieves the role details (by name). Returns nil if not found. 1037func (a *ACL) RoleReadByName(roleName string, q *QueryOptions) (*ACLRole, *QueryMeta, error) { 1038 r := a.c.newRequest("GET", "/v1/acl/role/name/"+url.QueryEscape(roleName)) 1039 r.setQueryOptions(q) 1040 found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r)) 1041 if err != nil { 1042 return nil, nil, err 1043 } 1044 defer closeResponseBody(resp) 1045 1046 qm := &QueryMeta{} 1047 parseQueryMeta(resp, qm) 1048 qm.RequestTime = rtt 1049 1050 if !found { 1051 return nil, qm, nil 1052 } 1053 1054 var out ACLRole 1055 if err := decodeBody(resp, &out); err != nil { 1056 return nil, nil, err 1057 } 1058 1059 return &out, qm, nil 1060} 1061 1062// RoleList retrieves a listing of all roles. The listing does not include some 1063// metadata for the role as those should be retrieved by subsequent calls to 1064// RoleRead. 1065func (a *ACL) RoleList(q *QueryOptions) ([]*ACLRole, *QueryMeta, error) { 1066 r := a.c.newRequest("GET", "/v1/acl/roles") 1067 r.setQueryOptions(q) 1068 rtt, resp, err := requireOK(a.c.doRequest(r)) 1069 if err != nil { 1070 return nil, nil, err 1071 } 1072 defer closeResponseBody(resp) 1073 1074 qm := &QueryMeta{} 1075 parseQueryMeta(resp, qm) 1076 qm.RequestTime = rtt 1077 1078 var entries []*ACLRole 1079 if err := decodeBody(resp, &entries); err != nil { 1080 return nil, nil, err 1081 } 1082 return entries, qm, nil 1083} 1084 1085// AuthMethodCreate will create a new auth method. 1086func (a *ACL) AuthMethodCreate(method *ACLAuthMethod, q *WriteOptions) (*ACLAuthMethod, *WriteMeta, error) { 1087 if method.Name == "" { 1088 return nil, nil, fmt.Errorf("Must specify a Name in Auth Method Creation") 1089 } 1090 1091 r := a.c.newRequest("PUT", "/v1/acl/auth-method") 1092 r.setWriteOptions(q) 1093 r.obj = method 1094 rtt, resp, err := requireOK(a.c.doRequest(r)) 1095 if err != nil { 1096 return nil, nil, err 1097 } 1098 defer closeResponseBody(resp) 1099 1100 wm := &WriteMeta{RequestTime: rtt} 1101 var out ACLAuthMethod 1102 if err := decodeBody(resp, &out); err != nil { 1103 return nil, nil, err 1104 } 1105 1106 return &out, wm, nil 1107} 1108 1109// AuthMethodUpdate updates an auth method. 1110func (a *ACL) AuthMethodUpdate(method *ACLAuthMethod, q *WriteOptions) (*ACLAuthMethod, *WriteMeta, error) { 1111 if method.Name == "" { 1112 return nil, nil, fmt.Errorf("Must specify a Name in Auth Method Update") 1113 } 1114 1115 r := a.c.newRequest("PUT", "/v1/acl/auth-method/"+url.QueryEscape(method.Name)) 1116 r.setWriteOptions(q) 1117 r.obj = method 1118 rtt, resp, err := requireOK(a.c.doRequest(r)) 1119 if err != nil { 1120 return nil, nil, err 1121 } 1122 defer closeResponseBody(resp) 1123 1124 wm := &WriteMeta{RequestTime: rtt} 1125 var out ACLAuthMethod 1126 if err := decodeBody(resp, &out); err != nil { 1127 return nil, nil, err 1128 } 1129 1130 return &out, wm, nil 1131} 1132 1133// AuthMethodDelete deletes an auth method given its Name. 1134func (a *ACL) AuthMethodDelete(methodName string, q *WriteOptions) (*WriteMeta, error) { 1135 if methodName == "" { 1136 return nil, fmt.Errorf("Must specify a Name in Auth Method Delete") 1137 } 1138 1139 r := a.c.newRequest("DELETE", "/v1/acl/auth-method/"+url.QueryEscape(methodName)) 1140 r.setWriteOptions(q) 1141 rtt, resp, err := requireOK(a.c.doRequest(r)) 1142 if err != nil { 1143 return nil, err 1144 } 1145 closeResponseBody(resp) 1146 1147 wm := &WriteMeta{RequestTime: rtt} 1148 return wm, nil 1149} 1150 1151// AuthMethodRead retrieves the auth method. Returns nil if not found. 1152func (a *ACL) AuthMethodRead(methodName string, q *QueryOptions) (*ACLAuthMethod, *QueryMeta, error) { 1153 if methodName == "" { 1154 return nil, nil, fmt.Errorf("Must specify a Name in Auth Method Read") 1155 } 1156 1157 r := a.c.newRequest("GET", "/v1/acl/auth-method/"+url.QueryEscape(methodName)) 1158 r.setQueryOptions(q) 1159 found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r)) 1160 if err != nil { 1161 return nil, nil, err 1162 } 1163 defer closeResponseBody(resp) 1164 1165 qm := &QueryMeta{} 1166 parseQueryMeta(resp, qm) 1167 qm.RequestTime = rtt 1168 1169 if !found { 1170 return nil, qm, nil 1171 } 1172 1173 var out ACLAuthMethod 1174 if err := decodeBody(resp, &out); err != nil { 1175 return nil, nil, err 1176 } 1177 1178 return &out, qm, nil 1179} 1180 1181// AuthMethodList retrieves a listing of all auth methods. The listing does not 1182// include some metadata for the auth method as those should be retrieved by 1183// subsequent calls to AuthMethodRead. 1184func (a *ACL) AuthMethodList(q *QueryOptions) ([]*ACLAuthMethodListEntry, *QueryMeta, error) { 1185 r := a.c.newRequest("GET", "/v1/acl/auth-methods") 1186 r.setQueryOptions(q) 1187 rtt, resp, err := requireOK(a.c.doRequest(r)) 1188 if err != nil { 1189 return nil, nil, err 1190 } 1191 defer closeResponseBody(resp) 1192 1193 qm := &QueryMeta{} 1194 parseQueryMeta(resp, qm) 1195 qm.RequestTime = rtt 1196 1197 var entries []*ACLAuthMethodListEntry 1198 if err := decodeBody(resp, &entries); err != nil { 1199 return nil, nil, err 1200 } 1201 return entries, qm, nil 1202} 1203 1204// BindingRuleCreate will create a new binding rule. It is not allowed for the 1205// binding rule parameter's ID field to be set as this will be generated by 1206// Consul while processing the request. 1207func (a *ACL) BindingRuleCreate(rule *ACLBindingRule, q *WriteOptions) (*ACLBindingRule, *WriteMeta, error) { 1208 if rule.ID != "" { 1209 return nil, nil, fmt.Errorf("Cannot specify an ID in Binding Rule Creation") 1210 } 1211 1212 r := a.c.newRequest("PUT", "/v1/acl/binding-rule") 1213 r.setWriteOptions(q) 1214 r.obj = rule 1215 rtt, resp, err := requireOK(a.c.doRequest(r)) 1216 if err != nil { 1217 return nil, nil, err 1218 } 1219 defer closeResponseBody(resp) 1220 1221 wm := &WriteMeta{RequestTime: rtt} 1222 var out ACLBindingRule 1223 if err := decodeBody(resp, &out); err != nil { 1224 return nil, nil, err 1225 } 1226 1227 return &out, wm, nil 1228} 1229 1230// BindingRuleUpdate updates a binding rule. The ID field of the role binding 1231// rule parameter must be set to an existing binding rule ID. 1232func (a *ACL) BindingRuleUpdate(rule *ACLBindingRule, q *WriteOptions) (*ACLBindingRule, *WriteMeta, error) { 1233 if rule.ID == "" { 1234 return nil, nil, fmt.Errorf("Must specify an ID in Binding Rule Update") 1235 } 1236 1237 r := a.c.newRequest("PUT", "/v1/acl/binding-rule/"+rule.ID) 1238 r.setWriteOptions(q) 1239 r.obj = rule 1240 rtt, resp, err := requireOK(a.c.doRequest(r)) 1241 if err != nil { 1242 return nil, nil, err 1243 } 1244 defer closeResponseBody(resp) 1245 1246 wm := &WriteMeta{RequestTime: rtt} 1247 var out ACLBindingRule 1248 if err := decodeBody(resp, &out); err != nil { 1249 return nil, nil, err 1250 } 1251 1252 return &out, wm, nil 1253} 1254 1255// BindingRuleDelete deletes a binding rule given its ID. 1256func (a *ACL) BindingRuleDelete(bindingRuleID string, q *WriteOptions) (*WriteMeta, error) { 1257 r := a.c.newRequest("DELETE", "/v1/acl/binding-rule/"+bindingRuleID) 1258 r.setWriteOptions(q) 1259 rtt, resp, err := requireOK(a.c.doRequest(r)) 1260 if err != nil { 1261 return nil, err 1262 } 1263 closeResponseBody(resp) 1264 1265 wm := &WriteMeta{RequestTime: rtt} 1266 return wm, nil 1267} 1268 1269// BindingRuleRead retrieves the binding rule details. Returns nil if not found. 1270func (a *ACL) BindingRuleRead(bindingRuleID string, q *QueryOptions) (*ACLBindingRule, *QueryMeta, error) { 1271 r := a.c.newRequest("GET", "/v1/acl/binding-rule/"+bindingRuleID) 1272 r.setQueryOptions(q) 1273 found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r)) 1274 if err != nil { 1275 return nil, nil, err 1276 } 1277 defer closeResponseBody(resp) 1278 1279 qm := &QueryMeta{} 1280 parseQueryMeta(resp, qm) 1281 qm.RequestTime = rtt 1282 1283 if !found { 1284 return nil, qm, nil 1285 } 1286 1287 var out ACLBindingRule 1288 if err := decodeBody(resp, &out); err != nil { 1289 return nil, nil, err 1290 } 1291 1292 return &out, qm, nil 1293} 1294 1295// BindingRuleList retrieves a listing of all binding rules. 1296func (a *ACL) BindingRuleList(methodName string, q *QueryOptions) ([]*ACLBindingRule, *QueryMeta, error) { 1297 r := a.c.newRequest("GET", "/v1/acl/binding-rules") 1298 if methodName != "" { 1299 r.params.Set("authmethod", methodName) 1300 } 1301 r.setQueryOptions(q) 1302 rtt, resp, err := requireOK(a.c.doRequest(r)) 1303 if err != nil { 1304 return nil, nil, err 1305 } 1306 defer closeResponseBody(resp) 1307 1308 qm := &QueryMeta{} 1309 parseQueryMeta(resp, qm) 1310 qm.RequestTime = rtt 1311 1312 var entries []*ACLBindingRule 1313 if err := decodeBody(resp, &entries); err != nil { 1314 return nil, nil, err 1315 } 1316 return entries, qm, nil 1317} 1318 1319// Login is used to exchange auth method credentials for a newly-minted Consul Token. 1320func (a *ACL) Login(auth *ACLLoginParams, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 1321 r := a.c.newRequest("POST", "/v1/acl/login") 1322 r.setWriteOptions(q) 1323 r.obj = auth 1324 1325 rtt, resp, err := requireOK(a.c.doRequest(r)) 1326 if err != nil { 1327 return nil, nil, err 1328 } 1329 defer closeResponseBody(resp) 1330 1331 wm := &WriteMeta{RequestTime: rtt} 1332 var out ACLToken 1333 if err := decodeBody(resp, &out); err != nil { 1334 return nil, nil, err 1335 } 1336 return &out, wm, nil 1337} 1338 1339// Logout is used to destroy a Consul Token created via Login(). 1340func (a *ACL) Logout(q *WriteOptions) (*WriteMeta, error) { 1341 r := a.c.newRequest("POST", "/v1/acl/logout") 1342 r.setWriteOptions(q) 1343 rtt, resp, err := requireOK(a.c.doRequest(r)) 1344 if err != nil { 1345 return nil, err 1346 } 1347 closeResponseBody(resp) 1348 1349 wm := &WriteMeta{RequestTime: rtt} 1350 return wm, nil 1351} 1352 1353// OIDCAuthURL requests an authorization URL to start an OIDC login flow. 1354func (a *ACL) OIDCAuthURL(auth *ACLOIDCAuthURLParams, q *WriteOptions) (string, *WriteMeta, error) { 1355 if auth.AuthMethod == "" { 1356 return "", nil, fmt.Errorf("Must specify an auth method name") 1357 } 1358 1359 r := a.c.newRequest("POST", "/v1/acl/oidc/auth-url") 1360 r.setWriteOptions(q) 1361 r.obj = auth 1362 1363 rtt, resp, err := requireOK(a.c.doRequest(r)) 1364 if err != nil { 1365 return "", nil, err 1366 } 1367 defer closeResponseBody(resp) 1368 1369 wm := &WriteMeta{RequestTime: rtt} 1370 var out aclOIDCAuthURLResponse 1371 if err := decodeBody(resp, &out); err != nil { 1372 return "", nil, err 1373 } 1374 return out.AuthURL, wm, nil 1375} 1376 1377type aclOIDCAuthURLResponse struct { 1378 AuthURL string 1379} 1380 1381type ACLOIDCCallbackParams struct { 1382 AuthMethod string 1383 State string 1384 Code string 1385 ClientNonce string 1386} 1387 1388// OIDCCallback is the callback endpoint to complete an OIDC login. 1389func (a *ACL) OIDCCallback(auth *ACLOIDCCallbackParams, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 1390 if auth.AuthMethod == "" { 1391 return nil, nil, fmt.Errorf("Must specify an auth method name") 1392 } 1393 1394 r := a.c.newRequest("POST", "/v1/acl/oidc/callback") 1395 r.setWriteOptions(q) 1396 r.obj = auth 1397 1398 rtt, resp, err := requireOK(a.c.doRequest(r)) 1399 if err != nil { 1400 return nil, nil, err 1401 } 1402 defer closeResponseBody(resp) 1403 1404 wm := &WriteMeta{RequestTime: rtt} 1405 var out ACLToken 1406 if err := decodeBody(resp, &out); err != nil { 1407 return nil, nil, err 1408 } 1409 return &out, wm, nil 1410} 1411