Merge pull request #4966 from mitake/auth-role-grant

*: support granting key permission to role in v3 auth
This commit is contained in:
Xiang Li 2016-04-10 20:31:05 -07:00
commit 27480f9ea4
14 changed files with 581 additions and 44 deletions

View File

@ -10,6 +10,7 @@
It has these top-level messages:
User
Permission
Role
*/
package authpb
@ -29,6 +30,29 @@ var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type Permission_Type int32
const (
READ Permission_Type = 0
WRITE Permission_Type = 1
READWRITE Permission_Type = 2
)
var Permission_Type_name = map[int32]string{
0: "READ",
1: "WRITE",
2: "READWRITE",
}
var Permission_Type_value = map[string]int32{
"READ": 0,
"WRITE": 1,
"READWRITE": 2,
}
func (x Permission_Type) String() string {
return proto.EnumName(Permission_Type_name, int32(x))
}
// User is a single entry in the bucket authUsers
type User struct {
Name []byte `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
@ -40,9 +64,20 @@ func (m *User) Reset() { *m = User{} }
func (m *User) String() string { return proto.CompactTextString(m) }
func (*User) ProtoMessage() {}
// Permission is a single entity
type Permission struct {
Key []byte `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"`
PermType Permission_Type `protobuf:"varint,2,opt,name=permType,proto3,enum=authpb.Permission_Type" json:"permType,omitempty"`
}
func (m *Permission) Reset() { *m = Permission{} }
func (m *Permission) String() string { return proto.CompactTextString(m) }
func (*Permission) ProtoMessage() {}
// Role is a single entry in the bucket authRoles
type Role struct {
Name []byte `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Name []byte `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
KeyPermission []*Permission `protobuf:"bytes,2,rep,name=keyPermission" json:"keyPermission,omitempty"`
}
func (m *Role) Reset() { *m = Role{} }
@ -51,7 +86,9 @@ func (*Role) ProtoMessage() {}
func init() {
proto.RegisterType((*User)(nil), "authpb.User")
proto.RegisterType((*Permission)(nil), "authpb.Permission")
proto.RegisterType((*Role)(nil), "authpb.Role")
proto.RegisterEnum("authpb.Permission_Type", Permission_Type_name, Permission_Type_value)
}
func (m *User) Marshal() (data []byte, err error) {
size := m.Size()
@ -92,6 +129,37 @@ func (m *User) MarshalTo(data []byte) (int, error) {
return i, nil
}
func (m *Permission) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
n, err := m.MarshalTo(data)
if err != nil {
return nil, err
}
return data[:n], nil
}
func (m *Permission) MarshalTo(data []byte) (int, error) {
var i int
_ = i
var l int
_ = l
if m.Key != nil {
if len(m.Key) > 0 {
data[i] = 0xa
i++
i = encodeVarintAuth(data, i, uint64(len(m.Key)))
i += copy(data[i:], m.Key)
}
}
if m.PermType != 0 {
data[i] = 0x10
i++
i = encodeVarintAuth(data, i, uint64(m.PermType))
}
return i, nil
}
func (m *Role) Marshal() (data []byte, err error) {
size := m.Size()
data = make([]byte, size)
@ -109,12 +177,24 @@ func (m *Role) MarshalTo(data []byte) (int, error) {
_ = l
if m.Name != nil {
if len(m.Name) > 0 {
data[i] = 0x12
data[i] = 0xa
i++
i = encodeVarintAuth(data, i, uint64(len(m.Name)))
i += copy(data[i:], m.Name)
}
}
if len(m.KeyPermission) > 0 {
for _, msg := range m.KeyPermission {
data[i] = 0x12
i++
i = encodeVarintAuth(data, i, uint64(msg.Size()))
n, err := msg.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n
}
}
return i, nil
}
@ -166,6 +246,21 @@ func (m *User) Size() (n int) {
return n
}
func (m *Permission) Size() (n int) {
var l int
_ = l
if m.Key != nil {
l = len(m.Key)
if l > 0 {
n += 1 + l + sovAuth(uint64(l))
}
}
if m.PermType != 0 {
n += 1 + sovAuth(uint64(m.PermType))
}
return n
}
func (m *Role) Size() (n int) {
var l int
_ = l
@ -175,6 +270,12 @@ func (m *Role) Size() (n int) {
n += 1 + l + sovAuth(uint64(l))
}
}
if len(m.KeyPermission) > 0 {
for _, e := range m.KeyPermission {
l = e.Size()
n += 1 + l + sovAuth(uint64(l))
}
}
return n
}
@ -322,6 +423,106 @@ func (m *User) Unmarshal(data []byte) error {
}
return nil
}
func (m *Permission) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
for iNdEx < l {
preIndex := iNdEx
var wire uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAuth
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
wire |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
fieldNum := int32(wire >> 3)
wireType := int(wire & 0x7)
if wireType == 4 {
return fmt.Errorf("proto: Permission: wiretype end group for non-group")
}
if fieldNum <= 0 {
return fmt.Errorf("proto: Permission: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Key", wireType)
}
var byteLen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAuth
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
byteLen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if byteLen < 0 {
return ErrInvalidLengthAuth
}
postIndex := iNdEx + byteLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Key = append(m.Key[:0], data[iNdEx:postIndex]...)
if m.Key == nil {
m.Key = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field PermType", wireType)
}
m.PermType = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAuth
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.PermType |= (Permission_Type(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
default:
iNdEx = preIndex
skippy, err := skipAuth(data[iNdEx:])
if err != nil {
return err
}
if skippy < 0 {
return ErrInvalidLengthAuth
}
if (iNdEx + skippy) > l {
return io.ErrUnexpectedEOF
}
iNdEx += skippy
}
}
if iNdEx > l {
return io.ErrUnexpectedEOF
}
return nil
}
func (m *Role) Unmarshal(data []byte) error {
l := len(data)
iNdEx := 0
@ -351,7 +552,7 @@ func (m *Role) Unmarshal(data []byte) error {
return fmt.Errorf("proto: Role: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 2:
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
@ -382,6 +583,37 @@ func (m *Role) Unmarshal(data []byte) error {
m.Name = []byte{}
}
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field KeyPermission", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowAuth
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthAuth
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.KeyPermission = append(m.KeyPermission, &Permission{})
if err := m.KeyPermission[len(m.KeyPermission)-1].Unmarshal(data[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipAuth(data[iNdEx:])

View File

@ -16,7 +16,21 @@ message User {
int64 tombstone = 3;
}
// Permission is a single entity
message Permission {
bytes key = 1;
enum Type {
READ = 0;
WRITE = 1;
READWRITE = 2;
}
Type permType = 2;
}
// Role is a single entry in the bucket authRoles
message Role {
bytes name = 2;
bytes name = 1;
repeated Permission keyPermission = 2;
}

View File

@ -16,6 +16,7 @@ package auth
import (
"errors"
"strings"
"github.com/coreos/etcd/auth/authpb"
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
@ -36,6 +37,7 @@ var (
ErrUserAlreadyExist = errors.New("auth: user already exists")
ErrUserNotFound = errors.New("auth: user not found")
ErrRoleAlreadyExist = errors.New("auth: role already exists")
ErrRoleNotFound = errors.New("auth: role not found")
)
type AuthStore interface {
@ -56,6 +58,9 @@ type AuthStore interface {
// RoleAdd adds a new role
RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error)
// RoleGrant grants a permission to a role
RoleGrant(r *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantResponse, error)
}
type authStore struct {
@ -195,6 +200,56 @@ func (as *authStore) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse,
return &pb.AuthRoleAddResponse{}, nil
}
func (as *authStore) RoleGrant(r *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantResponse, error) {
tx := as.be.BatchTx()
tx.Lock()
defer tx.Unlock()
_, vs := tx.UnsafeRange(authRolesBucketName, []byte(r.Name), nil, 0)
if len(vs) != 1 {
return nil, ErrRoleNotFound
}
role := &authpb.Role{}
err := role.Unmarshal(vs[0])
if err != nil {
plog.Errorf("failed to unmarshal a role %s: %s", r.Name, err)
return nil, err
}
if !updateExistingPermission(role.KeyPermission, string(r.Perm.Key), r.Perm.PermType) {
newPerm := &authpb.Permission{
Key: []byte(r.Perm.Key),
PermType: r.Perm.PermType,
}
role.KeyPermission = append(role.KeyPermission, newPerm)
}
marshaledRole, merr := role.Marshal()
if merr != nil {
plog.Errorf("failed to marshal updated role %s: %s", r.Name, merr)
return nil, merr
}
tx.UnsafePut(authRolesBucketName, []byte(r.Name), marshaledRole)
plog.Noticef("role %s's permission of key %s is updated as %s", r.Name, r.Perm.Key, authpb.Permission_Type_name[int32(r.Perm.PermType)])
return &pb.AuthRoleGrantResponse{}, nil
}
func updateExistingPermission(perms []*authpb.Permission, key string, newPerm authpb.Permission_Type) bool {
for _, perm := range perms {
if strings.Compare(string(perm.Key), key) == 0 {
perm.PermType = newPerm
return true
}
}
return false
}
func NewAuthStore(be backend.Backend) *authStore {
tx := be.BatchTx()
tx.Lock()

View File

@ -15,6 +15,10 @@
package clientv3
import (
"fmt"
"strings"
"github.com/coreos/etcd/auth/authpb"
pb "github.com/coreos/etcd/etcdserver/etcdserverpb"
"golang.org/x/net/context"
"google.golang.org/grpc"
@ -26,6 +30,15 @@ type (
AuthUserDeleteResponse pb.AuthUserDeleteResponse
AuthUserChangePasswordResponse pb.AuthUserChangePasswordResponse
AuthRoleAddResponse pb.AuthRoleAddResponse
AuthRoleGrantResponse pb.AuthRoleGrantResponse
PermissionType authpb.Permission_Type
)
const (
PermRead = authpb.READ
PermWrite = authpb.WRITE
PermReadWrite = authpb.READWRITE
)
type Auth interface {
@ -41,8 +54,11 @@ type Auth interface {
// UserChangePassword changes a password of a user.
UserChangePassword(ctx context.Context, name string, password string) (*AuthUserChangePasswordResponse, error)
// RoleAdd adds a new user to an etcd cluster.
// RoleAdd adds a new role to an etcd cluster.
RoleAdd(ctx context.Context, name string) (*AuthRoleAddResponse, error)
// RoleGrant grants a permission to a role.
RoleGrant(ctx context.Context, name string, key string, permType PermissionType) (*AuthRoleGrantResponse, error)
}
type auth struct {
@ -85,3 +101,20 @@ func (auth *auth) RoleAdd(ctx context.Context, name string) (*AuthRoleAddRespons
resp, err := auth.remote.RoleAdd(ctx, &pb.AuthRoleAddRequest{Name: name})
return (*AuthRoleAddResponse)(resp), err
}
func (auth *auth) RoleGrant(ctx context.Context, name string, key string, permType PermissionType) (*AuthRoleGrantResponse, error) {
perm := &authpb.Permission{
Key: []byte(key),
PermType: authpb.Permission_Type(permType),
}
resp, err := auth.remote.RoleGrant(ctx, &pb.AuthRoleGrantRequest{Name: name, Perm: perm})
return (*AuthRoleGrantResponse)(resp), err
}
func StrToPermissionType(s string) (PermissionType, error) {
val, ok := authpb.Permission_Type_value[strings.ToUpper(s)]
if ok {
return PermissionType(val), nil
}
return PermissionType(-1), fmt.Errorf("invalid permission type: %s", s)
}

View File

@ -17,6 +17,7 @@ package command
import (
"fmt"
"github.com/coreos/etcd/clientv3"
"github.com/spf13/cobra"
"golang.org/x/net/context"
)
@ -29,6 +30,7 @@ func NewRoleCommand() *cobra.Command {
}
ac.AddCommand(newRoleAddCommand())
ac.AddCommand(newRoleGrantCommand())
return ac
}
@ -41,6 +43,14 @@ func newRoleAddCommand() *cobra.Command {
}
}
func newRoleGrantCommand() *cobra.Command {
return &cobra.Command{
Use: "grant <role name> <permission type> <key>",
Short: "grant a key to a role",
Run: roleGrantCommandFunc,
}
}
// roleAddCommandFunc executes the "role add" command.
func roleAddCommandFunc(cmd *cobra.Command, args []string) {
if len(args) != 1 {
@ -54,3 +64,22 @@ func roleAddCommandFunc(cmd *cobra.Command, args []string) {
fmt.Printf("Role %s created\n", args[0])
}
// roleGrantCommandFunc executes the "role grant" command.
func roleGrantCommandFunc(cmd *cobra.Command, args []string) {
if len(args) != 3 {
ExitWithError(ExitBadArgs, fmt.Errorf("role grant command requires role name, permission type, and key as its argument."))
}
perm, err := clientv3.StrToPermissionType(args[1])
if err != nil {
ExitWithError(ExitBadArgs, err)
}
_, err = mustClientFromCmd(cmd).Auth.RoleGrant(context.TODO(), args[0], args[2], perm)
if err != nil {
ExitWithError(ExitError, err)
}
fmt.Printf("Role %s updated\n", args[0])
}

View File

@ -70,8 +70,11 @@ func (as *AuthServer) RoleRevoke(ctx context.Context, r *pb.AuthRoleRevokeReques
}
func (as *AuthServer) RoleGrant(ctx context.Context, r *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantResponse, error) {
plog.Info("not implemented yet")
return nil, nil
resp, err := as.authenticator.RoleGrant(ctx, r)
if err != nil {
return nil, togRPCError(err)
}
return resp, nil
}
func (as *AuthServer) UserAdd(ctx context.Context, r *pb.AuthUserAddRequest) (*pb.AuthUserAddResponse, error) {

View File

@ -40,4 +40,5 @@ var (
ErrUserAlreadyExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: user name already exists")
ErrUserNotFound = grpc.Errorf(codes.FailedPrecondition, "etcdserver: user name not found")
ErrRoleAlreadyExist = grpc.Errorf(codes.FailedPrecondition, "etcdserver: role name already exists")
ErrRoleNotFound = grpc.Errorf(codes.FailedPrecondition, "etcdserver: role name not found")
)

View File

@ -43,6 +43,8 @@ func togRPCError(err error) error {
return rpctypes.ErrUserNotFound
case auth.ErrRoleAlreadyExist:
return rpctypes.ErrRoleAlreadyExist
case auth.ErrRoleNotFound:
return rpctypes.ErrRoleNotFound
default:
return grpc.Errorf(codes.Internal, err.Error())
}

View File

@ -58,6 +58,7 @@ type applierV3 interface {
UserDelete(ua *pb.AuthUserDeleteRequest) (*pb.AuthUserDeleteResponse, error)
UserChangePassword(ua *pb.AuthUserChangePasswordRequest) (*pb.AuthUserChangePasswordResponse, error)
RoleAdd(ua *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error)
RoleGrant(ua *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantResponse, error)
}
type applierV3backend struct {
@ -93,6 +94,8 @@ func (s *EtcdServer) applyV3Request(r *pb.InternalRaftRequest) *applyResult {
ar.resp, ar.err = s.applyV3.UserChangePassword(r.AuthUserChangePassword)
case r.AuthRoleAdd != nil:
ar.resp, ar.err = s.applyV3.RoleAdd(r.AuthRoleAdd)
case r.AuthRoleGrant != nil:
ar.resp, ar.err = s.applyV3.RoleGrant(r.AuthRoleGrant)
default:
panic("not implemented")
}
@ -496,6 +499,10 @@ func (a *applierV3backend) RoleAdd(r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddRes
return a.s.AuthStore().RoleAdd(r)
}
func (a *applierV3backend) RoleGrant(r *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantResponse, error) {
return a.s.AuthStore().RoleGrant(r)
}
type quotaApplierV3 struct {
applierV3
q Quota

View File

@ -36,7 +36,8 @@ type InternalRaftRequest struct {
AuthUserDelete *AuthUserDeleteRequest `protobuf:"bytes,12,opt,name=auth_user_delete" json:"auth_user_delete,omitempty"`
AuthUserChangePassword *AuthUserChangePasswordRequest `protobuf:"bytes,13,opt,name=auth_user_change_password" json:"auth_user_change_password,omitempty"`
AuthRoleAdd *AuthRoleAddRequest `protobuf:"bytes,14,opt,name=auth_role_add" json:"auth_role_add,omitempty"`
Alarm *AlarmRequest `protobuf:"bytes,15,opt,name=alarm" json:"alarm,omitempty"`
AuthRoleGrant *AuthRoleGrantRequest `protobuf:"bytes,15,opt,name=auth_role_grant" json:"auth_role_grant,omitempty"`
Alarm *AlarmRequest `protobuf:"bytes,16,opt,name=alarm" json:"alarm,omitempty"`
}
func (m *InternalRaftRequest) Reset() { *m = InternalRaftRequest{} }
@ -204,16 +205,28 @@ func (m *InternalRaftRequest) MarshalTo(data []byte) (int, error) {
}
i += n13
}
if m.Alarm != nil {
if m.AuthRoleGrant != nil {
data[i] = 0x7a
i++
i = encodeVarintRaftInternal(data, i, uint64(m.Alarm.Size()))
n14, err := m.Alarm.MarshalTo(data[i:])
i = encodeVarintRaftInternal(data, i, uint64(m.AuthRoleGrant.Size()))
n14, err := m.AuthRoleGrant.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n14
}
if m.Alarm != nil {
data[i] = 0x82
i++
data[i] = 0x1
i++
i = encodeVarintRaftInternal(data, i, uint64(m.Alarm.Size()))
n15, err := m.Alarm.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n15
}
return i, nil
}
@ -320,9 +333,13 @@ func (m *InternalRaftRequest) Size() (n int) {
l = m.AuthRoleAdd.Size()
n += 1 + l + sovRaftInternal(uint64(l))
}
if m.AuthRoleGrant != nil {
l = m.AuthRoleGrant.Size()
n += 1 + l + sovRaftInternal(uint64(l))
}
if m.Alarm != nil {
l = m.Alarm.Size()
n += 1 + l + sovRaftInternal(uint64(l))
n += 2 + l + sovRaftInternal(uint64(l))
}
return n
}
@ -824,6 +841,39 @@ func (m *InternalRaftRequest) Unmarshal(data []byte) error {
}
iNdEx = postIndex
case 15:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field AuthRoleGrant", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthRaftInternal
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.AuthRoleGrant == nil {
m.AuthRoleGrant = &AuthRoleGrantRequest{}
}
if err := m.AuthRoleGrant.Unmarshal(data[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
case 16:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Alarm", wireType)
}

View File

@ -30,8 +30,9 @@ message InternalRaftRequest {
AuthUserDeleteRequest auth_user_delete = 12;
AuthUserChangePasswordRequest auth_user_change_password = 13;
AuthRoleAddRequest auth_role_add = 14;
AuthRoleGrantRequest auth_role_grant = 15;
AlarmRequest alarm = 15;
AlarmRequest alarm = 16;
}
message EmptyResponse {

View File

@ -11,14 +11,17 @@ import (
math "math"
context "golang.org/x/net/context"
authpb "github.com/coreos/etcd/auth/authpb"
grpc "google.golang.org/grpc"
io "io"
)
import storagepb "github.com/coreos/etcd/storage/storagepb"
import io "io"
import (
context "golang.org/x/net/context"
grpc "google.golang.org/grpc"
)
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
@ -1362,12 +1365,21 @@ func (m *AuthRoleDeleteRequest) String() string { return proto.CompactTextString
func (*AuthRoleDeleteRequest) ProtoMessage() {}
type AuthRoleGrantRequest struct {
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Perm *authpb.Permission `protobuf:"bytes,2,opt,name=perm" json:"perm,omitempty"`
}
func (m *AuthRoleGrantRequest) Reset() { *m = AuthRoleGrantRequest{} }
func (m *AuthRoleGrantRequest) String() string { return proto.CompactTextString(m) }
func (*AuthRoleGrantRequest) ProtoMessage() {}
func (m *AuthRoleGrantRequest) GetPerm() *authpb.Permission {
if m != nil {
return m.Perm
}
return nil
}
type AuthRoleRevokeRequest struct {
}
@ -4724,6 +4736,22 @@ func (m *AuthRoleGrantRequest) MarshalTo(data []byte) (int, error) {
_ = i
var l int
_ = l
if len(m.Name) > 0 {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(len(m.Name)))
i += copy(data[i:], m.Name)
}
if m.Perm != nil {
data[i] = 0x12
i++
i = encodeVarintRpc(data, i, uint64(m.Perm.Size()))
n31, err := m.Perm.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n31
}
return i, nil
}
@ -4764,11 +4792,11 @@ func (m *AuthEnableResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n31, err := m.Header.MarshalTo(data[i:])
n32, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n31
i += n32
}
return i, nil
}
@ -4792,11 +4820,11 @@ func (m *AuthDisableResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n32, err := m.Header.MarshalTo(data[i:])
n33, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n32
i += n33
}
return i, nil
}
@ -4820,11 +4848,11 @@ func (m *AuthenticateResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n33, err := m.Header.MarshalTo(data[i:])
n34, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n33
i += n34
}
return i, nil
}
@ -4848,11 +4876,11 @@ func (m *AuthUserAddResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n34, err := m.Header.MarshalTo(data[i:])
n35, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n34
i += n35
}
return i, nil
}
@ -4876,11 +4904,11 @@ func (m *AuthUserGetResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n35, err := m.Header.MarshalTo(data[i:])
n36, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n35
i += n36
}
return i, nil
}
@ -4904,11 +4932,11 @@ func (m *AuthUserDeleteResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n36, err := m.Header.MarshalTo(data[i:])
n37, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n36
i += n37
}
return i, nil
}
@ -4932,11 +4960,11 @@ func (m *AuthUserChangePasswordResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n37, err := m.Header.MarshalTo(data[i:])
n38, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n37
i += n38
}
return i, nil
}
@ -4960,11 +4988,11 @@ func (m *AuthUserGrantResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n38, err := m.Header.MarshalTo(data[i:])
n39, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n38
i += n39
}
return i, nil
}
@ -4988,11 +5016,11 @@ func (m *AuthUserRevokeResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n39, err := m.Header.MarshalTo(data[i:])
n40, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n39
i += n40
}
return i, nil
}
@ -5016,11 +5044,11 @@ func (m *AuthRoleAddResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n40, err := m.Header.MarshalTo(data[i:])
n41, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n40
i += n41
}
return i, nil
}
@ -5044,11 +5072,11 @@ func (m *AuthRoleGetResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n41, err := m.Header.MarshalTo(data[i:])
n42, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n41
i += n42
}
return i, nil
}
@ -5072,11 +5100,11 @@ func (m *AuthRoleDeleteResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n42, err := m.Header.MarshalTo(data[i:])
n43, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n42
i += n43
}
return i, nil
}
@ -5100,11 +5128,11 @@ func (m *AuthRoleGrantResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n43, err := m.Header.MarshalTo(data[i:])
n44, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n43
i += n44
}
return i, nil
}
@ -5128,11 +5156,11 @@ func (m *AuthRoleRevokeResponse) MarshalTo(data []byte) (int, error) {
data[i] = 0xa
i++
i = encodeVarintRpc(data, i, uint64(m.Header.Size()))
n44, err := m.Header.MarshalTo(data[i:])
n45, err := m.Header.MarshalTo(data[i:])
if err != nil {
return 0, err
}
i += n44
i += n45
}
return i, nil
}
@ -5962,6 +5990,14 @@ func (m *AuthRoleDeleteRequest) Size() (n int) {
func (m *AuthRoleGrantRequest) Size() (n int) {
var l int
_ = l
l = len(m.Name)
if l > 0 {
n += 1 + l + sovRpc(uint64(l))
}
if m.Perm != nil {
l = m.Perm.Size()
n += 1 + l + sovRpc(uint64(l))
}
return n
}
@ -11503,6 +11539,68 @@ func (m *AuthRoleGrantRequest) Unmarshal(data []byte) error {
return fmt.Errorf("proto: AuthRoleGrantRequest: illegal tag %d (wire type %d)", fieldNum, wire)
}
switch fieldNum {
case 1:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
}
var stringLen uint64
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRpc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
stringLen |= (uint64(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
intStringLen := int(stringLen)
if intStringLen < 0 {
return ErrInvalidLengthRpc
}
postIndex := iNdEx + intStringLen
if postIndex > l {
return io.ErrUnexpectedEOF
}
m.Name = string(data[iNdEx:postIndex])
iNdEx = postIndex
case 2:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Perm", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRpc
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
msglen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthRpc
}
postIndex := iNdEx + msglen
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.Perm == nil {
m.Perm = &authpb.Permission{}
}
if err := m.Perm.Unmarshal(data[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRpc(data[iNdEx:])

View File

@ -3,6 +3,7 @@ package etcdserverpb;
import "gogoproto/gogo.proto";
import "etcd/storage/storagepb/kv.proto";
import "etcd/auth/authpb/auth.proto";
option (gogoproto.marshaler_all) = true;
option (gogoproto.unmarshaler_all) = true;
@ -525,6 +526,8 @@ message AuthRoleDeleteRequest {
}
message AuthRoleGrantRequest {
string name = 1;
authpb.Permission perm = 2;
}
message AuthRoleRevokeRequest {

View File

@ -57,6 +57,7 @@ type Authenticator interface {
UserDelete(ctx context.Context, r *pb.AuthUserDeleteRequest) (*pb.AuthUserDeleteResponse, error)
UserChangePassword(ctx context.Context, r *pb.AuthUserChangePasswordRequest) (*pb.AuthUserChangePasswordResponse, error)
RoleAdd(ctx context.Context, r *pb.AuthRoleAddRequest) (*pb.AuthRoleAddResponse, error)
RoleGrant(ctx context.Context, r *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantResponse, error)
}
func (s *EtcdServer) Range(ctx context.Context, r *pb.RangeRequest) (*pb.RangeResponse, error) {
@ -242,6 +243,14 @@ func (s *EtcdServer) RoleAdd(ctx context.Context, r *pb.AuthRoleAddRequest) (*pb
return result.resp.(*pb.AuthRoleAddResponse), result.err
}
func (s *EtcdServer) RoleGrant(ctx context.Context, r *pb.AuthRoleGrantRequest) (*pb.AuthRoleGrantResponse, error) {
result, err := s.processInternalRaftRequest(ctx, pb.InternalRaftRequest{AuthRoleGrant: r})
if err != nil {
return nil, err
}
return result.resp.(*pb.AuthRoleGrantResponse), result.err
}
func (s *EtcdServer) processInternalRaftRequest(ctx context.Context, r pb.InternalRaftRequest) (*applyResult, error) {
r.ID = s.reqIDGen.Next()