Self token lookup

This commit is contained in:
Alex Dadgar 2017-10-13 13:10:26 -07:00
parent 377e63dc60
commit 96ef879c24
5 changed files with 170 additions and 9 deletions

View file

@ -144,6 +144,16 @@ func (a *ACLTokens) Info(accessorID string, q *QueryOptions) (*ACLToken, *QueryM
return &resp, wm, nil
}
// Self is used to query our own token
func (a *ACLTokens) Self(q *QueryOptions) (*ACLToken, *QueryMeta, error) {
var resp ACLToken
wm, err := a.client.query("/v1/acl/token/self", &resp, q)
if err != nil {
return nil, nil, err
}
return &resp, wm, nil
}
// ACLPolicyListStub is used to for listing ACL policies
type ACLPolicyListStub struct {
Name string

View file

@ -182,6 +182,36 @@ func TestACLTokens_Info(t *testing.T) {
assert.Equal(t, out, out2)
}
func TestACLTokens_Self(t *testing.T) {
t.Parallel()
c, s, _ := makeACLClient(t, nil, nil)
defer s.Stop()
at := c.ACLTokens()
token := &ACLToken{
Name: "foo",
Type: "client",
Policies: []string{"foo1"},
}
// Create the token
out, wm, err := at.Create(token, nil)
assert.Nil(t, err)
assertWriteMeta(t, wm)
assert.NotNil(t, out)
// Set the clients token to the new token
c.SetSecretID(out.SecretID)
at = c.ACLTokens()
// Query the token
out2, qm, err := at.Self(nil)
if assert.Nil(t, err) {
assertQueryMeta(t, qm)
assert.Equal(t, out, out2)
}
}
func TestACLTokens_Delete(t *testing.T) {
t.Parallel()
c, s, _ := makeACLClient(t, nil, nil)

View file

@ -154,29 +154,35 @@ func (s *HTTPServer) ACLTokenBootstrap(resp http.ResponseWriter, req *http.Reque
}
func (s *HTTPServer) ACLTokenSpecificRequest(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
accessor := strings.TrimPrefix(req.URL.Path, "/v1/acl/token")
path := req.URL.Path
// If there is no accessor, this must be a create
if len(accessor) == 0 {
switch path {
case "/v1/acl/token":
if !(req.Method == "PUT" || req.Method == "POST") {
return nil, CodedError(405, ErrInvalidMethod)
}
return s.aclTokenUpdate(resp, req, "")
case "/v1/acl/token/self":
return s.aclTokenSelf(resp, req)
}
// Check if no accessor is given past the slash
accessor = accessor[1:]
if accessor == "" {
accessor := strings.TrimPrefix(path, "/v1/acl/token/")
return s.aclTokenCrud(resp, req, accessor)
}
func (s *HTTPServer) aclTokenCrud(resp http.ResponseWriter, req *http.Request,
tokenAccessor string) (interface{}, error) {
if tokenAccessor == "" {
return nil, CodedError(400, "Missing Token Accessor")
}
switch req.Method {
case "GET":
return s.aclTokenQuery(resp, req, accessor)
return s.aclTokenQuery(resp, req, tokenAccessor)
case "PUT", "POST":
return s.aclTokenUpdate(resp, req, accessor)
return s.aclTokenUpdate(resp, req, tokenAccessor)
case "DELETE":
return s.aclTokenDelete(resp, req, accessor)
return s.aclTokenDelete(resp, req, tokenAccessor)
default:
return nil, CodedError(405, ErrInvalidMethod)
}
@ -203,6 +209,29 @@ func (s *HTTPServer) aclTokenQuery(resp http.ResponseWriter, req *http.Request,
return out.Token, nil
}
func (s *HTTPServer) aclTokenSelf(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
if req.Method != "GET" {
return nil, CodedError(405, ErrInvalidMethod)
}
args := structs.ResolveACLTokenRequest{}
if s.parse(resp, req, &args.Region, &args.QueryOptions) {
return nil, nil
}
args.SecretID = args.AuthToken
var out structs.ResolveACLTokenResponse
if err := s.agent.RPC("ACL.ResolveToken", &args, &out); err != nil {
return nil, err
}
setMeta(resp, &out.QueryMeta)
if out.Token == nil {
return nil, CodedError(404, "ACL token not found")
}
return out.Token, nil
}
func (s *HTTPServer) aclTokenUpdate(resp http.ResponseWriter, req *http.Request,
tokenAccessor string) (interface{}, error) {
// Parse the token

View file

@ -322,6 +322,55 @@ func TestHTTP_ACLTokenQuery(t *testing.T) {
})
}
func TestHTTP_ACLTokenSelf(t *testing.T) {
t.Parallel()
httpACLTest(t, nil, func(s *TestAgent) {
p1 := mock.ACLToken()
p1.AccessorID = ""
args := structs.ACLTokenUpsertRequest{
Tokens: []*structs.ACLToken{p1},
WriteRequest: structs.WriteRequest{
Region: "global",
AuthToken: s.RootToken.SecretID,
},
}
var resp structs.ACLTokenUpsertResponse
if err := s.Agent.RPC("ACL.UpsertTokens", &args, &resp); err != nil {
t.Fatalf("err: %v", err)
}
out := resp.Tokens[0]
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/acl/token/self", nil)
if err != nil {
t.Fatalf("err: %v", err)
}
respW := httptest.NewRecorder()
setToken(req, out)
// Make the request
obj, err := s.Server.ACLTokenSpecificRequest(respW, req)
if err != nil {
t.Fatalf("err: %v", err)
}
// Check for the index
if respW.HeaderMap.Get("X-Nomad-Index") == "" {
t.Fatalf("missing index")
}
if respW.HeaderMap.Get("X-Nomad-KnownLeader") != "true" {
t.Fatalf("missing known leader")
}
if respW.HeaderMap.Get("X-Nomad-LastContact") == "" {
t.Fatalf("missing last contact")
}
// Check the output
n := obj.(*structs.ACLToken)
assert.Equal(t, out, n)
})
}
func TestHTTP_ACLTokenCreate(t *testing.T) {
t.Parallel()
httpACLTest(t, nil, func(s *TestAgent) {

View file

@ -268,6 +268,49 @@ $ curl \
}
```
## Read Self Token
This endpoint reads the ACL token given by the passed SecretID. If the token is a global token
which has been replicated to the region it may lag behind the authoritative region.
| Method | Path | Produces |
| ------ | ---------------------------- | -------------------------- |
| `GET` | `/acl/token/self` | `application/json` |
The table below shows this endpoint's support for
[blocking queries](/api/index.html#blocking-queries), [consistency modes](/api/index.html#consistency-modes) and
[required ACLs](/api/index.html#acls).
| Blocking Queries | Consistency Modes | ACL Required |
| ---------------- | ----------------- | ------------ |
| `YES` | `all` | Any valid ACL token |
### Sample Request
```text
$ curl \
--header "X-Nomad-Token: 8176afd3-772d-0b71-8f85-7fa5d903e9d4"
https://nomad.rocks/v1/acl/token/self
```
### Sample Response
```json
{
"AccessorID": "aa534e09-6a07-0a45-2295-a7f77063d429",
"SecretID": "8176afd3-772d-0b71-8f85-7fa5d903e9d4",
"Name": "Read-write token",
"Type": "client",
"Policies": [
"readwrite"
],
"Global": false,
"CreateTime": "2017-08-23T23:25:41.429154233Z",
"CreateIndex": 52,
"ModifyIndex": 64
}
```
## Delete Token
This endpoint deletes the ACL token by accessor. This request is forwarded to the