2015-04-04 00:32:30 +03:00
|
|
|
// Copyright 2015 CoreOS, Inc.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package client
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
|
|
|
|
"github.com/coreos/etcd/Godeps/_workspace/src/golang.org/x/net/context"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Role struct {
|
|
|
|
Role string `json:"role"`
|
|
|
|
Permissions Permissions `json:"permissions"`
|
|
|
|
Grant *Permissions `json:"grant,omitempty"`
|
|
|
|
Revoke *Permissions `json:"revoke,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type Permissions struct {
|
|
|
|
KV rwPermission `json:"kv"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type rwPermission struct {
|
|
|
|
Read []string `json:"read"`
|
|
|
|
Write []string `json:"write"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type PermissionType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
ReadPermission PermissionType = iota
|
|
|
|
WritePermission
|
|
|
|
ReadWritePermission
|
|
|
|
)
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
// NewAuthRoleAPI constructs a new AuthRoleAPI that uses HTTP to
|
2015-04-04 00:32:30 +03:00
|
|
|
// interact with etcd's role creation and modification features.
|
2015-06-16 01:15:51 +03:00
|
|
|
func NewAuthRoleAPI(c Client) AuthRoleAPI {
|
|
|
|
return &httpAuthRoleAPI{
|
2015-04-04 00:32:30 +03:00
|
|
|
client: c,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
type AuthRoleAPI interface {
|
2015-04-04 00:32:30 +03:00
|
|
|
// Add a role.
|
|
|
|
AddRole(ctx context.Context, role string) error
|
|
|
|
|
|
|
|
// Remove a role.
|
|
|
|
RemoveRole(ctx context.Context, role string) error
|
|
|
|
|
|
|
|
// Get role details.
|
|
|
|
GetRole(ctx context.Context, role string) (*Role, error)
|
|
|
|
|
|
|
|
// Grant a role some permission prefixes for the KV store.
|
|
|
|
GrantRoleKV(ctx context.Context, role string, prefixes []string, permType PermissionType) (*Role, error)
|
|
|
|
|
|
|
|
// Revoke some some permission prefixes for a role on the KV store.
|
|
|
|
RevokeRoleKV(ctx context.Context, role string, prefixes []string, permType PermissionType) (*Role, error)
|
|
|
|
|
|
|
|
// List roles.
|
|
|
|
ListRoles(ctx context.Context) ([]string, error)
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
type httpAuthRoleAPI struct {
|
2015-04-04 00:32:30 +03:00
|
|
|
client httpClient
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
type authRoleAPIAction struct {
|
2015-04-04 00:32:30 +03:00
|
|
|
verb string
|
|
|
|
name string
|
|
|
|
role *Role
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
type authRoleAPIList struct{}
|
2015-04-04 00:32:30 +03:00
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (list *authRoleAPIList) HTTPRequest(ep url.URL) *http.Request {
|
|
|
|
u := v2AuthURL(ep, "roles", "")
|
2015-04-04 00:32:30 +03:00
|
|
|
req, _ := http.NewRequest("GET", u.String(), nil)
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (l *authRoleAPIAction) HTTPRequest(ep url.URL) *http.Request {
|
|
|
|
u := v2AuthURL(ep, "roles", l.name)
|
2015-04-04 00:32:30 +03:00
|
|
|
if l.role == nil {
|
|
|
|
req, _ := http.NewRequest(l.verb, u.String(), nil)
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
b, err := json.Marshal(l.role)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
body := bytes.NewReader(b)
|
|
|
|
req, _ := http.NewRequest(l.verb, u.String(), body)
|
|
|
|
req.Header.Set("Content-Type", "application/json")
|
|
|
|
return req
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (r *httpAuthRoleAPI) ListRoles(ctx context.Context) ([]string, error) {
|
|
|
|
resp, body, err := r.client.Do(ctx, &authRoleAPIList{})
|
2015-04-04 00:32:30 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-12-12 15:16:10 +03:00
|
|
|
if err = assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
|
2015-04-04 00:32:30 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var userList struct {
|
|
|
|
Roles []string `json:"roles"`
|
|
|
|
}
|
2015-12-12 15:16:10 +03:00
|
|
|
if err = json.Unmarshal(body, &userList); err != nil {
|
2015-04-04 00:32:30 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return userList.Roles, nil
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (r *httpAuthRoleAPI) AddRole(ctx context.Context, rolename string) error {
|
2015-04-04 00:32:30 +03:00
|
|
|
role := &Role{
|
|
|
|
Role: rolename,
|
|
|
|
}
|
2015-06-16 01:15:51 +03:00
|
|
|
return r.addRemoveRole(ctx, &authRoleAPIAction{
|
2015-04-04 00:32:30 +03:00
|
|
|
verb: "PUT",
|
|
|
|
name: rolename,
|
|
|
|
role: role,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (r *httpAuthRoleAPI) RemoveRole(ctx context.Context, rolename string) error {
|
|
|
|
return r.addRemoveRole(ctx, &authRoleAPIAction{
|
2015-04-04 00:32:30 +03:00
|
|
|
verb: "DELETE",
|
|
|
|
name: rolename,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (r *httpAuthRoleAPI) addRemoveRole(ctx context.Context, req *authRoleAPIAction) error {
|
2015-04-04 00:32:30 +03:00
|
|
|
resp, body, err := r.client.Do(ctx, req)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if err := assertStatusCode(resp.StatusCode, http.StatusOK, http.StatusCreated); err != nil {
|
2015-06-16 01:15:51 +03:00
|
|
|
var sec authError
|
2015-04-04 00:32:30 +03:00
|
|
|
err := json.Unmarshal(body, &sec)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return sec
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (r *httpAuthRoleAPI) GetRole(ctx context.Context, rolename string) (*Role, error) {
|
|
|
|
return r.modRole(ctx, &authRoleAPIAction{
|
2015-04-04 00:32:30 +03:00
|
|
|
verb: "GET",
|
|
|
|
name: rolename,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildRWPermission(prefixes []string, permType PermissionType) rwPermission {
|
|
|
|
var out rwPermission
|
|
|
|
switch permType {
|
|
|
|
case ReadPermission:
|
|
|
|
out.Read = prefixes
|
|
|
|
case WritePermission:
|
|
|
|
out.Write = prefixes
|
|
|
|
case ReadWritePermission:
|
|
|
|
out.Read = prefixes
|
|
|
|
out.Write = prefixes
|
|
|
|
}
|
|
|
|
return out
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (r *httpAuthRoleAPI) GrantRoleKV(ctx context.Context, rolename string, prefixes []string, permType PermissionType) (*Role, error) {
|
2015-04-04 00:32:30 +03:00
|
|
|
rwp := buildRWPermission(prefixes, permType)
|
|
|
|
role := &Role{
|
|
|
|
Role: rolename,
|
|
|
|
Grant: &Permissions{
|
|
|
|
KV: rwp,
|
|
|
|
},
|
|
|
|
}
|
2015-06-16 01:15:51 +03:00
|
|
|
return r.modRole(ctx, &authRoleAPIAction{
|
2015-04-04 00:32:30 +03:00
|
|
|
verb: "PUT",
|
|
|
|
name: rolename,
|
|
|
|
role: role,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (r *httpAuthRoleAPI) RevokeRoleKV(ctx context.Context, rolename string, prefixes []string, permType PermissionType) (*Role, error) {
|
2015-04-04 00:32:30 +03:00
|
|
|
rwp := buildRWPermission(prefixes, permType)
|
|
|
|
role := &Role{
|
|
|
|
Role: rolename,
|
|
|
|
Revoke: &Permissions{
|
|
|
|
KV: rwp,
|
|
|
|
},
|
|
|
|
}
|
2015-06-16 01:15:51 +03:00
|
|
|
return r.modRole(ctx, &authRoleAPIAction{
|
2015-04-04 00:32:30 +03:00
|
|
|
verb: "PUT",
|
|
|
|
name: rolename,
|
|
|
|
role: role,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-06-16 01:15:51 +03:00
|
|
|
func (r *httpAuthRoleAPI) modRole(ctx context.Context, req *authRoleAPIAction) (*Role, error) {
|
2015-04-04 00:32:30 +03:00
|
|
|
resp, body, err := r.client.Do(ctx, req)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-12-12 15:16:10 +03:00
|
|
|
if err = assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
|
2015-06-16 01:15:51 +03:00
|
|
|
var sec authError
|
2015-12-12 15:16:10 +03:00
|
|
|
err = json.Unmarshal(body, &sec)
|
2015-04-04 00:32:30 +03:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return nil, sec
|
|
|
|
}
|
|
|
|
var role Role
|
2015-12-12 15:16:10 +03:00
|
|
|
if err = json.Unmarshal(body, &role); err != nil {
|
2015-04-04 00:32:30 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &role, nil
|
|
|
|
}
|