From 2c17852a8af8ea8fda4f56420a10b29b4ecc07ac Mon Sep 17 00:00:00 2001 From: Fabian Seidl <fabian.b.seidl@stud.h-da.de> Date: Mon, 2 May 2022 06:32:51 +0000 Subject: [PATCH] Implement data persisting for user management See merge request danet/gosdn!287 Co-authored-by: Andre Sterba <andre.sterba@stud.h-da.de> Co-authored-by: Malte Bauch <malte.bauch@tbnet.works> --- api/go/gosdn/rbac/rbac.pb.go | 1898 ++++++++++++++--- api/go/gosdn/rbac/rbac.pb.gw.go | 577 +++++ api/go/gosdn/rbac/rbac_grpc.pb.go | 282 ++- api/openapiv2/gosdn_northbound.swagger.json | 447 +++- api/proto/buf.lock | 2 +- api/proto/gosdn/rbac/rbac.proto | 158 +- cli/adapter/PndAdapter.go | 64 +- cli/adapter/PndAdapter_test.go | 23 +- cli/cmd/changeCommit.go | 2 +- cli/cmd/changeConfirm.go | 2 +- cli/cmd/changeList.go | 4 +- cli/cmd/deviceCreate.go | 2 +- cli/cmd/deviceDelete.go | 1 + cli/cmd/deviceGet.go | 1 + cli/cmd/deviceList.go | 4 +- cli/cmd/deviceRemove.go | 2 +- cli/cmd/deviceSet.go | 1 + cli/cmd/deviceShow.go | 2 +- cli/cmd/init.go | 13 +- cli/cmd/list.go | 4 +- cli/cmd/login.go | 33 +- cli/cmd/logout.go | 13 +- cli/cmd/pndCreate.go | 2 +- cli/cmd/pndGet.go | 2 +- cli/cmd/pndList.go | 3 +- cli/cmd/pndRemove.go | 2 +- cli/cmd/pndUse.go | 2 +- cli/cmd/prompt.go | 4 +- cli/cmd/userCreate.go | 85 + cli/cmd/userDelete.go | 67 + cli/cmd/userGet.go | 66 + cli/cmd/userGetAll.go | 66 + cli/cmd/userUpdate.go | 87 + cli/cmd/utils.go | 16 +- controller/api/apiIntegration_test.go | 9 +- controller/api/api_test.go | 25 +- controller/api/grpc.go | 255 ++- controller/api/initialise_test.go | 8 +- controller/controller.go | 15 +- controller/interfaces/rbac/rbacService.go | 40 + controller/interfaces/rbac/role.go | 12 + controller/interfaces/rbac/roleStore.go | 12 + controller/interfaces/rbac/user.go | 13 + controller/interfaces/rbac/userStore.go | 14 + controller/northbound/server/auth.go | 337 ++- .../northbound/server/auth_interceptor.go | 130 +- controller/northbound/server/auth_test.go | 781 ++++++- controller/northbound/server/nbi.go | 7 +- controller/northbound/server/pnd_test.go | 11 + controller/nucleus/databaseSbiStore.go | 27 - controller/rbac/databaseRoleStore.go | 179 ++ controller/rbac/databaseUserStore.go | 179 ++ controller/rbac/jwtManager.go | 2 +- controller/rbac/jwtManager_test.go | 110 + controller/rbac/memoryRoleStore.go | 110 + controller/rbac/memoryUserStore.go | 110 + controller/rbac/rbacService.go | 151 ++ controller/rbac/role.go | 96 + controller/rbac/roleStore.go | 31 + controller/rbac/user.go | 110 +- controller/rbac/userStore.go | 31 + controller/store/genericStore.go | 126 +- controller/store/oldGenericStore.go | 89 + controller/store/query.go | 9 + controller/store/utils.go | 6 - go.mod | 2 +- 66 files changed, 6218 insertions(+), 756 deletions(-) create mode 100644 cli/cmd/userCreate.go create mode 100644 cli/cmd/userDelete.go create mode 100644 cli/cmd/userGet.go create mode 100644 cli/cmd/userGetAll.go create mode 100644 cli/cmd/userUpdate.go create mode 100644 controller/interfaces/rbac/rbacService.go create mode 100644 controller/interfaces/rbac/role.go create mode 100644 controller/interfaces/rbac/roleStore.go create mode 100644 controller/interfaces/rbac/user.go create mode 100644 controller/interfaces/rbac/userStore.go create mode 100644 controller/rbac/databaseRoleStore.go create mode 100644 controller/rbac/databaseUserStore.go create mode 100644 controller/rbac/jwtManager_test.go create mode 100644 controller/rbac/memoryRoleStore.go create mode 100644 controller/rbac/memoryUserStore.go create mode 100644 controller/rbac/rbacService.go create mode 100644 controller/rbac/role.go create mode 100644 controller/rbac/roleStore.go create mode 100644 controller/rbac/userStore.go create mode 100644 controller/store/oldGenericStore.go create mode 100644 controller/store/query.go diff --git a/api/go/gosdn/rbac/rbac.pb.go b/api/go/gosdn/rbac/rbac.pb.go index 72064841b..1752a165c 100644 --- a/api/go/gosdn/rbac/rbac.pb.go +++ b/api/go/gosdn/rbac/rbac.pb.go @@ -72,56 +72,156 @@ func (Status) EnumDescriptor() ([]byte, []int) { return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{0} } -// TODO: add additional data to user enum -type User int32 +type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields -const ( - User_USER_UNSPECIFIED User = 0 - User_USER_NAME User = 1 - User_USER_PWD User = 2 // ... -) + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Roles map[string]string `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // Key = pnd uuid, value= role name + Password string `protobuf:"bytes,4,opt,name=password,proto3" json:"password,omitempty"` + Token string `protobuf:"bytes,5,opt,name=token,proto3" json:"token,omitempty"` +} -// Enum value maps for User. -var ( - User_name = map[int32]string{ - 0: "USER_UNSPECIFIED", - 1: "USER_NAME", - 2: "USER_PWD", +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } - User_value = map[string]int32{ - "USER_UNSPECIFIED": 0, - "USER_NAME": 1, - "USER_PWD": 2, +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms } -) + return mi.MessageOf(x) +} -func (x User) Enum() *User { - p := new(User) - *p = x - return p +// Deprecated: Use User.ProtoReflect.Descriptor instead. +func (*User) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{0} } -func (x User) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +func (x *User) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *User) GetName() string { + if x != nil { + return x.Name + } + return "" } -func (User) Descriptor() protoreflect.EnumDescriptor { - return file_gosdn_rbac_rbac_proto_enumTypes[1].Descriptor() +func (x *User) GetRoles() map[string]string { + if x != nil { + return x.Roles + } + return nil } -func (User) Type() protoreflect.EnumType { - return &file_gosdn_rbac_rbac_proto_enumTypes[1] +func (x *User) GetPassword() string { + if x != nil { + return x.Password + } + return "" } -func (x User) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) +func (x *User) GetToken() string { + if x != nil { + return x.Token + } + return "" +} + +type Role struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` + Permissions []string `protobuf:"bytes,4,rep,name=permissions,proto3" json:"permissions,omitempty"` +} + +func (x *Role) Reset() { + *x = Role{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Role) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Role) ProtoMessage() {} + +func (x *Role) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -// Deprecated: Use User.Descriptor instead. -func (User) EnumDescriptor() ([]byte, []int) { +// Deprecated: Use Role.ProtoReflect.Descriptor instead. +func (*Role) Descriptor() ([]byte, []int) { return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{1} } +func (x *Role) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Role) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Role) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +func (x *Role) GetPermissions() []string { + if x != nil { + return x.Permissions + } + return nil +} + // Login type LoginRequest struct { state protoimpl.MessageState @@ -136,7 +236,7 @@ type LoginRequest struct { func (x *LoginRequest) Reset() { *x = LoginRequest{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[0] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -149,7 +249,7 @@ func (x *LoginRequest) String() string { func (*LoginRequest) ProtoMessage() {} func (x *LoginRequest) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[0] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -162,7 +262,7 @@ func (x *LoginRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginRequest.ProtoReflect.Descriptor instead. func (*LoginRequest) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{0} + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{2} } func (x *LoginRequest) GetTimestamp() int64 { @@ -199,7 +299,7 @@ type LoginResponse struct { func (x *LoginResponse) Reset() { *x = LoginResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[1] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -212,7 +312,7 @@ func (x *LoginResponse) String() string { func (*LoginResponse) ProtoMessage() {} func (x *LoginResponse) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[1] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -225,7 +325,7 @@ func (x *LoginResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LoginResponse.ProtoReflect.Descriptor instead. func (*LoginResponse) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{1} + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{3} } func (x *LoginResponse) GetTimestamp() int64 { @@ -262,7 +362,7 @@ type LogoutRequest struct { func (x *LogoutRequest) Reset() { *x = LogoutRequest{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[2] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -275,7 +375,7 @@ func (x *LogoutRequest) String() string { func (*LogoutRequest) ProtoMessage() {} func (x *LogoutRequest) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[2] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -288,7 +388,7 @@ func (x *LogoutRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LogoutRequest.ProtoReflect.Descriptor instead. func (*LogoutRequest) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{2} + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{4} } func (x *LogoutRequest) GetTimestamp() int64 { @@ -317,7 +417,7 @@ type LogoutResponse struct { func (x *LogoutResponse) Reset() { *x = LogoutResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[3] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -330,7 +430,7 @@ func (x *LogoutResponse) String() string { func (*LogoutResponse) ProtoMessage() {} func (x *LogoutResponse) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[3] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -343,7 +443,7 @@ func (x *LogoutResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use LogoutResponse.ProtoReflect.Descriptor instead. func (*LogoutResponse) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{3} + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{5} } func (x *LogoutResponse) GetTimestamp() int64 { @@ -366,14 +466,14 @@ type CreateUsersRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - User []User `protobuf:"varint,2,rep,packed,name=user,proto3,enum=gosdn.rbac.User" json:"user,omitempty"` + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + User []*User `protobuf:"bytes,2,rep,name=user,proto3" json:"user,omitempty"` } func (x *CreateUsersRequest) Reset() { *x = CreateUsersRequest{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[4] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -386,7 +486,7 @@ func (x *CreateUsersRequest) String() string { func (*CreateUsersRequest) ProtoMessage() {} func (x *CreateUsersRequest) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[4] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -399,7 +499,7 @@ func (x *CreateUsersRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateUsersRequest.ProtoReflect.Descriptor instead. func (*CreateUsersRequest) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{4} + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{6} } func (x *CreateUsersRequest) GetTimestamp() int64 { @@ -409,7 +509,7 @@ func (x *CreateUsersRequest) GetTimestamp() int64 { return 0 } -func (x *CreateUsersRequest) GetUser() []User { +func (x *CreateUsersRequest) GetUser() []*User { if x != nil { return x.User } @@ -428,7 +528,7 @@ type CreateUsersResponse struct { func (x *CreateUsersResponse) Reset() { *x = CreateUsersResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[5] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -441,7 +541,7 @@ func (x *CreateUsersResponse) String() string { func (*CreateUsersResponse) ProtoMessage() {} func (x *CreateUsersResponse) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[5] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -454,7 +554,7 @@ func (x *CreateUsersResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CreateUsersResponse.ProtoReflect.Descriptor instead. func (*CreateUsersResponse) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{5} + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{7} } func (x *CreateUsersResponse) GetTimestamp() int64 { @@ -471,33 +571,33 @@ func (x *CreateUsersResponse) GetStatus() Status { return Status_STATUS_UNSPECIFIED } -// GetUsers -type GetUsersRequest struct { +// GetUser +type GetUserRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Token string `protobuf:"bytes,2,opt,name=token,proto3" json:"token,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` } -func (x *GetUsersRequest) Reset() { - *x = GetUsersRequest{} +func (x *GetUserRequest) Reset() { + *x = GetUserRequest{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[6] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *GetUsersRequest) String() string { +func (x *GetUserRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetUsersRequest) ProtoMessage() {} +func (*GetUserRequest) ProtoMessage() {} -func (x *GetUsersRequest) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[6] +func (x *GetUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -508,52 +608,52 @@ func (x *GetUsersRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetUsersRequest.ProtoReflect.Descriptor instead. -func (*GetUsersRequest) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{6} +// Deprecated: Use GetUserRequest.ProtoReflect.Descriptor instead. +func (*GetUserRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{8} } -func (x *GetUsersRequest) GetTimestamp() int64 { +func (x *GetUserRequest) GetTimestamp() int64 { if x != nil { return x.Timestamp } return 0 } -func (x *GetUsersRequest) GetToken() string { +func (x *GetUserRequest) GetName() string { if x != nil { - return x.Token + return x.Name } return "" } -type GetUsersResponse struct { +type GetUserResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` - User []User `protobuf:"varint,3,rep,packed,name=user,proto3,enum=gosdn.rbac.User" json:"user,omitempty"` + User *User `protobuf:"bytes,3,opt,name=user,proto3" json:"user,omitempty"` } -func (x *GetUsersResponse) Reset() { - *x = GetUsersResponse{} +func (x *GetUserResponse) Reset() { + *x = GetUserResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[7] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *GetUsersResponse) String() string { +func (x *GetUserResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*GetUsersResponse) ProtoMessage() {} +func (*GetUserResponse) ProtoMessage() {} -func (x *GetUsersResponse) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[7] +func (x *GetUserResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -564,59 +664,58 @@ func (x *GetUsersResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use GetUsersResponse.ProtoReflect.Descriptor instead. -func (*GetUsersResponse) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{7} +// Deprecated: Use GetUserResponse.ProtoReflect.Descriptor instead. +func (*GetUserResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{9} } -func (x *GetUsersResponse) GetTimestamp() int64 { +func (x *GetUserResponse) GetTimestamp() int64 { if x != nil { return x.Timestamp } return 0 } -func (x *GetUsersResponse) GetStatus() Status { +func (x *GetUserResponse) GetStatus() Status { if x != nil { return x.Status } return Status_STATUS_UNSPECIFIED } -func (x *GetUsersResponse) GetUser() []User { +func (x *GetUserResponse) GetUser() *User { if x != nil { return x.User } return nil } -// UpdateUsers -type UpdateUsersRequest struct { +// GetUsers +type GetUsersRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - User []User `protobuf:"varint,2,rep,packed,name=user,proto3,enum=gosdn.rbac.User" json:"user,omitempty"` + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` } -func (x *UpdateUsersRequest) Reset() { - *x = UpdateUsersRequest{} +func (x *GetUsersRequest) Reset() { + *x = GetUsersRequest{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[8] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *UpdateUsersRequest) String() string { +func (x *GetUsersRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpdateUsersRequest) ProtoMessage() {} +func (*GetUsersRequest) ProtoMessage() {} -func (x *UpdateUsersRequest) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[8] +func (x *GetUsersRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -627,51 +726,45 @@ func (x *UpdateUsersRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpdateUsersRequest.ProtoReflect.Descriptor instead. -func (*UpdateUsersRequest) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{8} +// Deprecated: Use GetUsersRequest.ProtoReflect.Descriptor instead. +func (*GetUsersRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{10} } -func (x *UpdateUsersRequest) GetTimestamp() int64 { +func (x *GetUsersRequest) GetTimestamp() int64 { if x != nil { return x.Timestamp } return 0 } -func (x *UpdateUsersRequest) GetUser() []User { - if x != nil { - return x.User - } - return nil -} - -type UpdateUsersResponse struct { +type GetUsersResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` + User []*User `protobuf:"bytes,3,rep,name=user,proto3" json:"user,omitempty"` } -func (x *UpdateUsersResponse) Reset() { - *x = UpdateUsersResponse{} +func (x *GetUsersResponse) Reset() { + *x = GetUsersResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[9] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *UpdateUsersResponse) String() string { +func (x *GetUsersResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*UpdateUsersResponse) ProtoMessage() {} +func (*GetUsersResponse) ProtoMessage() {} -func (x *UpdateUsersResponse) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[9] +func (x *GetUsersResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -682,52 +775,59 @@ func (x *UpdateUsersResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use UpdateUsersResponse.ProtoReflect.Descriptor instead. -func (*UpdateUsersResponse) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{9} +// Deprecated: Use GetUsersResponse.ProtoReflect.Descriptor instead. +func (*GetUsersResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{11} } -func (x *UpdateUsersResponse) GetTimestamp() int64 { +func (x *GetUsersResponse) GetTimestamp() int64 { if x != nil { return x.Timestamp } return 0 } -func (x *UpdateUsersResponse) GetStatus() Status { +func (x *GetUsersResponse) GetStatus() Status { if x != nil { return x.Status } return Status_STATUS_UNSPECIFIED } -// DeleteUsers -type DeleteUsersRequest struct { +func (x *GetUsersResponse) GetUser() []*User { + if x != nil { + return x.User + } + return nil +} + +// UpdateUsers +type UpdateUsersRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Username []string `protobuf:"bytes,2,rep,name=username,proto3" json:"username,omitempty"` + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + User []*User `protobuf:"bytes,2,rep,name=user,proto3" json:"user,omitempty"` } -func (x *DeleteUsersRequest) Reset() { - *x = DeleteUsersRequest{} +func (x *UpdateUsersRequest) Reset() { + *x = UpdateUsersRequest{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[10] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *DeleteUsersRequest) String() string { +func (x *UpdateUsersRequest) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteUsersRequest) ProtoMessage() {} +func (*UpdateUsersRequest) ProtoMessage() {} -func (x *DeleteUsersRequest) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[10] +func (x *UpdateUsersRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -738,26 +838,819 @@ func (x *DeleteUsersRequest) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeleteUsersRequest.ProtoReflect.Descriptor instead. -func (*DeleteUsersRequest) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{10} +// Deprecated: Use UpdateUsersRequest.ProtoReflect.Descriptor instead. +func (*UpdateUsersRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{12} +} + +func (x *UpdateUsersRequest) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *UpdateUsersRequest) GetUser() []*User { + if x != nil { + return x.User + } + return nil +} + +type UpdateUsersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` +} + +func (x *UpdateUsersResponse) Reset() { + *x = UpdateUsersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUsersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUsersResponse) ProtoMessage() {} + +func (x *UpdateUsersResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUsersResponse.ProtoReflect.Descriptor instead. +func (*UpdateUsersResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{13} +} + +func (x *UpdateUsersResponse) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *UpdateUsersResponse) GetStatus() Status { + if x != nil { + return x.Status + } + return Status_STATUS_UNSPECIFIED +} + +// DeleteUsers +type DeleteUsersRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Username []string `protobuf:"bytes,2,rep,name=username,proto3" json:"username,omitempty"` +} + +func (x *DeleteUsersRequest) Reset() { + *x = DeleteUsersRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteUsersRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUsersRequest) ProtoMessage() {} + +func (x *DeleteUsersRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteUsersRequest.ProtoReflect.Descriptor instead. +func (*DeleteUsersRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{14} +} + +func (x *DeleteUsersRequest) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *DeleteUsersRequest) GetUsername() []string { + if x != nil { + return x.Username + } + return nil +} + +type DeleteUsersResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` +} + +func (x *DeleteUsersResponse) Reset() { + *x = DeleteUsersResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteUsersResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteUsersResponse) ProtoMessage() {} + +func (x *DeleteUsersResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteUsersResponse.ProtoReflect.Descriptor instead. +func (*DeleteUsersResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{15} +} + +func (x *DeleteUsersResponse) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *DeleteUsersResponse) GetStatus() Status { + if x != nil { + return x.Status + } + return Status_STATUS_UNSPECIFIED +} + +// CreateRoles +type CreateRolesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Roles []*Role `protobuf:"bytes,2,rep,name=roles,proto3" json:"roles,omitempty"` +} + +func (x *CreateRolesRequest) Reset() { + *x = CreateRolesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateRolesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateRolesRequest) ProtoMessage() {} + +func (x *CreateRolesRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateRolesRequest.ProtoReflect.Descriptor instead. +func (*CreateRolesRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{16} +} + +func (x *CreateRolesRequest) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *CreateRolesRequest) GetRoles() []*Role { + if x != nil { + return x.Roles + } + return nil +} + +type CreateRolesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` +} + +func (x *CreateRolesResponse) Reset() { + *x = CreateRolesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CreateRolesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CreateRolesResponse) ProtoMessage() {} + +func (x *CreateRolesResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CreateRolesResponse.ProtoReflect.Descriptor instead. +func (*CreateRolesResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{17} +} + +func (x *CreateRolesResponse) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *CreateRolesResponse) GetStatus() Status { + if x != nil { + return x.Status + } + return Status_STATUS_UNSPECIFIED +} + +// GetRole +type GetRoleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + RoleName string `protobuf:"bytes,2,opt,name=role_name,json=roleName,proto3" json:"role_name,omitempty"` +} + +func (x *GetRoleRequest) Reset() { + *x = GetRoleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRoleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRoleRequest) ProtoMessage() {} + +func (x *GetRoleRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRoleRequest.ProtoReflect.Descriptor instead. +func (*GetRoleRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{18} +} + +func (x *GetRoleRequest) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *GetRoleRequest) GetRoleName() string { + if x != nil { + return x.RoleName + } + return "" +} + +type GetRoleResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` + Role *Role `protobuf:"bytes,3,opt,name=role,proto3" json:"role,omitempty"` +} + +func (x *GetRoleResponse) Reset() { + *x = GetRoleResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRoleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRoleResponse) ProtoMessage() {} + +func (x *GetRoleResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRoleResponse.ProtoReflect.Descriptor instead. +func (*GetRoleResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{19} +} + +func (x *GetRoleResponse) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *GetRoleResponse) GetStatus() Status { + if x != nil { + return x.Status + } + return Status_STATUS_UNSPECIFIED +} + +func (x *GetRoleResponse) GetRole() *Role { + if x != nil { + return x.Role + } + return nil +} + +// GetRoles +type GetRolesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (x *GetRolesRequest) Reset() { + *x = GetRolesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRolesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRolesRequest) ProtoMessage() {} + +func (x *GetRolesRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRolesRequest.ProtoReflect.Descriptor instead. +func (*GetRolesRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{20} +} + +func (x *GetRolesRequest) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +type GetRolesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` + Roles []*Role `protobuf:"bytes,3,rep,name=roles,proto3" json:"roles,omitempty"` +} + +func (x *GetRolesResponse) Reset() { + *x = GetRolesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetRolesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetRolesResponse) ProtoMessage() {} + +func (x *GetRolesResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetRolesResponse.ProtoReflect.Descriptor instead. +func (*GetRolesResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{21} +} + +func (x *GetRolesResponse) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *GetRolesResponse) GetStatus() Status { + if x != nil { + return x.Status + } + return Status_STATUS_UNSPECIFIED +} + +func (x *GetRolesResponse) GetRoles() []*Role { + if x != nil { + return x.Roles + } + return nil +} + +// UpdateRoles +type UpdateRolesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Roles []*Role `protobuf:"bytes,2,rep,name=roles,proto3" json:"roles,omitempty"` +} + +func (x *UpdateRolesRequest) Reset() { + *x = UpdateRolesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateRolesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRolesRequest) ProtoMessage() {} + +func (x *UpdateRolesRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateRolesRequest.ProtoReflect.Descriptor instead. +func (*UpdateRolesRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{22} +} + +func (x *UpdateRolesRequest) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *UpdateRolesRequest) GetRoles() []*Role { + if x != nil { + return x.Roles + } + return nil +} + +type UpdateRolesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` +} + +func (x *UpdateRolesResponse) Reset() { + *x = UpdateRolesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateRolesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateRolesResponse) ProtoMessage() {} + +func (x *UpdateRolesResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateRolesResponse.ProtoReflect.Descriptor instead. +func (*UpdateRolesResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{23} +} + +func (x *UpdateRolesResponse) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *UpdateRolesResponse) GetStatus() Status { + if x != nil { + return x.Status + } + return Status_STATUS_UNSPECIFIED +} + +// DeletePermissionsForRole +type DeletePermissionsForRoleRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + RoleName string `protobuf:"bytes,2,opt,name=role_name,json=roleName,proto3" json:"role_name,omitempty"` + PermissionsToDelete []string `protobuf:"bytes,3,rep,name=permissions_to_delete,json=permissionsToDelete,proto3" json:"permissions_to_delete,omitempty"` +} + +func (x *DeletePermissionsForRoleRequest) Reset() { + *x = DeletePermissionsForRoleRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeletePermissionsForRoleRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletePermissionsForRoleRequest) ProtoMessage() {} + +func (x *DeletePermissionsForRoleRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeletePermissionsForRoleRequest.ProtoReflect.Descriptor instead. +func (*DeletePermissionsForRoleRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{24} +} + +func (x *DeletePermissionsForRoleRequest) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *DeletePermissionsForRoleRequest) GetRoleName() string { + if x != nil { + return x.RoleName + } + return "" +} + +func (x *DeletePermissionsForRoleRequest) GetPermissionsToDelete() []string { + if x != nil { + return x.PermissionsToDelete + } + return nil +} + +type DeletePermissionsForRoleResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` +} + +func (x *DeletePermissionsForRoleResponse) Reset() { + *x = DeletePermissionsForRoleResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeletePermissionsForRoleResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeletePermissionsForRoleResponse) ProtoMessage() {} + +func (x *DeletePermissionsForRoleResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) } -func (x *DeleteUsersRequest) GetTimestamp() int64 { +// Deprecated: Use DeletePermissionsForRoleResponse.ProtoReflect.Descriptor instead. +func (*DeletePermissionsForRoleResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{25} +} + +func (x *DeletePermissionsForRoleResponse) GetTimestamp() int64 { if x != nil { return x.Timestamp } return 0 } -func (x *DeleteUsersRequest) GetUsername() []string { +func (x *DeletePermissionsForRoleResponse) GetStatus() Status { if x != nil { - return x.Username + return x.Status + } + return Status_STATUS_UNSPECIFIED +} + +// DeleteRoles +type DeleteRolesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timestamp int64 `protobuf:"varint,1,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + RoleName []string `protobuf:"bytes,2,rep,name=role_name,json=roleName,proto3" json:"role_name,omitempty"` +} + +func (x *DeleteRolesRequest) Reset() { + *x = DeleteRolesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DeleteRolesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DeleteRolesRequest) ProtoMessage() {} + +func (x *DeleteRolesRequest) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DeleteRolesRequest.ProtoReflect.Descriptor instead. +func (*DeleteRolesRequest) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{26} +} + +func (x *DeleteRolesRequest) GetTimestamp() int64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *DeleteRolesRequest) GetRoleName() []string { + if x != nil { + return x.RoleName } return nil } -type DeleteUsersResponse struct { +type DeleteRolesResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields @@ -766,23 +1659,23 @@ type DeleteUsersResponse struct { Status Status `protobuf:"varint,2,opt,name=status,proto3,enum=gosdn.rbac.Status" json:"status,omitempty"` } -func (x *DeleteUsersResponse) Reset() { - *x = DeleteUsersResponse{} +func (x *DeleteRolesResponse) Reset() { + *x = DeleteRolesResponse{} if protoimpl.UnsafeEnabled { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[11] + mi := &file_gosdn_rbac_rbac_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } } -func (x *DeleteUsersResponse) String() string { +func (x *DeleteRolesResponse) String() string { return protoimpl.X.MessageStringOf(x) } -func (*DeleteUsersResponse) ProtoMessage() {} +func (*DeleteRolesResponse) ProtoMessage() {} -func (x *DeleteUsersResponse) ProtoReflect() protoreflect.Message { - mi := &file_gosdn_rbac_rbac_proto_msgTypes[11] +func (x *DeleteRolesResponse) ProtoReflect() protoreflect.Message { + mi := &file_gosdn_rbac_rbac_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -793,19 +1686,19 @@ func (x *DeleteUsersResponse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use DeleteUsersResponse.ProtoReflect.Descriptor instead. -func (*DeleteUsersResponse) Descriptor() ([]byte, []int) { - return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{11} +// Deprecated: Use DeleteRolesResponse.ProtoReflect.Descriptor instead. +func (*DeleteRolesResponse) Descriptor() ([]byte, []int) { + return file_gosdn_rbac_rbac_proto_rawDescGZIP(), []int{27} } -func (x *DeleteUsersResponse) GetTimestamp() int64 { +func (x *DeleteRolesResponse) GetTimestamp() int64 { if x != nil { return x.Timestamp } return 0 } -func (x *DeleteUsersResponse) GetStatus() Status { +func (x *DeleteRolesResponse) GetStatus() Status { if x != nil { return x.Status } @@ -824,126 +1717,274 @@ var file_gosdn_rbac_rbac_proto_rawDesc = []byte{ 0x6f, 0x74, 0x6f, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x22, 0x5a, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, - 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, - 0x03, 0x70, 0x77, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x77, 0x64, 0x22, - 0x6f, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x6f, 0x74, 0x6f, 0x22, 0xc9, 0x01, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x31, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x05, 0x72, 0x6f, + 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, + 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x1a, 0x38, 0x0a, 0x0a, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, + 0x6e, 0x0a, 0x04, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, + 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, + 0x5a, 0x0a, 0x0c, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, + 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x70, 0x77, 0x64, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x70, 0x77, 0x64, 0x22, 0x6f, 0x0a, 0x0d, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, + 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x49, 0x0a, 0x0d, + 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5a, 0x0a, 0x0e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, + 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x22, 0x58, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, + 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x5f, 0x0a, + 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x42, + 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, - 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, - 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, - 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x22, 0x49, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, - 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5a, 0x0a, 0x0e, 0x4c, - 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, + 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, + 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x2f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, + 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x82, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, + 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, + 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x58, 0x0a, 0x12, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, + 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x5f, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x58, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4e, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x04, 0x75, - 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, - 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, - 0x72, 0x22, 0x5f, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, - 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, - 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, - 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x22, 0x45, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, - 0x61, 0x6d, 0x70, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x82, 0x01, 0x0a, 0x10, 0x47, 0x65, - 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x75, + 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5f, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, - 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x58, - 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x5a, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, + 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x26, 0x0a, 0x05, + 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, + 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x05, 0x72, + 0x6f, 0x6c, 0x65, 0x73, 0x22, 0x5f, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, + 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, + 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6c, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x22, 0x81, 0x01, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, + 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, + 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x12, 0x24, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, + 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x52, 0x6f, 0x6c, 0x65, + 0x52, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x22, 0x2f, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, + 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x84, 0x01, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x52, + 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, + 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, + 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x26, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, + 0x61, 0x63, 0x2e, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x22, 0x5a, + 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, - 0x6d, 0x70, 0x12, 0x24, 0x0a, 0x04, 0x75, 0x73, 0x65, 0x72, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0e, - 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x52, 0x04, 0x75, 0x73, 0x65, 0x72, 0x22, 0x5f, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, - 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, - 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, - 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4e, 0x0a, 0x12, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x6d, 0x70, 0x12, 0x26, 0x0a, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x52, + 0x6f, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x22, 0x5f, 0x0a, 0x13, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, + 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x90, 0x01, 0x0a, 0x1f, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x46, 0x6f, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1a, 0x0a, - 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x5f, 0x0a, 0x13, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x2a, - 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, - 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, 0x41, 0x0a, 0x06, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x55, - 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, - 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x53, - 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x2a, 0x39, 0x0a, - 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x55, 0x4e, - 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x55, - 0x53, 0x45, 0x52, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x55, 0x53, - 0x45, 0x52, 0x5f, 0x50, 0x57, 0x44, 0x10, 0x02, 0x32, 0xcd, 0x04, 0x0a, 0x0b, 0x41, 0x75, 0x74, - 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4f, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, - 0x6e, 0x12, 0x18, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x4c, - 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, - 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x3a, 0x01, - 0x2a, 0x22, 0x06, 0x2f, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x5b, 0x0a, 0x06, 0x4c, 0x6f, 0x67, - 0x6f, 0x75, 0x74, 0x12, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, - 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, - 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, - 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x14, 0x22, 0x12, 0x2f, 0x6c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x2f, 0x7b, 0x75, 0x73, 0x65, - 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, 0x68, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, - 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, - 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, - 0x2a, 0x22, 0x0d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x12, 0x55, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, 0x67, - 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, - 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, - 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, - 0x06, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x68, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, - 0x62, 0x61, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, + 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x1b, 0x0a, + 0x09, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x72, 0x6f, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x65, + 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x5f, 0x74, 0x6f, 0x5f, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x13, 0x70, 0x65, 0x72, 0x6d, 0x69, + 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x54, 0x6f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x22, 0x6c, + 0x0a, 0x20, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x46, 0x6f, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x4f, 0x0a, 0x12, + 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6c, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x6c, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x5f, 0x0a, + 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, + 0x6d, 0x70, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, 0x41, + 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, 0x53, 0x54, 0x41, 0x54, + 0x55, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x0d, 0x0a, 0x09, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x4f, 0x4b, 0x10, 0x01, 0x12, + 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, + 0x02, 0x32, 0xaa, 0x0a, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x4f, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x18, 0x2e, 0x67, 0x6f, 0x73, + 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, + 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x11, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0b, 0x3a, 0x01, 0x2a, 0x22, 0x06, 0x2f, 0x6c, 0x6f, 0x67, + 0x69, 0x6e, 0x12, 0x5b, 0x0a, 0x06, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x19, 0x2e, 0x67, + 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, + 0x72, 0x62, 0x61, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x22, 0x12, 0x2f, 0x6c, 0x6f, + 0x67, 0x6f, 0x75, 0x74, 0x2f, 0x7b, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x7d, 0x12, + 0x68, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, + 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, + 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2f, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x56, 0x0a, 0x07, 0x47, 0x65, 0x74, + 0x55, 0x73, 0x65, 0x72, 0x12, 0x1a, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, + 0x74, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x67, 0x65, + 0x74, 0x12, 0x55, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1b, 0x2e, + 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x73, + 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x0e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, + 0x12, 0x06, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x12, 0x68, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, + 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, + 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, + 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, + 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x44, + 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x2a, 0x0d, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x68, 0x0a, 0x0b, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, + 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, + 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, + 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x2f, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x12, 0x56, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x1a, + 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, + 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x67, 0x6f, 0x73, + 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, + 0x0a, 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x2f, 0x67, 0x65, 0x74, 0x12, 0x55, 0x0a, 0x08, 0x47, + 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, + 0x72, 0x62, 0x61, 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, + 0x63, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x0e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, 0x06, 0x2f, 0x72, 0x6f, 0x6c, + 0x65, 0x73, 0x12, 0x68, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, + 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, + 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x98, 0x01, 0x0a, + 0x18, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x46, 0x6f, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x2b, 0x2e, 0x67, 0x6f, 0x73, 0x64, + 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x72, + 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x46, 0x6f, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, + 0x62, 0x61, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, + 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x46, 0x6f, 0x72, 0x52, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x2a, 0x19, 0x2f, 0x72, + 0x6f, 0x6c, 0x65, 0x73, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x2f, 0x70, 0x65, 0x72, 0x6d, + 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x65, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, + 0x62, 0x61, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, - 0x62, 0x61, 0x63, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, - 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x12, 0x65, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, - 0x12, 0x1e, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x1a, 0x1f, 0x2e, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2e, 0x72, 0x62, 0x61, 0x63, 0x2e, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x2a, 0x0d, 0x2f, 0x75, 0x73, 0x65, 0x72, - 0x73, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x30, 0x5a, 0x2e, 0x63, 0x6f, 0x64, 0x65, - 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, - 0x65, 0x74, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, - 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x72, 0x62, 0x61, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x62, 0x61, 0x63, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x2a, + 0x0d, 0x2f, 0x72, 0x6f, 0x6c, 0x65, 0x73, 0x2f, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x30, + 0x5a, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x2e, 0x66, 0x62, 0x69, 0x2e, 0x68, 0x2d, 0x64, 0x61, 0x2e, + 0x64, 0x65, 0x2f, 0x64, 0x61, 0x6e, 0x65, 0x74, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x67, 0x6f, 0x73, 0x64, 0x6e, 0x2f, 0x72, 0x62, 0x61, 0x63, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -958,51 +1999,94 @@ func file_gosdn_rbac_rbac_proto_rawDescGZIP() []byte { return file_gosdn_rbac_rbac_proto_rawDescData } -var file_gosdn_rbac_rbac_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_gosdn_rbac_rbac_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_gosdn_rbac_rbac_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_gosdn_rbac_rbac_proto_msgTypes = make([]protoimpl.MessageInfo, 29) var file_gosdn_rbac_rbac_proto_goTypes = []interface{}{ - (Status)(0), // 0: gosdn.rbac.Status - (User)(0), // 1: gosdn.rbac.User - (*LoginRequest)(nil), // 2: gosdn.rbac.LoginRequest - (*LoginResponse)(nil), // 3: gosdn.rbac.LoginResponse - (*LogoutRequest)(nil), // 4: gosdn.rbac.LogoutRequest - (*LogoutResponse)(nil), // 5: gosdn.rbac.LogoutResponse - (*CreateUsersRequest)(nil), // 6: gosdn.rbac.CreateUsersRequest - (*CreateUsersResponse)(nil), // 7: gosdn.rbac.CreateUsersResponse - (*GetUsersRequest)(nil), // 8: gosdn.rbac.GetUsersRequest - (*GetUsersResponse)(nil), // 9: gosdn.rbac.GetUsersResponse - (*UpdateUsersRequest)(nil), // 10: gosdn.rbac.UpdateUsersRequest - (*UpdateUsersResponse)(nil), // 11: gosdn.rbac.UpdateUsersResponse - (*DeleteUsersRequest)(nil), // 12: gosdn.rbac.DeleteUsersRequest - (*DeleteUsersResponse)(nil), // 13: gosdn.rbac.DeleteUsersResponse + (Status)(0), // 0: gosdn.rbac.Status + (*User)(nil), // 1: gosdn.rbac.User + (*Role)(nil), // 2: gosdn.rbac.Role + (*LoginRequest)(nil), // 3: gosdn.rbac.LoginRequest + (*LoginResponse)(nil), // 4: gosdn.rbac.LoginResponse + (*LogoutRequest)(nil), // 5: gosdn.rbac.LogoutRequest + (*LogoutResponse)(nil), // 6: gosdn.rbac.LogoutResponse + (*CreateUsersRequest)(nil), // 7: gosdn.rbac.CreateUsersRequest + (*CreateUsersResponse)(nil), // 8: gosdn.rbac.CreateUsersResponse + (*GetUserRequest)(nil), // 9: gosdn.rbac.GetUserRequest + (*GetUserResponse)(nil), // 10: gosdn.rbac.GetUserResponse + (*GetUsersRequest)(nil), // 11: gosdn.rbac.GetUsersRequest + (*GetUsersResponse)(nil), // 12: gosdn.rbac.GetUsersResponse + (*UpdateUsersRequest)(nil), // 13: gosdn.rbac.UpdateUsersRequest + (*UpdateUsersResponse)(nil), // 14: gosdn.rbac.UpdateUsersResponse + (*DeleteUsersRequest)(nil), // 15: gosdn.rbac.DeleteUsersRequest + (*DeleteUsersResponse)(nil), // 16: gosdn.rbac.DeleteUsersResponse + (*CreateRolesRequest)(nil), // 17: gosdn.rbac.CreateRolesRequest + (*CreateRolesResponse)(nil), // 18: gosdn.rbac.CreateRolesResponse + (*GetRoleRequest)(nil), // 19: gosdn.rbac.GetRoleRequest + (*GetRoleResponse)(nil), // 20: gosdn.rbac.GetRoleResponse + (*GetRolesRequest)(nil), // 21: gosdn.rbac.GetRolesRequest + (*GetRolesResponse)(nil), // 22: gosdn.rbac.GetRolesResponse + (*UpdateRolesRequest)(nil), // 23: gosdn.rbac.UpdateRolesRequest + (*UpdateRolesResponse)(nil), // 24: gosdn.rbac.UpdateRolesResponse + (*DeletePermissionsForRoleRequest)(nil), // 25: gosdn.rbac.DeletePermissionsForRoleRequest + (*DeletePermissionsForRoleResponse)(nil), // 26: gosdn.rbac.DeletePermissionsForRoleResponse + (*DeleteRolesRequest)(nil), // 27: gosdn.rbac.DeleteRolesRequest + (*DeleteRolesResponse)(nil), // 28: gosdn.rbac.DeleteRolesResponse + nil, // 29: gosdn.rbac.User.RolesEntry } var file_gosdn_rbac_rbac_proto_depIdxs = []int32{ - 0, // 0: gosdn.rbac.LoginResponse.status:type_name -> gosdn.rbac.Status - 0, // 1: gosdn.rbac.LogoutResponse.status:type_name -> gosdn.rbac.Status - 1, // 2: gosdn.rbac.CreateUsersRequest.user:type_name -> gosdn.rbac.User - 0, // 3: gosdn.rbac.CreateUsersResponse.status:type_name -> gosdn.rbac.Status - 0, // 4: gosdn.rbac.GetUsersResponse.status:type_name -> gosdn.rbac.Status - 1, // 5: gosdn.rbac.GetUsersResponse.user:type_name -> gosdn.rbac.User - 1, // 6: gosdn.rbac.UpdateUsersRequest.user:type_name -> gosdn.rbac.User - 0, // 7: gosdn.rbac.UpdateUsersResponse.status:type_name -> gosdn.rbac.Status - 0, // 8: gosdn.rbac.DeleteUsersResponse.status:type_name -> gosdn.rbac.Status - 2, // 9: gosdn.rbac.AuthService.Login:input_type -> gosdn.rbac.LoginRequest - 4, // 10: gosdn.rbac.AuthService.Logout:input_type -> gosdn.rbac.LogoutRequest - 6, // 11: gosdn.rbac.AuthService.CreateUsers:input_type -> gosdn.rbac.CreateUsersRequest - 8, // 12: gosdn.rbac.AuthService.GetUsers:input_type -> gosdn.rbac.GetUsersRequest - 10, // 13: gosdn.rbac.AuthService.UpdateUsers:input_type -> gosdn.rbac.UpdateUsersRequest - 12, // 14: gosdn.rbac.AuthService.DeleteUsers:input_type -> gosdn.rbac.DeleteUsersRequest - 3, // 15: gosdn.rbac.AuthService.Login:output_type -> gosdn.rbac.LoginResponse - 5, // 16: gosdn.rbac.AuthService.Logout:output_type -> gosdn.rbac.LogoutResponse - 7, // 17: gosdn.rbac.AuthService.CreateUsers:output_type -> gosdn.rbac.CreateUsersResponse - 9, // 18: gosdn.rbac.AuthService.GetUsers:output_type -> gosdn.rbac.GetUsersResponse - 11, // 19: gosdn.rbac.AuthService.UpdateUsers:output_type -> gosdn.rbac.UpdateUsersResponse - 13, // 20: gosdn.rbac.AuthService.DeleteUsers:output_type -> gosdn.rbac.DeleteUsersResponse - 15, // [15:21] is the sub-list for method output_type - 9, // [9:15] is the sub-list for method input_type - 9, // [9:9] is the sub-list for extension type_name - 9, // [9:9] is the sub-list for extension extendee - 0, // [0:9] is the sub-list for field type_name + 29, // 0: gosdn.rbac.User.roles:type_name -> gosdn.rbac.User.RolesEntry + 0, // 1: gosdn.rbac.LoginResponse.status:type_name -> gosdn.rbac.Status + 0, // 2: gosdn.rbac.LogoutResponse.status:type_name -> gosdn.rbac.Status + 1, // 3: gosdn.rbac.CreateUsersRequest.user:type_name -> gosdn.rbac.User + 0, // 4: gosdn.rbac.CreateUsersResponse.status:type_name -> gosdn.rbac.Status + 0, // 5: gosdn.rbac.GetUserResponse.status:type_name -> gosdn.rbac.Status + 1, // 6: gosdn.rbac.GetUserResponse.user:type_name -> gosdn.rbac.User + 0, // 7: gosdn.rbac.GetUsersResponse.status:type_name -> gosdn.rbac.Status + 1, // 8: gosdn.rbac.GetUsersResponse.user:type_name -> gosdn.rbac.User + 1, // 9: gosdn.rbac.UpdateUsersRequest.user:type_name -> gosdn.rbac.User + 0, // 10: gosdn.rbac.UpdateUsersResponse.status:type_name -> gosdn.rbac.Status + 0, // 11: gosdn.rbac.DeleteUsersResponse.status:type_name -> gosdn.rbac.Status + 2, // 12: gosdn.rbac.CreateRolesRequest.roles:type_name -> gosdn.rbac.Role + 0, // 13: gosdn.rbac.CreateRolesResponse.status:type_name -> gosdn.rbac.Status + 0, // 14: gosdn.rbac.GetRoleResponse.status:type_name -> gosdn.rbac.Status + 2, // 15: gosdn.rbac.GetRoleResponse.role:type_name -> gosdn.rbac.Role + 0, // 16: gosdn.rbac.GetRolesResponse.status:type_name -> gosdn.rbac.Status + 2, // 17: gosdn.rbac.GetRolesResponse.roles:type_name -> gosdn.rbac.Role + 2, // 18: gosdn.rbac.UpdateRolesRequest.roles:type_name -> gosdn.rbac.Role + 0, // 19: gosdn.rbac.UpdateRolesResponse.status:type_name -> gosdn.rbac.Status + 0, // 20: gosdn.rbac.DeletePermissionsForRoleResponse.status:type_name -> gosdn.rbac.Status + 0, // 21: gosdn.rbac.DeleteRolesResponse.status:type_name -> gosdn.rbac.Status + 3, // 22: gosdn.rbac.AuthService.Login:input_type -> gosdn.rbac.LoginRequest + 5, // 23: gosdn.rbac.AuthService.Logout:input_type -> gosdn.rbac.LogoutRequest + 7, // 24: gosdn.rbac.AuthService.CreateUsers:input_type -> gosdn.rbac.CreateUsersRequest + 9, // 25: gosdn.rbac.AuthService.GetUser:input_type -> gosdn.rbac.GetUserRequest + 11, // 26: gosdn.rbac.AuthService.GetUsers:input_type -> gosdn.rbac.GetUsersRequest + 13, // 27: gosdn.rbac.AuthService.UpdateUsers:input_type -> gosdn.rbac.UpdateUsersRequest + 15, // 28: gosdn.rbac.AuthService.DeleteUsers:input_type -> gosdn.rbac.DeleteUsersRequest + 17, // 29: gosdn.rbac.AuthService.CreateRoles:input_type -> gosdn.rbac.CreateRolesRequest + 19, // 30: gosdn.rbac.AuthService.GetRole:input_type -> gosdn.rbac.GetRoleRequest + 21, // 31: gosdn.rbac.AuthService.GetRoles:input_type -> gosdn.rbac.GetRolesRequest + 23, // 32: gosdn.rbac.AuthService.UpdateRoles:input_type -> gosdn.rbac.UpdateRolesRequest + 25, // 33: gosdn.rbac.AuthService.DeletePermissionsForRole:input_type -> gosdn.rbac.DeletePermissionsForRoleRequest + 27, // 34: gosdn.rbac.AuthService.DeleteRoles:input_type -> gosdn.rbac.DeleteRolesRequest + 4, // 35: gosdn.rbac.AuthService.Login:output_type -> gosdn.rbac.LoginResponse + 6, // 36: gosdn.rbac.AuthService.Logout:output_type -> gosdn.rbac.LogoutResponse + 8, // 37: gosdn.rbac.AuthService.CreateUsers:output_type -> gosdn.rbac.CreateUsersResponse + 10, // 38: gosdn.rbac.AuthService.GetUser:output_type -> gosdn.rbac.GetUserResponse + 12, // 39: gosdn.rbac.AuthService.GetUsers:output_type -> gosdn.rbac.GetUsersResponse + 14, // 40: gosdn.rbac.AuthService.UpdateUsers:output_type -> gosdn.rbac.UpdateUsersResponse + 16, // 41: gosdn.rbac.AuthService.DeleteUsers:output_type -> gosdn.rbac.DeleteUsersResponse + 18, // 42: gosdn.rbac.AuthService.CreateRoles:output_type -> gosdn.rbac.CreateRolesResponse + 20, // 43: gosdn.rbac.AuthService.GetRole:output_type -> gosdn.rbac.GetRoleResponse + 22, // 44: gosdn.rbac.AuthService.GetRoles:output_type -> gosdn.rbac.GetRolesResponse + 24, // 45: gosdn.rbac.AuthService.UpdateRoles:output_type -> gosdn.rbac.UpdateRolesResponse + 26, // 46: gosdn.rbac.AuthService.DeletePermissionsForRole:output_type -> gosdn.rbac.DeletePermissionsForRoleResponse + 28, // 47: gosdn.rbac.AuthService.DeleteRoles:output_type -> gosdn.rbac.DeleteRolesResponse + 35, // [35:48] is the sub-list for method output_type + 22, // [22:35] is the sub-list for method input_type + 22, // [22:22] is the sub-list for extension type_name + 22, // [22:22] is the sub-list for extension extendee + 0, // [0:22] is the sub-list for field type_name } func init() { file_gosdn_rbac_rbac_proto_init() } @@ -1012,7 +2096,7 @@ func file_gosdn_rbac_rbac_proto_init() { } if !protoimpl.UnsafeEnabled { file_gosdn_rbac_rbac_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoginRequest); i { + switch v := v.(*User); i { case 0: return &v.state case 1: @@ -1024,7 +2108,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LoginResponse); i { + switch v := v.(*Role); i { case 0: return &v.state case 1: @@ -1036,7 +2120,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LogoutRequest); i { + switch v := v.(*LoginRequest); i { case 0: return &v.state case 1: @@ -1048,7 +2132,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LogoutResponse); i { + switch v := v.(*LoginResponse); i { case 0: return &v.state case 1: @@ -1060,7 +2144,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateUsersRequest); i { + switch v := v.(*LogoutRequest); i { case 0: return &v.state case 1: @@ -1072,7 +2156,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CreateUsersResponse); i { + switch v := v.(*LogoutResponse); i { case 0: return &v.state case 1: @@ -1084,7 +2168,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUsersRequest); i { + switch v := v.(*CreateUsersRequest); i { case 0: return &v.state case 1: @@ -1096,7 +2180,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetUsersResponse); i { + switch v := v.(*CreateUsersResponse); i { case 0: return &v.state case 1: @@ -1108,7 +2192,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateUsersRequest); i { + switch v := v.(*GetUserRequest); i { case 0: return &v.state case 1: @@ -1120,7 +2204,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateUsersResponse); i { + switch v := v.(*GetUserResponse); i { case 0: return &v.state case 1: @@ -1132,7 +2216,7 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteUsersRequest); i { + switch v := v.(*GetUsersRequest); i { case 0: return &v.state case 1: @@ -1144,6 +2228,54 @@ func file_gosdn_rbac_rbac_proto_init() { } } file_gosdn_rbac_rbac_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetUsersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUsersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUsersResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteUsersRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DeleteUsersResponse); i { case 0: return &v.state @@ -1155,14 +2287,158 @@ func file_gosdn_rbac_rbac_proto_init() { return nil } } + file_gosdn_rbac_rbac_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateRolesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CreateRolesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetRoleRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetRoleResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetRolesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetRolesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateRolesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateRolesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeletePermissionsForRoleRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeletePermissionsForRoleResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteRolesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_gosdn_rbac_rbac_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeleteRolesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_gosdn_rbac_rbac_proto_rawDesc, - NumEnums: 2, - NumMessages: 12, + NumEnums: 1, + NumMessages: 29, NumExtensions: 0, NumServices: 1, }, diff --git a/api/go/gosdn/rbac/rbac.pb.gw.go b/api/go/gosdn/rbac/rbac.pb.gw.go index 23cff1f99..d5a6a249c 100644 --- a/api/go/gosdn/rbac/rbac.pb.gw.go +++ b/api/go/gosdn/rbac/rbac.pb.gw.go @@ -169,6 +169,42 @@ func local_request_AuthService_CreateUsers_0(ctx context.Context, marshaler runt } +var ( + filter_AuthService_GetUser_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_AuthService_GetUser_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetUserRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_GetUser_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetUser(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_GetUser_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetUserRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_GetUser_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetUser(ctx, &protoReq) + return msg, metadata, err + +} + var ( filter_AuthService_GetUsers_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} ) @@ -275,6 +311,218 @@ func local_request_AuthService_DeleteUsers_0(ctx context.Context, marshaler runt } +func request_AuthService_CreateRoles_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreateRolesRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.CreateRoles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_CreateRoles_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CreateRolesRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.CreateRoles(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_AuthService_GetRole_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_AuthService_GetRole_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetRoleRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_GetRole_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_GetRole_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetRoleRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_GetRole_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetRole(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_AuthService_GetRoles_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_AuthService_GetRoles_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetRolesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_GetRoles_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.GetRoles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_GetRoles_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq GetRolesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_GetRoles_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.GetRoles(ctx, &protoReq) + return msg, metadata, err + +} + +func request_AuthService_UpdateRoles_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateRolesRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.UpdateRoles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_UpdateRoles_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UpdateRolesRequest + var metadata runtime.ServerMetadata + + newReader, berr := utilities.IOReaderFactory(req.Body) + if berr != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) + } + if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.UpdateRoles(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_AuthService_DeletePermissionsForRole_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_AuthService_DeletePermissionsForRole_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeletePermissionsForRoleRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_DeletePermissionsForRole_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.DeletePermissionsForRole(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_DeletePermissionsForRole_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeletePermissionsForRoleRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_DeletePermissionsForRole_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.DeletePermissionsForRole(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_AuthService_DeleteRoles_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_AuthService_DeleteRoles_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteRolesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_DeleteRoles_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.DeleteRoles(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_AuthService_DeleteRoles_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq DeleteRolesRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_AuthService_DeleteRoles_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.DeleteRoles(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterAuthServiceHandlerServer registers the http handlers for service AuthService to "mux". // UnaryRPC :call AuthServiceServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -350,6 +598,29 @@ func RegisterAuthServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("GET", pattern_AuthService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.rbac.AuthService/GetUser", runtime.WithHTTPPathPattern("/users/get")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_GetUser_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_GetUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_AuthService_GetUsers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -419,6 +690,144 @@ func RegisterAuthServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("POST", pattern_AuthService_CreateRoles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.rbac.AuthService/CreateRoles", runtime.WithHTTPPathPattern("/roles/create")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_CreateRoles_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_CreateRoles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_AuthService_GetRole_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.rbac.AuthService/GetRole", runtime.WithHTTPPathPattern("/roles/get")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_GetRole_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_GetRole_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_AuthService_GetRoles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.rbac.AuthService/GetRoles", runtime.WithHTTPPathPattern("/roles")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_GetRoles_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_GetRoles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_AuthService_UpdateRoles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.rbac.AuthService/UpdateRoles", runtime.WithHTTPPathPattern("/roles/update")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_UpdateRoles_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_UpdateRoles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_AuthService_DeletePermissionsForRole_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.rbac.AuthService/DeletePermissionsForRole", runtime.WithHTTPPathPattern("/roles/delete/permissions")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_DeletePermissionsForRole_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_DeletePermissionsForRole_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_AuthService_DeleteRoles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req, "/gosdn.rbac.AuthService/DeleteRoles", runtime.WithHTTPPathPattern("/roles/delete")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_AuthService_DeleteRoles_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_DeleteRoles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -520,6 +929,26 @@ func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("GET", pattern_AuthService_GetUser_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.rbac.AuthService/GetUser", runtime.WithHTTPPathPattern("/users/get")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_GetUser_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_GetUser_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("GET", pattern_AuthService_GetUsers_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -580,6 +1009,126 @@ func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("POST", pattern_AuthService_CreateRoles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.rbac.AuthService/CreateRoles", runtime.WithHTTPPathPattern("/roles/create")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_CreateRoles_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_CreateRoles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_AuthService_GetRole_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.rbac.AuthService/GetRole", runtime.WithHTTPPathPattern("/roles/get")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_GetRole_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_GetRole_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_AuthService_GetRoles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.rbac.AuthService/GetRoles", runtime.WithHTTPPathPattern("/roles")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_GetRoles_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_GetRoles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_AuthService_UpdateRoles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.rbac.AuthService/UpdateRoles", runtime.WithHTTPPathPattern("/roles/update")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_UpdateRoles_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_UpdateRoles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_AuthService_DeletePermissionsForRole_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.rbac.AuthService/DeletePermissionsForRole", runtime.WithHTTPPathPattern("/roles/delete/permissions")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_DeletePermissionsForRole_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_DeletePermissionsForRole_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("DELETE", pattern_AuthService_DeleteRoles_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req, "/gosdn.rbac.AuthService/DeleteRoles", runtime.WithHTTPPathPattern("/roles/delete")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_DeleteRoles_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_DeleteRoles_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -590,11 +1139,25 @@ var ( pattern_AuthService_CreateUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"users", "create"}, "")) + pattern_AuthService_GetUser_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"users", "get"}, "")) + pattern_AuthService_GetUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"users"}, "")) pattern_AuthService_UpdateUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"users", "update"}, "")) pattern_AuthService_DeleteUsers_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"users", "delete"}, "")) + + pattern_AuthService_CreateRoles_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"roles", "create"}, "")) + + pattern_AuthService_GetRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"roles", "get"}, "")) + + pattern_AuthService_GetRoles_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"roles"}, "")) + + pattern_AuthService_UpdateRoles_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"roles", "update"}, "")) + + pattern_AuthService_DeletePermissionsForRole_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"roles", "delete", "permissions"}, "")) + + pattern_AuthService_DeleteRoles_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"roles", "delete"}, "")) ) var ( @@ -604,9 +1167,23 @@ var ( forward_AuthService_CreateUsers_0 = runtime.ForwardResponseMessage + forward_AuthService_GetUser_0 = runtime.ForwardResponseMessage + forward_AuthService_GetUsers_0 = runtime.ForwardResponseMessage forward_AuthService_UpdateUsers_0 = runtime.ForwardResponseMessage forward_AuthService_DeleteUsers_0 = runtime.ForwardResponseMessage + + forward_AuthService_CreateRoles_0 = runtime.ForwardResponseMessage + + forward_AuthService_GetRole_0 = runtime.ForwardResponseMessage + + forward_AuthService_GetRoles_0 = runtime.ForwardResponseMessage + + forward_AuthService_UpdateRoles_0 = runtime.ForwardResponseMessage + + forward_AuthService_DeletePermissionsForRole_0 = runtime.ForwardResponseMessage + + forward_AuthService_DeleteRoles_0 = runtime.ForwardResponseMessage ) diff --git a/api/go/gosdn/rbac/rbac_grpc.pb.go b/api/go/gosdn/rbac/rbac_grpc.pb.go index 781a8fd9b..8ba7a4f68 100644 --- a/api/go/gosdn/rbac/rbac_grpc.pb.go +++ b/api/go/gosdn/rbac/rbac_grpc.pb.go @@ -26,16 +26,36 @@ type AuthServiceClient interface { // Highest possible permissions of new users is of current permission level. // If not logged in: Created user has lowest possible permissions, only one user can be created this way. CreateUsers(ctx context.Context, in *CreateUsersRequest, opts ...grpc.CallOption) (*CreateUsersResponse, error) + // Requests information about one user, requires login beforehand.option + GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) // Requests information about available users, requires login beforehand. // Requires highest possible permissions. GetUsers(ctx context.Context, in *GetUsersRequest, opts ...grpc.CallOption) (*GetUsersResponse, error) // Updates users with the provided parameters, requires login beforehand. // Requires highest permissions to change other users, everyone else can only update their own account. - // // Requires highest permissions to change multiple users at the same time. + // Requires highest permissions to change multiple users at the same time. UpdateUsers(ctx context.Context, in *UpdateUsersRequest, opts ...grpc.CallOption) (*UpdateUsersResponse, error) // Deletes users, requires login beforehand. // Requires highest permissions. DeleteUsers(ctx context.Context, in *DeleteUsersRequest, opts ...grpc.CallOption) (*DeleteUsersResponse, error) + // Creates roles, requires login beforehand. + // Requires highest permissions. + CreateRoles(ctx context.Context, in *CreateRolesRequest, opts ...grpc.CallOption) (*CreateRolesResponse, error) + // Requests one role with its permissions, requires login beforehand. + // Requires highest permissions. + GetRole(ctx context.Context, in *GetRoleRequest, opts ...grpc.CallOption) (*GetRoleResponse, error) + // Requests all roles with their permissions, requires login beforehand. + // Requires highest permissions. + GetRoles(ctx context.Context, in *GetRolesRequest, opts ...grpc.CallOption) (*GetRolesResponse, error) + // Updates roles by setting the provided permissions, requires login beforehand. + // Requires highest permissions. + UpdateRoles(ctx context.Context, in *UpdateRolesRequest, opts ...grpc.CallOption) (*UpdateRolesResponse, error) + // Deletes permissions from given role, requires login beforehand. + // Requires highest permissions. + DeletePermissionsForRole(ctx context.Context, in *DeletePermissionsForRoleRequest, opts ...grpc.CallOption) (*DeletePermissionsForRoleResponse, error) + // Deletes roles with their permissions, requires login beforehand. + // Requires highest permissions. + DeleteRoles(ctx context.Context, in *DeleteRolesRequest, opts ...grpc.CallOption) (*DeleteRolesResponse, error) } type authServiceClient struct { @@ -73,6 +93,15 @@ func (c *authServiceClient) CreateUsers(ctx context.Context, in *CreateUsersRequ return out, nil } +func (c *authServiceClient) GetUser(ctx context.Context, in *GetUserRequest, opts ...grpc.CallOption) (*GetUserResponse, error) { + out := new(GetUserResponse) + err := c.cc.Invoke(ctx, "/gosdn.rbac.AuthService/GetUser", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *authServiceClient) GetUsers(ctx context.Context, in *GetUsersRequest, opts ...grpc.CallOption) (*GetUsersResponse, error) { out := new(GetUsersResponse) err := c.cc.Invoke(ctx, "/gosdn.rbac.AuthService/GetUsers", in, out, opts...) @@ -100,6 +129,60 @@ func (c *authServiceClient) DeleteUsers(ctx context.Context, in *DeleteUsersRequ return out, nil } +func (c *authServiceClient) CreateRoles(ctx context.Context, in *CreateRolesRequest, opts ...grpc.CallOption) (*CreateRolesResponse, error) { + out := new(CreateRolesResponse) + err := c.cc.Invoke(ctx, "/gosdn.rbac.AuthService/CreateRoles", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) GetRole(ctx context.Context, in *GetRoleRequest, opts ...grpc.CallOption) (*GetRoleResponse, error) { + out := new(GetRoleResponse) + err := c.cc.Invoke(ctx, "/gosdn.rbac.AuthService/GetRole", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) GetRoles(ctx context.Context, in *GetRolesRequest, opts ...grpc.CallOption) (*GetRolesResponse, error) { + out := new(GetRolesResponse) + err := c.cc.Invoke(ctx, "/gosdn.rbac.AuthService/GetRoles", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) UpdateRoles(ctx context.Context, in *UpdateRolesRequest, opts ...grpc.CallOption) (*UpdateRolesResponse, error) { + out := new(UpdateRolesResponse) + err := c.cc.Invoke(ctx, "/gosdn.rbac.AuthService/UpdateRoles", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) DeletePermissionsForRole(ctx context.Context, in *DeletePermissionsForRoleRequest, opts ...grpc.CallOption) (*DeletePermissionsForRoleResponse, error) { + out := new(DeletePermissionsForRoleResponse) + err := c.cc.Invoke(ctx, "/gosdn.rbac.AuthService/DeletePermissionsForRole", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *authServiceClient) DeleteRoles(ctx context.Context, in *DeleteRolesRequest, opts ...grpc.CallOption) (*DeleteRolesResponse, error) { + out := new(DeleteRolesResponse) + err := c.cc.Invoke(ctx, "/gosdn.rbac.AuthService/DeleteRoles", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // AuthServiceServer is the server API for AuthService service. // All implementations must embed UnimplementedAuthServiceServer // for forward compatibility @@ -112,16 +195,36 @@ type AuthServiceServer interface { // Highest possible permissions of new users is of current permission level. // If not logged in: Created user has lowest possible permissions, only one user can be created this way. CreateUsers(context.Context, *CreateUsersRequest) (*CreateUsersResponse, error) + // Requests information about one user, requires login beforehand.option + GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) // Requests information about available users, requires login beforehand. // Requires highest possible permissions. GetUsers(context.Context, *GetUsersRequest) (*GetUsersResponse, error) // Updates users with the provided parameters, requires login beforehand. // Requires highest permissions to change other users, everyone else can only update their own account. - // // Requires highest permissions to change multiple users at the same time. + // Requires highest permissions to change multiple users at the same time. UpdateUsers(context.Context, *UpdateUsersRequest) (*UpdateUsersResponse, error) // Deletes users, requires login beforehand. // Requires highest permissions. DeleteUsers(context.Context, *DeleteUsersRequest) (*DeleteUsersResponse, error) + // Creates roles, requires login beforehand. + // Requires highest permissions. + CreateRoles(context.Context, *CreateRolesRequest) (*CreateRolesResponse, error) + // Requests one role with its permissions, requires login beforehand. + // Requires highest permissions. + GetRole(context.Context, *GetRoleRequest) (*GetRoleResponse, error) + // Requests all roles with their permissions, requires login beforehand. + // Requires highest permissions. + GetRoles(context.Context, *GetRolesRequest) (*GetRolesResponse, error) + // Updates roles by setting the provided permissions, requires login beforehand. + // Requires highest permissions. + UpdateRoles(context.Context, *UpdateRolesRequest) (*UpdateRolesResponse, error) + // Deletes permissions from given role, requires login beforehand. + // Requires highest permissions. + DeletePermissionsForRole(context.Context, *DeletePermissionsForRoleRequest) (*DeletePermissionsForRoleResponse, error) + // Deletes roles with their permissions, requires login beforehand. + // Requires highest permissions. + DeleteRoles(context.Context, *DeleteRolesRequest) (*DeleteRolesResponse, error) mustEmbedUnimplementedAuthServiceServer() } @@ -138,6 +241,9 @@ func (UnimplementedAuthServiceServer) Logout(context.Context, *LogoutRequest) (* func (UnimplementedAuthServiceServer) CreateUsers(context.Context, *CreateUsersRequest) (*CreateUsersResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method CreateUsers not implemented") } +func (UnimplementedAuthServiceServer) GetUser(context.Context, *GetUserRequest) (*GetUserResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetUser not implemented") +} func (UnimplementedAuthServiceServer) GetUsers(context.Context, *GetUsersRequest) (*GetUsersResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetUsers not implemented") } @@ -147,6 +253,24 @@ func (UnimplementedAuthServiceServer) UpdateUsers(context.Context, *UpdateUsersR func (UnimplementedAuthServiceServer) DeleteUsers(context.Context, *DeleteUsersRequest) (*DeleteUsersResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method DeleteUsers not implemented") } +func (UnimplementedAuthServiceServer) CreateRoles(context.Context, *CreateRolesRequest) (*CreateRolesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CreateRoles not implemented") +} +func (UnimplementedAuthServiceServer) GetRole(context.Context, *GetRoleRequest) (*GetRoleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRole not implemented") +} +func (UnimplementedAuthServiceServer) GetRoles(context.Context, *GetRolesRequest) (*GetRolesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetRoles not implemented") +} +func (UnimplementedAuthServiceServer) UpdateRoles(context.Context, *UpdateRolesRequest) (*UpdateRolesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method UpdateRoles not implemented") +} +func (UnimplementedAuthServiceServer) DeletePermissionsForRole(context.Context, *DeletePermissionsForRoleRequest) (*DeletePermissionsForRoleResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeletePermissionsForRole not implemented") +} +func (UnimplementedAuthServiceServer) DeleteRoles(context.Context, *DeleteRolesRequest) (*DeleteRolesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method DeleteRoles not implemented") +} func (UnimplementedAuthServiceServer) mustEmbedUnimplementedAuthServiceServer() {} // UnsafeAuthServiceServer may be embedded to opt out of forward compatibility for this service. @@ -214,6 +338,24 @@ func _AuthService_CreateUsers_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _AuthService_GetUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).GetUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gosdn.rbac.AuthService/GetUser", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).GetUser(ctx, req.(*GetUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AuthService_GetUsers_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(GetUsersRequest) if err := dec(in); err != nil { @@ -268,6 +410,114 @@ func _AuthService_DeleteUsers_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _AuthService_CreateRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CreateRolesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).CreateRoles(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gosdn.rbac.AuthService/CreateRoles", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).CreateRoles(ctx, req.(*CreateRolesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_GetRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRoleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).GetRole(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gosdn.rbac.AuthService/GetRole", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).GetRole(ctx, req.(*GetRoleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_GetRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetRolesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).GetRoles(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gosdn.rbac.AuthService/GetRoles", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).GetRoles(ctx, req.(*GetRolesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_UpdateRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UpdateRolesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).UpdateRoles(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gosdn.rbac.AuthService/UpdateRoles", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).UpdateRoles(ctx, req.(*UpdateRolesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_DeletePermissionsForRole_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeletePermissionsForRoleRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).DeletePermissionsForRole(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gosdn.rbac.AuthService/DeletePermissionsForRole", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).DeletePermissionsForRole(ctx, req.(*DeletePermissionsForRoleRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _AuthService_DeleteRoles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DeleteRolesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).DeleteRoles(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/gosdn.rbac.AuthService/DeleteRoles", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).DeleteRoles(ctx, req.(*DeleteRolesRequest)) + } + return interceptor(ctx, in, info, handler) +} + // AuthService_ServiceDesc is the grpc.ServiceDesc for AuthService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -287,6 +537,10 @@ var AuthService_ServiceDesc = grpc.ServiceDesc{ MethodName: "CreateUsers", Handler: _AuthService_CreateUsers_Handler, }, + { + MethodName: "GetUser", + Handler: _AuthService_GetUser_Handler, + }, { MethodName: "GetUsers", Handler: _AuthService_GetUsers_Handler, @@ -299,6 +553,30 @@ var AuthService_ServiceDesc = grpc.ServiceDesc{ MethodName: "DeleteUsers", Handler: _AuthService_DeleteUsers_Handler, }, + { + MethodName: "CreateRoles", + Handler: _AuthService_CreateRoles_Handler, + }, + { + MethodName: "GetRole", + Handler: _AuthService_GetRole_Handler, + }, + { + MethodName: "GetRoles", + Handler: _AuthService_GetRoles_Handler, + }, + { + MethodName: "UpdateRoles", + Handler: _AuthService_UpdateRoles_Handler, + }, + { + MethodName: "DeletePermissionsForRole", + Handler: _AuthService_DeletePermissionsForRole_Handler, + }, + { + MethodName: "DeleteRoles", + Handler: _AuthService_DeleteRoles_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "gosdn/rbac/rbac.proto", diff --git a/api/openapiv2/gosdn_northbound.swagger.json b/api/openapiv2/gosdn_northbound.swagger.json index d7787740e..95b7be710 100644 --- a/api/openapiv2/gosdn_northbound.swagger.json +++ b/api/openapiv2/gosdn_northbound.swagger.json @@ -809,15 +809,80 @@ ] } }, - "/users": { + "/roles": { "get": { - "summary": "Requests information about available users, requires login beforehand.\nRequires highest possible permissions.", - "operationId": "AuthService_GetUsers", + "summary": "Requests all roles with their permissions, requires login beforehand.\nRequires highest permissions.", + "operationId": "AuthService_GetRoles", "responses": { "200": { "description": "A successful response.", "schema": { - "$ref": "#/definitions/rbacGetUsersResponse" + "$ref": "#/definitions/rbacGetRolesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "timestamp", + "in": "query", + "required": false, + "type": "string", + "format": "int64" + } + ], + "tags": [ + "AuthService" + ] + } + }, + "/roles/create": { + "post": { + "summary": "Creates roles, requires login beforehand.\nRequires highest permissions.", + "operationId": "AuthService_CreateRoles", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/rbacCreateRolesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/rbacCreateRolesRequest" + } + } + ], + "tags": [ + "AuthService" + ] + } + }, + "/roles/delete": { + "delete": { + "summary": "Deletes roles with their permissions, requires login beforehand.\nRequires highest permissions.", + "operationId": "AuthService_DeleteRoles", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/rbacDeleteRolesResponse" } }, "default": { @@ -836,7 +901,97 @@ "format": "int64" }, { - "name": "token", + "name": "roleName", + "in": "query", + "required": false, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi" + } + ], + "tags": [ + "AuthService" + ] + } + }, + "/roles/delete/permissions": { + "delete": { + "summary": "Deletes permissions from given role, requires login beforehand.\nRequires highest permissions.", + "operationId": "AuthService_DeletePermissionsForRole", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/rbacDeletePermissionsForRoleResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "timestamp", + "in": "query", + "required": false, + "type": "string", + "format": "int64" + }, + { + "name": "roleName", + "in": "query", + "required": false, + "type": "string" + }, + { + "name": "permissionsToDelete", + "in": "query", + "required": false, + "type": "array", + "items": { + "type": "string" + }, + "collectionFormat": "multi" + } + ], + "tags": [ + "AuthService" + ] + } + }, + "/roles/get": { + "get": { + "summary": "Requests one role with its permissions, requires login beforehand.\nRequires highest permissions.", + "operationId": "AuthService_GetRole", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/rbacGetRoleResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "timestamp", + "in": "query", + "required": false, + "type": "string", + "format": "int64" + }, + { + "name": "roleName", "in": "query", "required": false, "type": "string" @@ -847,6 +1002,71 @@ ] } }, + "/roles/update": { + "post": { + "summary": "Updates roles by setting the provided permissions, requires login beforehand.\nRequires highest permissions.", + "operationId": "AuthService_UpdateRoles", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/rbacUpdateRolesResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/rbacUpdateRolesRequest" + } + } + ], + "tags": [ + "AuthService" + ] + } + }, + "/users": { + "get": { + "summary": "Requests information about available users, requires login beforehand.\nRequires highest possible permissions.", + "operationId": "AuthService_GetUsers", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/rbacGetUsersResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "timestamp", + "in": "query", + "required": false, + "type": "string", + "format": "int64" + } + ], + "tags": [ + "AuthService" + ] + } + }, "/users/create": { "post": { "summary": "Create users with the provided parameters, creation of multiple users requires login beforehand.\nHighest possible permissions of new users is of current permission level.\nIf not logged in: Created user has lowest possible permissions, only one user can be created this way.", @@ -922,9 +1142,47 @@ ] } }, + "/users/get": { + "get": { + "summary": "Requests information about one user, requires login beforehand.option", + "operationId": "AuthService_GetUser", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/rbacGetUserResponse" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/googlerpcStatus" + } + } + }, + "parameters": [ + { + "name": "timestamp", + "in": "query", + "required": false, + "type": "string", + "format": "int64" + }, + { + "name": "name", + "in": "query", + "required": false, + "type": "string" + } + ], + "tags": [ + "AuthService" + ] + } + }, "/users/update": { "post": { - "summary": "Updates users with the provided parameters, requires login beforehand.\nRequires highest permissions to change other users, everyone else can only update their own account.\n// Requires highest permissions to change multiple users at the same time.", + "summary": "Updates users with the provided parameters, requires login beforehand.\nRequires highest permissions to change other users, everyone else can only update their own account.\nRequires highest permissions to change multiple users at the same time.", "operationId": "AuthService_UpdateUsers", "responses": { "200": { @@ -2229,6 +2487,26 @@ ], "default": "STATUS_UNSPECIFIED" }, + "gosdnrbacRole": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "permissions": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "gosdnrbacStatus": { "type": "string", "enum": [ @@ -2620,6 +2898,34 @@ "additionalProperties": {}, "description": "`Any` contains an arbitrary serialized protocol buffer message along with a\nURL that describes the type of the serialized message.\n\nProtobuf library provides support to pack/unpack Any values in the form\nof utility functions or additional generated methods of the Any type.\n\nExample 1: Pack and unpack a message in C++.\n\n Foo foo = ...;\n Any any;\n any.PackFrom(foo);\n ...\n if (any.UnpackTo(\u0026foo)) {\n ...\n }\n\nExample 2: Pack and unpack a message in Java.\n\n Foo foo = ...;\n Any any = Any.pack(foo);\n ...\n if (any.is(Foo.class)) {\n foo = any.unpack(Foo.class);\n }\n\n Example 3: Pack and unpack a message in Python.\n\n foo = Foo(...)\n any = Any()\n any.Pack(foo)\n ...\n if any.Is(Foo.DESCRIPTOR):\n any.Unpack(foo)\n ...\n\n Example 4: Pack and unpack a message in Go\n\n foo := \u0026pb.Foo{...}\n any, err := anypb.New(foo)\n if err != nil {\n ...\n }\n ...\n foo := \u0026pb.Foo{}\n if err := any.UnmarshalTo(foo); err != nil {\n ...\n }\n\nThe pack methods provided by protobuf library will by default use\n'type.googleapis.com/full.type.name' as the type URL and the unpack\nmethods only use the fully qualified type name after the last '/'\nin the type URL, for example \"foo.bar.com/x/y.z\" will yield type\nname \"y.z\".\n\n\nJSON\n====\nThe JSON representation of an `Any` value uses the regular\nrepresentation of the deserialized, embedded message, with an\nadditional field `@type` which contains the type URL. Example:\n\n package google.profile;\n message Person {\n string first_name = 1;\n string last_name = 2;\n }\n\n {\n \"@type\": \"type.googleapis.com/google.profile.Person\",\n \"firstName\": \u003cstring\u003e,\n \"lastName\": \u003cstring\u003e\n }\n\nIf the embedded message type is well-known and has a custom JSON\nrepresentation, that representation will be embedded adding a field\n`value` which holds the custom JSON in addition to the `@type`\nfield. Example (for message [google.protobuf.Duration][]):\n\n {\n \"@type\": \"type.googleapis.com/google.protobuf.Duration\",\n \"value\": \"1.212s\"\n }" }, + "rbacCreateRolesRequest": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "roles": { + "type": "array", + "items": { + "$ref": "#/definitions/gosdnrbacRole" + } + } + }, + "title": "CreateRoles" + }, + "rbacCreateRolesResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "status": { + "$ref": "#/definitions/gosdnrbacStatus" + } + } + }, "rbacCreateUsersRequest": { "type": "object", "properties": { @@ -2648,6 +2954,30 @@ } } }, + "rbacDeletePermissionsForRoleResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "status": { + "$ref": "#/definitions/gosdnrbacStatus" + } + } + }, + "rbacDeleteRolesResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "status": { + "$ref": "#/definitions/gosdnrbacStatus" + } + } + }, "rbacDeleteUsersResponse": { "type": "object", "properties": { @@ -2660,6 +2990,54 @@ } } }, + "rbacGetRoleResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "status": { + "$ref": "#/definitions/gosdnrbacStatus" + }, + "role": { + "$ref": "#/definitions/gosdnrbacRole" + } + } + }, + "rbacGetRolesResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "status": { + "$ref": "#/definitions/gosdnrbacStatus" + }, + "roles": { + "type": "array", + "items": { + "$ref": "#/definitions/gosdnrbacRole" + } + } + } + }, + "rbacGetUserResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "status": { + "$ref": "#/definitions/gosdnrbacStatus" + }, + "user": { + "$ref": "#/definitions/rbacUser" + } + } + }, "rbacGetUsersResponse": { "type": "object", "properties": { @@ -2721,6 +3099,34 @@ } } }, + "rbacUpdateRolesRequest": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "roles": { + "type": "array", + "items": { + "$ref": "#/definitions/gosdnrbacRole" + } + } + }, + "title": "UpdateRoles" + }, + "rbacUpdateRolesResponse": { + "type": "object", + "properties": { + "timestamp": { + "type": "string", + "format": "int64" + }, + "status": { + "$ref": "#/definitions/gosdnrbacStatus" + } + } + }, "rbacUpdateUsersRequest": { "type": "object", "properties": { @@ -2750,14 +3156,27 @@ } }, "rbacUser": { - "type": "string", - "enum": [ - "USER_UNSPECIFIED", - "USER_NAME", - "USER_PWD" - ], - "default": "USER_UNSPECIFIED", - "title": "TODO: add additional data to user enum" + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roles": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "password": { + "type": "string" + }, + "token": { + "type": "string" + } + } }, "southboundSouthboundInterface": { "type": "object", diff --git a/api/proto/buf.lock b/api/proto/buf.lock index 184246005..cbd6cb43b 100644 --- a/api/proto/buf.lock +++ b/api/proto/buf.lock @@ -4,7 +4,7 @@ deps: - remote: buf.build owner: googleapis repository: googleapis - commit: 0f45818f23164927b753ca450a5ed5bf + commit: b6631422c6964600bf3bdd9bf09c6636 - remote: buf.build owner: grpc-ecosystem repository: grpc-gateway diff --git a/api/proto/gosdn/rbac/rbac.proto b/api/proto/gosdn/rbac/rbac.proto index 9145b8d64..6208518c6 100644 --- a/api/proto/gosdn/rbac/rbac.proto +++ b/api/proto/gosdn/rbac/rbac.proto @@ -35,6 +35,13 @@ service AuthService { }; } + // Requests information about one user, requires login beforehand.option + rpc GetUser (GetUserRequest) returns (GetUserResponse) { + option (google.api.http) = { + get: "/users/get" + }; + } + // Requests information about available users, requires login beforehand. // Requires highest possible permissions. rpc GetUsers (GetUsersRequest) returns (GetUsersResponse) { @@ -45,7 +52,7 @@ service AuthService { // Updates users with the provided parameters, requires login beforehand. // Requires highest permissions to change other users, everyone else can only update their own account. - // // Requires highest permissions to change multiple users at the same time. + // Requires highest permissions to change multiple users at the same time. rpc UpdateUsers (UpdateUsersRequest) returns (UpdateUsersResponse) { option (google.api.http) = { post: "/users/update" @@ -61,6 +68,55 @@ service AuthService { }; } + // Creates roles, requires login beforehand. + // Requires highest permissions. + rpc CreateRoles(CreateRolesRequest) returns (CreateRolesResponse) { + option (google.api.http) = { + post: "/roles/create" + body: "*" + }; + } + + // Requests one role with its permissions, requires login beforehand. + // Requires highest permissions. + rpc GetRole(GetRoleRequest) returns (GetRoleResponse) { + option (google.api.http) = { + get: "/roles/get" + }; + } + + // Requests all roles with their permissions, requires login beforehand. + // Requires highest permissions. + rpc GetRoles(GetRolesRequest) returns (GetRolesResponse) { + option (google.api.http) = { + get: "/roles" + }; + } + + // Updates roles by setting the provided permissions, requires login beforehand. + // Requires highest permissions. + rpc UpdateRoles(UpdateRolesRequest) returns (UpdateRolesResponse) { + option (google.api.http) = { + post: "/roles/update" + body: "*" + }; + } + + // Deletes permissions from given role, requires login beforehand. + // Requires highest permissions. + rpc DeletePermissionsForRole(DeletePermissionsForRoleRequest) returns (DeletePermissionsForRoleResponse) { + option (google.api.http) = { + delete: "/roles/delete/permissions" + }; + } + + // Deletes roles with their permissions, requires login beforehand. + // Requires highest permissions. + rpc DeleteRoles(DeleteRolesRequest) returns (DeleteRolesResponse) { + option (google.api.http) = { + delete: "/roles/delete" + }; + } } enum Status { @@ -69,12 +125,19 @@ enum Status { STATUS_ERROR = 2; } -// TODO: add additional data to user enum -enum User { - USER_UNSPECIFIED = 0; - USER_NAME = 1; - USER_PWD = 2; - // ... +message User { + string id = 1; + string name = 2; + map<string, string> roles = 3; // Key = pnd uuid, value= role name + string password = 4; + string token = 5; +} + +message Role { + string id = 1; + string name = 2; + string description = 3; + repeated string permissions = 4; } // Login @@ -112,10 +175,21 @@ message CreateUsersResponse { Status status = 2; } +// GetUser +message GetUserRequest { + int64 timestamp = 1; + string name = 2; +} + +message GetUserResponse { + int64 timestamp = 1; + Status status = 2; + User user = 3; +} + // GetUsers message GetUsersRequest { int64 timestamp = 1; - string token = 2; } message GetUsersResponse { @@ -145,3 +219,71 @@ message DeleteUsersResponse { int64 timestamp = 1; Status status = 2; } + +// CreateRoles +message CreateRolesRequest { + int64 timestamp = 1; + repeated Role roles = 2; +} + +message CreateRolesResponse { + int64 timestamp = 1; + Status status = 2; +} + +// GetRole +message GetRoleRequest { + int64 timestamp = 1; + string role_name = 2; +} + +message GetRoleResponse { + int64 timestamp = 1; + Status status = 2; + Role role = 3; +} + +// GetRoles +message GetRolesRequest { + int64 timestamp = 1; +} + +message GetRolesResponse { + int64 timestamp = 1; + Status status = 2; + repeated Role roles = 3; +} + +// UpdateRoles +message UpdateRolesRequest { + int64 timestamp = 1; + repeated Role roles = 2; +} + +message UpdateRolesResponse { + int64 timestamp = 1; + Status status = 2; +} + +// DeletePermissionsForRole +message DeletePermissionsForRoleRequest { + int64 timestamp = 1; + string role_name = 2; + repeated string permissions_to_delete = 3; +} + +message DeletePermissionsForRoleResponse { + int64 timestamp = 1; + Status status = 2; +} + +// DeleteRoles +message DeleteRolesRequest { + int64 timestamp = 1; + repeated string role_name = 2; +} + +message DeleteRolesResponse { + int64 timestamp = 1; + Status status = 2; +} diff --git a/cli/adapter/PndAdapter.go b/cli/adapter/PndAdapter.go index e593d40f4..a03b5480b 100644 --- a/cli/adapter/PndAdapter.go +++ b/cli/adapter/PndAdapter.go @@ -1,6 +1,8 @@ package adapter import ( + "context" + "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/core" ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd" spb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/southbound" @@ -48,8 +50,8 @@ func (p *PndAdapter) RemoveSbi(uuid.UUID) error { // AddDevice adds a new device to the controller. The device name is optional. // If no name is provided a name will be generated upon device creation. -func (p *PndAdapter) AddDevice(name string, opts *tpb.TransportOption, sid uuid.UUID) (*ppb.SetOndListResponse, error) { - resp, err := api.AddDevice(p.endpoint, name, opts, sid, p.ID()) +func (p *PndAdapter) AddDevice(ctx context.Context, name string, opts *tpb.TransportOption, sid uuid.UUID) (*ppb.SetOndListResponse, error) { + resp, err := api.AddDevice(ctx, p.endpoint, name, opts, sid, p.ID()) if err != nil { return nil, err } @@ -57,8 +59,8 @@ func (p *PndAdapter) AddDevice(name string, opts *tpb.TransportOption, sid uuid. } // GetSbiSchemaTree requests a sbi schema tree. -func (p *PndAdapter) GetSbiSchemaTree(sid uuid.UUID) (map[string]*yang.Entry, error) { - resp, err := api.GetSbiSchemaTree(p.Endpoint(), p.ID(), sid) +func (p *PndAdapter) GetSbiSchemaTree(ctx context.Context, sid uuid.UUID) (map[string]*yang.Entry, error) { + resp, err := api.GetSbiSchemaTree(ctx, p.Endpoint(), p.ID(), sid) if err != nil { return nil, err } @@ -67,8 +69,8 @@ func (p *PndAdapter) GetSbiSchemaTree(sid uuid.UUID) (map[string]*yang.Entry, er // GetDevice requests one or multiple devices belonging to a given // PrincipalNetworkDomain from the controller. -func (p *PndAdapter) GetDevice(identifier ...string) ([]*ppb.OrchestratedNetworkingDevice, error) { - resp, err := api.GetDevice(p.endpoint, p.id.String(), identifier...) +func (p *PndAdapter) GetDevice(ctx context.Context, identifier ...string) ([]*ppb.OrchestratedNetworkingDevice, error) { + resp, err := api.GetDevice(ctx, p.endpoint, p.id.String(), identifier...) if err != nil { return nil, err } @@ -77,8 +79,8 @@ func (p *PndAdapter) GetDevice(identifier ...string) ([]*ppb.OrchestratedNetwork // GetDevices requests all devices belonging to the PrincipalNetworkDomain // attached to this adapter. -func (p *PndAdapter) GetDevices() ([]*ppb.OrchestratedNetworkingDevice, error) { - resp, err := api.GetDevices(p.endpoint, p.id.String()) +func (p *PndAdapter) GetDevices(ctx context.Context) ([]*ppb.OrchestratedNetworkingDevice, error) { + resp, err := api.GetDevices(ctx, p.endpoint, p.id.String()) if err != nil { return nil, err } @@ -86,8 +88,8 @@ func (p *PndAdapter) GetDevices() ([]*ppb.OrchestratedNetworkingDevice, error) { } // RemoveDevice removes a device from the controller -func (p *PndAdapter) RemoveDevice(did uuid.UUID) (*ppb.DeleteOndResponse, error) { - resp, err := api.DeleteDevice(p.endpoint, p.id.String(), did.String()) +func (p *PndAdapter) RemoveDevice(ctx context.Context, did uuid.UUID) (*ppb.DeleteOndResponse, error) { + resp, err := api.DeleteDevice(ctx, p.endpoint, p.id.String(), did.String()) if err != nil { return nil, err } @@ -95,8 +97,8 @@ func (p *PndAdapter) RemoveDevice(did uuid.UUID) (*ppb.DeleteOndResponse, error) } // RemovePnd removes a PND from the controller -func (p *PndAdapter) RemovePnd(pid uuid.UUID) (*core.DeletePndResponse, error) { - resp, err := api.DeletePnd(p.endpoint, pid.String()) +func (p *PndAdapter) RemovePnd(ctx context.Context, pid uuid.UUID) (*core.DeletePndResponse, error) { + resp, err := api.DeletePnd(ctx, p.endpoint, pid.String()) if err != nil { return nil, err } @@ -106,12 +108,12 @@ func (p *PndAdapter) RemovePnd(pid uuid.UUID) (*core.DeletePndResponse, error) { // ChangeOND sends an API call to the controller requesting the creation of // a change from the provided Operation, path and value. The Change is marked // as Pending and times out after the specified timeout period -func (p *PndAdapter) ChangeOND(duid uuid.UUID, operation ppb.ApiOperation, path string, value ...string) (uuid.UUID, error) { +func (p *PndAdapter) ChangeOND(ctx context.Context, duid uuid.UUID, operation ppb.ApiOperation, path string, value ...string) (uuid.UUID, error) { var v string if len(value) != 0 { v = value[0] } - resp, err := api.ChangeRequest(p.endpoint, duid.String(), p.id.String(), path, v, operation) + resp, err := api.ChangeRequest(ctx, p.endpoint, duid.String(), p.id.String(), path, v, operation) if err != nil { return uuid.Nil, err } @@ -121,8 +123,8 @@ func (p *PndAdapter) ChangeOND(duid uuid.UUID, operation ppb.ApiOperation, path // Request sends an API call to the controller requesting the specified path // for the specified device -func (p *PndAdapter) Request(did uuid.UUID, path string) (proto.Message, error) { - resp, err := api.GetPath(p.endpoint, p.id.String(), did.String(), path) +func (p *PndAdapter) Request(ctx context.Context, did uuid.UUID, path string) (proto.Message, error) { + resp, err := api.GetPath(ctx, p.endpoint, p.id.String(), did.String(), path) if err != nil { return nil, err } @@ -131,8 +133,8 @@ func (p *PndAdapter) Request(did uuid.UUID, path string) (proto.Message, error) // RequestAll sends an API call to the controller requesting the specified path // for all registered devices. Not yet implemented. -func (p *PndAdapter) RequestAll(path string) ([]proto.Message, error) { - resp, err := api.GetDevices(p.Endpoint(), p.ID().String()) +func (p *PndAdapter) RequestAll(ctx context.Context, path string) ([]proto.Message, error) { + resp, err := api.GetDevices(ctx, p.Endpoint(), p.ID().String()) if err != nil { return []proto.Message{}, err } @@ -143,7 +145,7 @@ func (p *PndAdapter) RequestAll(path string) ([]proto.Message, error) { // TODO: probably the controller should do this; this would result in a // single request from CLI side. g.Go(func() error { - resp, err := api.GetPath(p.endpoint, p.id.String(), ond.GetId(), path) + resp, err := api.GetPath(ctx, p.endpoint, p.id.String(), ond.GetId(), path) if err != nil { return err } @@ -167,8 +169,8 @@ func (p *PndAdapter) ContainsDevice(uuid.UUID) bool { // GetSbi sends an API call to the controller requesting the // registered SBI with the provided ID. -func (p *PndAdapter) GetSbi(sid ...string) ([]*spb.SouthboundInterface, error) { - resp, err := api.GetSbi(p.endpoint, p.id.String(), sid...) +func (p *PndAdapter) GetSbi(ctx context.Context, sid ...string) ([]*spb.SouthboundInterface, error) { + resp, err := api.GetSbi(ctx, p.endpoint, p.id.String(), sid...) if err != nil { return nil, err } @@ -177,8 +179,8 @@ func (p *PndAdapter) GetSbi(sid ...string) ([]*spb.SouthboundInterface, error) { // GetSBIs sends an API call to the controller requesting the // registered SBIs. Not implemented, always returns nil -func (p *PndAdapter) GetSBIs() ([]*spb.SouthboundInterface, error) { - resp, err := api.GetSBIs(p.endpoint, p.id.String()) +func (p *PndAdapter) GetSBIs(ctx context.Context) ([]*spb.SouthboundInterface, error) { + resp, err := api.GetSBIs(ctx, p.endpoint, p.id.String()) if err != nil { return nil, err } @@ -197,8 +199,8 @@ func (p *PndAdapter) Endpoint() string { // PendingChanges sends an API call to the controller requesting // the UUIDs of all pending changes -func (p *PndAdapter) PendingChanges() []uuid.UUID { - resp, err := api.GetChanges(p.endpoint, p.id.String()) +func (p *PndAdapter) PendingChanges(ctx context.Context) []uuid.UUID { + resp, err := api.GetChanges(ctx, p.endpoint, p.id.String()) if err != nil { log.Error(err) return nil @@ -208,8 +210,8 @@ func (p *PndAdapter) PendingChanges() []uuid.UUID { // CommittedChanges sends an API call to the controller requesting // the UUIDs of all committed changes -func (p *PndAdapter) CommittedChanges() []uuid.UUID { - resp, err := api.GetChanges(p.endpoint, p.id.String()) +func (p *PndAdapter) CommittedChanges(ctx context.Context) []uuid.UUID { + resp, err := api.GetChanges(ctx, p.endpoint, p.id.String()) if err != nil { log.Error(err) return nil @@ -223,8 +225,8 @@ func (p *PndAdapter) GetChange(uuid.UUID) (change.Change, error) { } // Commit sends an API call to the controller committing the specified change -func (p *PndAdapter) Commit(cuid uuid.UUID) error { - resp, err := api.Commit(p.endpoint, p.id.String(), cuid.String()) +func (p *PndAdapter) Commit(ctx context.Context, cuid uuid.UUID) error { + resp, err := api.Commit(ctx, p.endpoint, p.id.String(), cuid.String()) if err != nil { return err } @@ -233,8 +235,8 @@ func (p *PndAdapter) Commit(cuid uuid.UUID) error { } // Confirm sends an API call to the controller confirming the specified change -func (p *PndAdapter) Confirm(cuid uuid.UUID) error { - resp, err := api.Confirm(p.endpoint, p.id.String(), cuid.String()) +func (p *PndAdapter) Confirm(ctx context.Context, cuid uuid.UUID) error { + resp, err := api.Confirm(ctx, p.endpoint, p.id.String(), cuid.String()) if err != nil { return err } diff --git a/cli/adapter/PndAdapter_test.go b/cli/adapter/PndAdapter_test.go index 6cccc3512..2f5b1612a 100644 --- a/cli/adapter/PndAdapter_test.go +++ b/cli/adapter/PndAdapter_test.go @@ -1,6 +1,7 @@ package adapter import ( + "context" "reflect" "testing" @@ -123,7 +124,7 @@ func TestPndAdapter_AddDevice(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - if _, err := p.AddDevice(tt.args.name, tt.args.opts, tt.args.sid); (err != nil) != tt.wantErr { + if _, err := p.AddDevice(context.TODO(), tt.args.name, tt.args.opts, tt.args.sid); (err != nil) != tt.wantErr { t.Errorf("PndAdapter.AddDevice() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -153,7 +154,7 @@ func TestPndAdapter_GetDevice(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - got, err := p.GetDevice(tt.args.identifier) + got, err := p.GetDevice(context.TODO(), tt.args.identifier) if (err != nil) != tt.wantErr { t.Errorf("PndAdapter.GetDevice() error = %v, wantErr %v", err, tt.wantErr) return @@ -187,7 +188,7 @@ func TestPndAdapter_RemoveDevice(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - if _, err := p.RemoveDevice(tt.args.did); (err != nil) != tt.wantErr { + if _, err := p.RemoveDevice(context.TODO(), tt.args.did); (err != nil) != tt.wantErr { t.Errorf("PndAdapter.RemoveDevice() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -219,7 +220,7 @@ func TestPndAdapter_ChangeOND(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - _, err := p.ChangeOND(tt.args.uuid, tt.args.operation, tt.args.path, tt.args.value...) + _, err := p.ChangeOND(context.TODO(), tt.args.uuid, tt.args.operation, tt.args.path, tt.args.value...) if (err != nil) != tt.wantErr { t.Errorf("PndAdapter.ChangeOND() error = %v, wantErr %v", err, tt.wantErr) } @@ -250,7 +251,7 @@ func TestPndAdapter_Request(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - _, err := p.Request(tt.args.did, tt.args.path) + _, err := p.Request(context.TODO(), tt.args.did, tt.args.path) if (err != nil) != tt.wantErr { t.Errorf("PndAdapter.Request() error = %v, wantErr %v", err, tt.wantErr) } @@ -280,7 +281,7 @@ func TestPndAdapter_RequestAll(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - if _, err := p.RequestAll(tt.args.in0); (err != nil) != tt.wantErr { + if _, err := p.RequestAll(context.TODO(), tt.args.in0); (err != nil) != tt.wantErr { t.Errorf("PndAdapter.RequestAll() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -334,7 +335,7 @@ func TestPndAdapter_GetSBIs(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - if got, _ := p.GetSBIs(); !reflect.DeepEqual(got, tt.want) { + if got, _ := p.GetSBIs(context.TODO()); !reflect.DeepEqual(got, tt.want) { t.Errorf("PndAdapter.GetSBIs() = %v, want %v", got, tt.want) } }) @@ -384,7 +385,7 @@ func TestPndAdapter_PendingChanges(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - if got := p.PendingChanges(); !reflect.DeepEqual(got, tt.want) { + if got := p.PendingChanges(context.TODO()); !reflect.DeepEqual(got, tt.want) { t.Errorf("PndAdapter.PendingChanges() = %v, want %v", got, tt.want) } }) @@ -409,7 +410,7 @@ func TestPndAdapter_CommittedChanges(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - if got := p.CommittedChanges(); !reflect.DeepEqual(got, tt.want) { + if got := p.CommittedChanges(context.TODO()); !reflect.DeepEqual(got, tt.want) { t.Errorf("PndAdapter.CommittedChanges() = %v, want %v", got, tt.want) } }) @@ -473,7 +474,7 @@ func TestPndAdapter_Commit(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - if err := p.Commit(tt.args.cuid); (err != nil) != tt.wantErr { + if err := p.Commit(context.TODO(), tt.args.cuid); (err != nil) != tt.wantErr { t.Errorf("PndAdapter.Commit() error = %v, wantErr %v", err, tt.wantErr) } }) @@ -502,7 +503,7 @@ func TestPndAdapter_Confirm(t *testing.T) { id: tt.fields.id, endpoint: tt.fields.endpoint, } - if err := p.Confirm(tt.args.cuid); (err != nil) != tt.wantErr { + if err := p.Confirm(context.TODO(), tt.args.cuid); (err != nil) != tt.wantErr { t.Errorf("PndAdapter.Confirm() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/cli/cmd/changeCommit.go b/cli/cmd/changeCommit.go index 49798b98d..8bdc0ea41 100644 --- a/cli/cmd/changeCommit.go +++ b/cli/cmd/changeCommit.go @@ -50,7 +50,7 @@ Change UUID must be specified as positional argument.`, if err != nil { log.Fatal(err) } - if err := pndAdapter.Commit(cuid); err != nil { + if err := pndAdapter.Commit(createContextWithAuthorization(), cuid); err != nil { log.Fatal(err) } }, diff --git a/cli/cmd/changeConfirm.go b/cli/cmd/changeConfirm.go index 3818fc4ea..4fa511580 100644 --- a/cli/cmd/changeConfirm.go +++ b/cli/cmd/changeConfirm.go @@ -50,7 +50,7 @@ Change UUID must be specified as positional argument`, if err != nil { log.Fatal(err) } - if err := pndAdapter.Confirm(cuid); err != nil { + if err := pndAdapter.Confirm(createContextWithAuthorization(), cuid); err != nil { log.Fatal(err) } }, diff --git a/cli/cmd/changeList.go b/cli/cmd/changeList.go index f11a6274a..dcd3dc4f4 100644 --- a/cli/cmd/changeList.go +++ b/cli/cmd/changeList.go @@ -44,12 +44,12 @@ var changeListCmd = &cobra.Command{ Long: `Lists all configuration changes with their UUIDs.`, Run: func(cmd *cobra.Command, args []string) { - committed := pndAdapter.CommittedChanges() + committed := pndAdapter.CommittedChanges(createContextWithAuthorization()) log.Info("committed changes:") for i, ch := range committed { log.Infof(" Change %v: %v", i+1, ch.String()) } - pending := pndAdapter.PendingChanges() + pending := pndAdapter.PendingChanges(createContextWithAuthorization()) log.Info("pending changes:") for i, ch := range pending { log.Infof(" Change %v: %v", i+1, ch.String()) diff --git a/cli/cmd/deviceCreate.go b/cli/cmd/deviceCreate.go index 86b430788..56781bf23 100644 --- a/cli/cmd/deviceCreate.go +++ b/cli/cmd/deviceCreate.go @@ -76,7 +76,7 @@ if they diverge from the default credentials (user:'admin' and pw:'arista').`, return err } - resp, err := pndAdapter.AddDevice(deviceName, opt, sid) + resp, err := pndAdapter.AddDevice(createContextWithAuthorization(), deviceName, opt, sid) if err != nil { return err } diff --git a/cli/cmd/deviceDelete.go b/cli/cmd/deviceDelete.go index 1dc333899..82769ea90 100644 --- a/cli/cmd/deviceDelete.go +++ b/cli/cmd/deviceDelete.go @@ -52,6 +52,7 @@ The device UUID and request path must be specified as a positional arguments.`, log.Fatal(err) } log.Info(pndAdapter.ChangeOND( + createContextWithAuthorization(), did, ppb.ApiOperation_API_OPERATION_DELETE, args[1], diff --git a/cli/cmd/deviceGet.go b/cli/cmd/deviceGet.go index feb2c5c2d..0bbaaff0b 100644 --- a/cli/cmd/deviceGet.go +++ b/cli/cmd/deviceGet.go @@ -53,6 +53,7 @@ The device UUID and request path must be specified as a positional arguments.`, } message, err := pndAdapter.Request( + createContextWithAuthorization(), did, args[1], ) diff --git a/cli/cmd/deviceList.go b/cli/cmd/deviceList.go index 3ad626279..3e0d7408f 100644 --- a/cli/cmd/deviceList.go +++ b/cli/cmd/deviceList.go @@ -46,7 +46,7 @@ var deviceListCmd = &cobra.Command{ Long: "List all orchestrated network devices within the current PND.", RunE: func(cmd *cobra.Command, args []string) error { - respONDs, err := pndAdapter.GetDevices() + respONDs, err := pndAdapter.GetDevices(createContextWithAuthorization()) if err != nil { return err } @@ -57,7 +57,7 @@ var deviceListCmd = &cobra.Command{ if err != nil { return err } - tree, err := pndAdapter.GetSbiSchemaTree(sid) + tree, err := pndAdapter.GetSbiSchemaTree(createContextWithAuthorization(), sid) if err != nil { return err } diff --git a/cli/cmd/deviceRemove.go b/cli/cmd/deviceRemove.go index a076819b0..37170c2de 100644 --- a/cli/cmd/deviceRemove.go +++ b/cli/cmd/deviceRemove.go @@ -52,7 +52,7 @@ The device UUID must be specified as a positional argument.`, if err != nil { return err } - resp, err := pndAdapter.RemoveDevice(did) + resp, err := pndAdapter.RemoveDevice(createContextWithAuthorization(), did) if err != nil { return err } diff --git a/cli/cmd/deviceSet.go b/cli/cmd/deviceSet.go index 257b0e831..a8088d34a 100644 --- a/cli/cmd/deviceSet.go +++ b/cli/cmd/deviceSet.go @@ -65,6 +65,7 @@ To enable replacing behaviour (destructive!), set the --replace flag."`, log.Info("Update") } log.Info(pndAdapter.ChangeOND( + createContextWithAuthorization(), did, operation, args[1], diff --git a/cli/cmd/deviceShow.go b/cli/cmd/deviceShow.go index d6d495317..7fb419883 100644 --- a/cli/cmd/deviceShow.go +++ b/cli/cmd/deviceShow.go @@ -47,7 +47,7 @@ The device information returned is the information as currently stored in the co The actual device is not queried directly.`, Run: func(cmd *cobra.Command, args []string) { - log.Info(pndAdapter.GetDevice(args[0])) + log.Info(pndAdapter.GetDevice(createContextWithAuthorization(), args[0])) }, } diff --git a/cli/cmd/init.go b/cli/cmd/init.go index b23c67c46..f2d809e87 100644 --- a/cli/cmd/init.go +++ b/cli/cmd/init.go @@ -35,7 +35,6 @@ import ( "fmt" "os" - "code.fbi.h-da.de/danet/gosdn/controller/api" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -51,17 +50,7 @@ var initCmd = &cobra.Command{ The --controller flag is required to change the controller address`, RunE: func(cmd *cobra.Command, args []string) error { - if err := api.Init(viper.GetString("controllerAPIEndpoint")); err != nil { - return err - } - resp, err := api.GetSBIs(viper.GetString("controllerAPIEndpoint"), viper.GetString("CLI_PND")) - if err != nil { - return err - } - - sid := resp.Sbi[0].GetId() - viper.Set("CLI_SBI", sid) - log.Infof("SBI: %v", sid) + log.Infof("New controller address: %v", viper.GetString("controllerAPIEndpoint")) if err := viper.WriteConfig(); err != nil { fmt.Fprintln(os.Stderr, "Could not write config:", err) diff --git a/cli/cmd/list.go b/cli/cmd/list.go index 27fcf3135..f8d8bbb5a 100644 --- a/cli/cmd/list.go +++ b/cli/cmd/list.go @@ -49,12 +49,12 @@ var listCmd = &cobra.Command{ RunE: func(cmd *cobra.Command, args []string) error { addr := viper.GetString("controllerApiEndpoint") - resp, err := api.GetIds(addr) + resp, err := api.GetIds(createContextWithAuthorization(), addr) if err != nil { return err } for i, pnd := range resp { - ondResp, err := api.GetDevices(addr, pnd.GetId()) + ondResp, err := api.GetDevices(createContextWithAuthorization(), addr, pnd.GetId()) if err != nil { return err } diff --git a/cli/cmd/login.go b/cli/cmd/login.go index d8a1891ec..3d9aba572 100644 --- a/cli/cmd/login.go +++ b/cli/cmd/login.go @@ -32,6 +32,8 @@ POSSIBILITY OF SUCH DAMAGE. package cmd import ( + "context" + "code.fbi.h-da.de/danet/gosdn/controller/api" log "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -46,33 +48,36 @@ var loginCmd = &cobra.Command{ User credentials need to be provided in the body`, RunE: func(cmd *cobra.Command, args []string) error { - resp, err := api.Login(viper.GetString("controllerAPIEndpoint"), nbUser, nbUserPwd) + // TODO: maybe add credentials in context instead of context.TODO() + resp, err := api.Login(context.TODO(), viper.GetString("controllerAPIEndpoint"), nbUserName, nbUserPwd) if err != nil { return err } - // TODO: set token here - log.Info("LoginResponse: " + resp.Token) + userToken = resp.Token + + if err := api.Init(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint")); err != nil { + return err + } + + sbiResp, err := api.GetSBIs(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), viper.GetString("CLI_PND")) + if err != nil { + return err + } + sid := sbiResp.Sbi[0].GetId() + viper.Set("CLI_SBI", sid) + log.Infof("SBI: %v", sid) return nil }, } -var nbUser string +var nbUserName string var nbUserPwd string func init() { rootCmd.AddCommand(loginCmd) - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // loginCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // loginCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") - loginCmd.Flags().StringVar(&nbUser, "u", "", "username for login") + loginCmd.Flags().StringVar(&nbUserName, "u", "", "username for login") loginCmd.Flags().StringVar(&nbUserPwd, "p", "", "pwd for login") } diff --git a/cli/cmd/logout.go b/cli/cmd/logout.go index 3fd3ac068..a797c80e5 100644 --- a/cli/cmd/logout.go +++ b/cli/cmd/logout.go @@ -45,7 +45,7 @@ var logoutCmd = &cobra.Command{ Long: `Logs the current user out. Further actions on the controller are not permitted after this.`, RunE: func(cmd *cobra.Command, args []string) error { - resp, err := api.Logout(viper.GetString("controllerAPIEndpoint"), nbUser) + resp, err := api.Logout(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), nbUserName) if err != nil { return err } @@ -60,14 +60,5 @@ var logoutCmd = &cobra.Command{ func init() { rootCmd.AddCommand(logoutCmd) - // Here you will define your flags and configuration settings. - - // Cobra supports Persistent Flags which will work for this command - // and all subcommands, e.g.: - // loginCmd.PersistentFlags().String("foo", "", "A help for foo") - - // Cobra supports local flags which will only run when this command - // is called directly, e.g.: - // loginCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") - logoutCmd.Flags().StringVar(&nbUser, "u", "", "username for logout") + logoutCmd.Flags().StringVar(&nbUserName, "u", "", "username for logout") } diff --git a/cli/cmd/pndCreate.go b/cli/cmd/pndCreate.go index 9a0edf3ee..f08d429d2 100644 --- a/cli/cmd/pndCreate.go +++ b/cli/cmd/pndCreate.go @@ -52,7 +52,7 @@ A description must be passed as positional argument. A name and default SBI can passed using parameters.`, RunE: func(cmd *cobra.Command, args []string) error { - resp, err := api.AddPnd(viper.GetString("controllerApiEndpoint"), pndName, args[0], pndDefaultSbi) + resp, err := api.AddPnd(createContextWithAuthorization(), viper.GetString("controllerApiEndpoint"), pndName, args[0], pndDefaultSbi) if err != nil { return err } diff --git a/cli/cmd/pndGet.go b/cli/cmd/pndGet.go index ce8016a95..ef5e36a32 100644 --- a/cli/cmd/pndGet.go +++ b/cli/cmd/pndGet.go @@ -44,7 +44,7 @@ var pndGetCmd = &cobra.Command{ Long: `Get one or multiple PNDs by uuid or name and print them to stdout.`, RunE: func(cmd *cobra.Command, args []string) error { - resp, err := api.GetPnd(viper.GetString("controllerApiEndpoint"), args...) + resp, err := api.GetPnd(createContextWithAuthorization(), viper.GetString("controllerApiEndpoint"), args...) if err != nil { return err } diff --git a/cli/cmd/pndList.go b/cli/cmd/pndList.go index aa6608cb1..2f44d74b6 100644 --- a/cli/cmd/pndList.go +++ b/cli/cmd/pndList.go @@ -46,7 +46,8 @@ var pndListCmd = &cobra.Command{ Long: `List all information about the current PND.`, RunE: func(cmd *cobra.Command, args []string) error { - resp, err := api.GetPnd(pndAdapter.Endpoint(), pndAdapter.ID().String()) + + resp, err := api.GetPnd(createContextWithAuthorization(), pndAdapter.Endpoint(), pndAdapter.ID().String()) if err != nil { return err } diff --git a/cli/cmd/pndRemove.go b/cli/cmd/pndRemove.go index 6ff42079f..ed4890a75 100644 --- a/cli/cmd/pndRemove.go +++ b/cli/cmd/pndRemove.go @@ -50,7 +50,7 @@ var pndRemoveCmd = &cobra.Command{ if err != nil { return err } - resp, err := pndAdapter.RemovePnd(pid) + resp, err := pndAdapter.RemovePnd(createContextWithAuthorization(), pid) if err != nil { return err } diff --git a/cli/cmd/pndUse.go b/cli/cmd/pndUse.go index 5b3c34529..22be64cab 100644 --- a/cli/cmd/pndUse.go +++ b/cli/cmd/pndUse.go @@ -55,7 +55,7 @@ var pndUseCmd = &cobra.Command{ return err } - _, err = api.GetPnd(viper.GetString("controllerAPIEndpoint"), newPND) + _, err = api.GetPnd(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), newPND) if err != nil { log.Fatal(err) return err diff --git a/cli/cmd/prompt.go b/cli/cmd/prompt.go index f4828889d..e9704be94 100644 --- a/cli/cmd/prompt.go +++ b/cli/cmd/prompt.go @@ -131,7 +131,7 @@ func deviceGetCompletion(c *PromptCompleter, d prompt.Document, inputSplit []str if c, ok := c.yangSchemaCompleterMap[id]; ok { return c.Complete(d) } - dev, err := pndAdapter.GetDevice(id.String()) + dev, err := pndAdapter.GetDevice(createContextWithAuthorization(), id.String()) if err != nil { return []prompt.Suggest{} } @@ -139,7 +139,7 @@ func deviceGetCompletion(c *PromptCompleter, d prompt.Document, inputSplit []str if err != nil { return []prompt.Suggest{} } - schemaTree, err := pndAdapter.GetSbiSchemaTree(sid) + schemaTree, err := pndAdapter.GetSbiSchemaTree(createContextWithAuthorization(), sid) if err != nil { return []prompt.Suggest{} } diff --git a/cli/cmd/userCreate.go b/cli/cmd/userCreate.go new file mode 100644 index 000000000..0b64cad0f --- /dev/null +++ b/cli/cmd/userCreate.go @@ -0,0 +1,85 @@ +/* +Copyright © 2021 da/net Research Group <danet@h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/api" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// loginCmd represents the login command +var userCreateCmd = &cobra.Command{ + Use: "userCreate", + Short: "Creates a user with provided data", + Long: `Creates a user with provided data. + User name and password hashed with (add hash method here!) required, + role is optional but needed to operate on PNDs.`, + + RunE: func(cmd *cobra.Command, args []string) error { + + roles := map[string]string{} + // only active pnd for now, add option for additional param later + roles[viper.GetString("CLI_PND")] = nbUserRole + + //TODO(faseid): hash password + + // only one for now, add option to add more users at once later + users := []*apb.User{ + { + Name: nbUserName, + Password: nbUserPwd, + Roles: roles, + }, + } + + resp, err := api.CreateUsers(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), users) + if err != nil { + return err + } + log.Infof("Users created: %v", resp.Status) + + return nil + }, +} + +var nbUserRole string + +func init() { + rootCmd.AddCommand(userCreateCmd) + + userCreateCmd.Flags().StringVar(&nbUserName, "u", "", "username for login") + userCreateCmd.Flags().StringVar(&nbUserPwd, "p", "", "pwd for login") + userCreateCmd.Flags().StringVar(&nbUserRole, "r", "", "role for user") +} diff --git a/cli/cmd/userDelete.go b/cli/cmd/userDelete.go new file mode 100644 index 000000000..c8bfb2151 --- /dev/null +++ b/cli/cmd/userDelete.go @@ -0,0 +1,67 @@ +/* +Copyright © 2021 da/net Research Group <danet@h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/api" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// loginCmd represents the login command +var userDeleteCmd = &cobra.Command{ + Use: "userDelete", + Short: "Deletes a user with provided data", + Long: `Deletes a user with provided data. + Requires the user name of the user which should be deleted.`, + + RunE: func(cmd *cobra.Command, args []string) error { + + // only one user for now, add more later if needed + users := []string{nbUserName} + + resp, err := api.DeleteUsers(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), users) + if err != nil { + return err + } + log.Infof("Users deleted: %v", resp.Status) + + return nil + }, +} + +func init() { + rootCmd.AddCommand(userDeleteCmd) + + userDeleteCmd.Flags().StringVar(&nbUserName, "u", "", "username to delete") +} diff --git a/cli/cmd/userGet.go b/cli/cmd/userGet.go new file mode 100644 index 000000000..b5f1a0bd9 --- /dev/null +++ b/cli/cmd/userGet.go @@ -0,0 +1,66 @@ +/* +Copyright © 2021 da/net Research Group <danet@h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/api" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// loginCmd represents the login command +var userGetCmd = &cobra.Command{ + Use: "userGet", + Short: "Requests one user", + Long: `Requests one user using the provided name to search for it in the stored users.`, + + RunE: func(cmd *cobra.Command, args []string) error { + resp, err := api.GetUser(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), nbUserName) + if err != nil { + return err + } + + log.Infof("ID: %v, Name: %v \n", resp.User.Id, resp.User.Name) + for key, elem := range resp.User.Roles { + log.Infof("Role on PND: %v %v \n", key, elem) + } + + return nil + }, +} + +func init() { + rootCmd.AddCommand(userGetCmd) + + userGetCmd.Flags().StringVar(&nbUserName, "u", "", "username to find") +} diff --git a/cli/cmd/userGetAll.go b/cli/cmd/userGetAll.go new file mode 100644 index 000000000..e0719ef78 --- /dev/null +++ b/cli/cmd/userGetAll.go @@ -0,0 +1,66 @@ +/* +Copyright © 2021 da/net Research Group <danet@h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/api" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// loginCmd represents the login command +var userGetAllCmd = &cobra.Command{ + Use: "userGetAll", + Short: "Requests all the available users", + Long: `Requests all the available users.`, + + RunE: func(cmd *cobra.Command, args []string) error { + resp, err := api.GetAllUsers(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint")) + if err != nil { + return err + } + + for i, u := range resp.User { + log.Infof("User %v: ID: %v, Name: %v \n", i+1, u.Id, u.Name) + for key, elem := range u.Roles { + log.Infof("Role on PND: %v %v \n", key, elem) + } + } + + return nil + }, +} + +func init() { + rootCmd.AddCommand(userGetAllCmd) +} diff --git a/cli/cmd/userUpdate.go b/cli/cmd/userUpdate.go new file mode 100644 index 000000000..a85365a5b --- /dev/null +++ b/cli/cmd/userUpdate.go @@ -0,0 +1,87 @@ +/* +Copyright © 2021 da/net Research Group <danet@h-da.de> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +package cmd + +import ( + apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/api" + log "github.com/sirupsen/logrus" + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +// loginCmd represents the login command +var userUpdateCmd = &cobra.Command{ + Use: "userUpdate", + Short: "Updates a user with provided data", + Long: `Updates a user with provided data. + User name and password hashed with (add hash method here!) required, + role is optional but needed to operate on PNDs.`, + + RunE: func(cmd *cobra.Command, args []string) error { + + roles := map[string]string{} + // only active pnd for now, add option for additional param later + roles[viper.GetString("CLI_PND")] = nbUserRole + + //TODO(faseid): hash password + + // only one for now, add option to update more users at once later + users := []*apb.User{ + { + Id: nbUserID, + Name: nbUserName, + Password: nbUserPwd, + Roles: roles, + }, + } + + resp, err := api.UpdateUsers(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint"), users) + if err != nil { + return err + } + log.Infof("Users updated: %v", resp.Status) + + return nil + }, +} + +var nbUserID string + +func init() { + rootCmd.AddCommand(userUpdateCmd) + + userUpdateCmd.Flags().StringVar(&nbUserID, "i", "", "id of the user") + userUpdateCmd.Flags().StringVar(&nbUserName, "u", "", "username for login") + userUpdateCmd.Flags().StringVar(&nbUserPwd, "p", "", "pwd for login") + userUpdateCmd.Flags().StringVar(&nbUserRole, "r", "", "role for user") +} diff --git a/cli/cmd/utils.go b/cli/cmd/utils.go index 05a538af1..cf6a03780 100644 --- a/cli/cmd/utils.go +++ b/cli/cmd/utils.go @@ -32,6 +32,7 @@ POSSIBILITY OF SUCH DAMAGE. package cmd import ( + "context" "errors" "net" @@ -40,8 +41,11 @@ import ( "code.fbi.h-da.de/danet/gosdn/controller/api" "github.com/c-bata/go-prompt" "github.com/spf13/viper" + "google.golang.org/grpc/metadata" ) +var userToken string + func checkIPPort(string) error { // check if address is in the format <IP>:<port> ip, _, err := net.SplitHostPort(address) @@ -57,7 +61,7 @@ func checkIPPort(string) error { } func getDevices() []prompt.Suggest { - resp, err := api.GetDevices(pndAdapter.Endpoint(), pndAdapter.ID().String()) + resp, err := api.GetDevices(createContextWithAuthorization(), pndAdapter.Endpoint(), pndAdapter.ID().String()) if err != nil { return []prompt.Suggest{} } @@ -70,7 +74,7 @@ func getDevices() []prompt.Suggest { } func getPnds() []prompt.Suggest { - resp, err := api.GetIds(viper.GetString("controllerAPIEndpoint")) + resp, err := api.GetIds(createContextWithAuthorization(), viper.GetString("controllerAPIEndpoint")) if err != nil { return []prompt.Suggest{} } @@ -83,7 +87,7 @@ func getPnds() []prompt.Suggest { } func getChangesByType(cType pnd.ChangeState) []prompt.Suggest { - resp, err := api.GetChanges(pndAdapter.Endpoint(), pndAdapter.ID().String()) + resp, err := api.GetChanges(createContextWithAuthorization(), pndAdapter.Endpoint(), pndAdapter.ID().String()) if err != nil { return []prompt.Suggest{} } @@ -96,3 +100,9 @@ func getChangesByType(cType pnd.ChangeState) []prompt.Suggest { } return completer.SortSuggestionByText(s) } + +func createContextWithAuthorization() context.Context { + //TODO: try to get token string first, if "" return err, followed by print in cli about required login + md := metadata.Pairs("authorize", userToken) + return metadata.NewOutgoingContext(context.Background(), md) +} diff --git a/controller/api/apiIntegration_test.go b/controller/api/apiIntegration_test.go index 761b3577c..8a2888473 100644 --- a/controller/api/apiIntegration_test.go +++ b/controller/api/apiIntegration_test.go @@ -1,6 +1,7 @@ package api import ( + "context" "testing" "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd" @@ -29,7 +30,7 @@ func TestApiIntegration(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { defer viper.Reset() - if err := Init(testAPIEndpoint); (err != nil) != tt.wantErr { + if err := Init(context.TODO(), testAPIEndpoint); (err != nil) != tt.wantErr { switch err.(type) { case viper.ConfigFileNotFoundError: default: @@ -58,6 +59,7 @@ func TestApiIntegration(t *testing.T) { }, } if _, err := AddDevice( + context.TODO(), testAPIEndpoint, "test-device", opt, @@ -70,6 +72,7 @@ func TestApiIntegration(t *testing.T) { did := viper.GetString("LAST_DEVICE_UUID") _, err = GetDevice( + context.TODO(), testAPIEndpoint, cliPnd, did, @@ -80,6 +83,7 @@ func TestApiIntegration(t *testing.T) { } _, err = GetDevice( + context.TODO(), testAPIEndpoint, cliPnd, "", @@ -92,6 +96,7 @@ func TestApiIntegration(t *testing.T) { hostname := guuid.New().String() _, err = ChangeRequest( + context.TODO(), testAPIEndpoint, did, cliPnd, @@ -104,7 +109,7 @@ func TestApiIntegration(t *testing.T) { return } - resp, err := GetDevice(testAddress, testUsername, testPassword, testPath) + resp, err := GetDevice(context.TODO(), testAddress, testUsername, testPassword, testPath) if err != nil { if !tt.wantErr { t.Errorf("Get() error = %v, wantErr %v", err, tt.wantErr) diff --git a/controller/api/api_test.go b/controller/api/api_test.go index c7ccbc4e9..0f4f904af 100644 --- a/controller/api/api_test.go +++ b/controller/api/api_test.go @@ -1,6 +1,7 @@ package api import ( + "context" "testing" ppb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/pnd" @@ -13,13 +14,13 @@ import ( func Test_Init(t *testing.T) { viper.SetConfigFile("./api_test.toml") - if err := Init(bufnet); err != nil { + if err := Init(context.TODO(), bufnet); err != nil { t.Error(err) } } func Test_GetIds(t *testing.T) { - resp, err := GetIds(bufnet) + resp, err := GetIds(context.TODO(), bufnet) if err != nil { t.Error(err) return @@ -32,7 +33,7 @@ func Test_AddPnd(t *testing.T) { if err != nil { t.Errorf("AddPnd() error = %v", err) } - resp, err := AddPnd(bufnet, "test", "test pnd", sbi.ID().String()) + resp, err := AddPnd(context.TODO(), bufnet, "test", "test pnd", sbi.ID().String()) if err != nil { t.Error(err) return @@ -41,7 +42,7 @@ func Test_AddPnd(t *testing.T) { } func Test_GetPnd(t *testing.T) { - resp, err := GetPnd(bufnet, pndID) + resp, err := GetPnd(context.TODO(), bufnet, pndID) if err != nil { t.Error(err) return @@ -53,7 +54,7 @@ func Test_GetPnd(t *testing.T) { } func Test_GetChanges(t *testing.T) { - resp, err := GetChanges(bufnet, pndID) + resp, err := GetChanges(context.TODO(), bufnet, pndID) if err != nil { t.Error(err) return @@ -62,14 +63,14 @@ func Test_GetChanges(t *testing.T) { } func Test_CommitConfirm(t *testing.T) { - resp, err := Commit(bufnet, pndID, changeID) + resp, err := Commit(context.TODO(), bufnet, pndID, changeID) if err != nil { t.Error(err) return } log.Info(resp) - resp, err = Confirm(bufnet, pndID, changeID) + resp, err = Confirm(context.TODO(), bufnet, pndID, changeID) if err != nil { t.Error(err) return @@ -86,7 +87,7 @@ func Test_AddDevice(t *testing.T) { GnmiTransportOption: &tpb.GnmiTransportOption{}, }, } - resp, err := AddDevice(bufnet, "test", opt, sbiUUID, pndUUID) + resp, err := AddDevice(context.TODO(), bufnet, "test", opt, sbiUUID, pndUUID) if err != nil { t.Error(err) return @@ -95,7 +96,7 @@ func Test_AddDevice(t *testing.T) { } func Test_GetDevice(t *testing.T) { - resp, err := GetDevice(bufnet, pndID, ondID) + resp, err := GetDevice(context.TODO(), bufnet, pndID, ondID) if err != nil { t.Error(err) return @@ -107,7 +108,7 @@ func Test_GetDevice(t *testing.T) { } func Test_Update(t *testing.T) { - resp, err := ChangeRequest(bufnet, ondID, pndID, "", "", ppb.ApiOperation_API_OPERATION_UPDATE) + resp, err := ChangeRequest(context.TODO(), bufnet, ondID, pndID, "", "", ppb.ApiOperation_API_OPERATION_UPDATE) if err != nil { t.Error(err) return @@ -116,7 +117,7 @@ func Test_Update(t *testing.T) { } func Test_Replace(t *testing.T) { - resp, err := ChangeRequest(bufnet, ondID, pndID, "", "", ppb.ApiOperation_API_OPERATION_REPLACE) + resp, err := ChangeRequest(context.TODO(), bufnet, ondID, pndID, "", "", ppb.ApiOperation_API_OPERATION_REPLACE) if err != nil { t.Error(err) return @@ -125,7 +126,7 @@ func Test_Replace(t *testing.T) { } func Test_Delete(t *testing.T) { - resp, err := ChangeRequest(bufnet, ondID, pndID, "", "", ppb.ApiOperation_API_OPERATION_DELETE) + resp, err := ChangeRequest(context.TODO(), bufnet, ondID, pndID, "", "", ppb.ApiOperation_API_OPERATION_DELETE) if err != nil { t.Error(err) return diff --git a/controller/api/grpc.go b/controller/api/grpc.go index 71f08e6de..dc1105b5f 100644 --- a/controller/api/grpc.go +++ b/controller/api/grpc.go @@ -31,28 +31,23 @@ func init() { } // Init initialises the CLI client. -func Init(addr string) error { - ctx := context.Background() +func Init(ctx context.Context, addr string) error { resp, err := GetAllCore(ctx, addr) if err != nil { return err } + if len(resp.Pnd) > 0 { pid := resp.Pnd[0].Id viper.Set("CLI_PND", pid) log.Infof("PND: %v", pid) - // if len(resp.Pnd[0].Sbi) != 0 { - // sbi := resp.Pnd[0].Sbi[0].Id - // viper.Set("CLI_SBI", sbi) - // log.Infof("SBI: %v", sbi) - // } } + return viper.WriteConfig() } // GetIds requests all UUID information from the controller -func GetIds(addr string) ([]*ppb.PrincipalNetworkDomain, error) { - ctx := context.Background() +func GetIds(ctx context.Context, addr string) ([]*ppb.PrincipalNetworkDomain, error) { resp, err := GetAllCore(ctx, addr) if err != nil { return nil, err @@ -74,12 +69,12 @@ func GetAllCore(ctx context.Context, addr string) (*pb.GetPndListResponse, error // AddPnd takes a name, description and SBI UUID to create a new // PrincipalNetworkDomain on the controller -func AddPnd(addr, name, description, sbi string) (*pb.CreatePndListResponse, error) { +func AddPnd(ctx context.Context, addr, name, description, sbi string) (*pb.CreatePndListResponse, error) { coreClient, err := nbi.CoreClient(addr, dialOptions...) if err != nil { return nil, err } - ctx := context.Background() + req := &pb.CreatePndListRequest{ Timestamp: time.Now().UnixNano(), Pnd: []*pb.PndCreateProperties{ @@ -96,7 +91,7 @@ func AddPnd(addr, name, description, sbi string) (*pb.CreatePndListResponse, err // GetPnd requests one PrincipalNetworkDomain from the // controller. -func GetPnd(addr string, args ...string) (*pb.GetPndResponse, error) { +func GetPnd(ctx context.Context, addr string, args ...string) (*pb.GetPndResponse, error) { coreClient, err := nbi.CoreClient(addr, dialOptions...) if err != nil { return nil, err @@ -104,7 +99,7 @@ func GetPnd(addr string, args ...string) (*pb.GetPndResponse, error) { if len(args) <= 0 { return nil, errors.New("not enough arguments") } - ctx := context.Background() + req := &pb.GetPndRequest{ Timestamp: time.Now().UnixNano(), Pid: args, @@ -114,7 +109,7 @@ func GetPnd(addr string, args ...string) (*pb.GetPndResponse, error) { // GetPnds requests all PrincipalNetworkDomains from the // controller. -func GetPnds(addr string, args ...string) (*pb.GetPndListResponse, error) { +func GetPnds(ctx context.Context, addr string, args ...string) (*pb.GetPndListResponse, error) { coreClient, err := nbi.CoreClient(addr, dialOptions...) if err != nil { return nil, err @@ -122,7 +117,7 @@ func GetPnds(addr string, args ...string) (*pb.GetPndListResponse, error) { if len(args) <= 0 { return nil, errors.New("not enough arguments") } - ctx := context.Background() + req := &pb.GetPndListRequest{ Timestamp: time.Now().UnixNano(), } @@ -130,12 +125,12 @@ func GetPnds(addr string, args ...string) (*pb.GetPndListResponse, error) { } // DeletePnd requests a deletion of the provided PND. -func DeletePnd(addr string, pid string) (*pb.DeletePndResponse, error) { +func DeletePnd(ctx context.Context, addr string, pid string) (*pb.DeletePndResponse, error) { coreClient, err := nbi.CoreClient(addr, dialOptions...) if err != nil { return nil, err } - ctx := context.Background() + req := &pb.DeletePndRequest{ Timestamp: time.Now().UnixNano(), Pid: pid, @@ -145,12 +140,12 @@ func DeletePnd(addr string, pid string) (*pb.DeletePndResponse, error) { // GetSbi requests one or more to the provided PND belonging SBIs from the // controller. -func GetSbi(addr string, pid string, sid ...string) (*ppb.GetSbiResponse, error) { +func GetSbi(ctx context.Context, addr string, pid string, sid ...string) (*ppb.GetSbiResponse, error) { client, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err } - ctx := context.Background() + req := &ppb.GetSbiRequest{ Timestamp: time.Now().UnixNano(), Pid: pid, @@ -160,12 +155,12 @@ func GetSbi(addr string, pid string, sid ...string) (*ppb.GetSbiResponse, error) } //GetSBIs requests all to the provided PND belonging SBIs from the controller. -func GetSBIs(addr string, pid string) (*ppb.GetSbiListResponse, error) { +func GetSBIs(ctx context.Context, addr string, pid string) (*ppb.GetSbiListResponse, error) { client, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err } - ctx := context.Background() + req := &ppb.GetSbiListRequest{ Timestamp: time.Now().UnixNano(), Pid: pid, @@ -174,8 +169,7 @@ func GetSBIs(addr string, pid string) (*ppb.GetSbiListResponse, error) { } // GetChanges requests all pending and unconfirmed changes from the controller -func GetChanges(addr, pnd string) (*ppb.GetChangeListResponse, error) { - ctx := context.Background() +func GetChanges(ctx context.Context, addr, pnd string) (*ppb.GetChangeListResponse, error) { client, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err @@ -189,7 +183,7 @@ func GetChanges(addr, pnd string) (*ppb.GetChangeListResponse, error) { // Commit sends a Commit request for one or multiple changes to the // controller. -func Commit(addr, pnd string, cuids ...string) (*ppb.SetChangeListResponse, error) { +func Commit(ctx context.Context, addr, pnd string, cuids ...string) (*ppb.SetChangeListResponse, error) { changes := make([]*ppb.SetChange, len(cuids)) for i, arg := range cuids { changes[i] = &ppb.SetChange{ @@ -197,12 +191,12 @@ func Commit(addr, pnd string, cuids ...string) (*ppb.SetChangeListResponse, erro Op: ppb.Operation_OPERATION_COMMIT, } } - return CommitConfirm(addr, pnd, changes) + return CommitConfirm(ctx, addr, pnd, changes) } // Confirm sends a Confirm request for one or multiple changes to the // controller -func Confirm(addr, pnd string, cuids ...string) (*ppb.SetChangeListResponse, error) { +func Confirm(ctx context.Context, addr, pnd string, cuids ...string) (*ppb.SetChangeListResponse, error) { changes := make([]*ppb.SetChange, len(cuids)) for i, arg := range cuids { changes[i] = &ppb.SetChange{ @@ -210,12 +204,11 @@ func Confirm(addr, pnd string, cuids ...string) (*ppb.SetChangeListResponse, err Op: ppb.Operation_OPERATION_CONFIRM, } } - return CommitConfirm(addr, pnd, changes) + return CommitConfirm(ctx, addr, pnd, changes) } // CommitConfirm confirms a commit -func CommitConfirm(addr, pnd string, changes []*ppb.SetChange) (*ppb.SetChangeListResponse, error) { - ctx := context.Background() +func CommitConfirm(ctx context.Context, addr, pnd string, changes []*ppb.SetChange) (*ppb.SetChangeListResponse, error) { client, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err @@ -230,7 +223,7 @@ func CommitConfirm(addr, pnd string, changes []*ppb.SetChange) (*ppb.SetChangeLi // AddDevice adds a new device to the controller. The device name is optional. // If no name is provided a name will be generated upon device creation. -func AddDevice(addr, deviceName string, opt *tpb.TransportOption, sid, pid uuid.UUID) (*ppb.SetOndListResponse, error) { +func AddDevice(ctx context.Context, addr, deviceName string, opt *tpb.TransportOption, sid, pid uuid.UUID) (*ppb.SetOndListResponse, error) { pndClient, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err @@ -257,14 +250,14 @@ func AddDevice(addr, deviceName string, opt *tpb.TransportOption, sid, pid uuid. req.Ond[0].TransportOption.Type = t default: } - ctx := context.Background() + return pndClient.SetOndList(ctx, req) } // GetDevice requests one device belonging to a given // PrincipalNetworkDomain from the controller. If no device identifier // is provided, an error is thrown. -func GetDevice(addr, pid string, did ...string) (*ppb.GetOndResponse, error) { +func GetDevice(ctx context.Context, addr, pid string, did ...string) (*ppb.GetOndResponse, error) { pndClient, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err @@ -279,12 +272,12 @@ func GetDevice(addr, pid string, did ...string) (*ppb.GetOndResponse, error) { Did: did, Pid: pid, } - ctx := context.Background() + return pndClient.GetOnd(ctx, req) } // GetSbiSchemaTree gets the sbi tree for a sbi -func GetSbiSchemaTree(addr string, pid, sid uuid.UUID) (map[string]*yang.Entry, error) { +func GetSbiSchemaTree(ctx context.Context, addr string, pid, sid uuid.UUID) (map[string]*yang.Entry, error) { sbiClient, err := nbi.SbiClient(addr, dialOptions...) if err != nil { return map[string]*yang.Entry{}, err @@ -296,7 +289,7 @@ func GetSbiSchemaTree(addr string, pid, sid uuid.UUID) (map[string]*yang.Entry, Sid: sid.String(), } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute*10) + ctx, cancel := context.WithTimeout(ctx, time.Minute*10) defer cancel() sClient, err := sbiClient.GetSchema(ctx, req) if err != nil { @@ -328,7 +321,7 @@ func GetSbiSchemaTree(addr string, pid, sid uuid.UUID) (map[string]*yang.Entry, // GetDevices requests all devices belonging to a given // PrincipalNetworkDomain from the controller. -func GetDevices(addr, pid string) (*ppb.GetOndListResponse, error) { +func GetDevices(ctx context.Context, addr, pid string) (*ppb.GetOndListResponse, error) { pndClient, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err @@ -338,12 +331,12 @@ func GetDevices(addr, pid string) (*ppb.GetOndListResponse, error) { Timestamp: time.Now().UnixNano(), Pid: pid, } - ctx := context.Background() + return pndClient.GetOndList(ctx, req) } // GetPath requests a specific path -func GetPath(addr, pid, did, path string) (*ppb.GetPathResponse, error) { +func GetPath(ctx context.Context, addr, pid, did, path string) (*ppb.GetPathResponse, error) { pndClient, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err @@ -355,12 +348,12 @@ func GetPath(addr, pid, did, path string) (*ppb.GetPathResponse, error) { Pid: pid, Path: path, } - ctx := context.Background() + return pndClient.GetPath(ctx, req) } // DeleteDevice deletes a device -func DeleteDevice(addr, pid, did string) (*ppb.DeleteOndResponse, error) { +func DeleteDevice(ctx context.Context, addr, pid, did string) (*ppb.DeleteOndResponse, error) { pndClient, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err @@ -371,7 +364,7 @@ func DeleteDevice(addr, pid, did string) (*ppb.DeleteOndResponse, error) { Did: did, Pid: pid, } - ctx := context.Background() + return pndClient.DeleteOnd(ctx, req) } @@ -379,23 +372,23 @@ func DeleteDevice(addr, pid, did string) (*ppb.DeleteOndResponse, error) { // used to specify the type of the change (update, replace, delete as specified // in https://github.com/openconfig/reference/blob/master/rpc/gnmi/gnmi-specification.md#34-modifying-state) // For delete operations the value field needs to contain an empty string. -func ChangeRequest(addr, did, pid, path, value string, op ppb.ApiOperation) (*ppb.SetPathListResponse, error) { +func ChangeRequest(ctx context.Context, addr, did, pid, path, value string, op ppb.ApiOperation) (*ppb.SetPathListResponse, error) { req := &ppb.ChangeRequest{ Did: did, Path: path, Value: value, ApiOp: op, } - return SendChangeRequest(addr, pid, req) + return SendChangeRequest(ctx, addr, pid, req) } // SendChangeRequest sends a change request -func SendChangeRequest(addr, pid string, req *ppb.ChangeRequest) (*ppb.SetPathListResponse, error) { +func SendChangeRequest(ctx context.Context, addr, pid string, req *ppb.ChangeRequest) (*ppb.SetPathListResponse, error) { pndClient, err := nbi.PndClient(addr, dialOptions...) if err != nil { return nil, err } - ctx := context.Background() + r := &ppb.SetPathListRequest{ Timestamp: time.Now().UnixNano(), ChangeRequest: []*ppb.ChangeRequest{req}, @@ -405,12 +398,12 @@ func SendChangeRequest(addr, pid string, req *ppb.ChangeRequest) (*ppb.SetPathLi } // Login logs a user in -func Login(addr, username, pwd string) (*apb.LoginResponse, error) { +func Login(ctx context.Context, addr, username, pwd string) (*apb.LoginResponse, error) { authClient, err := nbi.AuthClient(addr, dialOptions...) if err != nil { return nil, err } - ctx := context.Background() + r := &apb.LoginRequest{ Timestamp: time.Now().UnixNano(), Username: username, @@ -420,15 +413,179 @@ func Login(addr, username, pwd string) (*apb.LoginResponse, error) { } // Logout logs a user out -func Logout(addr, username string) (*apb.LogoutResponse, error) { +func Logout(ctx context.Context, addr, username string) (*apb.LogoutResponse, error) { authClient, err := nbi.AuthClient(addr, dialOptions...) if err != nil { return nil, err } - ctx := context.Background() + r := &apb.LogoutRequest{ Timestamp: time.Now().UnixNano(), Username: username, } return authClient.Logout(ctx, r) } + +// CreateUsers creates users with provided data +func CreateUsers(ctx context.Context, addr string, users []*apb.User) (*apb.CreateUsersResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.CreateUsersRequest{ + Timestamp: time.Now().UnixNano(), + User: users, + } + + return authClient.CreateUsers(ctx, r) +} + +//GetUser returns one requested user found by name +func GetUser(ctx context.Context, addr, name string) (*apb.GetUserResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.GetUserRequest{ + Timestamp: time.Now().UnixNano(), + Name: name, + } + + return authClient.GetUser(ctx, r) +} + +// GetAllUsers return all the available users +func GetAllUsers(ctx context.Context, addr string) (*apb.GetUsersResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.GetUsersRequest{ + Timestamp: time.Now().UnixNano(), + } + + return authClient.GetUsers(ctx, r) +} + +// UpdateUsers updates all provided users +func UpdateUsers(ctx context.Context, addr string, users []*apb.User) (*apb.UpdateUsersResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.UpdateUsersRequest{ + Timestamp: time.Now().UnixNano(), + User: users, + } + + return authClient.UpdateUsers(ctx, r) +} + +// DeleteUsers deletes all provided users +func DeleteUsers(ctx context.Context, addr string, userNames []string) (*apb.DeleteUsersResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.DeleteUsersRequest{ + Timestamp: time.Now().UnixNano(), + Username: userNames, + } + + return authClient.DeleteUsers(ctx, r) +} + +// CreateRoles creates roles with provided data +func CreateRoles(ctx context.Context, addr string, roles []*apb.Role) (*apb.CreateRolesResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.CreateRolesRequest{ + Timestamp: time.Now().UnixNano(), + Roles: roles, + } + + return authClient.CreateRoles(ctx, r) +} + +// GetRole returns one requested role found by name +func GetRole(ctx context.Context, addr, name string) (*apb.GetRoleResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.GetRoleRequest{ + Timestamp: time.Now().UnixNano(), + RoleName: name, + } + + return authClient.GetRole(ctx, r) +} + +// GetRoles returns all available roles +func GetRoles(ctx context.Context, addr string) (*apb.GetRolesResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.GetRolesRequest{ + Timestamp: time.Now().UnixNano(), + } + + return authClient.GetRoles(ctx, r) +} + +// UpdateRoles updates the procided roles +func UpdateRoles(ctx context.Context, addr string, roles []*apb.Role) (*apb.UpdateRolesResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.UpdateRolesRequest{ + Timestamp: time.Now().UnixNano(), + Roles: roles, + } + + return authClient.UpdateRoles(ctx, r) +} + +// DeletePermissionForRole deletes the provided permissions from one role found by name +func DeletePermissionForRole(ctx context.Context, addr, name string, permissionsToDelete []string) (*apb.DeletePermissionsForRoleResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.DeletePermissionsForRoleRequest{ + Timestamp: time.Now().UnixNano(), + RoleName: name, + PermissionsToDelete: permissionsToDelete, + } + + return authClient.DeletePermissionsForRole(ctx, r) +} + +// DeleteRoles deletes all the provided roles with their permissions +func DeleteRoles(ctx context.Context, addr string, roleName []string) (*apb.DeleteRolesResponse, error) { + authClient, err := nbi.AuthClient(addr, dialOptions...) + if err != nil { + return nil, err + } + + r := &apb.DeleteRolesRequest{ + Timestamp: time.Now().UnixNano(), + RoleName: roleName, + } + + return authClient.DeleteRoles(ctx, r) +} diff --git a/controller/api/initialise_test.go b/controller/api/initialise_test.go index ab531d3d8..efcc249ed 100644 --- a/controller/api/initialise_test.go +++ b/controller/api/initialise_test.go @@ -14,11 +14,13 @@ import ( "code.fbi.h-da.de/danet/gosdn/controller/config" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/device" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain" + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound" "code.fbi.h-da.de/danet/gosdn/controller/mocks" nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/server" "code.fbi.h-da.de/danet/gosdn/controller/nucleus" "code.fbi.h-da.de/danet/gosdn/controller/nucleus/util/proto" + rbacImpl "code.fbi.h-da.de/danet/gosdn/controller/rbac" "code.fbi.h-da.de/danet/yang-models/generated/openconfig" "github.com/google/uuid" log "github.com/sirupsen/logrus" @@ -43,6 +45,8 @@ const sbiID = "f6fd4b35-f039-4111-9156-5e4501bb8a5a" const ondID = "7e0ed8cc-ebf5-46fa-9794-741494914883" var pndStore networkdomain.PndStore +var userService rbac.UserService +var roleService rbac.RoleService var sbiStore southbound.Store var lis *bufconn.Listener var pndUUID uuid.UUID @@ -78,6 +82,8 @@ func bootstrapUnitTest() { pndStore = nucleus.NewPndStore() sbiStore = nucleus.NewSbiStore(pndUUID) + userService = rbacImpl.NewUserService(rbacImpl.NewMemoryUserStore()) + roleService = rbacImpl.NewRoleService(rbacImpl.NewMemoryRoleStore()) mockChange := &mocks.Change{} mockChange.On("Age").Return(time.Hour) @@ -109,7 +115,7 @@ func bootstrapUnitTest() { if err := pndStore.Add(&mockPnd); err != nil { log.Fatal(err) } - northbound := nbi.NewNBI(pndStore) + northbound := nbi.NewNBI(pndStore, userService, roleService) cpb.RegisterCoreServiceServer(s, northbound.Core) ppb.RegisterPndServiceServer(s, northbound.Pnd) go func() { diff --git a/controller/controller.go b/controller/controller.go index 0de056392..570c7439a 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -24,10 +24,11 @@ import ( "code.fbi.h-da.de/danet/gosdn/controller/config" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/device" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain" + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound" "code.fbi.h-da.de/danet/gosdn/controller/northbound/server" nbi "code.fbi.h-da.de/danet/gosdn/controller/northbound/server" - "code.fbi.h-da.de/danet/gosdn/controller/rbac" + rbacImpl "code.fbi.h-da.de/danet/gosdn/controller/rbac" "code.fbi.h-da.de/danet/gosdn/controller/store" "code.fbi.h-da.de/danet/gosdn/controller/nucleus" @@ -39,6 +40,8 @@ var coreOnce sync.Once // Core is the representation of the controller's core type Core struct { pndc networkdomain.PndStore + userc rbac.UserService + rolec rbac.RoleService httpServer *http.Server grpcServer *grpc.Server nbi *nbi.NorthboundInterface @@ -58,6 +61,8 @@ func initialize() error { c = &Core{ pndc: nucleus.NewPndStore(), + userc: rbacImpl.NewUserService(rbacImpl.NewUserStore()), + rolec: rbacImpl.NewRoleService(rbacImpl.NewRoleStore()), stopChan: make(chan os.Signal, 1), } @@ -93,10 +98,10 @@ func startGrpc() error { } log.Infof("listening to %v", lis.Addr()) - jwtManager := rbac.NewJWTManager("", (60 * time.Minute)) //TODO add real secret and proper duration data here! + jwtManager := rbacImpl.NewJWTManager("", (10000 * time.Hour)) //TODO(faseid): add real secret and proper duration data here! setupGRPCServerWithCorrectSecurityLevel(jwtManager) - c.nbi = nbi.NewNBI(c.pndc) + c.nbi = nbi.NewNBI(c.pndc, c.userc, c.rolec) c.nbi.Auth = nbi.NewAuthServer(jwtManager) pb.RegisterCoreServiceServer(c.grpcServer, c.nbi.Core) @@ -204,14 +209,14 @@ func callback(id uuid.UUID, ch chan device.Details) { // This allows users to operate on the controller without any authentication/authorization, // but they could still login if they want to. // Use insecure only for testing purposes and with caution. -func setupGRPCServerWithCorrectSecurityLevel(jwt *rbac.JWTManager) { +func setupGRPCServerWithCorrectSecurityLevel(jwt *rbacImpl.JWTManager) { securityLevel := viper.GetString("security") if securityLevel == "insecure" { c.grpcServer = grpc.NewServer() log.Info("set up grpc server in insecure mode") } else { interceptor := server.NewAuthInterceptor(jwt) - c.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(interceptor.Unary())) + c.grpcServer = grpc.NewServer(grpc.UnaryInterceptor(interceptor.Unary()), grpc.StreamInterceptor(interceptor.Stream())) log.Info("set up grpc server in secure mode") } } diff --git a/controller/interfaces/rbac/rbacService.go b/controller/interfaces/rbac/rbacService.go new file mode 100644 index 000000000..e5a543e8c --- /dev/null +++ b/controller/interfaces/rbac/rbacService.go @@ -0,0 +1,40 @@ +package rbac + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/store" +) + +// UserService describes an interface for user service implementation. +type UserService interface { + Add(User) error + Delete(User) error + Update(User) error + Get(store.Query) (User, error) + GetAll() ([]User, error) +} + +// LoadedUser represents a User that was loaded +type LoadedUser struct { + ID string `json:"_id" bson:"_id"` + UserName string `json:"username"` + Roles map[string]string `json:"roles,omitempty"` + Password string `json:"password"` + Token string `json:"token,omitempty"` +} + +// RoleService describes an interface for role service implementations. +type RoleService interface { + Add(Role) error + Delete(Role) error + Update(Role) error + Get(store.Query) (Role, error) + GetAll() ([]Role, error) +} + +// LoadedRole represents a Role that was loaded +type LoadedRole struct { + ID string `json:"_id" bson:"_id"` + RoleName string `json:"rolename"` + Description string `json:"description,omitempty"` + Permissions []string `json:"permissions,omitempty"` +} diff --git a/controller/interfaces/rbac/role.go b/controller/interfaces/rbac/role.go new file mode 100644 index 000000000..41ab642f9 --- /dev/null +++ b/controller/interfaces/rbac/role.go @@ -0,0 +1,12 @@ +package rbac + +import "github.com/google/uuid" + +// Role represents a role with permissions +type Role interface { + ID() uuid.UUID + Name() string + GetDescription() string + GetPermissions() []string + RemovePermissionsFromRole([]string) +} diff --git a/controller/interfaces/rbac/roleStore.go b/controller/interfaces/rbac/roleStore.go new file mode 100644 index 000000000..88ee8f59f --- /dev/null +++ b/controller/interfaces/rbac/roleStore.go @@ -0,0 +1,12 @@ +package rbac + +import "code.fbi.h-da.de/danet/gosdn/controller/store" + +// RoleStore describes an interface for role store implementations. +type RoleStore interface { + Add(r Role) error + Update(r Role) error + Delete(Role) error + Get(store.Query) (LoadedRole, error) + GetAll() ([]LoadedRole, error) +} diff --git a/controller/interfaces/rbac/user.go b/controller/interfaces/rbac/user.go new file mode 100644 index 000000000..8ed0fc254 --- /dev/null +++ b/controller/interfaces/rbac/user.go @@ -0,0 +1,13 @@ +package rbac + +import "github.com/google/uuid" + +// User represents an User which is managed by rbac +type User interface { + ID() uuid.UUID + Name() string + GetRoles() map[string]string + GetPassword() string + GetToken() string + SetToken(string) +} diff --git a/controller/interfaces/rbac/userStore.go b/controller/interfaces/rbac/userStore.go new file mode 100644 index 000000000..014a20ce0 --- /dev/null +++ b/controller/interfaces/rbac/userStore.go @@ -0,0 +1,14 @@ +package rbac + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/store" +) + +// UserStore describes an interface for user store implementations. +type UserStore interface { + Add(u User) error + Update(u User) error + Delete(User) error + Get(store.Query) (LoadedUser, error) + GetAll() ([]LoadedUser, error) +} diff --git a/controller/northbound/server/auth.go b/controller/northbound/server/auth.go index 2307abf27..4c159193a 100644 --- a/controller/northbound/server/auth.go +++ b/controller/northbound/server/auth.go @@ -7,7 +7,10 @@ import ( apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" "code.fbi.h-da.de/danet/gosdn/controller/metrics" "code.fbi.h-da.de/danet/gosdn/controller/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/store" + "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" + log "github.com/sirupsen/logrus" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -27,29 +30,21 @@ func NewAuthServer(jwtManager *rbac.JWTManager) *Auth { // Login logs a user in func (s Auth) Login(ctx context.Context, request *apb.LoginRequest) (*apb.LoginResponse, error) { - labels := prometheus.Labels{"service": "core", "rpc": "post"} + labels := prometheus.Labels{"service": "auth", "rpc": "post"} start := metrics.StartHook(labels, grpcRequestsTotal) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) user := rbac.User{ - Name: request.Username, + UserName: request.Username, Password: request.Pwd, } - // check if user is already logged in - loggedIn, err := s.isLoggedIn(user.Name) - if err != nil { - return nil, err - } else if loggedIn { - return nil, status.Errorf(codes.Canceled, "already logged in") - } + //TODO: add check if user is logged in with session handling // validation of credentials validCredentials, err := s.isValidUser(user) - if err != nil { + if (err != nil) || !validCredentials { return nil, err - } else if !validCredentials { - return nil, status.Errorf(codes.Unauthenticated, "incorrect user name or password") } // generate token, persist session and return to user @@ -58,7 +53,17 @@ func (s Auth) Login(ctx context.Context, request *apb.LoginRequest) (*apb.LoginR return nil, err } - //TODO(faseid): persist token for session handling here! + userToUpdate, err := userc.Get(store.Query{Name: user.UserName}) + if err != nil { + return nil, err + } + + userToUpdate.SetToken(token) + + err = userc.Update(userToUpdate) + if err != nil { + return nil, err + } return &apb.LoginResponse{ Timestamp: time.Now().UnixNano(), @@ -69,18 +74,12 @@ func (s Auth) Login(ctx context.Context, request *apb.LoginRequest) (*apb.LoginR // Logout logs a user out func (s Auth) Logout(ctx context.Context, request *apb.LogoutRequest) (*apb.LogoutResponse, error) { - labels := prometheus.Labels{"service": "core", "rpc": "post"} + labels := prometheus.Labels{"service": "auth", "rpc": "post"} start := metrics.StartHook(labels, grpcRequestsTotal) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) - loggedIn, err := s.isLoggedIn(request.Username) - if err != nil { - return nil, err - } else if !loggedIn { - return nil, status.Errorf(codes.Canceled, "not logged in") - } else if loggedIn { - // TODO(faseid): delete active session from storage - } + // not implemented yet + // TODO: add session handling and logout return &apb.LogoutResponse{ Timestamp: time.Now().UnixNano(), @@ -90,11 +89,29 @@ func (s Auth) Logout(ctx context.Context, request *apb.LogoutRequest) (*apb.Logo // CreateUsers creates new users, can be 1 or more func (s Auth) CreateUsers(ctx context.Context, request *apb.CreateUsersRequest) (*apb.CreateUsersResponse, error) { - labels := prometheus.Labels{"service": "core", "rpc": "post"} + labels := prometheus.Labels{"service": "auth", "rpc": "post"} start := metrics.StartHook(labels, grpcRequestsTotal) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) - // TODO: implement proper user creation + // TODO: implement check if user is allowed to create users with this role + // e.g. non-admin shouldn't be allowed to create admin users + for _, u := range request.User { + roles := map[string]string{} + for key, elem := range u.Roles { + _, err := uuid.Parse(key) + if err != nil { + return nil, handleRPCError(labels, err) + } + roles[key] = elem + } + + user := rbac.NewUser(uuid.New(), u.Name, roles, u.Password, u.Token) + err := userc.Add(user) + if err != nil { + log.Error(err) + return nil, status.Errorf(codes.Aborted, "%v", err) + } + } return &apb.CreateUsersResponse{ Timestamp: time.Now().UnixNano(), @@ -102,28 +119,83 @@ func (s Auth) CreateUsers(ctx context.Context, request *apb.CreateUsersRequest) }, nil } +// GetUser returns one user by name. +func (s Auth) GetUser(ctx context.Context, request *apb.GetUserRequest) (*apb.GetUserResponse, error) { + labels := prometheus.Labels{"service": "auth", "rpc": "get"} + start := metrics.StartHook(labels, grpcRequestsTotal) + defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) + + // TODO: implement check if user is allowed to get this user data; only their own if not admin + userData, err := userc.Get(store.Query{Name: request.Name}) + if err != nil { + return nil, err + } + + user := &apb.User{ + Id: userData.ID().String(), + Name: userData.Name(), + Roles: userData.GetRoles(), + } + + return &apb.GetUserResponse{ + Timestamp: time.Now().UnixNano(), + Status: apb.Status_STATUS_OK, + User: user, + }, nil +} + // GetUsers returns all availbale users func (s Auth) GetUsers(ctx context.Context, request *apb.GetUsersRequest) (*apb.GetUsersResponse, error) { - labels := prometheus.Labels{"service": "core", "rpc": "get"} + labels := prometheus.Labels{"service": "auth", "rpc": "get"} start := metrics.StartHook(labels, grpcRequestsTotal) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) - // TODO: implement proper user fetching + userList, err := userc.GetAll() + if err != nil { + return nil, err + } + + users := []*apb.User{} + for _, u := range userList { + users = append(users, &apb.User{ + Id: u.ID().String(), + Name: u.Name(), + Roles: u.GetRoles(), + }) + } return &apb.GetUsersResponse{ Timestamp: time.Now().UnixNano(), Status: apb.Status_STATUS_OK, - // User here, probably needs fixing in proto! + User: users, }, nil } // UpdateUsers updates the user data of one or more users provided in the request func (s Auth) UpdateUsers(ctx context.Context, request *apb.UpdateUsersRequest) (*apb.UpdateUsersResponse, error) { - labels := prometheus.Labels{"service": "core", "rpc": "post"} + labels := prometheus.Labels{"service": "auth", "rpc": "post"} start := metrics.StartHook(labels, grpcRequestsTotal) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) - // TODO: implement proper user updating here + // TODO: check if current user is allowed to update the user they try to update; only their own if not admin + for _, u := range request.User { + uid, err := uuid.Parse(u.Id) + if err != nil { + return nil, handleRPCError(labels, err) + } + + _, err = userc.Get(store.Query{ID: uid}) + if err != nil { + return nil, status.Errorf(codes.Canceled, "user not found %v", err) + } + + userToUpdate := rbac.NewUser(uid, u.Name, u.Roles, u.Password, u.Token) + + err = userc.Update(userToUpdate) + if err != nil { + return nil, status.Errorf(codes.Aborted, "could not update user %v", err) + } + } return &apb.UpdateUsersResponse{ Timestamp: time.Now().UnixNano(), @@ -133,33 +205,212 @@ func (s Auth) UpdateUsers(ctx context.Context, request *apb.UpdateUsersRequest) // DeleteUsers deletes one or more users provided in the request func (s Auth) DeleteUsers(ctx context.Context, request *apb.DeleteUsersRequest) (*apb.DeleteUsersResponse, error) { - labels := prometheus.Labels{"service": "core", "rpc": "delete"} + labels := prometheus.Labels{"service": "auth", "rpc": "delete"} start := metrics.StartHook(labels, grpcRequestsTotal) defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) - // TODO: implement proper user deletion + for _, u := range request.Username { + userToDelete, err := userc.Get(store.Query{Name: u}) + if err != nil { + return nil, status.Errorf(codes.Canceled, "user not found %v", err) + } + err = userc.Delete(userToDelete) + if err != nil { + return nil, status.Errorf(codes.Aborted, "error deleting user %v", err) + } + } return &apb.DeleteUsersResponse{ Timestamp: time.Now().UnixNano(), Status: apb.Status_STATUS_OK, }, nil } -//TODO(faseid): implement proper log in check -func (s Auth) isLoggedIn(username string) (bool, error) { - // if user not found - // return nil, err +func (s Auth) isValidUser(user rbac.User) (bool, error) { + storedUser, err := userc.Get(store.Query{Name: user.Name()}) + if err != nil { + return false, err + } else if storedUser == nil { + return false, status.Errorf(codes.Aborted, "no user object") + } - // if already user logged in - // return true, nil + if storedUser.Name() == user.Name() { + if storedUser.GetPassword() == user.GetPassword() { + return true, nil + } + } - return false, nil + return false, status.Errorf(codes.Unauthenticated, "incorrect user name or password") } -// TODO(faseid): implement proper validation -func (s Auth) isValidUser(user rbac.User) (bool, error) { - // check correct credentials here +// CreateRoles creates roles with permissions for the roles used in rbac. +func (s Auth) CreateRoles(ctx context.Context, request *apb.CreateRolesRequest) (*apb.CreateRolesResponse, error) { + labels := prometheus.Labels{"service": "auth", "rpc": "post"} + start := metrics.StartHook(labels, grpcRequestsTotal) + defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) + + for _, r := range request.Roles { + role := rbac.NewRole(uuid.New(), r.Name, r.Description, r.Permissions) + + err := rolec.Add(role) + if err != nil { + log.Error(err) + return nil, status.Errorf(codes.Aborted, "%v", err) + } + } + + return &apb.CreateRolesResponse{ + Timestamp: time.Now().UnixNano(), + Status: apb.Status_STATUS_OK, + }, nil +} + +// GetRole returns one role with its permissions found by name. +func (s Auth) GetRole(ctx context.Context, request *apb.GetRoleRequest) (*apb.GetRoleResponse, error) { + labels := prometheus.Labels{"service": "auth", "rpc": "get"} + start := metrics.StartHook(labels, grpcRequestsTotal) + defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) + + roleData, err := rolec.Get(store.Query{Name: request.RoleName}) + if err != nil { + return nil, err + } + + role := &apb.Role{ + Id: roleData.ID().String(), + Name: roleData.Name(), + Description: roleData.GetDescription(), + Permissions: roleData.GetPermissions(), + } + + return &apb.GetRoleResponse{ + Timestamp: time.Now().UnixNano(), + Status: apb.Status_STATUS_OK, + Role: role, + }, nil +} + +// GetRoles returns all roles with their permissions. +func (s Auth) GetRoles(ctx context.Context, request *apb.GetRolesRequest) (*apb.GetRolesResponse, error) { + labels := prometheus.Labels{"service": "auth", "rpc": "get"} + start := metrics.StartHook(labels, grpcRequestsTotal) + defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) + + roleList, err := rolec.GetAll() + if err != nil { + return nil, err + } - // return true for now, change to false when there is a user storage for actual validation available - return true, nil + roles := []*apb.Role{} + for _, r := range roleList { + roles = append(roles, &apb.Role{ + Id: r.ID().String(), + Name: r.Name(), + Description: r.GetDescription(), + Permissions: r.GetPermissions(), + }) + } + + return &apb.GetRolesResponse{ + Timestamp: time.Now().UnixNano(), + Status: apb.Status_STATUS_OK, + Roles: roles, + }, nil +} + +// UpdateRoles updates data of the provided roles. +func (s Auth) UpdateRoles(ctx context.Context, request *apb.UpdateRolesRequest) (*apb.UpdateRolesResponse, error) { + labels := prometheus.Labels{"service": "auth", "rpc": "post"} + start := metrics.StartHook(labels, grpcRequestsTotal) + defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) + + // TODO: check if current user is allowed to update the role they try to update; only their own if not admin + for _, r := range request.Roles { + rid, err := uuid.Parse(r.Id) + if err != nil { + return nil, handleRPCError(labels, err) + } + + _, err = rolec.Get(store.Query{ID: rid}) + if err != nil { + return nil, status.Errorf(codes.Canceled, "role not found %v", err) + } + + roleToUpdate := rbac.NewRole(rid, r.Name, r.Description, r.Permissions) + err = rolec.Update(roleToUpdate) + if err != nil { + return nil, status.Errorf(codes.Aborted, "could not update role %v", err) + } + } + + return &apb.UpdateRolesResponse{ + Timestamp: time.Now().UnixNano(), + Status: apb.Status_STATUS_OK, + }, nil +} + +// DeletePermissionsForRole deletes the provided permissions from one role found by name. +func (s Auth) DeletePermissionsForRole(ctx context.Context, request *apb.DeletePermissionsForRoleRequest) (*apb.DeletePermissionsForRoleResponse, error) { + labels := prometheus.Labels{"service": "auth", "rpc": "delete"} + start := metrics.StartHook(labels, grpcRequestsTotal) + defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) + + roleToUpdate, err := rolec.Get(store.Query{Name: request.RoleName}) + if err != nil { + return nil, status.Errorf(codes.Canceled, "role not found %v", err) + } + + // checks if there is at least one valid permission to delete + // in the provided set of permissions to delete + nonFound := true + for _, perm := range roleToUpdate.GetPermissions() { + for _, permToDelete := range request.PermissionsToDelete { + if perm == permToDelete { + nonFound = false + break + } + } + if !nonFound { + break + } + } + if nonFound { + return nil, status.Errorf(codes.Canceled, "no fitting permissions") + } + + // updates the existing role with the trimmed set of permissions + roleToUpdate.RemovePermissionsFromRole(request.PermissionsToDelete) + err = rolec.Update(roleToUpdate) + if err != nil { + return nil, status.Errorf(codes.Aborted, "could not update role %v", err) + } + + return &apb.DeletePermissionsForRoleResponse{ + Timestamp: time.Now().UnixNano(), + Status: apb.Status_STATUS_OK, + }, nil +} + +// DeleteRoles deletes all the provided roles with their permissions. +func (s Auth) DeleteRoles(ctx context.Context, request *apb.DeleteRolesRequest) (*apb.DeleteRolesResponse, error) { + labels := prometheus.Labels{"service": "auth", "rpc": "delete"} + start := metrics.StartHook(labels, grpcRequestsTotal) + defer metrics.FinishHook(labels, start, grpcRequestDurationSecondsTotal, grpcRequestDurationSeconds) + + for _, r := range request.RoleName { + roleToDelete, err := rolec.Get(store.Query{Name: r}) + if err != nil { + return nil, status.Errorf(codes.Canceled, "role not found") + } + + err = rolec.Delete(roleToDelete) + if err != nil { + return nil, status.Errorf(codes.Aborted, "error deleting role %v", err) + } + } + + return &apb.DeleteRolesResponse{ + Timestamp: time.Now().UnixNano(), + Status: apb.Status_STATUS_OK, + }, nil } diff --git a/controller/northbound/server/auth_interceptor.go b/controller/northbound/server/auth_interceptor.go index 65d63fd77..428b5873b 100644 --- a/controller/northbound/server/auth_interceptor.go +++ b/controller/northbound/server/auth_interceptor.go @@ -5,8 +5,11 @@ import ( apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" "code.fbi.h-da.de/danet/gosdn/controller/rbac" - log "github.com/sirupsen/logrus" + "code.fbi.h-da.de/danet/gosdn/controller/store" "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" ) // AuthInterceptor provides an AuthInterceptor @@ -21,23 +24,122 @@ func NewAuthInterceptor(jwtManager *rbac.JWTManager) *AuthInterceptor { } } -// Unary provides middleware functionality -func (auth AuthInterceptor) Unary() grpc.UnaryServerInterceptor { +// Unary returns a unary interceptor function to authenticate and authorize unary RPC calls +func (auth *AuthInterceptor) Unary() grpc.UnaryServerInterceptor { return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) { - // TODO: Implement proper auth logic here - if _, ok := req.(*apb.LoginRequest); ok { + switch r := req.(type) { + case *apb.LoginRequest: return handler(ctx, req) - } + case *apb.LogoutRequest: + return handler(ctx, req) + case *apb.CreateUsersRequest: + if len(r.User) < 2 { + return handler(ctx, req) + } - // // validate token here - // claims, err := auth.jwtManager.VerifyToken("") // add token from context here! - // if err != nil { - // return nil, status.Errorf(codes.PermissionDenied, "%v", err) - // } - // // use claims for authorization - // log.Info("User: " + claims.Username) - log.Info("Interceptor called") + err := auth.authorize(ctx, info.FullMethod) + if err != nil { + return nil, err + } + default: + err := auth.authorize(ctx, info.FullMethod) + if err != nil { + return nil, err + } + } return handler(ctx, req) } } + +// Stream returns a server interceptor function to authorize stream RPC calls +func (auth *AuthInterceptor) Stream() grpc.StreamServerInterceptor { + return func( + srv interface{}, + stream grpc.ServerStream, + info *grpc.StreamServerInfo, + handler grpc.StreamHandler, + ) error { + err := auth.authorize(stream.Context(), info.FullMethod) + if err != nil { + return err + } + + return handler(srv, stream) + } +} + +func (auth *AuthInterceptor) authorize(ctx context.Context, method string) error { + md, ok := metadata.FromIncomingContext(ctx) + if !ok { + return status.Errorf(codes.Unauthenticated, "metadata is not provided") + } + + // validate token and check permission here + token := "" + if len(md["authorize"]) > 0 { + token = md["authorize"][0] + + claims, err := auth.jwtManager.VerifyToken(token) + if err != nil { + return err + } + + user, err := userc.Get(store.Query{Name: claims.Username}) + if err != nil { + return err + } + + if user.GetToken() != token { + return status.Errorf(codes.PermissionDenied, "invalid token") + } + + err = auth.verifyPermisisonForRequestedCall(user.GetRoles(), method) + if err != nil { + return err + } + } else { + return status.Errorf(codes.PermissionDenied, "no auth token provided") + } + + return nil +} + +func (auth *AuthInterceptor) verifyPermisisonForRequestedCall(userRoles map[string]string, requestedMethod string) error { + for _, userRole := range userRoles { + err := auth.verifyUserRoleAndRequestedCall(userRole, requestedMethod) + if err != nil { + return err + } + } + + return nil +} + +func (auth *AuthInterceptor) verifyUserRoleAndRequestedCall(userRole, requestedMethod string) error { + storedRoles, err := rolec.GetAll() + if err != nil { + return err + } + + for _, storedRole := range storedRoles { + if userRole == storedRole.Name() { + err := auth.compareRequestedPermissionWithRolePermissions(requestedMethod, storedRole.GetPermissions()) + if err != nil { + return err + } + } + } + + return nil +} + +func (auth *AuthInterceptor) compareRequestedPermissionWithRolePermissions(requestedMethod string, storedRolePermissions []string) error { + for _, permission := range storedRolePermissions { + if permission == requestedMethod { + return nil + } + } + + return status.Errorf(codes.PermissionDenied, "user not authorized for this call") +} diff --git a/controller/northbound/server/auth_test.go b/controller/northbound/server/auth_test.go index d8f8746d9..ba6487644 100644 --- a/controller/northbound/server/auth_test.go +++ b/controller/northbound/server/auth_test.go @@ -1,135 +1,219 @@ package server import ( + "bytes" "context" + "log" "reflect" "testing" - "time" apb "code.fbi.h-da.de/danet/gosdn/api/go/gosdn/rbac" "code.fbi.h-da.de/danet/gosdn/controller/rbac" + "github.com/google/uuid" ) -func Test_auth_Login(t *testing.T) { - type fields struct { - UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer - } +const adminID = "5c248a22-8eb7-48cf-b392-45680a1863a5" +const userID = "57005d13-7a4d-493d-a02b-50ca51c40197" +const adminRoleID = "126683ae-5ff2-43ee-92f7-0e2b936f8c77" +const randomRoleName = "bertram" + +var adminRoleMap = map[string]string{pndID: "admin"} +var userRoleMap = map[string]string{pndID: "user"} +var jwt *rbac.JWTManager + +func TestAuth_Login(t *testing.T) { type args struct { ctx context.Context request *apb.LoginRequest } tests := []struct { name string - fields fields args args want string wantErr bool }{ - // TODO: Add test cases. { - name: "login test", + name: "default login", + want: "testAdmin", + args: args{ + request: &apb.LoginRequest{ + Username: "testAdmin", + Pwd: "admin", + }, + }, + wantErr: false, + }, + { + name: "login fail wrong pwd", want: "", args: args{ - request: &apb.LoginRequest{}, + request: &apb.LoginRequest{ + Username: "testAdmin", + Pwd: "nope", + }, }, + wantErr: true, }, } - jwt := rbac.NewJWTManager("", 1*time.Minute) - for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := Auth{ - UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, - jwtManager: jwt, + jwtManager: jwt, } resp, err := r.Login(tt.args.ctx, tt.args.request) if (err != nil) != tt.wantErr { - t.Errorf("rbac.Login() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Auth.Login() error = %v, wantErr %v", err, tt.wantErr) return } - got := resp.GetStatus().String() - got = "" - - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("rbac.Login() = %v, want %v", got, tt.want) + if resp != nil { + got := resp.Token + if got == "" { + t.Errorf("Auth.Login() = %v, want non empty token", got) + } } }) } } -func Test_auth_Logout(t *testing.T) { - type fields struct { - UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer - } +func TestAuth_Logout(t *testing.T) { type args struct { ctx context.Context request *apb.LogoutRequest } tests := []struct { name string - fields fields args args want *apb.LogoutResponse wantErr bool }{ // TODO: Add test cases. + // Implement after session hdanling was added } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Auth{ - UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, - } - got, err := r.Logout(tt.args.ctx, tt.args.request) + s := Auth{} + got, err := s.Logout(tt.args.ctx, tt.args.request) if (err != nil) != tt.wantErr { - t.Errorf("rbac.Logout() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Auth.Logout() error = %v, wantErr %v", err, tt.wantErr) return } if !reflect.DeepEqual(got, tt.want) { - t.Errorf("rbac.Logout() = %v, want %v", got, tt.want) + t.Errorf("Auth.Logout() = %v, want %v", got, tt.want) } }) } } -func Test_rbac_CreateUsers(t *testing.T) { - type fields struct { - UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer - } +func TestAuth_CreateUsers(t *testing.T) { type args struct { ctx context.Context request *apb.CreateUsersRequest } tests := []struct { name string - fields fields args args - want *apb.CreateUsersResponse + want apb.Status wantErr bool }{ - // TODO: Add test cases. + { + name: "default create users", + args: args{ctx: context.TODO(), + request: &apb.CreateUsersRequest{ + User: []*apb.User{ + { + Name: "asdf", + Roles: map[string]string{pndID: "asdf"}, + Password: "asdf", + Token: "", + }, + }, + }, + }, + want: apb.Status_STATUS_OK, + wantErr: false, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Auth{ - UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, + s := Auth{} + got, err := s.CreateUsers(tt.args.ctx, tt.args.request) + if (err != nil) != tt.wantErr { + t.Errorf("Auth.CreateUsers() error = %v, wantErr %v", err, tt.wantErr) + return } - got, err := r.CreateUsers(tt.args.ctx, tt.args.request) + + if !reflect.DeepEqual(got.Status, tt.want) { + t.Errorf("Auth.CreateUsers() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAuth_GetUser(t *testing.T) { + patchLogger(t) + type args struct { + ctx context.Context + request *apb.GetUserRequest + } + tests := []struct { + name string + args args + want *apb.GetUserResponse + wantErr bool + }{ + { + name: "default get user", + args: args{ + ctx: context.TODO(), + request: &apb.GetUserRequest{ + Name: "testAdmin", + }, + }, + want: &apb.GetUserResponse{Status: apb.Status_STATUS_OK, + User: &apb.User{Id: adminID, + Name: "testAdmin"}}, + wantErr: false, + }, + { + name: "fail get user", + args: args{ + ctx: context.TODO(), + request: &apb.GetUserRequest{ + Name: "nope", + }, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Auth{} + got, err := s.GetUser(tt.args.ctx, tt.args.request) if (err != nil) != tt.wantErr { - t.Errorf("rbac.CreateUsers() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Auth.GetUser() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("rbac.CreateUsers() = %v, want %v", got, tt.want) + + if got != nil && got.Status == tt.want.Status { + if got.User.Name != tt.want.User.Name || got.User.Id != tt.want.User.Id { + t.Errorf("Auth.GetUser() = %v, want %v", got, tt.want) + } + } else { + if got != nil { + t.Errorf("Auth.GetUser() = %v, want %v", got, tt.want) + } } }) } } -func Test_rbac_GetUsers(t *testing.T) { - type fields struct { - UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer +func TestAuth_GetUsers(t *testing.T) { + err := clearAndCreateAuthTestSetup() + if err != nil { + t.Fatalf("%v", err) } type args struct { ctx context.Context @@ -137,94 +221,631 @@ func Test_rbac_GetUsers(t *testing.T) { } tests := []struct { name string - fields fields args args want *apb.GetUsersResponse + wantLen int wantErr bool }{ - // TODO: Add test cases. + { + name: "default get users", + args: args{ctx: context.TODO(), + request: &apb.GetUsersRequest{}, + }, + want: &apb.GetUsersResponse{Status: apb.Status_STATUS_OK, + User: []*apb.User{ + {Name: "testAdmin"}, + {Name: "testUser"}, + {Name: "testRandom"}}, + }, + wantLen: 3, + wantErr: false, + }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Auth{ - UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, - } - got, err := r.GetUsers(tt.args.ctx, tt.args.request) + s := Auth{} + got, err := s.GetUsers(tt.args.ctx, tt.args.request) if (err != nil) != tt.wantErr { - t.Errorf("rbac.GetUsers() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Auth.GetUsers() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("rbac.GetUsers() = %v, want %v", got, tt.want) + + if got != nil && got.Status == apb.Status_STATUS_OK { + if len(got.User) != tt.wantLen { + t.Errorf("Auth.GetUsers() = %v, want %v", got, tt.want) + } + + for _, gotU := range got.User { + containsExpected := false + for _, wantU := range tt.want.User { + if gotU.Name == wantU.Name { + containsExpected = true + break + } + } + if !containsExpected { + t.Errorf("Auth.GetUsers() = %v, want %v", got, tt.want) + } + } } }) } } -func Test_rbac_UpdateUsers(t *testing.T) { - type fields struct { - UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer - } +func TestAuth_UpdateUsers(t *testing.T) { type args struct { ctx context.Context request *apb.UpdateUsersRequest } tests := []struct { name string - fields fields args args want *apb.UpdateUsersResponse wantErr bool }{ - // TODO: Add test cases. + { + name: "default update user", + args: args{ctx: context.TODO(), + request: &apb.UpdateUsersRequest{User: []*apb.User{ + {Id: adminID, + Name: "sth Else"}, + }, + }, + }, + want: &apb.UpdateUsersResponse{ + Status: apb.Status_STATUS_OK}, + wantErr: false, + }, + { + name: "error update user", + args: args{ctx: context.TODO(), + request: &apb.UpdateUsersRequest{User: []*apb.User{ + {Id: uuid.NewString(), + Name: "not a user"}, + }, + }, + }, + want: nil, + wantErr: true, + }, } + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Auth{ - UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, - } - got, err := r.UpdateUsers(tt.args.ctx, tt.args.request) + s := Auth{} + got, err := s.UpdateUsers(tt.args.ctx, tt.args.request) if (err != nil) != tt.wantErr { - t.Errorf("rbac.UpdateUsers() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Auth.UpdateUsers() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("rbac.UpdateUsers() = %v, want %v", got, tt.want) + if got != nil && got.Status != tt.want.Status { + t.Errorf("Auth.UpdateUsers() = %v, want %v", got, tt.want) } }) } } -func Test_rbac_DeleteUsers(t *testing.T) { - type fields struct { - UnimplementedAuthServiceServer apb.UnimplementedAuthServiceServer - } +func TestAuth_DeleteUsers(t *testing.T) { type args struct { ctx context.Context request *apb.DeleteUsersRequest } tests := []struct { name string - fields fields args args want *apb.DeleteUsersResponse wantErr bool }{ - // TODO: Add test cases. + { + name: "default delete users", + args: args{ctx: context.TODO(), + request: &apb.DeleteUsersRequest{Username: []string{"testUser"}}, + }, + want: &apb.DeleteUsersResponse{Status: apb.Status_STATUS_OK}, + wantErr: false, + }, + { + name: "error delete users", + args: args{ctx: context.TODO(), + request: &apb.DeleteUsersRequest{Username: []string{"no user"}}, + }, + want: &apb.DeleteUsersResponse{Status: apb.Status_STATUS_OK}, + wantErr: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - r := Auth{ - UnimplementedAuthServiceServer: tt.fields.UnimplementedAuthServiceServer, + s := Auth{} + got, err := s.DeleteUsers(tt.args.ctx, tt.args.request) + if (err != nil) != tt.wantErr { + t.Errorf("Auth.DeleteUsers() error = %v, wantErr %v", err, tt.wantErr) + return } - got, err := r.DeleteUsers(tt.args.ctx, tt.args.request) + if got != nil && got.Status != tt.want.Status { + t.Errorf("Auth.DeleteUsers() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAuth_CreateRoles(t *testing.T) { + type args struct { + ctx context.Context + request *apb.CreateRolesRequest + } + tests := []struct { + name string + args args + want *apb.CreateRolesResponse + wantErr bool + }{ + { + name: "default create roles", + args: args{ctx: context.TODO(), + request: &apb.CreateRolesRequest{ + Roles: []*apb.Role{ + { + Name: "new role 1", + Description: "Role 1", + Permissions: []string{"permission 1", "permission 2"}, + }, + }, + }, + }, + want: &apb.CreateRolesResponse{Status: apb.Status_STATUS_OK}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Auth{} + got, err := s.CreateRoles(tt.args.ctx, tt.args.request) if (err != nil) != tt.wantErr { - t.Errorf("rbac.DeleteUsers() error = %v, wantErr %v", err, tt.wantErr) + t.Errorf("Auth.CreateRoles() error = %v, wantErr %v", err, tt.wantErr) return } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("rbac.DeleteUsers() = %v, want %v", got, tt.want) + + if got != nil && got.Status != tt.want.Status { + t.Errorf("Auth.CreateRoles() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAuth_GetRole(t *testing.T) { + type args struct { + ctx context.Context + request *apb.GetRoleRequest + } + tests := []struct { + name string + args args + want *apb.GetRoleResponse + wantErr bool + }{ + { + name: "default get role", + args: args{ + ctx: context.TODO(), + request: &apb.GetRoleRequest{ + RoleName: "adminTestRole", + }, + }, + want: &apb.GetRoleResponse{ + Role: &apb.Role{ + Name: "adminTestRole", + Description: "Admin", + }, + Status: apb.Status_STATUS_OK, + }, + wantErr: false, + }, + { + name: "error get role", + args: args{ + ctx: context.TODO(), + request: &apb.GetRoleRequest{ + RoleName: "not role", + }, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Auth{} + got, err := s.GetRole(tt.args.ctx, tt.args.request) + if (err != nil) != tt.wantErr { + t.Errorf("Auth.GetRole() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != nil && got.Status == tt.want.Status { + if got.Role.Name != tt.want.Role.Name || got.Role.Description != tt.want.Role.Description { + t.Errorf("Auth.GetRole() = %v, want %v", got, tt.want) + } + } else { + if got != nil { + t.Errorf("Auth.GetRole() = %v, want %v", got, tt.want) + } + } + }) + } +} + +func TestAuth_GetRoles(t *testing.T) { + err := clearAndCreateAuthTestSetup() + if err != nil { + t.Fatalf("%v", err) + } + + type args struct { + ctx context.Context + request *apb.GetRolesRequest + } + tests := []struct { + name string + args args + want *apb.GetRolesResponse + wantLen int + wantErr bool + }{ + { + name: "default get roles", + args: args{ + ctx: context.TODO(), + request: &apb.GetRolesRequest{}, + }, + want: &apb.GetRolesResponse{ + Status: apb.Status_STATUS_OK, + Roles: []*apb.Role{ + { + Name: "adminTestRole", + Description: "Admin", + Permissions: []string{ + "/gosdn.core.CoreService/GetPnd", + "/gosdn.core.CoreService/GetPndList", + }}, + { + Name: "userTestRole", + Description: "User", + Permissions: []string{ + "/gosdn.pnd.PndService/GetChangeList", + }}, + { + Name: randomRoleName, + Description: "Not a role", + Permissions: []string{ + "nope", + }, + }, + }, + }, + wantLen: 3, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Auth{} + got, err := s.GetRoles(tt.args.ctx, tt.args.request) + if (err != nil) != tt.wantErr { + t.Errorf("Auth.GetRoles() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != nil && got.Status == tt.want.Status { + if len(got.Roles) != 3 { + t.Errorf("Auth.GetRoles() = %v, want %v", got, tt.want) + } + for _, gotR := range got.Roles { + containsExpected := false + for _, wantR := range tt.want.Roles { + gotPerm := gotR.Permissions + wantPerm := wantR.Permissions + if gotR.Description == wantR.Description && gotR.Name == wantR.Name && + reflect.DeepEqual(gotPerm, wantPerm) { + containsExpected = true + break + } + } + if !containsExpected { + t.Errorf("Auth.GetRoles() = %v, want %v", got, tt.want) + } + } } }) } } + +func TestAuth_UpdateRoles(t *testing.T) { + type args struct { + ctx context.Context + request *apb.UpdateRolesRequest + } + tests := []struct { + name string + args args + want *apb.UpdateRolesResponse + wantErr bool + }{ + { + name: "default update roles", + args: args{ + ctx: context.TODO(), + request: &apb.UpdateRolesRequest{ + Roles: []*apb.Role{ + { + Id: adminRoleID, + Name: "New Name", + }, + }, + }, + }, + want: &apb.UpdateRolesResponse{ + Status: apb.Status_STATUS_OK, + }, + wantErr: false, + }, + { + name: "error update roles", + args: args{ + ctx: context.TODO(), + request: &apb.UpdateRolesRequest{ + Roles: []*apb.Role{ + { + Id: uuid.NewString(), + Name: "New Name", + }, + }, + }, + }, + want: nil, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Auth{} + got, err := s.UpdateRoles(tt.args.ctx, tt.args.request) + if (err != nil) != tt.wantErr { + t.Errorf("Auth.UpdateRoles() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != nil && got.Status != tt.want.Status { + t.Errorf("Auth.UpdateRoles() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAuth_DeletePermissionsForRole(t *testing.T) { + type args struct { + ctx context.Context + request *apb.DeletePermissionsForRoleRequest + } + tests := []struct { + name string + args args + want *apb.DeletePermissionsForRoleResponse + wantErr bool + }{ + { + name: "default delete permissions for role", + args: args{ + ctx: context.TODO(), + request: &apb.DeletePermissionsForRoleRequest{ + RoleName: "adminTestRole", + PermissionsToDelete: []string{ + "/gosdn.core.CoreService/GetPnd", + "/gosdn.core.CoreService/GetPndList", + }, + }, + }, + want: &apb.DeletePermissionsForRoleResponse{ + Status: apb.Status_STATUS_OK, + }, + wantErr: false, + }, + { + name: "error delete permissions for role no proper permissions provided", + args: args{ + ctx: context.TODO(), + request: &apb.DeletePermissionsForRoleRequest{ + RoleName: "adminTestRole", + PermissionsToDelete: []string{ + "no", + }, + }, + }, + want: &apb.DeletePermissionsForRoleResponse{ + Status: apb.Status_STATUS_OK, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Auth{} + got, err := s.DeletePermissionsForRole(tt.args.ctx, tt.args.request) + if (err != nil) != tt.wantErr { + t.Errorf("Auth.DeletePermissionsForRole() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != nil && got.Status != tt.want.Status { + t.Errorf("Auth.DeletePermissionsForRole() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestAuth_DeleteRoles(t *testing.T) { + type args struct { + ctx context.Context + request *apb.DeleteRolesRequest + } + tests := []struct { + name string + args args + want *apb.DeleteRolesResponse + wantErr bool + }{ + { + name: "default delete roles", + args: args{ + ctx: context.TODO(), + request: &apb.DeleteRolesRequest{ + RoleName: []string{ + "userTestRole", + }, + }, + }, + want: &apb.DeleteRolesResponse{ + Status: apb.Status_STATUS_OK, + }, + wantErr: false, + }, + { + name: "error delete roles", + args: args{ + ctx: context.TODO(), + request: &apb.DeleteRolesRequest{ + RoleName: []string{ + "no", + }, + }, + }, + want: &apb.DeleteRolesResponse{ + Status: apb.Status_STATUS_OK, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := Auth{} + got, err := s.DeleteRoles(tt.args.ctx, tt.args.request) + if (err != nil) != tt.wantErr { + t.Errorf("Auth.DeleteRoles() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != nil && got.Status != tt.want.Status { + t.Errorf("Auth.DeleteRoles() = %v, want %v", got, tt.want) + } + }) + } +} + +func clearAndCreateAuthTestSetup() error { + //clear setup if changed + storedUsers, err := userc.GetAll() + if err != nil { + return err + } + for _, u := range storedUsers { + err = userc.Delete(u) + if err != nil { + return err + } + } + + storedRoles, err := rolec.GetAll() + if err != nil { + return err + } + for _, r := range storedRoles { + err = rolec.Delete(r) + if err != nil { + return err + } + } + + // create dataset + err = createTestUsers() + if err != nil { + return err + } + + err = createTestRoles() + if err != nil { + return err + } + + return nil +} + +//TODO(faseid): change password to hashed/encrypted one +func createTestUsers() error { + randomRoleMap := map[string]string{pndID: randomRoleName} + + users := []rbac.User{ + {UserID: uuid.MustParse(adminID), UserName: "testAdmin", Roles: adminRoleMap, Password: "admin"}, + {UserID: uuid.MustParse(userID), UserName: "testUser", Roles: userRoleMap, Password: "user"}, + {UserID: uuid.New(), UserName: "testRandom", Roles: randomRoleMap, Password: "aurelius", Token: "wrong token"}, + } + + for _, u := range users { + err := userc.Add(rbac.NewUser(u.ID(), u.Name(), u.Roles, u.Password, "")) + if err != nil { + return err + } + } + + return nil +} + +func createTestRoles() error { + roles := []rbac.Role{ + { + RoleID: uuid.MustParse(adminRoleID), + RoleName: "adminTestRole", + Description: "Admin", + Permissions: []string{ + "/gosdn.core.CoreService/GetPnd", + "/gosdn.core.CoreService/GetPndList", + }, + }, + { + RoleID: uuid.New(), + RoleName: "userTestRole", + Description: "User", + Permissions: []string{ + "/gosdn.pnd.PndService/GetChangeList", + }, + }, + { + RoleID: uuid.New(), + RoleName: randomRoleName, + Description: "Not a role", + Permissions: []string{ + "nope", + }, + }, + } + + for _, r := range roles { + err := rolec.Add(rbac.NewRole(r.ID(), r.Name(), r.Description, r.Permissions)) + if err != nil { + return err + } + } + + return nil +} + +// This is needed as a workaround for a bug where the output of the getUser test falsely was +// that it failed while actually passing. Apparantely, this can happen when loggers write +// the output of test cases. +// Solution found here: https://github.com/gotestyourself/gotestsum/issues/141#issuecomment-686243110 +func patchLogger(t *testing.T) { + orig := log.Writer() + buf := new(bytes.Buffer) + log.SetOutput(buf) + + t.Cleanup(func() { + // optionally check t.Failed here if you only want to print logs on failure + + t.Log(buf.String()) + log.SetOutput(orig) + }) +} diff --git a/controller/northbound/server/nbi.go b/controller/northbound/server/nbi.go index 38230e7f0..35fa92ab2 100644 --- a/controller/northbound/server/nbi.go +++ b/controller/northbound/server/nbi.go @@ -2,6 +2,7 @@ package server import ( "code.fbi.h-da.de/danet/gosdn/controller/interfaces/networkdomain" + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" "code.fbi.h-da.de/danet/gosdn/controller/metrics" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" @@ -10,6 +11,8 @@ import ( ) var pndc networkdomain.PndStore +var userc rbac.UserService +var rolec rbac.RoleService // NorthboundInterface is the representation of the // gRPC services used provided. @@ -22,8 +25,10 @@ type NorthboundInterface struct { } // NewNBI receives a PndStore and returns a new gRPC *NorthboundInterface -func NewNBI(pnds networkdomain.PndStore) *NorthboundInterface { +func NewNBI(pnds networkdomain.PndStore, users rbac.UserService, roles rbac.RoleService) *NorthboundInterface { pndc = pnds + userc = users + rolec = roles return &NorthboundInterface{ Pnd: &pndServer{}, Core: &core{}, diff --git a/controller/northbound/server/pnd_test.go b/controller/northbound/server/pnd_test.go index b2acf2d7f..6fa7ea406 100644 --- a/controller/northbound/server/pnd_test.go +++ b/controller/northbound/server/pnd_test.go @@ -15,6 +15,7 @@ import ( "code.fbi.h-da.de/danet/gosdn/controller/interfaces/southbound" "code.fbi.h-da.de/danet/gosdn/controller/mocks" "code.fbi.h-da.de/danet/gosdn/controller/nucleus" + "code.fbi.h-da.de/danet/gosdn/controller/rbac" "code.fbi.h-da.de/danet/yang-models/generated/openconfig" "github.com/golang/protobuf/proto" "github.com/google/go-cmp/cmp" @@ -44,6 +45,7 @@ var committedChangeUUID uuid.UUID var deviceUUID uuid.UUID var mockPnd *mocks.NetworkDomain var mockDevice device.Device +var mockJwt *rbac.JWTManager var sbiStore southbound.Store func callback(id uuid.UUID, ch chan device.Details) { @@ -147,6 +149,15 @@ func TestMain(m *testing.M) { log.Fatal(err) } + // everyting auth related + userc = rbac.NewUserService(rbac.NewMemoryUserStore()) + rolec = rbac.NewRoleService(rbac.NewMemoryRoleStore()) + err = clearAndCreateAuthTestSetup() + if err != nil { + log.Fatal(err) + } + jwt = rbac.NewJWTManager("", 1*time.Minute) + os.Exit(m.Run()) } diff --git a/controller/nucleus/databaseSbiStore.go b/controller/nucleus/databaseSbiStore.go index 4c1ebe70f..484311007 100644 --- a/controller/nucleus/databaseSbiStore.go +++ b/controller/nucleus/databaseSbiStore.go @@ -10,7 +10,6 @@ import ( "go.mongodb.org/mongo-driver/bson/primitive" "go.mongodb.org/mongo-driver/mongo" - "github.com/google/uuid" log "github.com/sirupsen/logrus" ) @@ -109,32 +108,6 @@ func (s *DatabaseSbiStore) GetAll() ([]southbound.LoadedSbi, error) { return loadedSbis, nil } -// GetSBI takes a SouthboundInterface's UUID or name and returns the SouthboundInterface. If the requested -// SouthboundInterface does not exist an error is returned. -func (s *DatabaseSbiStore) GetSBI(id uuid.UUID) (southbound.LoadedSbi, error) { - var loadedSbi southbound.LoadedSbi - - client, ctx, cancel := database.GetMongoConnection() - defer cancel() - defer client.Disconnect(ctx) - - db := client.Database(database.DatabaseName) - collection := db.Collection(s.sbiStoreName) - result := collection.FindOne(ctx, bson.D{primitive.E{Key: "_id", Value: id.String()}}) - if result == nil { - return loadedSbi, nil - } - - err := result.Decode(&loadedSbi) - if err != nil { - log.Printf("Failed marshalling %v", err) - - return loadedSbi, errors.ErrCouldNotMarshall{StoreName: sbiStoreName} - } - - return loadedSbi, nil -} - func getSbiTypeFromString(sbiTypeAsString string) spb.Type { sbiTypeInt := spb.Type_value[sbiTypeAsString] diff --git a/controller/rbac/databaseRoleStore.go b/controller/rbac/databaseRoleStore.go new file mode 100644 index 000000000..4ee86a6c0 --- /dev/null +++ b/controller/rbac/databaseRoleStore.go @@ -0,0 +1,179 @@ +package rbac + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/nucleus/database" + "code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors" + "code.fbi.h-da.de/danet/gosdn/controller/store" + "github.com/google/uuid" + log "github.com/sirupsen/logrus" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +// DatabaseRoleStore is used to store roles in database +type DatabaseRoleStore struct { + roleStoreName string +} + +// Add adds a Role. +func (s *DatabaseRoleStore) Add(roleToAdd rbac.Role) error { + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + _, err := client.Database(database.DatabaseName). + Collection(s.roleStoreName). + InsertOne(ctx, roleToAdd) + if err != nil { + if mongo.IsDuplicateKeyError(err) { + return nil + } + + return errors.ErrCouldNotCreate{StoreName: s.roleStoreName} + } + + return nil +} + +// Delete deletes a Role. +func (s *DatabaseRoleStore) Delete(roleToDelete rbac.Role) error { + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + _, err := client.Database(database.DatabaseName). + Collection(s.roleStoreName). + DeleteOne(ctx, bson.D{primitive.E{Key: "_id", Value: roleToDelete.ID().String()}}) + if err != nil { + return errors.ErrCouldNotFind{StoreName: s.roleStoreName} + } + + return nil +} + +// Get takes a Roles's UUID or name and returns the Role. If the requested +// Role does not exist an error is returned. +func (s *DatabaseRoleStore) Get(query store.Query) (rbac.LoadedRole, error) { + var loadedRole rbac.LoadedRole + + if query.ID != uuid.Nil { + loadedRole, err := s.getByID(query.ID) + if err != nil { + return loadedRole, errors.ErrCouldNotFind{StoreName: s.roleStoreName} + } + + return loadedRole, nil + } + + loadedRole, err := s.getByName(query.Name) + if err != nil { + return loadedRole, errors.ErrCouldNotFind{StoreName: s.roleStoreName} + } + + return loadedRole, nil +} + +func (s *DatabaseRoleStore) getByID(idOfRole uuid.UUID) (rbac.LoadedRole, error) { + var loadedRole rbac.LoadedRole + + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + db := client.Database(database.DatabaseName) + collection := db.Collection(s.roleStoreName) + result := collection.FindOne(ctx, bson.D{primitive.E{Key: "_id", Value: idOfRole.String()}}) + if result == nil { + return loadedRole, errors.ErrCouldNotFind{StoreName: s.roleStoreName} + } + + err := result.Decode(&loadedRole) + if err != nil { + log.Printf("Failed marshalling %v", err) + return loadedRole, errors.ErrCouldNotFind{StoreName: s.roleStoreName} + } + + return loadedRole, nil +} + +func (s *DatabaseRoleStore) getByName(nameOfRole string) (rbac.LoadedRole, error) { + var loadedRole rbac.LoadedRole + + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + db := client.Database(database.DatabaseName) + collection := db.Collection(s.roleStoreName) + result := collection.FindOne(ctx, bson.D{primitive.E{Key: "rolename", Value: nameOfRole}}) + if result == nil { + return loadedRole, errors.ErrCouldNotFind{StoreName: s.roleStoreName} + } + + err := result.Decode(&loadedRole) + if err != nil { + log.Printf("Failed marshalling %v", err) + return loadedRole, errors.ErrCouldNotFind{StoreName: s.roleStoreName} + } + + return loadedRole, nil +} + +// GetAll returns all Roles. +func (s *DatabaseRoleStore) GetAll() ([]rbac.LoadedRole, error) { + var loadedRoles []rbac.LoadedRole + + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + db := client.Database(database.DatabaseName) + collection := db.Collection(s.roleStoreName) + + cursor, err := collection.Find(ctx, bson.D{}) + if err != nil { + return nil, err + } + defer cursor.Close(ctx) + + err = cursor.All(ctx, &loadedRoles) + if err != nil { + log.Printf("Failed marshalling %v", err) + + return nil, errors.ErrCouldNotMarshall{StoreName: s.roleStoreName} + } + return loadedRoles, nil +} + +// Update updates the role +func (s *DatabaseRoleStore) Update(roleToUpdate rbac.Role) error { + var updatedLoadedRole rbac.LoadedRole + + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + update := bson.D{primitive.E{Key: "$set", Value: roleToUpdate}} + + upsert := false + after := options.After + opt := options.FindOneAndUpdateOptions{ + Upsert: &upsert, + ReturnDocument: &after, + } + + err := client.Database(database.DatabaseName). + Collection(s.roleStoreName). + FindOneAndUpdate( + ctx, bson.M{"_id": roleToUpdate.ID().String()}, update, &opt). + Decode(&updatedLoadedRole) + if err != nil { + log.Printf("Could not update Role: %v", err) + + return errors.ErrCouldNotUpdate{StoreName: s.roleStoreName} + } + + return nil +} diff --git a/controller/rbac/databaseUserStore.go b/controller/rbac/databaseUserStore.go new file mode 100644 index 000000000..f6b0064c3 --- /dev/null +++ b/controller/rbac/databaseUserStore.go @@ -0,0 +1,179 @@ +package rbac + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/nucleus/database" + "code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors" + "code.fbi.h-da.de/danet/gosdn/controller/store" + "github.com/google/uuid" + log "github.com/sirupsen/logrus" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +// DatabaseUserStore is used to store users in database +type DatabaseUserStore struct { + userStoreName string +} + +// Add adds an User. +func (s *DatabaseUserStore) Add(userToAdd rbac.User) error { + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + _, err := client.Database(database.DatabaseName). + Collection(s.userStoreName). + InsertOne(ctx, userToAdd) + if err != nil { + if mongo.IsDuplicateKeyError(err) { + return nil + } + + return errors.ErrCouldNotCreate{StoreName: s.userStoreName} + } + + return nil +} + +// Delete deletes an User. +func (s *DatabaseUserStore) Delete(userToDelete rbac.User) error { + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + _, err := client.Database(database.DatabaseName). + Collection(s.userStoreName). + DeleteOne(ctx, bson.D{primitive.E{Key: "_id", Value: userToDelete.ID().String()}}) + if err != nil { + return errors.ErrCouldNotFind{StoreName: s.userStoreName} + } + + return nil +} + +// Get takes a User's UUID or name and returns the User. If the requested +// User does not exist an error is returned. +func (s *DatabaseUserStore) Get(query store.Query) (rbac.LoadedUser, error) { + var loadedUser rbac.LoadedUser + + if query.ID != uuid.Nil { + loadedUser, err := s.getByID(query.ID) + if err != nil { + return loadedUser, errors.ErrCouldNotFind{StoreName: s.userStoreName} + } + + return loadedUser, nil + } + + loadedUser, err := s.getByName(query.Name) + if err != nil { + return loadedUser, errors.ErrCouldNotFind{StoreName: s.userStoreName} + } + + return loadedUser, nil +} + +func (s *DatabaseUserStore) getByID(idOfUser uuid.UUID) (rbac.LoadedUser, error) { + var loadedUser rbac.LoadedUser + + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + db := client.Database(database.DatabaseName) + collection := db.Collection(s.userStoreName) + result := collection.FindOne(ctx, bson.D{primitive.E{Key: "_id", Value: idOfUser.String()}}) + if result == nil { + return loadedUser, errors.ErrCouldNotFind{StoreName: s.userStoreName} + } + + err := result.Decode(&loadedUser) + if err != nil { + log.Printf("Failed marshalling %v", err) + return loadedUser, errors.ErrCouldNotFind{StoreName: s.userStoreName} + } + + return loadedUser, nil +} + +func (s *DatabaseUserStore) getByName(nameOfUser string) (rbac.LoadedUser, error) { + var loadedUser rbac.LoadedUser + + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + db := client.Database(database.DatabaseName) + collection := db.Collection(s.userStoreName) + result := collection.FindOne(ctx, bson.D{primitive.E{Key: "username", Value: nameOfUser}}) + if result == nil { + return loadedUser, errors.ErrCouldNotFind{StoreName: s.userStoreName} + } + + err := result.Decode(&loadedUser) + if err != nil { + log.Printf("Failed marshalling %v", err) + return loadedUser, errors.ErrCouldNotFind{StoreName: s.userStoreName} + } + + return loadedUser, nil +} + +// GetAll returns all Users +func (s *DatabaseUserStore) GetAll() ([]rbac.LoadedUser, error) { + var loadedUsers []rbac.LoadedUser + + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + db := client.Database(database.DatabaseName) + collection := db.Collection(s.userStoreName) + + cursor, err := collection.Find(ctx, bson.D{}) + if err != nil { + return nil, err + } + defer cursor.Close(ctx) + + err = cursor.All(ctx, &loadedUsers) + if err != nil { + log.Printf("Failed marshalling %v", err) + + return nil, errors.ErrCouldNotMarshall{StoreName: s.userStoreName} + } + return loadedUsers, nil +} + +// Update updates the User. +func (s *DatabaseUserStore) Update(userToUpdate rbac.User) error { + var updatedLoadedUser rbac.LoadedUser + + client, ctx, cancel := database.GetMongoConnection() + defer cancel() + defer client.Disconnect(ctx) + + update := bson.D{primitive.E{Key: "$set", Value: userToUpdate}} + + upsert := false + after := options.After + opt := options.FindOneAndUpdateOptions{ + Upsert: &upsert, + ReturnDocument: &after, + } + + err := client.Database(database.DatabaseName). + Collection(s.userStoreName). + FindOneAndUpdate( + ctx, bson.M{"_id": userToUpdate.ID().String()}, update, &opt). + Decode(&updatedLoadedUser) + if err != nil { + log.Printf("Could not update User: %v", err) + + return errors.ErrCouldNotUpdate{StoreName: s.userStoreName} + } + + return nil +} diff --git a/controller/rbac/jwtManager.go b/controller/rbac/jwtManager.go index 40eae4924..981310821 100644 --- a/controller/rbac/jwtManager.go +++ b/controller/rbac/jwtManager.go @@ -31,7 +31,7 @@ type UserClaims struct { func (man *JWTManager) GenerateToken(user User) (string, error) { claims := UserClaims{ StandardClaims: jwt.StandardClaims{ExpiresAt: time.Now().Add(man.tokenDuration).Unix()}, - Username: user.GetName(), + Username: user.Name(), } token := jwt.NewWithClaims(signingMethod, claims) diff --git a/controller/rbac/jwtManager_test.go b/controller/rbac/jwtManager_test.go new file mode 100644 index 000000000..e79ec1b9a --- /dev/null +++ b/controller/rbac/jwtManager_test.go @@ -0,0 +1,110 @@ +package rbac + +import ( + "reflect" + "testing" + "time" + + "github.com/golang-jwt/jwt" +) + +func TestJWTManager_GenerateToken(t *testing.T) { + type fields struct { + secretKey string + tokenDuration time.Duration + } + type args struct { + user User + } + tests := []struct { + name string + fields fields + args args + want string + wantErr bool + }{ + { + name: "default generate token", + fields: fields{ + secretKey: "", + tokenDuration: 1 * time.Minute, + }, + args: args{ + user: User{ + UserName: "testUser", + }, + }, + want: "testUser", + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + man := &JWTManager{ + secretKey: tt.fields.secretKey, + tokenDuration: tt.fields.tokenDuration, + } + got, err := man.GenerateToken(tt.args.user) + if (err != nil) != tt.wantErr { + t.Errorf("JWTManager.GenerateToken() error = %v, wantErr %v", err, tt.wantErr) + return + } + + gotClaims, _ := man.VerifyToken(got) + claimsUser := gotClaims.Username + + if claimsUser != tt.want { + t.Errorf("JWTManager.GenerateToken() = %v, want %v", claimsUser, tt.want) + } + }) + } +} + +func TestJWTManager_VerifyToken(t *testing.T) { + type fields struct { + secretKey string + tokenDuration time.Duration + } + tests := []struct { + name string + fields fields + userName string + want *UserClaims + wantErr bool + }{ + { + name: "default verify token", + fields: fields{ + secretKey: "", + tokenDuration: 1 * time.Minute, + }, + userName: "testUser", + want: &UserClaims{ + StandardClaims: jwt.StandardClaims{ + ExpiresAt: time.Now().Add(1 * time.Minute).Unix(), + }, + Username: "testUser", + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + man := &JWTManager{ + secretKey: tt.fields.secretKey, + tokenDuration: tt.fields.tokenDuration, + } + + token, err := man.GenerateToken(User{UserName: tt.userName}) + got, err := man.VerifyToken(token) + if (err != nil) != tt.wantErr { + t.Errorf("JWTManager.VerifyToken() error = %v, wantErr %v", err, tt.wantErr) + return + } + + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("JWTManager.VerifyToken() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/controller/rbac/memoryRoleStore.go b/controller/rbac/memoryRoleStore.go new file mode 100644 index 000000000..e40dc60b7 --- /dev/null +++ b/controller/rbac/memoryRoleStore.go @@ -0,0 +1,110 @@ +package rbac + +import ( + "encoding/json" + + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors" + "code.fbi.h-da.de/danet/gosdn/controller/store" +) + +//MemoryRoleStore provides a in-memory implementation for roles. +type MemoryRoleStore struct { + Store map[string]rbac.LoadedRole + nameLookupTable map[string]string +} + +// NewMemoryRoleStore returns a specific in-memory store for roles. +func NewMemoryRoleStore() rbac.RoleStore { + return &MemoryRoleStore{ + Store: make(map[string]rbac.LoadedRole), + nameLookupTable: make(map[string]string), + } +} + +// Add adds a item to the store. +func (s *MemoryRoleStore) Add(item rbac.Role) error { + var role rbac.LoadedRole + + b, err := json.Marshal(item) + if err != nil { + return err + } + err = json.Unmarshal(b, &role) + if err != nil { + return err + } + + _, ok := s.Store[role.ID] + if ok { + return nil + } + + s.Store[role.ID] = role + s.nameLookupTable[item.Name()] = role.ID + + return nil +} + +// Delete deletes a role from the role store. +func (s *MemoryRoleStore) Delete(item rbac.Role) error { + delete(s.Store, item.ID().String()) + return nil +} + +// Update updates an existing role. +func (s *MemoryRoleStore) Update(item rbac.Role) error { + _, ok := s.Store[item.ID().String()] + if ok { + return nil + } + + var role rbac.LoadedRole + + b, err := json.Marshal(item) + if err != nil { + return err + } + err = json.Unmarshal(b, &role) + if err != nil { + return err + } + + s.Store[item.ID().String()] = role + s.nameLookupTable[item.Name()] = item.ID().String() + + return nil +} + +// Get takes a role's UUID or name and returns the role. +func (s *MemoryRoleStore) Get(query store.Query) (rbac.LoadedRole, error) { + // First search for direct hit on UUID. + item, ok := s.Store[query.ID.String()] + if !ok { + // Second search for name + id, ok := s.nameLookupTable[query.Name] + if !ok { + return item, errors.ErrCouldNotFind{StoreName: roleStoreName} + } + + item, ok := s.Store[id] + if !ok { + return item, errors.ErrCouldNotFind{StoreName: roleStoreName} + } + + return item, nil + } + + return item, nil +} + +// GetAll returns all stored roles. +func (s *MemoryRoleStore) GetAll() ([]rbac.LoadedRole, error) { + var allItems []rbac.LoadedRole + + for _, item := range s.Store { + allItems = append(allItems, item) + } + + return allItems, nil +} diff --git a/controller/rbac/memoryUserStore.go b/controller/rbac/memoryUserStore.go new file mode 100644 index 000000000..338f56180 --- /dev/null +++ b/controller/rbac/memoryUserStore.go @@ -0,0 +1,110 @@ +package rbac + +import ( + "encoding/json" + + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors" + "code.fbi.h-da.de/danet/gosdn/controller/store" +) + +//MemoryUserStore provides a in-memory implementation for users. +type MemoryUserStore struct { + Store map[string]rbac.LoadedUser + nameLookupTable map[string]string +} + +// NewMemoryUserStore returns a specific in-memory store for users. +func NewMemoryUserStore() rbac.UserStore { + return &MemoryUserStore{ + Store: make(map[string]rbac.LoadedUser), + nameLookupTable: make(map[string]string), + } +} + +// Add adds a item to the store. +func (s *MemoryUserStore) Add(item rbac.User) error { + var user rbac.LoadedUser + + b, err := json.Marshal(item) + if err != nil { + return err + } + err = json.Unmarshal(b, &user) + if err != nil { + return err + } + + _, ok := s.Store[user.ID] + if ok { + return nil + } + + s.Store[user.ID] = user + s.nameLookupTable[item.Name()] = user.ID + + return nil +} + +// Delete deletes a user from the user store. +func (s *MemoryUserStore) Delete(item rbac.User) error { + delete(s.Store, item.ID().String()) + return nil +} + +// Update updates an existing user. +func (s *MemoryUserStore) Update(item rbac.User) error { + _, ok := s.Store[item.ID().String()] + if ok { + return nil + } + + var user rbac.LoadedUser + + b, err := json.Marshal(item) + if err != nil { + return err + } + err = json.Unmarshal(b, &user) + if err != nil { + return err + } + + s.Store[item.ID().String()] = user + s.nameLookupTable[item.Name()] = item.ID().String() + + return nil +} + +// Get takes a user's UUID or name and returns the user. +func (s *MemoryUserStore) Get(query store.Query) (rbac.LoadedUser, error) { + // First search for direct hit on UUID. + item, ok := s.Store[query.ID.String()] + if !ok { + // Second search for name + id, ok := s.nameLookupTable[query.Name] + if !ok { + return item, errors.ErrCouldNotFind{StoreName: userStoreName} + } + + item, ok := s.Store[id] + if !ok { + return item, errors.ErrCouldNotFind{StoreName: userStoreName} + } + + return item, nil + } + + return item, nil +} + +// GetAll returns all stored users. +func (s *MemoryUserStore) GetAll() ([]rbac.LoadedUser, error) { + var allItems []rbac.LoadedUser + + for _, item := range s.Store { + allItems = append(allItems, item) + } + + return allItems, nil +} diff --git a/controller/rbac/rbacService.go b/controller/rbac/rbacService.go new file mode 100644 index 000000000..e6f000c3d --- /dev/null +++ b/controller/rbac/rbacService.go @@ -0,0 +1,151 @@ +package rbac + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/store" + "github.com/google/uuid" +) + +//UserService provides a user service implementation. +type UserService struct { + userStore rbac.UserStore +} + +// NewUserService creates a user service. +func NewUserService(userStore rbac.UserStore) rbac.UserService { + return &UserService{ + userStore: userStore, + } +} + +// Add adds a user to the user store. +func (s *UserService) Add(userToAdd rbac.User) error { + err := s.userStore.Add(userToAdd) + if err != nil { + return err + } + + return nil +} + +// Delete deletes a user from the user store. +func (s *UserService) Delete(userToDelete rbac.User) error { + err := s.userStore.Delete(userToDelete) + if err != nil { + return err + } + + return nil +} + +// Update updates a existing user. +func (s *UserService) Update(userToUpdate rbac.User) error { + err := s.userStore.Update(userToUpdate) + if err != nil { + return err + } + + return nil +} + +// Get takes a user's UUID or name and returns the user. +func (s *UserService) Get(query store.Query) (rbac.User, error) { + loadedUser, err := s.userStore.Get(query) + if err != nil { + return nil, err + } + + return s.createUserFromStore(loadedUser), nil +} + +// GetAll returns all stored users. +func (s *UserService) GetAll() ([]rbac.User, error) { + var users []rbac.User + + loadedUsers, err := s.userStore.GetAll() + if err != nil { + return nil, err + } + + for _, loadedUser := range loadedUsers { + users = append(users, s.createUserFromStore(loadedUser)) + } + + return users, nil +} + +func (s *UserService) createUserFromStore(loadedUser rbac.LoadedUser) rbac.User { + return NewUser(uuid.MustParse(loadedUser.ID), loadedUser.UserName, loadedUser.Roles, loadedUser.Password, loadedUser.Token) +} + +//RoleService provides a role service implementation. +type RoleService struct { + roleStore rbac.RoleStore +} + +// NewRoleService creates a role service. +func NewRoleService(roleStore rbac.RoleStore) rbac.RoleService { + return &RoleService{ + roleStore: roleStore, + } +} + +// Add adds a role to the role store. +func (s *RoleService) Add(roleToAdd rbac.Role) error { + err := s.roleStore.Add(roleToAdd) + if err != nil { + return err + } + + return nil +} + +// Delete deletes a role from the role store. +func (s *RoleService) Delete(roleToDelete rbac.Role) error { + err := s.roleStore.Delete(roleToDelete) + if err != nil { + return err + } + + return nil +} + +// Update updates a existing role. +func (s *RoleService) Update(roleToUpdate rbac.Role) error { + err := s.roleStore.Update(roleToUpdate) + if err != nil { + return err + } + + return nil +} + +// Get takes a roles's UUID or name and returns the role. +func (s *RoleService) Get(query store.Query) (rbac.Role, error) { + loadedRole, err := s.roleStore.Get(query) + if err != nil { + return nil, err + } + + return s.createRoleFromStore(loadedRole), nil +} + +// GetAll returns all stored roles. +func (s *RoleService) GetAll() ([]rbac.Role, error) { + var roles []rbac.Role + + loadedRoles, err := s.roleStore.GetAll() + if err != nil { + return nil, err + } + + for _, loadedRole := range loadedRoles { + roles = append(roles, s.createRoleFromStore(loadedRole)) + } + + return roles, nil +} + +func (s *RoleService) createRoleFromStore(loadedRole rbac.LoadedRole) rbac.Role { + return NewRole(uuid.MustParse(loadedRole.ID), loadedRole.RoleName, loadedRole.Description, loadedRole.Permissions) +} diff --git a/controller/rbac/role.go b/controller/rbac/role.go new file mode 100644 index 000000000..a506247ac --- /dev/null +++ b/controller/rbac/role.go @@ -0,0 +1,96 @@ +package rbac + +import ( + "encoding/json" + + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" +) + +// Role represents the data of a role used for access control and is stored in a storage. +type Role struct { + RoleID uuid.UUID `json:"_id"` + RoleName string `json:"rolename"` + Description string `json:"description,omitempty"` + Permissions []string `json:"permissions,omitempty"` +} + +// NewRole creates a new role. +func NewRole(id uuid.UUID, + name string, + description string, + permissions []string) rbac.Role { + return &Role{ + RoleID: id, + RoleName: name, + Description: description, + Permissions: permissions, + } +} + +// ID returns a UUID of the role. +func (r Role) ID() uuid.UUID { + return r.RoleID +} + +// Name returns the name of the role. +func (r Role) Name() string { + return r.RoleName +} + +// GetDescription returns the description of the role. +func (r *Role) GetDescription() string { + return r.Description +} + +// GetPermissions returns the permissions linked to the role. +func (r Role) GetPermissions() []string { + return r.Permissions +} + +// RemovePermissionsFromRole takes permissions that should be removed from a role and updates the current permissions accordingly +func (r *Role) RemovePermissionsFromRole(permissionsToRemove []string) { + for _, permToRemove := range permissionsToRemove { + r.removePermissionFromRoles(permToRemove) + } +} + +func (r *Role) removePermissionFromRoles(permToRemove string) { + for i, perm := range r.Permissions { + if perm == permToRemove { + r.Permissions = append(r.Permissions[:i], r.Permissions[i+1:]...) + break + } + } +} + +// MarshalJSON implements the MarshalJSON interface to store a role as JSON +func (r *Role) MarshalJSON() ([]byte, error) { + return json.Marshal(&struct { + RoleID uuid.UUID `json:"_id"` + RoleName string `json:"rolename"` + Description string `json:"description,omitempty"` + Permissions []string `json:"permissions,omitempty"` + }{ + RoleID: r.ID(), + RoleName: r.Name(), + Description: r.Description, + Permissions: r.Permissions, + }) +} + +// MarshalBSON implments the MarshalBSON interface to store a role as BSON +func (r *Role) MarshalBSON() ([]byte, error) { + return bson.Marshal(&struct { + RoleID string `bson:"_id"` + RoleName string `bson:"rolename"` + Description string `bson:"description,omitempty"` + Permissions []string `bson:"permissions,omitempty"` + }{ + RoleID: r.ID().String(), + RoleName: r.Name(), + Description: r.Description, + Permissions: r.Permissions, + }) +} diff --git a/controller/rbac/roleStore.go b/controller/rbac/roleStore.go new file mode 100644 index 000000000..4482168fa --- /dev/null +++ b/controller/rbac/roleStore.go @@ -0,0 +1,31 @@ +package rbac + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/store" +) + +const ( + roleStoreName = "role" +) + +// RoleStore is used to store Roles +type RoleStore struct { + roleStoreName string +} + +// NewRoleStore returns a roleStore +func NewRoleStore() rbac.RoleStore { + storeMode := store.GetStoreMode() + + switch storeMode { + case store.Filesystem: + return NewMemoryRoleStore() + case store.Database: + return &DatabaseRoleStore{"role.json"} + case store.Memory: + return NewMemoryRoleStore() + default: + return nil + } +} diff --git a/controller/rbac/user.go b/controller/rbac/user.go index 475b403ff..0ff1ecd3c 100644 --- a/controller/rbac/user.go +++ b/controller/rbac/user.go @@ -1,25 +1,107 @@ package rbac import ( + "encoding/json" + + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" ) -// Users represents a set of multiple users. -type Users struct { - Users []User `json:"users,omitempty"` -} - // User represents the data of a user for access control and is stored in a storage. type User struct { - ID uuid.UUID `json:"id,omitempty"` - Name string `json:"name,omitempty"` - Roles []string `json:"roles,omitempty"` - PndID uuid.UUID `json:"pndId,omitempty"` - Password string `json:"password,omitempty"` - Token string `json:"token,omitempty"` + UserID uuid.UUID `json:"_id"` + UserName string `json:"username"` + Roles map[string]string `json:"roles,omitempty"` + Password string `json:"password"` + Token string `json:"token,omitempty"` +} + +// NewUser creates a new user. +func NewUser(id uuid.UUID, + name string, + roles map[string]string, + pw string, + token string) rbac.User { + return &User{ + UserID: id, + UserName: name, + Roles: roles, + Password: pw, + Token: token, + } +} + +// ID returns a UUID of the user. +func (u *User) ID() uuid.UUID { + return u.UserID +} + +// Name returns the name of the user. +func (u *User) Name() string { + return u.UserName +} + +// IsCorrectPassword compares the provided with the stored password of a user. +func (u *User) IsCorrectPassword(pwd string) bool { + return pwd == u.Password +} + +// GetPassword returns the password of the user. +func (u *User) GetPassword() string { + return u.Password +} + +// GetRoles returns the roles of the user. +func (u *User) GetRoles() map[string]string { + return u.Roles +} + +// GetToken returns the token of the user. +func (u *User) GetToken() string { + return u.Token +} + +// SetName sets the name of the user +func (u *User) SetName(name string) { + u.UserName = name +} + +// SetToken sets the token of the user +func (u *User) SetToken(token string) { + u.Token = token +} + +// MarshalJSON implements the MarshalJSON interface to store a user as JSON +func (u *User) MarshalJSON() ([]byte, error) { + return json.Marshal(&struct { + UserID uuid.UUID `json:"_id"` + UserName string `json:"username"` + Roles map[string]string `json:"roles,omitempty"` + Password string `json:"password"` + Token string `json:"token,omitempty"` + }{ + UserID: u.ID(), + UserName: u.Name(), + Roles: u.Roles, + Password: u.Password, + Token: u.Token, + }) } -// GetName returns the name of the User -func (u *User) GetName() string { - return u.Name +// MarshalBSON implments the MarshalBSON interface to store a user as BSON +func (u *User) MarshalBSON() ([]byte, error) { + return bson.Marshal(&struct { + UserID string `bson:"_id"` + UserName string `bson:"username"` + Roles map[string]string `bson:"roles,omitempty"` + Password string `bson:"password"` + Token string `bson:"token,omitempty"` + }{ + UserID: u.ID().String(), + UserName: u.Name(), + Roles: u.Roles, + Password: u.Password, + Token: u.Token, + }) } diff --git a/controller/rbac/userStore.go b/controller/rbac/userStore.go new file mode 100644 index 000000000..1524abe9c --- /dev/null +++ b/controller/rbac/userStore.go @@ -0,0 +1,31 @@ +package rbac + +import ( + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/rbac" + "code.fbi.h-da.de/danet/gosdn/controller/store" +) + +const ( + userStoreName = "user" +) + +// UserStore is used to store Users +type UserStore struct { + userStoreName string +} + +// NewUserStore returns a userStore +func NewUserStore() rbac.UserStore { + storeMode := store.GetStoreMode() + + switch storeMode { + case store.Filesystem: + return NewMemoryUserStore() + case store.Database: + return &DatabaseUserStore{"user.json"} + case store.Memory: + return NewMemoryUserStore() + default: + return nil + } +} diff --git a/controller/store/genericStore.go b/controller/store/genericStore.go index d33e81be6..cb4c255cf 100644 --- a/controller/store/genericStore.go +++ b/controller/store/genericStore.go @@ -1,89 +1,87 @@ package store import ( - "reflect" - "sync" - - "code.fbi.h-da.de/danet/gosdn/controller/interfaces/store" - "code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors" + "errors" "github.com/google/uuid" - log "github.com/sirupsen/logrus" ) -// newGenericStore returns a genericStore -func newGenericStore() *genericStore { - return &genericStore{Store: make(map[uuid.UUID]store.Storable), storeLock: sync.RWMutex{}} +type storableConstraint interface { + ID() uuid.UUID + Name() string } -type genericStore struct { - Store map[uuid.UUID]store.Storable - storeLock sync.RWMutex +// GenericStore provides a in-memory implementation for multiple stores. +type GenericStore[T storableConstraint] struct { + Store map[uuid.UUID]T + nameLookupTable map[string]uuid.UUID } -// Exists takes a Storable's UUID and checks its existence in the store. -func (s *genericStore) Exists(id uuid.UUID) bool { - s.storeLock.RLock() - defer s.storeLock.RUnlock() - _, ok := s.Store[id] - return ok +// NewGenericStore returns a specific in-memory store for a type T. +func NewGenericStore[T storableConstraint]() GenericStore[T] { + return GenericStore[T]{ + Store: make(map[uuid.UUID]T), + nameLookupTable: make(map[string]uuid.UUID), + } } -// Add adds a Storable to the Store -func (s *genericStore) Add(item store.Storable) error { - if s.Exists(item.ID()) { - return &errors.ErrAlreadyExists{Item: item} +func (t *GenericStore[T]) Add(item T) error { + _, ok := t.Store[item.ID()] + if ok { + return errors.New("item not found") } - s.storeLock.Lock() - s.Store[item.ID()] = item - s.storeLock.Unlock() - log.WithFields(log.Fields{ - "type": reflect.TypeOf(item), - "uuid": item.ID(), - }).Debug("storable was added") + + t.Store[item.ID()] = item + t.nameLookupTable[item.Name()] = item.ID() + return nil } -// Get takes a Storable's UUID and returns the Storable. If the requested -// Storable does not exist an error is returned. Get is only type safe for -// this Storable interface. For type safe get operations on specialised stores -// use GetDevice, GetPND, GetSBI, or GetChange respectively. -func (s *genericStore) Get(id uuid.UUID) (store.Storable, error) { - if !s.Exists(id) { - return nil, &errors.ErrNotFound{ID: id} +func (t *GenericStore[T]) Update(item T) error { + _, ok := t.Store[item.ID()] + if ok { + return nil } - log.WithFields(log.Fields{ - "uuid": id, - }).Debug("storable was accessed") - s.storeLock.RLock() - defer s.storeLock.RUnlock() - return s.Store[id], nil + + t.Store[item.ID()] = item + t.nameLookupTable[item.Name()] = item.ID() + + return nil } -// Delete takes a Storable's UUID and deletes it. If the specified UUID does not -// exist in the Store an error is returned. -func (s *genericStore) Delete(id uuid.UUID) error { - if !s.Exists(id) { - return &errors.ErrNotFound{ID: id} - } - s.storeLock.Lock() - delete(s.Store, id) - s.storeLock.Unlock() - log.WithFields(log.Fields{ - "uuid": id, - }).Debug("storable was deleted") +func (t *GenericStore[T]) Delete(item T) error { + delete(t.Store, item.ID()) + return nil } -// UUIDs returns all UUIDs in the store. -func (s *genericStore) UUIDs() []uuid.UUID { - s.storeLock.RLock() - defer s.storeLock.RUnlock() - keys := make([]uuid.UUID, len(s.Store)) - i := 0 - for k := range s.Store { - keys[i] = k - i++ +func (t *GenericStore[T]) Get(query Query) (T, error) { + // First search for direct hit on UUID. + item, ok := t.Store[query.ID] + if !ok { + // Second search for name + id, ok := t.nameLookupTable[query.Name] + if !ok { + return *new(T), errors.New("item not found") + } + + item, ok := t.Store[id] + if !ok { + return *new(T), errors.New("item not found") + } + + return item, nil + } + + return item, nil +} + +func (t *GenericStore[T]) GetAll() ([]T, error) { + var allItems []T + + for _, item := range t.Store { + allItems = append(allItems, item) } - return keys + + return allItems, nil } diff --git a/controller/store/oldGenericStore.go b/controller/store/oldGenericStore.go new file mode 100644 index 000000000..d33e81be6 --- /dev/null +++ b/controller/store/oldGenericStore.go @@ -0,0 +1,89 @@ +package store + +import ( + "reflect" + "sync" + + "code.fbi.h-da.de/danet/gosdn/controller/interfaces/store" + "code.fbi.h-da.de/danet/gosdn/controller/nucleus/errors" + + "github.com/google/uuid" + log "github.com/sirupsen/logrus" +) + +// newGenericStore returns a genericStore +func newGenericStore() *genericStore { + return &genericStore{Store: make(map[uuid.UUID]store.Storable), storeLock: sync.RWMutex{}} +} + +type genericStore struct { + Store map[uuid.UUID]store.Storable + storeLock sync.RWMutex +} + +// Exists takes a Storable's UUID and checks its existence in the store. +func (s *genericStore) Exists(id uuid.UUID) bool { + s.storeLock.RLock() + defer s.storeLock.RUnlock() + _, ok := s.Store[id] + return ok +} + +// Add adds a Storable to the Store +func (s *genericStore) Add(item store.Storable) error { + if s.Exists(item.ID()) { + return &errors.ErrAlreadyExists{Item: item} + } + s.storeLock.Lock() + s.Store[item.ID()] = item + s.storeLock.Unlock() + log.WithFields(log.Fields{ + "type": reflect.TypeOf(item), + "uuid": item.ID(), + }).Debug("storable was added") + return nil +} + +// Get takes a Storable's UUID and returns the Storable. If the requested +// Storable does not exist an error is returned. Get is only type safe for +// this Storable interface. For type safe get operations on specialised stores +// use GetDevice, GetPND, GetSBI, or GetChange respectively. +func (s *genericStore) Get(id uuid.UUID) (store.Storable, error) { + if !s.Exists(id) { + return nil, &errors.ErrNotFound{ID: id} + } + log.WithFields(log.Fields{ + "uuid": id, + }).Debug("storable was accessed") + s.storeLock.RLock() + defer s.storeLock.RUnlock() + return s.Store[id], nil +} + +// Delete takes a Storable's UUID and deletes it. If the specified UUID does not +// exist in the Store an error is returned. +func (s *genericStore) Delete(id uuid.UUID) error { + if !s.Exists(id) { + return &errors.ErrNotFound{ID: id} + } + s.storeLock.Lock() + delete(s.Store, id) + s.storeLock.Unlock() + log.WithFields(log.Fields{ + "uuid": id, + }).Debug("storable was deleted") + return nil +} + +// UUIDs returns all UUIDs in the store. +func (s *genericStore) UUIDs() []uuid.UUID { + s.storeLock.RLock() + defer s.storeLock.RUnlock() + keys := make([]uuid.UUID, len(s.Store)) + i := 0 + for k := range s.Store { + keys[i] = k + i++ + } + return keys +} diff --git a/controller/store/query.go b/controller/store/query.go new file mode 100644 index 000000000..31b198bfd --- /dev/null +++ b/controller/store/query.go @@ -0,0 +1,9 @@ +package store + +import "github.com/google/uuid" + +// Query is used to query objects from stores. +type Query struct { + ID uuid.UUID + Name string +} diff --git a/controller/store/utils.go b/controller/store/utils.go index a3e52bf0a..de8033786 100644 --- a/controller/store/utils.go +++ b/controller/store/utils.go @@ -13,12 +13,6 @@ const ( pathToStores string = "stores" ) -// Query is used to query objects from stores. -type Query struct { - ID uuid.UUID - Name string -} - // FromString is a helper to check if a provided string as a valid UUID or a name. func FromString(id string) (uuid.UUID, error) { idAsUUID, err := uuid.Parse(id) diff --git a/go.mod b/go.mod index ee4533b62..f14f10e38 100644 --- a/go.mod +++ b/go.mod @@ -50,7 +50,7 @@ require ( github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang/glog v1.0.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect - github.com/golang/protobuf v1.5.2 // indirect + github.com/golang/protobuf v1.5.2 github.com/golang/snappy v0.0.3 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect -- GitLab