...

Source file src/go.etcd.io/etcd/client/v2/auth_role.go

Documentation: go.etcd.io/etcd/client/v2

     1  // Copyright 2015 The etcd Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package client
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"encoding/json"
    21  	"net/http"
    22  	"net/url"
    23  )
    24  
    25  type Role struct {
    26  	Role        string       `json:"role"`
    27  	Permissions Permissions  `json:"permissions"`
    28  	Grant       *Permissions `json:"grant,omitempty"`
    29  	Revoke      *Permissions `json:"revoke,omitempty"`
    30  }
    31  
    32  type Permissions struct {
    33  	KV rwPermission `json:"kv"`
    34  }
    35  
    36  type rwPermission struct {
    37  	Read  []string `json:"read"`
    38  	Write []string `json:"write"`
    39  }
    40  
    41  type PermissionType int
    42  
    43  const (
    44  	ReadPermission PermissionType = iota
    45  	WritePermission
    46  	ReadWritePermission
    47  )
    48  
    49  // NewAuthRoleAPI constructs a new AuthRoleAPI that uses HTTP to
    50  // interact with etcd's role creation and modification features.
    51  func NewAuthRoleAPI(c Client) AuthRoleAPI {
    52  	return &httpAuthRoleAPI{
    53  		client: c,
    54  	}
    55  }
    56  
    57  type AuthRoleAPI interface {
    58  	// AddRole adds a role.
    59  	AddRole(ctx context.Context, role string) error
    60  
    61  	// RemoveRole removes a role.
    62  	RemoveRole(ctx context.Context, role string) error
    63  
    64  	// GetRole retrieves role details.
    65  	GetRole(ctx context.Context, role string) (*Role, error)
    66  
    67  	// GrantRoleKV grants a role some permission prefixes for the KV store.
    68  	GrantRoleKV(ctx context.Context, role string, prefixes []string, permType PermissionType) (*Role, error)
    69  
    70  	// RevokeRoleKV revokes some permission prefixes for a role on the KV store.
    71  	RevokeRoleKV(ctx context.Context, role string, prefixes []string, permType PermissionType) (*Role, error)
    72  
    73  	// ListRoles lists roles.
    74  	ListRoles(ctx context.Context) ([]string, error)
    75  }
    76  
    77  type httpAuthRoleAPI struct {
    78  	client httpClient
    79  }
    80  
    81  type authRoleAPIAction struct {
    82  	verb string
    83  	name string
    84  	role *Role
    85  }
    86  
    87  type authRoleAPIList struct{}
    88  
    89  func (list *authRoleAPIList) HTTPRequest(ep url.URL) *http.Request {
    90  	u := v2AuthURL(ep, "roles", "")
    91  	req, _ := http.NewRequest("GET", u.String(), nil)
    92  	req.Header.Set("Content-Type", "application/json")
    93  	return req
    94  }
    95  
    96  func (l *authRoleAPIAction) HTTPRequest(ep url.URL) *http.Request {
    97  	u := v2AuthURL(ep, "roles", l.name)
    98  	if l.role == nil {
    99  		req, _ := http.NewRequest(l.verb, u.String(), nil)
   100  		return req
   101  	}
   102  	b, err := json.Marshal(l.role)
   103  	if err != nil {
   104  		panic(err)
   105  	}
   106  	body := bytes.NewReader(b)
   107  	req, _ := http.NewRequest(l.verb, u.String(), body)
   108  	req.Header.Set("Content-Type", "application/json")
   109  	return req
   110  }
   111  
   112  func (r *httpAuthRoleAPI) ListRoles(ctx context.Context) ([]string, error) {
   113  	resp, body, err := r.client.Do(ctx, &authRoleAPIList{})
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  	if err = assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
   118  		return nil, err
   119  	}
   120  	var roleList struct {
   121  		Roles []Role `json:"roles"`
   122  	}
   123  	if err = json.Unmarshal(body, &roleList); err != nil {
   124  		return nil, err
   125  	}
   126  	ret := make([]string, 0, len(roleList.Roles))
   127  	for _, r := range roleList.Roles {
   128  		ret = append(ret, r.Role)
   129  	}
   130  	return ret, nil
   131  }
   132  
   133  func (r *httpAuthRoleAPI) AddRole(ctx context.Context, rolename string) error {
   134  	role := &Role{
   135  		Role: rolename,
   136  	}
   137  	return r.addRemoveRole(ctx, &authRoleAPIAction{
   138  		verb: "PUT",
   139  		name: rolename,
   140  		role: role,
   141  	})
   142  }
   143  
   144  func (r *httpAuthRoleAPI) RemoveRole(ctx context.Context, rolename string) error {
   145  	return r.addRemoveRole(ctx, &authRoleAPIAction{
   146  		verb: "DELETE",
   147  		name: rolename,
   148  	})
   149  }
   150  
   151  func (r *httpAuthRoleAPI) addRemoveRole(ctx context.Context, req *authRoleAPIAction) error {
   152  	resp, body, err := r.client.Do(ctx, req)
   153  	if err != nil {
   154  		return err
   155  	}
   156  	if err := assertStatusCode(resp.StatusCode, http.StatusOK, http.StatusCreated); err != nil {
   157  		var sec authError
   158  		err := json.Unmarshal(body, &sec)
   159  		if err != nil {
   160  			return err
   161  		}
   162  		return sec
   163  	}
   164  	return nil
   165  }
   166  
   167  func (r *httpAuthRoleAPI) GetRole(ctx context.Context, rolename string) (*Role, error) {
   168  	return r.modRole(ctx, &authRoleAPIAction{
   169  		verb: "GET",
   170  		name: rolename,
   171  	})
   172  }
   173  
   174  func buildRWPermission(prefixes []string, permType PermissionType) rwPermission {
   175  	var out rwPermission
   176  	switch permType {
   177  	case ReadPermission:
   178  		out.Read = prefixes
   179  	case WritePermission:
   180  		out.Write = prefixes
   181  	case ReadWritePermission:
   182  		out.Read = prefixes
   183  		out.Write = prefixes
   184  	}
   185  	return out
   186  }
   187  
   188  func (r *httpAuthRoleAPI) GrantRoleKV(ctx context.Context, rolename string, prefixes []string, permType PermissionType) (*Role, error) {
   189  	rwp := buildRWPermission(prefixes, permType)
   190  	role := &Role{
   191  		Role: rolename,
   192  		Grant: &Permissions{
   193  			KV: rwp,
   194  		},
   195  	}
   196  	return r.modRole(ctx, &authRoleAPIAction{
   197  		verb: "PUT",
   198  		name: rolename,
   199  		role: role,
   200  	})
   201  }
   202  
   203  func (r *httpAuthRoleAPI) RevokeRoleKV(ctx context.Context, rolename string, prefixes []string, permType PermissionType) (*Role, error) {
   204  	rwp := buildRWPermission(prefixes, permType)
   205  	role := &Role{
   206  		Role: rolename,
   207  		Revoke: &Permissions{
   208  			KV: rwp,
   209  		},
   210  	}
   211  	return r.modRole(ctx, &authRoleAPIAction{
   212  		verb: "PUT",
   213  		name: rolename,
   214  		role: role,
   215  	})
   216  }
   217  
   218  func (r *httpAuthRoleAPI) modRole(ctx context.Context, req *authRoleAPIAction) (*Role, error) {
   219  	resp, body, err := r.client.Do(ctx, req)
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  	if err = assertStatusCode(resp.StatusCode, http.StatusOK); err != nil {
   224  		var sec authError
   225  		err = json.Unmarshal(body, &sec)
   226  		if err != nil {
   227  			return nil, err
   228  		}
   229  		return nil, sec
   230  	}
   231  	var role Role
   232  	if err = json.Unmarshal(body, &role); err != nil {
   233  		return nil, err
   234  	}
   235  	return &role, nil
   236  }
   237  

View as plain text