mirror of https://github.com/k3s-io/k3s
237 lines
5.7 KiB
Go
237 lines
5.7 KiB
Go
|
// Copyright 2015 The etcd Authors
|
||
|
//
|
||
|
// 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"
|
||
|
"context"
|
||
|
"encoding/json"
|
||
|
"net/http"
|
||
|
"net/url"
|
||
|
)
|
||
|
|
||
|
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
|
||
|
)
|
||
|
|
||
|
// NewAuthRoleAPI constructs a new AuthRoleAPI that uses HTTP to
|
||
|
// interact with etcd's role creation and modification features.
|
||
|
func NewAuthRoleAPI(c Client) AuthRoleAPI {
|
||
|
return &httpAuthRoleAPI{
|
||
|
client: c,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type AuthRoleAPI interface {
|
||
|
// AddRole adds a role.
|
||
|
AddRole(ctx context.Context, role string) error
|
||
|
|
||
|
// RemoveRole removes a role.
|
||
|
RemoveRole(ctx context.Context, role string) error
|
||
|
|
||
|
// GetRole retrieves role details.
|
||
|
GetRole(ctx context.Context, role string) (*Role, error)
|
||
|
|
||
|
// GrantRoleKV grants a role some permission prefixes for the KV store.
|
||
|
GrantRoleKV(ctx context.Context, role string, prefixes []string, permType PermissionType) (*Role, error)
|
||
|
|
||
|
// RevokeRoleKV revokes some permission prefixes for a role on the KV store.
|
||
|
RevokeRoleKV(ctx context.Context, role string, prefixes []string, permType PermissionType) (*Role, error)
|
||
|
|
||
|
// ListRoles lists roles.
|
||
|
ListRoles(ctx context.Context) ([]string, error)
|
||
|
}
|
||
|
|
||
|
type httpAuthRoleAPI struct {
|
||
|
client httpClient
|
||
|
}
|
||
|
|
||
|
type authRoleAPIAction struct {
|
||
|
verb string
|
||
|
name string
|
||
|
role *Role
|
||
|
}
|
||
|
|
||
|
type authRoleAPIList struct{}
|
||
|
|
||
|
func (list *authRoleAPIList) HTTPRequest(ep url.URL) *http.Request {
|
||
|
u := v2AuthURL(ep, "roles", "")
|
||
|
req, _ := http.NewRequest("GET", u.String(), nil)
|
||
|
req.Header.Set("Content-Type", "application/json")
|
||
|
return req
|
||
|
}
|
||
|
|
||
|
func (l *authRoleAPIAction) HTTPRequest(ep url.URL) *http.Request {
|
||
|
u := v2AuthURL(ep, "roles", l.name)
|
||
|
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
|
||
|
}
|
||
|
|
||
|
func (r *httpAuthRoleAPI) ListRoles(ctx context.Context) ([]string, error) {
|
||
|
resp, body, err := r.client.Do(ctx, &authRoleAPIList{})
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if err = assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
var roleList struct {
|
||
|
Roles []Role `json:"roles"`
|
||
|
}
|
||
|
if err = json.Unmarshal(body, &roleList); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
ret := make([]string, 0, len(roleList.Roles))
|
||
|
for _, r := range roleList.Roles {
|
||
|
ret = append(ret, r.Role)
|
||
|
}
|
||
|
return ret, nil
|
||
|
}
|
||
|
|
||
|
func (r *httpAuthRoleAPI) AddRole(ctx context.Context, rolename string) error {
|
||
|
role := &Role{
|
||
|
Role: rolename,
|
||
|
}
|
||
|
return r.addRemoveRole(ctx, &authRoleAPIAction{
|
||
|
verb: "PUT",
|
||
|
name: rolename,
|
||
|
role: role,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (r *httpAuthRoleAPI) RemoveRole(ctx context.Context, rolename string) error {
|
||
|
return r.addRemoveRole(ctx, &authRoleAPIAction{
|
||
|
verb: "DELETE",
|
||
|
name: rolename,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (r *httpAuthRoleAPI) addRemoveRole(ctx context.Context, req *authRoleAPIAction) error {
|
||
|
resp, body, err := r.client.Do(ctx, req)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if err := assertStatusCode(resp.StatusCode, http.StatusOK, http.StatusCreated); err != nil {
|
||
|
var sec authError
|
||
|
err := json.Unmarshal(body, &sec)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
return sec
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (r *httpAuthRoleAPI) GetRole(ctx context.Context, rolename string) (*Role, error) {
|
||
|
return r.modRole(ctx, &authRoleAPIAction{
|
||
|
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
|
||
|
}
|
||
|
|
||
|
func (r *httpAuthRoleAPI) GrantRoleKV(ctx context.Context, rolename string, prefixes []string, permType PermissionType) (*Role, error) {
|
||
|
rwp := buildRWPermission(prefixes, permType)
|
||
|
role := &Role{
|
||
|
Role: rolename,
|
||
|
Grant: &Permissions{
|
||
|
KV: rwp,
|
||
|
},
|
||
|
}
|
||
|
return r.modRole(ctx, &authRoleAPIAction{
|
||
|
verb: "PUT",
|
||
|
name: rolename,
|
||
|
role: role,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (r *httpAuthRoleAPI) RevokeRoleKV(ctx context.Context, rolename string, prefixes []string, permType PermissionType) (*Role, error) {
|
||
|
rwp := buildRWPermission(prefixes, permType)
|
||
|
role := &Role{
|
||
|
Role: rolename,
|
||
|
Revoke: &Permissions{
|
||
|
KV: rwp,
|
||
|
},
|
||
|
}
|
||
|
return r.modRole(ctx, &authRoleAPIAction{
|
||
|
verb: "PUT",
|
||
|
name: rolename,
|
||
|
role: role,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
func (r *httpAuthRoleAPI) modRole(ctx context.Context, req *authRoleAPIAction) (*Role, error) {
|
||
|
resp, body, err := r.client.Do(ctx, req)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if err = assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
|
||
|
var sec authError
|
||
|
err = json.Unmarshal(body, &sec)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return nil, sec
|
||
|
}
|
||
|
var role Role
|
||
|
if err = json.Unmarshal(body, &role); err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &role, nil
|
||
|
}
|