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