1package api 2 3import ( 4 "fmt" 5 "io" 6 "io/ioutil" 7 "net/url" 8 "time" 9 10 "github.com/mitchellh/mapstructure" 11) 12 13const ( 14 // ACLClientType is the client type token 15 ACLClientType = "client" 16 17 // ACLManagementType is the management type token 18 ACLManagementType = "management" 19) 20 21type ACLTokenPolicyLink struct { 22 ID string 23 Name string 24} 25type ACLTokenRoleLink struct { 26 ID string 27 Name string 28} 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 Local bool 41 ExpirationTTL time.Duration `json:",omitempty"` 42 ExpirationTime *time.Time `json:",omitempty"` 43 CreateTime time.Time `json:",omitempty"` 44 Hash []byte `json:",omitempty"` 45 46 // DEPRECATED (ACL-Legacy-Compat) 47 // Rules will only be present for legacy tokens returned via the new APIs 48 Rules string `json:",omitempty"` 49} 50 51type ACLTokenListEntry struct { 52 CreateIndex uint64 53 ModifyIndex uint64 54 AccessorID string 55 Description string 56 Policies []*ACLTokenPolicyLink `json:",omitempty"` 57 Roles []*ACLTokenRoleLink `json:",omitempty"` 58 ServiceIdentities []*ACLServiceIdentity `json:",omitempty"` 59 Local bool 60 ExpirationTime *time.Time `json:",omitempty"` 61 CreateTime time.Time 62 Hash []byte 63 Legacy bool 64} 65 66// ACLEntry is used to represent a legacy ACL token 67// The legacy tokens are deprecated. 68type ACLEntry struct { 69 CreateIndex uint64 70 ModifyIndex uint64 71 ID string 72 Name string 73 Type string 74 Rules string 75} 76 77// ACLReplicationStatus is used to represent the status of ACL replication. 78type ACLReplicationStatus struct { 79 Enabled bool 80 Running bool 81 SourceDatacenter string 82 ReplicationType string 83 ReplicatedIndex uint64 84 ReplicatedRoleIndex uint64 85 ReplicatedTokenIndex uint64 86 LastSuccess time.Time 87 LastError time.Time 88} 89 90// ACLServiceIdentity represents a high-level grant of all necessary privileges 91// to assume the identity of the named Service in the Catalog and within 92// Connect. 93type ACLServiceIdentity struct { 94 ServiceName string 95 Datacenters []string `json:",omitempty"` 96} 97 98// ACLPolicy represents an ACL Policy. 99type ACLPolicy struct { 100 ID string 101 Name string 102 Description string 103 Rules string 104 Datacenters []string 105 Hash []byte 106 CreateIndex uint64 107 ModifyIndex uint64 108} 109 110type ACLPolicyListEntry struct { 111 ID string 112 Name string 113 Description string 114 Datacenters []string 115 Hash []byte 116 CreateIndex uint64 117 ModifyIndex uint64 118} 119 120type ACLRolePolicyLink struct { 121 ID string 122 Name string 123} 124 125// ACLRole represents an ACL Role. 126type ACLRole struct { 127 ID string 128 Name string 129 Description string 130 Policies []*ACLRolePolicyLink `json:",omitempty"` 131 ServiceIdentities []*ACLServiceIdentity `json:",omitempty"` 132 Hash []byte 133 CreateIndex uint64 134 ModifyIndex uint64 135} 136 137// BindingRuleBindType is the type of binding rule mechanism used. 138type BindingRuleBindType string 139 140const ( 141 // BindingRuleBindTypeService binds to a service identity with the given name. 142 BindingRuleBindTypeService BindingRuleBindType = "service" 143 144 // BindingRuleBindTypeRole binds to pre-existing roles with the given name. 145 BindingRuleBindTypeRole BindingRuleBindType = "role" 146) 147 148type ACLBindingRule struct { 149 ID string 150 Description string 151 AuthMethod string 152 Selector string 153 BindType BindingRuleBindType 154 BindName string 155 156 CreateIndex uint64 157 ModifyIndex uint64 158} 159 160type ACLAuthMethod struct { 161 Name string 162 Type string 163 Description string 164 165 // Configuration is arbitrary configuration for the auth method. This 166 // should only contain primitive values and containers (such as lists and 167 // maps). 168 Config map[string]interface{} 169 170 CreateIndex uint64 171 ModifyIndex uint64 172} 173 174type ACLAuthMethodListEntry struct { 175 Name string 176 Type string 177 Description string 178 CreateIndex uint64 179 ModifyIndex uint64 180} 181 182// ParseKubernetesAuthMethodConfig takes a raw config map and returns a parsed 183// KubernetesAuthMethodConfig. 184func ParseKubernetesAuthMethodConfig(raw map[string]interface{}) (*KubernetesAuthMethodConfig, error) { 185 var config KubernetesAuthMethodConfig 186 decodeConf := &mapstructure.DecoderConfig{ 187 Result: &config, 188 WeaklyTypedInput: true, 189 } 190 191 decoder, err := mapstructure.NewDecoder(decodeConf) 192 if err != nil { 193 return nil, err 194 } 195 196 if err := decoder.Decode(raw); err != nil { 197 return nil, fmt.Errorf("error decoding config: %s", err) 198 } 199 200 return &config, nil 201} 202 203// KubernetesAuthMethodConfig is the config for the built-in Consul auth method 204// for Kubernetes. 205type KubernetesAuthMethodConfig struct { 206 Host string `json:",omitempty"` 207 CACert string `json:",omitempty"` 208 ServiceAccountJWT string `json:",omitempty"` 209} 210 211// RenderToConfig converts this into a map[string]interface{} suitable for use 212// in the ACLAuthMethod.Config field. 213func (c *KubernetesAuthMethodConfig) RenderToConfig() map[string]interface{} { 214 return map[string]interface{}{ 215 "Host": c.Host, 216 "CACert": c.CACert, 217 "ServiceAccountJWT": c.ServiceAccountJWT, 218 } 219} 220 221type ACLLoginParams struct { 222 AuthMethod string 223 BearerToken string 224 Meta map[string]string `json:",omitempty"` 225} 226 227// ACL can be used to query the ACL endpoints 228type ACL struct { 229 c *Client 230} 231 232// ACL returns a handle to the ACL endpoints 233func (c *Client) ACL() *ACL { 234 return &ACL{c} 235} 236 237// Bootstrap is used to perform a one-time ACL bootstrap operation on a cluster 238// to get the first management token. 239func (a *ACL) Bootstrap() (*ACLToken, *WriteMeta, error) { 240 r := a.c.newRequest("PUT", "/v1/acl/bootstrap") 241 rtt, resp, err := requireOK(a.c.doRequest(r)) 242 if err != nil { 243 return nil, nil, err 244 } 245 defer resp.Body.Close() 246 247 wm := &WriteMeta{RequestTime: rtt} 248 var out ACLToken 249 if err := decodeBody(resp, &out); err != nil { 250 return nil, nil, err 251 } 252 return &out, wm, nil 253} 254 255// Create is used to generate a new token with the given parameters 256// 257// Deprecated: Use TokenCreate instead. 258func (a *ACL) Create(acl *ACLEntry, q *WriteOptions) (string, *WriteMeta, error) { 259 r := a.c.newRequest("PUT", "/v1/acl/create") 260 r.setWriteOptions(q) 261 r.obj = acl 262 rtt, resp, err := requireOK(a.c.doRequest(r)) 263 if err != nil { 264 return "", nil, err 265 } 266 defer resp.Body.Close() 267 268 wm := &WriteMeta{RequestTime: rtt} 269 var out struct{ ID string } 270 if err := decodeBody(resp, &out); err != nil { 271 return "", nil, err 272 } 273 return out.ID, wm, nil 274} 275 276// Update is used to update the rules of an existing token 277// 278// Deprecated: Use TokenUpdate instead. 279func (a *ACL) Update(acl *ACLEntry, q *WriteOptions) (*WriteMeta, error) { 280 r := a.c.newRequest("PUT", "/v1/acl/update") 281 r.setWriteOptions(q) 282 r.obj = acl 283 rtt, resp, err := requireOK(a.c.doRequest(r)) 284 if err != nil { 285 return nil, err 286 } 287 defer resp.Body.Close() 288 289 wm := &WriteMeta{RequestTime: rtt} 290 return wm, nil 291} 292 293// Destroy is used to destroy a given ACL token ID 294// 295// Deprecated: Use TokenDelete instead. 296func (a *ACL) Destroy(id string, q *WriteOptions) (*WriteMeta, error) { 297 r := a.c.newRequest("PUT", "/v1/acl/destroy/"+id) 298 r.setWriteOptions(q) 299 rtt, resp, err := requireOK(a.c.doRequest(r)) 300 if err != nil { 301 return nil, err 302 } 303 resp.Body.Close() 304 305 wm := &WriteMeta{RequestTime: rtt} 306 return wm, nil 307} 308 309// Clone is used to return a new token cloned from an existing one 310// 311// Deprecated: Use TokenClone instead. 312func (a *ACL) Clone(id string, q *WriteOptions) (string, *WriteMeta, error) { 313 r := a.c.newRequest("PUT", "/v1/acl/clone/"+id) 314 r.setWriteOptions(q) 315 rtt, resp, err := requireOK(a.c.doRequest(r)) 316 if err != nil { 317 return "", nil, err 318 } 319 defer resp.Body.Close() 320 321 wm := &WriteMeta{RequestTime: rtt} 322 var out struct{ ID string } 323 if err := decodeBody(resp, &out); err != nil { 324 return "", nil, err 325 } 326 return out.ID, wm, nil 327} 328 329// Info is used to query for information about an ACL token 330// 331// Deprecated: Use TokenRead instead. 332func (a *ACL) Info(id string, q *QueryOptions) (*ACLEntry, *QueryMeta, error) { 333 r := a.c.newRequest("GET", "/v1/acl/info/"+id) 334 r.setQueryOptions(q) 335 rtt, resp, err := requireOK(a.c.doRequest(r)) 336 if err != nil { 337 return nil, nil, err 338 } 339 defer resp.Body.Close() 340 341 qm := &QueryMeta{} 342 parseQueryMeta(resp, qm) 343 qm.RequestTime = rtt 344 345 var entries []*ACLEntry 346 if err := decodeBody(resp, &entries); err != nil { 347 return nil, nil, err 348 } 349 if len(entries) > 0 { 350 return entries[0], qm, nil 351 } 352 return nil, qm, nil 353} 354 355// List is used to get all the ACL tokens 356// 357// Deprecated: Use TokenList instead. 358func (a *ACL) List(q *QueryOptions) ([]*ACLEntry, *QueryMeta, error) { 359 r := a.c.newRequest("GET", "/v1/acl/list") 360 r.setQueryOptions(q) 361 rtt, resp, err := requireOK(a.c.doRequest(r)) 362 if err != nil { 363 return nil, nil, err 364 } 365 defer resp.Body.Close() 366 367 qm := &QueryMeta{} 368 parseQueryMeta(resp, qm) 369 qm.RequestTime = rtt 370 371 var entries []*ACLEntry 372 if err := decodeBody(resp, &entries); err != nil { 373 return nil, nil, err 374 } 375 return entries, qm, nil 376} 377 378// Replication returns the status of the ACL replication process in the datacenter 379func (a *ACL) Replication(q *QueryOptions) (*ACLReplicationStatus, *QueryMeta, error) { 380 r := a.c.newRequest("GET", "/v1/acl/replication") 381 r.setQueryOptions(q) 382 rtt, resp, err := requireOK(a.c.doRequest(r)) 383 if err != nil { 384 return nil, nil, err 385 } 386 defer resp.Body.Close() 387 388 qm := &QueryMeta{} 389 parseQueryMeta(resp, qm) 390 qm.RequestTime = rtt 391 392 var entries *ACLReplicationStatus 393 if err := decodeBody(resp, &entries); err != nil { 394 return nil, nil, err 395 } 396 return entries, qm, nil 397} 398 399// TokenCreate creates a new ACL token. If either the AccessorID or SecretID fields 400// of the ACLToken structure are empty they will be filled in by Consul. 401func (a *ACL) TokenCreate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 402 r := a.c.newRequest("PUT", "/v1/acl/token") 403 r.setWriteOptions(q) 404 r.obj = token 405 rtt, resp, err := requireOK(a.c.doRequest(r)) 406 if err != nil { 407 return nil, nil, err 408 } 409 defer resp.Body.Close() 410 411 wm := &WriteMeta{RequestTime: rtt} 412 var out ACLToken 413 if err := decodeBody(resp, &out); err != nil { 414 return nil, nil, err 415 } 416 417 return &out, wm, nil 418} 419 420// TokenUpdate updates a token in place without modifying its AccessorID or SecretID. A valid 421// AccessorID must be set in the ACLToken structure passed to this function but the SecretID may 422// be omitted and will be filled in by Consul with its existing value. 423func (a *ACL) TokenUpdate(token *ACLToken, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 424 if token.AccessorID == "" { 425 return nil, nil, fmt.Errorf("Must specify an AccessorID for Token Updating") 426 } 427 r := a.c.newRequest("PUT", "/v1/acl/token/"+token.AccessorID) 428 r.setWriteOptions(q) 429 r.obj = token 430 rtt, resp, err := requireOK(a.c.doRequest(r)) 431 if err != nil { 432 return nil, nil, err 433 } 434 defer resp.Body.Close() 435 436 wm := &WriteMeta{RequestTime: rtt} 437 var out ACLToken 438 if err := decodeBody(resp, &out); err != nil { 439 return nil, nil, err 440 } 441 442 return &out, wm, nil 443} 444 445// TokenClone will create a new token with the same policies and locality as the original 446// token but will have its own auto-generated AccessorID and SecretID as well having the 447// description passed to this function. The tokenID parameter must be a valid Accessor ID 448// of an existing token. 449func (a *ACL) TokenClone(tokenID string, description string, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 450 if tokenID == "" { 451 return nil, nil, fmt.Errorf("Must specify a tokenID for Token Cloning") 452 } 453 454 r := a.c.newRequest("PUT", "/v1/acl/token/"+tokenID+"/clone") 455 r.setWriteOptions(q) 456 r.obj = struct{ Description string }{description} 457 rtt, resp, err := requireOK(a.c.doRequest(r)) 458 if err != nil { 459 return nil, nil, err 460 } 461 defer resp.Body.Close() 462 463 wm := &WriteMeta{RequestTime: rtt} 464 var out ACLToken 465 if err := decodeBody(resp, &out); err != nil { 466 return nil, nil, err 467 } 468 469 return &out, wm, nil 470} 471 472// TokenDelete removes a single ACL token. The tokenID parameter must be a valid 473// Accessor ID of an existing token. 474func (a *ACL) TokenDelete(tokenID string, q *WriteOptions) (*WriteMeta, error) { 475 r := a.c.newRequest("DELETE", "/v1/acl/token/"+tokenID) 476 r.setWriteOptions(q) 477 rtt, resp, err := requireOK(a.c.doRequest(r)) 478 if err != nil { 479 return nil, err 480 } 481 resp.Body.Close() 482 483 wm := &WriteMeta{RequestTime: rtt} 484 return wm, nil 485} 486 487// TokenRead retrieves the full token details. The tokenID parameter must be a valid 488// Accessor ID of an existing token. 489func (a *ACL) TokenRead(tokenID string, q *QueryOptions) (*ACLToken, *QueryMeta, error) { 490 r := a.c.newRequest("GET", "/v1/acl/token/"+tokenID) 491 r.setQueryOptions(q) 492 rtt, resp, err := requireOK(a.c.doRequest(r)) 493 if err != nil { 494 return nil, nil, err 495 } 496 defer resp.Body.Close() 497 498 qm := &QueryMeta{} 499 parseQueryMeta(resp, qm) 500 qm.RequestTime = rtt 501 502 var out ACLToken 503 if err := decodeBody(resp, &out); err != nil { 504 return nil, nil, err 505 } 506 507 return &out, qm, nil 508} 509 510// TokenReadSelf retrieves the full token details of the token currently 511// assigned to the API Client. In this manner its possible to read a token 512// by its Secret ID. 513func (a *ACL) TokenReadSelf(q *QueryOptions) (*ACLToken, *QueryMeta, error) { 514 r := a.c.newRequest("GET", "/v1/acl/token/self") 515 r.setQueryOptions(q) 516 rtt, resp, err := requireOK(a.c.doRequest(r)) 517 if err != nil { 518 return nil, nil, err 519 } 520 defer resp.Body.Close() 521 522 qm := &QueryMeta{} 523 parseQueryMeta(resp, qm) 524 qm.RequestTime = rtt 525 526 var out ACLToken 527 if err := decodeBody(resp, &out); err != nil { 528 return nil, nil, err 529 } 530 531 return &out, qm, nil 532} 533 534// TokenList lists all tokens. The listing does not contain any SecretIDs as those 535// may only be retrieved by a call to TokenRead. 536func (a *ACL) TokenList(q *QueryOptions) ([]*ACLTokenListEntry, *QueryMeta, error) { 537 r := a.c.newRequest("GET", "/v1/acl/tokens") 538 r.setQueryOptions(q) 539 rtt, resp, err := requireOK(a.c.doRequest(r)) 540 if err != nil { 541 return nil, nil, err 542 } 543 defer resp.Body.Close() 544 545 qm := &QueryMeta{} 546 parseQueryMeta(resp, qm) 547 qm.RequestTime = rtt 548 549 var entries []*ACLTokenListEntry 550 if err := decodeBody(resp, &entries); err != nil { 551 return nil, nil, err 552 } 553 return entries, qm, nil 554} 555 556// PolicyCreate will create a new policy. It is not allowed for the policy parameters 557// ID field to be set as this will be generated by Consul while processing the request. 558func (a *ACL) PolicyCreate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) { 559 if policy.ID != "" { 560 return nil, nil, fmt.Errorf("Cannot specify an ID in Policy Creation") 561 } 562 r := a.c.newRequest("PUT", "/v1/acl/policy") 563 r.setWriteOptions(q) 564 r.obj = policy 565 rtt, resp, err := requireOK(a.c.doRequest(r)) 566 if err != nil { 567 return nil, nil, err 568 } 569 defer resp.Body.Close() 570 571 wm := &WriteMeta{RequestTime: rtt} 572 var out ACLPolicy 573 if err := decodeBody(resp, &out); err != nil { 574 return nil, nil, err 575 } 576 577 return &out, wm, nil 578} 579 580// PolicyUpdate updates a policy. The ID field of the policy parameter must be set to an 581// existing policy ID 582func (a *ACL) PolicyUpdate(policy *ACLPolicy, q *WriteOptions) (*ACLPolicy, *WriteMeta, error) { 583 if policy.ID == "" { 584 return nil, nil, fmt.Errorf("Must specify an ID in Policy Update") 585 } 586 587 r := a.c.newRequest("PUT", "/v1/acl/policy/"+policy.ID) 588 r.setWriteOptions(q) 589 r.obj = policy 590 rtt, resp, err := requireOK(a.c.doRequest(r)) 591 if err != nil { 592 return nil, nil, err 593 } 594 defer resp.Body.Close() 595 596 wm := &WriteMeta{RequestTime: rtt} 597 var out ACLPolicy 598 if err := decodeBody(resp, &out); err != nil { 599 return nil, nil, err 600 } 601 602 return &out, wm, nil 603} 604 605// PolicyDelete deletes a policy given its ID. 606func (a *ACL) PolicyDelete(policyID string, q *WriteOptions) (*WriteMeta, error) { 607 r := a.c.newRequest("DELETE", "/v1/acl/policy/"+policyID) 608 r.setWriteOptions(q) 609 rtt, resp, err := requireOK(a.c.doRequest(r)) 610 if err != nil { 611 return nil, err 612 } 613 resp.Body.Close() 614 615 wm := &WriteMeta{RequestTime: rtt} 616 return wm, nil 617} 618 619// PolicyRead retrieves the policy details including the rule set. 620func (a *ACL) PolicyRead(policyID string, q *QueryOptions) (*ACLPolicy, *QueryMeta, error) { 621 r := a.c.newRequest("GET", "/v1/acl/policy/"+policyID) 622 r.setQueryOptions(q) 623 rtt, resp, err := requireOK(a.c.doRequest(r)) 624 if err != nil { 625 return nil, nil, err 626 } 627 defer resp.Body.Close() 628 629 qm := &QueryMeta{} 630 parseQueryMeta(resp, qm) 631 qm.RequestTime = rtt 632 633 var out ACLPolicy 634 if err := decodeBody(resp, &out); err != nil { 635 return nil, nil, err 636 } 637 638 return &out, qm, nil 639} 640 641// PolicyList retrieves a listing of all policies. The listing does not include the 642// rules for any policy as those should be retrieved by subsequent calls to PolicyRead. 643func (a *ACL) PolicyList(q *QueryOptions) ([]*ACLPolicyListEntry, *QueryMeta, error) { 644 r := a.c.newRequest("GET", "/v1/acl/policies") 645 r.setQueryOptions(q) 646 rtt, resp, err := requireOK(a.c.doRequest(r)) 647 if err != nil { 648 return nil, nil, err 649 } 650 defer resp.Body.Close() 651 652 qm := &QueryMeta{} 653 parseQueryMeta(resp, qm) 654 qm.RequestTime = rtt 655 656 var entries []*ACLPolicyListEntry 657 if err := decodeBody(resp, &entries); err != nil { 658 return nil, nil, err 659 } 660 return entries, qm, nil 661} 662 663// RulesTranslate translates the legacy rule syntax into the current syntax. 664// 665// Deprecated: Support for the legacy syntax translation will be removed 666// when legacy ACL support is removed. 667func (a *ACL) RulesTranslate(rules io.Reader) (string, error) { 668 r := a.c.newRequest("POST", "/v1/acl/rules/translate") 669 r.body = rules 670 rtt, resp, err := requireOK(a.c.doRequest(r)) 671 if err != nil { 672 return "", err 673 } 674 defer resp.Body.Close() 675 qm := &QueryMeta{} 676 parseQueryMeta(resp, qm) 677 qm.RequestTime = rtt 678 679 ruleBytes, err := ioutil.ReadAll(resp.Body) 680 if err != nil { 681 return "", fmt.Errorf("Failed to read translated rule body: %v", err) 682 } 683 684 return string(ruleBytes), nil 685} 686 687// RulesTranslateToken translates the rules associated with the legacy syntax 688// into the current syntax and returns the results. 689// 690// Deprecated: Support for the legacy syntax translation will be removed 691// when legacy ACL support is removed. 692func (a *ACL) RulesTranslateToken(tokenID string) (string, error) { 693 r := a.c.newRequest("GET", "/v1/acl/rules/translate/"+tokenID) 694 rtt, resp, err := requireOK(a.c.doRequest(r)) 695 if err != nil { 696 return "", err 697 } 698 defer resp.Body.Close() 699 qm := &QueryMeta{} 700 parseQueryMeta(resp, qm) 701 qm.RequestTime = rtt 702 703 ruleBytes, err := ioutil.ReadAll(resp.Body) 704 if err != nil { 705 return "", fmt.Errorf("Failed to read translated rule body: %v", err) 706 } 707 708 return string(ruleBytes), nil 709} 710 711// RoleCreate will create a new role. It is not allowed for the role parameters 712// ID field to be set as this will be generated by Consul while processing the request. 713func (a *ACL) RoleCreate(role *ACLRole, q *WriteOptions) (*ACLRole, *WriteMeta, error) { 714 if role.ID != "" { 715 return nil, nil, fmt.Errorf("Cannot specify an ID in Role Creation") 716 } 717 718 r := a.c.newRequest("PUT", "/v1/acl/role") 719 r.setWriteOptions(q) 720 r.obj = role 721 rtt, resp, err := requireOK(a.c.doRequest(r)) 722 if err != nil { 723 return nil, nil, err 724 } 725 defer resp.Body.Close() 726 727 wm := &WriteMeta{RequestTime: rtt} 728 var out ACLRole 729 if err := decodeBody(resp, &out); err != nil { 730 return nil, nil, err 731 } 732 733 return &out, wm, nil 734} 735 736// RoleUpdate updates a role. The ID field of the role parameter must be set to an 737// existing role ID 738func (a *ACL) RoleUpdate(role *ACLRole, q *WriteOptions) (*ACLRole, *WriteMeta, error) { 739 if role.ID == "" { 740 return nil, nil, fmt.Errorf("Must specify an ID in Role Update") 741 } 742 743 r := a.c.newRequest("PUT", "/v1/acl/role/"+role.ID) 744 r.setWriteOptions(q) 745 r.obj = role 746 rtt, resp, err := requireOK(a.c.doRequest(r)) 747 if err != nil { 748 return nil, nil, err 749 } 750 defer resp.Body.Close() 751 752 wm := &WriteMeta{RequestTime: rtt} 753 var out ACLRole 754 if err := decodeBody(resp, &out); err != nil { 755 return nil, nil, err 756 } 757 758 return &out, wm, nil 759} 760 761// RoleDelete deletes a role given its ID. 762func (a *ACL) RoleDelete(roleID string, q *WriteOptions) (*WriteMeta, error) { 763 r := a.c.newRequest("DELETE", "/v1/acl/role/"+roleID) 764 r.setWriteOptions(q) 765 rtt, resp, err := requireOK(a.c.doRequest(r)) 766 if err != nil { 767 return nil, err 768 } 769 resp.Body.Close() 770 771 wm := &WriteMeta{RequestTime: rtt} 772 return wm, nil 773} 774 775// RoleRead retrieves the role details (by ID). Returns nil if not found. 776func (a *ACL) RoleRead(roleID string, q *QueryOptions) (*ACLRole, *QueryMeta, error) { 777 r := a.c.newRequest("GET", "/v1/acl/role/"+roleID) 778 r.setQueryOptions(q) 779 found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r)) 780 if err != nil { 781 return nil, nil, err 782 } 783 defer resp.Body.Close() 784 785 qm := &QueryMeta{} 786 parseQueryMeta(resp, qm) 787 qm.RequestTime = rtt 788 789 if !found { 790 return nil, qm, nil 791 } 792 793 var out ACLRole 794 if err := decodeBody(resp, &out); err != nil { 795 return nil, nil, err 796 } 797 798 return &out, qm, nil 799} 800 801// RoleReadByName retrieves the role details (by name). Returns nil if not found. 802func (a *ACL) RoleReadByName(roleName string, q *QueryOptions) (*ACLRole, *QueryMeta, error) { 803 r := a.c.newRequest("GET", "/v1/acl/role/name/"+url.QueryEscape(roleName)) 804 r.setQueryOptions(q) 805 found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r)) 806 if err != nil { 807 return nil, nil, err 808 } 809 defer resp.Body.Close() 810 811 qm := &QueryMeta{} 812 parseQueryMeta(resp, qm) 813 qm.RequestTime = rtt 814 815 if !found { 816 return nil, qm, nil 817 } 818 819 var out ACLRole 820 if err := decodeBody(resp, &out); err != nil { 821 return nil, nil, err 822 } 823 824 return &out, qm, nil 825} 826 827// RoleList retrieves a listing of all roles. The listing does not include some 828// metadata for the role as those should be retrieved by subsequent calls to 829// RoleRead. 830func (a *ACL) RoleList(q *QueryOptions) ([]*ACLRole, *QueryMeta, error) { 831 r := a.c.newRequest("GET", "/v1/acl/roles") 832 r.setQueryOptions(q) 833 rtt, resp, err := requireOK(a.c.doRequest(r)) 834 if err != nil { 835 return nil, nil, err 836 } 837 defer resp.Body.Close() 838 839 qm := &QueryMeta{} 840 parseQueryMeta(resp, qm) 841 qm.RequestTime = rtt 842 843 var entries []*ACLRole 844 if err := decodeBody(resp, &entries); err != nil { 845 return nil, nil, err 846 } 847 return entries, qm, nil 848} 849 850// AuthMethodCreate will create a new auth method. 851func (a *ACL) AuthMethodCreate(method *ACLAuthMethod, q *WriteOptions) (*ACLAuthMethod, *WriteMeta, error) { 852 if method.Name == "" { 853 return nil, nil, fmt.Errorf("Must specify a Name in Auth Method Creation") 854 } 855 856 r := a.c.newRequest("PUT", "/v1/acl/auth-method") 857 r.setWriteOptions(q) 858 r.obj = method 859 rtt, resp, err := requireOK(a.c.doRequest(r)) 860 if err != nil { 861 return nil, nil, err 862 } 863 defer resp.Body.Close() 864 865 wm := &WriteMeta{RequestTime: rtt} 866 var out ACLAuthMethod 867 if err := decodeBody(resp, &out); err != nil { 868 return nil, nil, err 869 } 870 871 return &out, wm, nil 872} 873 874// AuthMethodUpdate updates an auth method. 875func (a *ACL) AuthMethodUpdate(method *ACLAuthMethod, q *WriteOptions) (*ACLAuthMethod, *WriteMeta, error) { 876 if method.Name == "" { 877 return nil, nil, fmt.Errorf("Must specify a Name in Auth Method Update") 878 } 879 880 r := a.c.newRequest("PUT", "/v1/acl/auth-method/"+url.QueryEscape(method.Name)) 881 r.setWriteOptions(q) 882 r.obj = method 883 rtt, resp, err := requireOK(a.c.doRequest(r)) 884 if err != nil { 885 return nil, nil, err 886 } 887 defer resp.Body.Close() 888 889 wm := &WriteMeta{RequestTime: rtt} 890 var out ACLAuthMethod 891 if err := decodeBody(resp, &out); err != nil { 892 return nil, nil, err 893 } 894 895 return &out, wm, nil 896} 897 898// AuthMethodDelete deletes an auth method given its Name. 899func (a *ACL) AuthMethodDelete(methodName string, q *WriteOptions) (*WriteMeta, error) { 900 if methodName == "" { 901 return nil, fmt.Errorf("Must specify a Name in Auth Method Delete") 902 } 903 904 r := a.c.newRequest("DELETE", "/v1/acl/auth-method/"+url.QueryEscape(methodName)) 905 r.setWriteOptions(q) 906 rtt, resp, err := requireOK(a.c.doRequest(r)) 907 if err != nil { 908 return nil, err 909 } 910 resp.Body.Close() 911 912 wm := &WriteMeta{RequestTime: rtt} 913 return wm, nil 914} 915 916// AuthMethodRead retrieves the auth method. Returns nil if not found. 917func (a *ACL) AuthMethodRead(methodName string, q *QueryOptions) (*ACLAuthMethod, *QueryMeta, error) { 918 if methodName == "" { 919 return nil, nil, fmt.Errorf("Must specify a Name in Auth Method Read") 920 } 921 922 r := a.c.newRequest("GET", "/v1/acl/auth-method/"+url.QueryEscape(methodName)) 923 r.setQueryOptions(q) 924 found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r)) 925 if err != nil { 926 return nil, nil, err 927 } 928 defer resp.Body.Close() 929 930 qm := &QueryMeta{} 931 parseQueryMeta(resp, qm) 932 qm.RequestTime = rtt 933 934 if !found { 935 return nil, qm, nil 936 } 937 938 var out ACLAuthMethod 939 if err := decodeBody(resp, &out); err != nil { 940 return nil, nil, err 941 } 942 943 return &out, qm, nil 944} 945 946// AuthMethodList retrieves a listing of all auth methods. The listing does not 947// include some metadata for the auth method as those should be retrieved by 948// subsequent calls to AuthMethodRead. 949func (a *ACL) AuthMethodList(q *QueryOptions) ([]*ACLAuthMethodListEntry, *QueryMeta, error) { 950 r := a.c.newRequest("GET", "/v1/acl/auth-methods") 951 r.setQueryOptions(q) 952 rtt, resp, err := requireOK(a.c.doRequest(r)) 953 if err != nil { 954 return nil, nil, err 955 } 956 defer resp.Body.Close() 957 958 qm := &QueryMeta{} 959 parseQueryMeta(resp, qm) 960 qm.RequestTime = rtt 961 962 var entries []*ACLAuthMethodListEntry 963 if err := decodeBody(resp, &entries); err != nil { 964 return nil, nil, err 965 } 966 return entries, qm, nil 967} 968 969// BindingRuleCreate will create a new binding rule. It is not allowed for the 970// binding rule parameter's ID field to be set as this will be generated by 971// Consul while processing the request. 972func (a *ACL) BindingRuleCreate(rule *ACLBindingRule, q *WriteOptions) (*ACLBindingRule, *WriteMeta, error) { 973 if rule.ID != "" { 974 return nil, nil, fmt.Errorf("Cannot specify an ID in Binding Rule Creation") 975 } 976 977 r := a.c.newRequest("PUT", "/v1/acl/binding-rule") 978 r.setWriteOptions(q) 979 r.obj = rule 980 rtt, resp, err := requireOK(a.c.doRequest(r)) 981 if err != nil { 982 return nil, nil, err 983 } 984 defer resp.Body.Close() 985 986 wm := &WriteMeta{RequestTime: rtt} 987 var out ACLBindingRule 988 if err := decodeBody(resp, &out); err != nil { 989 return nil, nil, err 990 } 991 992 return &out, wm, nil 993} 994 995// BindingRuleUpdate updates a binding rule. The ID field of the role binding 996// rule parameter must be set to an existing binding rule ID. 997func (a *ACL) BindingRuleUpdate(rule *ACLBindingRule, q *WriteOptions) (*ACLBindingRule, *WriteMeta, error) { 998 if rule.ID == "" { 999 return nil, nil, fmt.Errorf("Must specify an ID in Binding Rule Update") 1000 } 1001 1002 r := a.c.newRequest("PUT", "/v1/acl/binding-rule/"+rule.ID) 1003 r.setWriteOptions(q) 1004 r.obj = rule 1005 rtt, resp, err := requireOK(a.c.doRequest(r)) 1006 if err != nil { 1007 return nil, nil, err 1008 } 1009 defer resp.Body.Close() 1010 1011 wm := &WriteMeta{RequestTime: rtt} 1012 var out ACLBindingRule 1013 if err := decodeBody(resp, &out); err != nil { 1014 return nil, nil, err 1015 } 1016 1017 return &out, wm, nil 1018} 1019 1020// BindingRuleDelete deletes a binding rule given its ID. 1021func (a *ACL) BindingRuleDelete(bindingRuleID string, q *WriteOptions) (*WriteMeta, error) { 1022 r := a.c.newRequest("DELETE", "/v1/acl/binding-rule/"+bindingRuleID) 1023 r.setWriteOptions(q) 1024 rtt, resp, err := requireOK(a.c.doRequest(r)) 1025 if err != nil { 1026 return nil, err 1027 } 1028 resp.Body.Close() 1029 1030 wm := &WriteMeta{RequestTime: rtt} 1031 return wm, nil 1032} 1033 1034// BindingRuleRead retrieves the binding rule details. Returns nil if not found. 1035func (a *ACL) BindingRuleRead(bindingRuleID string, q *QueryOptions) (*ACLBindingRule, *QueryMeta, error) { 1036 r := a.c.newRequest("GET", "/v1/acl/binding-rule/"+bindingRuleID) 1037 r.setQueryOptions(q) 1038 found, rtt, resp, err := requireNotFoundOrOK(a.c.doRequest(r)) 1039 if err != nil { 1040 return nil, nil, err 1041 } 1042 defer resp.Body.Close() 1043 1044 qm := &QueryMeta{} 1045 parseQueryMeta(resp, qm) 1046 qm.RequestTime = rtt 1047 1048 if !found { 1049 return nil, qm, nil 1050 } 1051 1052 var out ACLBindingRule 1053 if err := decodeBody(resp, &out); err != nil { 1054 return nil, nil, err 1055 } 1056 1057 return &out, qm, nil 1058} 1059 1060// BindingRuleList retrieves a listing of all binding rules. 1061func (a *ACL) BindingRuleList(methodName string, q *QueryOptions) ([]*ACLBindingRule, *QueryMeta, error) { 1062 r := a.c.newRequest("GET", "/v1/acl/binding-rules") 1063 if methodName != "" { 1064 r.params.Set("authmethod", methodName) 1065 } 1066 r.setQueryOptions(q) 1067 rtt, resp, err := requireOK(a.c.doRequest(r)) 1068 if err != nil { 1069 return nil, nil, err 1070 } 1071 defer resp.Body.Close() 1072 1073 qm := &QueryMeta{} 1074 parseQueryMeta(resp, qm) 1075 qm.RequestTime = rtt 1076 1077 var entries []*ACLBindingRule 1078 if err := decodeBody(resp, &entries); err != nil { 1079 return nil, nil, err 1080 } 1081 return entries, qm, nil 1082} 1083 1084// Login is used to exchange auth method credentials for a newly-minted Consul Token. 1085func (a *ACL) Login(auth *ACLLoginParams, q *WriteOptions) (*ACLToken, *WriteMeta, error) { 1086 r := a.c.newRequest("POST", "/v1/acl/login") 1087 r.setWriteOptions(q) 1088 r.obj = auth 1089 1090 rtt, resp, err := requireOK(a.c.doRequest(r)) 1091 if err != nil { 1092 return nil, nil, err 1093 } 1094 defer resp.Body.Close() 1095 1096 wm := &WriteMeta{RequestTime: rtt} 1097 var out ACLToken 1098 if err := decodeBody(resp, &out); err != nil { 1099 return nil, nil, err 1100 } 1101 return &out, wm, nil 1102} 1103 1104// Logout is used to destroy a Consul Token created via Login(). 1105func (a *ACL) Logout(q *WriteOptions) (*WriteMeta, error) { 1106 r := a.c.newRequest("POST", "/v1/acl/logout") 1107 r.setWriteOptions(q) 1108 rtt, resp, err := requireOK(a.c.doRequest(r)) 1109 if err != nil { 1110 return nil, err 1111 } 1112 resp.Body.Close() 1113 1114 wm := &WriteMeta{RequestTime: rtt} 1115 return wm, nil 1116} 1117