diff --git a/cmd/authctl/main.go b/cmd/authctl/main.go new file mode 100644 index 0000000000..4b5a12ad5a --- /dev/null +++ b/cmd/authctl/main.go @@ -0,0 +1,31 @@ +// Package main implements Cobra commands for management operations on authd. +package main + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/ubuntu/authd/cmd/authctl/user" +) + +const cmdName = "authctl" + +var rootCmd = &cobra.Command{ + Use: fmt.Sprintf("%s COMMAND", cmdName), + Short: "CLI tool to interact with authd", + Long: "authctl is a CLI tool which can be used to interact with authd.", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) {}, +} + +func init() { + rootCmd.AddCommand(user.UserCmd) +} + +func main() { + if err := rootCmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err.Error()) + os.Exit(1) + } +} diff --git a/cmd/authctl/user/disable.go b/cmd/authctl/user/disable.go new file mode 100644 index 0000000000..66395e9a32 --- /dev/null +++ b/cmd/authctl/user/disable.go @@ -0,0 +1,41 @@ +package user + +import ( + "context" + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/ubuntu/authd/internal/consts" + "github.com/ubuntu/authd/internal/proto/authd" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +// disableCmd is a command to disable a user. +var disableCmd = &cobra.Command{ + Use: "disable", + Short: "Disable a user managed by authd", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + fmt.Printf("Disabling user %q\n", args[0]) + + authdSocket := os.Getenv("AUTHD_SOCKET") + if authdSocket == "" { + authdSocket = "unix://" + consts.DefaultSocketPath + } + + conn, err := grpc.NewClient(authdSocket, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return err + } + + client := authd.NewNSSClient(conn) + _, err = client.DisableUser(context.Background(), &authd.DisableUserRequest{Name: args[0]}) + if err != nil { + return err + } + + return nil + }, +} diff --git a/cmd/authctl/user/enable.go b/cmd/authctl/user/enable.go new file mode 100644 index 0000000000..15a59c48c1 --- /dev/null +++ b/cmd/authctl/user/enable.go @@ -0,0 +1,41 @@ +package user + +import ( + "context" + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/ubuntu/authd/internal/consts" + "github.com/ubuntu/authd/internal/proto/authd" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +// enableCmd is a command to enable a user. +var enableCmd = &cobra.Command{ + Use: "enable", + Short: "Enable a user managed by authd", + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + fmt.Printf("Enabling user %q\n", args[0]) + + authdSocket := os.Getenv("AUTHD_SOCKET") + if authdSocket == "" { + authdSocket = "unix://" + consts.DefaultSocketPath + } + + conn, err := grpc.NewClient(authdSocket, grpc.WithTransportCredentials(insecure.NewCredentials())) + if err != nil { + return err + } + + client := authd.NewNSSClient(conn) + _, err = client.EnableUser(context.Background(), &authd.EnableUserRequest{Name: args[0]}) + if err != nil { + return err + } + + return nil + }, +} diff --git a/cmd/authctl/user/user.go b/cmd/authctl/user/user.go new file mode 100644 index 0000000000..3b3fd20c97 --- /dev/null +++ b/cmd/authctl/user/user.go @@ -0,0 +1,19 @@ +// Package user provides utilities for managing user operations. +package user + +import ( + "github.com/spf13/cobra" +) + +// UserCmd is a command to perform user-related operations. +var UserCmd = &cobra.Command{ + Use: "user", + Short: "Commands related to users", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) {}, +} + +func init() { + UserCmd.AddCommand(disableCmd) + UserCmd.AddCommand(enableCmd) +} diff --git a/internal/proto/authd/authd.pb.go b/internal/proto/authd/authd.pb.go index 9fe09fd89a..12f3767f8f 100644 --- a/internal/proto/authd/authd.pb.go +++ b/internal/proto/authd/authd.pb.go @@ -1497,6 +1497,96 @@ func (x *ShadowEntries) GetEntries() []*ShadowEntry { return nil } +type DisableUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *DisableUserRequest) Reset() { + *x = DisableUserRequest{} + mi := &file_authd_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *DisableUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DisableUserRequest) ProtoMessage() {} + +func (x *DisableUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_authd_proto_msgTypes[26] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DisableUserRequest.ProtoReflect.Descriptor instead. +func (*DisableUserRequest) Descriptor() ([]byte, []int) { + return file_authd_proto_rawDescGZIP(), []int{26} +} + +func (x *DisableUserRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +type EnableUserRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` +} + +func (x *EnableUserRequest) Reset() { + *x = EnableUserRequest{} + mi := &file_authd_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *EnableUserRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EnableUserRequest) ProtoMessage() {} + +func (x *EnableUserRequest) ProtoReflect() protoreflect.Message { + mi := &file_authd_proto_msgTypes[27] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EnableUserRequest.ProtoReflect.Descriptor instead. +func (*EnableUserRequest) Descriptor() ([]byte, []int) { + return file_authd_proto_rawDescGZIP(), []int{27} +} + +func (x *EnableUserRequest) GetName() string { + if x != nil { + return x.Name + } + return "" +} + type ABResponse_BrokerInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1509,7 +1599,7 @@ type ABResponse_BrokerInfo struct { func (x *ABResponse_BrokerInfo) Reset() { *x = ABResponse_BrokerInfo{} - mi := &file_authd_proto_msgTypes[26] + mi := &file_authd_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1521,7 +1611,7 @@ func (x *ABResponse_BrokerInfo) String() string { func (*ABResponse_BrokerInfo) ProtoMessage() {} func (x *ABResponse_BrokerInfo) ProtoReflect() protoreflect.Message { - mi := &file_authd_proto_msgTypes[26] + mi := &file_authd_proto_msgTypes[28] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1569,7 +1659,7 @@ type GAMResponse_AuthenticationMode struct { func (x *GAMResponse_AuthenticationMode) Reset() { *x = GAMResponse_AuthenticationMode{} - mi := &file_authd_proto_msgTypes[27] + mi := &file_authd_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1581,7 +1671,7 @@ func (x *GAMResponse_AuthenticationMode) String() string { func (*GAMResponse_AuthenticationMode) ProtoMessage() {} func (x *GAMResponse_AuthenticationMode) ProtoReflect() protoreflect.Message { - mi := &file_authd_proto_msgTypes[27] + mi := &file_authd_proto_msgTypes[29] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1626,7 +1716,7 @@ type IARequest_AuthenticationData struct { func (x *IARequest_AuthenticationData) Reset() { *x = IARequest_AuthenticationData{} - mi := &file_authd_proto_msgTypes[28] + mi := &file_authd_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1638,7 +1728,7 @@ func (x *IARequest_AuthenticationData) String() string { func (*IARequest_AuthenticationData) ProtoMessage() {} func (x *IARequest_AuthenticationData) ProtoReflect() protoreflect.Message { - mi := &file_authd_proto_msgTypes[28] + mi := &file_authd_proto_msgTypes[30] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1875,75 +1965,88 @@ var file_authd_proto_rawDesc = []byte{ 0x22, 0x3d, 0x0a, 0x0d, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x2c, 0x0a, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, - 0x77, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2a, - 0x3c, 0x0a, 0x0b, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0d, - 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, - 0x05, 0x4c, 0x4f, 0x47, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, 0x48, 0x41, 0x4e, - 0x47, 0x45, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x10, 0x02, 0x32, 0xd3, 0x03, - 0x0a, 0x03, 0x50, 0x41, 0x4d, 0x12, 0x33, 0x0a, 0x10, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, - 0x6c, 0x65, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, - 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, - 0x41, 0x42, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, 0x11, 0x47, 0x65, - 0x74, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x12, - 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x50, 0x42, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x50, 0x42, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0c, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, - 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x12, 0x10, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x53, - 0x42, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, - 0x2e, 0x53, 0x42, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x16, 0x47, - 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x4d, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x41, - 0x4d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, - 0x2e, 0x47, 0x41, 0x4d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x41, 0x0a, 0x18, - 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, - 0x2e, 0x53, 0x41, 0x4d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, - 0x74, 0x68, 0x64, 0x2e, 0x53, 0x41, 0x4d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, - 0x36, 0x0a, 0x0f, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, - 0x65, 0x64, 0x12, 0x10, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x49, 0x41, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x49, 0x41, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x0a, 0x45, 0x6e, 0x64, 0x53, 0x65, - 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x45, 0x53, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, - 0x12, 0x13, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x53, 0x44, 0x42, 0x46, 0x55, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x32, 0xf2, 0x03, 0x0a, 0x03, 0x4e, 0x53, 0x53, 0x12, 0x44, 0x0a, 0x0f, 0x47, - 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, - 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, - 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, + 0x77, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x65, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, + 0x28, 0x0a, 0x12, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x27, 0x0a, 0x11, 0x45, 0x6e, 0x61, + 0x62, 0x6c, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x2a, 0x3c, 0x0a, 0x0b, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, + 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x09, 0x0a, 0x05, 0x4c, 0x4f, 0x47, 0x49, 0x4e, 0x10, 0x01, 0x12, 0x13, 0x0a, 0x0f, 0x43, + 0x48, 0x41, 0x4e, 0x47, 0x45, 0x5f, 0x50, 0x41, 0x53, 0x53, 0x57, 0x4f, 0x52, 0x44, 0x10, 0x02, + 0x32, 0xd3, 0x03, 0x0a, 0x03, 0x50, 0x41, 0x4d, 0x12, 0x33, 0x0a, 0x10, 0x41, 0x76, 0x61, 0x69, + 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x73, 0x12, 0x0c, 0x2e, 0x61, + 0x75, 0x74, 0x68, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x11, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x64, 0x2e, 0x41, 0x42, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3a, 0x0a, + 0x11, 0x47, 0x65, 0x74, 0x50, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x42, 0x72, 0x6f, 0x6b, + 0x65, 0x72, 0x12, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x50, 0x42, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x50, + 0x42, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x0c, 0x53, 0x65, 0x6c, + 0x65, 0x63, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x12, 0x10, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x64, 0x2e, 0x53, 0x42, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x64, 0x2e, 0x53, 0x42, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, + 0x0a, 0x16, 0x47, 0x65, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x73, 0x12, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, + 0x2e, 0x47, 0x41, 0x4d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x64, 0x2e, 0x47, 0x41, 0x4d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x41, 0x0a, 0x18, 0x53, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x11, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x64, 0x2e, 0x53, 0x41, 0x4d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, + 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x53, 0x41, 0x4d, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x36, 0x0a, 0x0f, 0x49, 0x73, 0x41, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x10, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x49, 0x41, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, + 0x49, 0x41, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2c, 0x0a, 0x0a, 0x45, 0x6e, + 0x64, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, + 0x2e, 0x45, 0x53, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3c, 0x0a, 0x17, 0x53, 0x65, 0x74, 0x44, + 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x72, 0x46, 0x6f, 0x72, 0x55, + 0x73, 0x65, 0x72, 0x12, 0x13, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x53, 0x44, 0x42, 0x46, + 0x55, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0xe0, 0x04, 0x0a, 0x03, 0x4e, 0x53, 0x53, 0x12, 0x44, + 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, 0x42, 0x79, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1d, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x64, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, 0x45, + 0x6e, 0x74, 0x72, 0x79, 0x12, 0x3b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x64, 0x42, 0x79, 0x55, 0x49, 0x44, 0x12, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, + 0x65, 0x74, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x3b, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, 0x42, 0x79, - 0x55, 0x49, 0x44, 0x12, 0x15, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, - 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, 0x75, 0x74, - 0x68, 0x64, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x36, - 0x0a, 0x10, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x69, - 0x65, 0x73, 0x12, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, 0x45, - 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, - 0x75, 0x70, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, - 0x2e, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x39, 0x0a, 0x0d, 0x47, 0x65, 0x74, - 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x47, 0x49, 0x44, 0x12, 0x15, 0x2e, 0x61, 0x75, 0x74, - 0x68, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x34, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, + 0x79, 0x12, 0x36, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x64, 0x45, 0x6e, + 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x50, 0x61, 0x73, 0x73, + 0x77, 0x64, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x41, 0x0a, 0x0e, 0x47, 0x65, 0x74, + 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x4e, 0x61, + 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x64, 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x39, 0x0a, 0x0d, + 0x47, 0x65, 0x74, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x42, 0x79, 0x47, 0x49, 0x44, 0x12, 0x15, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x34, 0x0a, 0x0f, 0x47, 0x65, 0x74, 0x47, 0x72, + 0x6f, 0x75, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x0c, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, + 0x2e, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x44, 0x0a, + 0x0f, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1d, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x64, + 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x12, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x12, 0x36, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x13, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x72, - 0x6f, 0x75, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x44, 0x0a, 0x0f, 0x47, 0x65, - 0x74, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x42, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x2e, - 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x42, - 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x61, - 0x75, 0x74, 0x68, 0x64, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x36, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x53, 0x68, 0x61, 0x64, 0x6f, 0x77, 0x45, 0x6e, 0x74, - 0x72, 0x69, 0x65, 0x73, 0x12, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x53, 0x68, 0x61, 0x64, 0x6f, - 0x77, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x2f, 0x61, 0x75, - 0x74, 0x68, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x53, 0x68, + 0x61, 0x64, 0x6f, 0x77, 0x45, 0x6e, 0x74, 0x72, 0x69, 0x65, 0x73, 0x12, 0x36, 0x0a, 0x0b, 0x44, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x19, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x64, 0x2e, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x0a, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x55, 0x73, 0x65, + 0x72, 0x12, 0x18, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x64, 0x2e, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x2f, 0x61, + 0x75, 0x74, 0x68, 0x64, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x64, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -1959,7 +2062,7 @@ func file_authd_proto_rawDescGZIP() []byte { } var file_authd_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_authd_proto_msgTypes = make([]protoimpl.MessageInfo, 29) +var file_authd_proto_msgTypes = make([]protoimpl.MessageInfo, 31) var file_authd_proto_goTypes = []any{ (SessionMode)(0), // 0: authd.SessionMode (*Empty)(nil), // 1: authd.Empty @@ -1988,17 +2091,19 @@ var file_authd_proto_goTypes = []any{ (*GroupEntries)(nil), // 24: authd.GroupEntries (*ShadowEntry)(nil), // 25: authd.ShadowEntry (*ShadowEntries)(nil), // 26: authd.ShadowEntries - (*ABResponse_BrokerInfo)(nil), // 27: authd.ABResponse.BrokerInfo - (*GAMResponse_AuthenticationMode)(nil), // 28: authd.GAMResponse.AuthenticationMode - (*IARequest_AuthenticationData)(nil), // 29: authd.IARequest.AuthenticationData + (*DisableUserRequest)(nil), // 27: authd.DisableUserRequest + (*EnableUserRequest)(nil), // 28: authd.EnableUserRequest + (*ABResponse_BrokerInfo)(nil), // 29: authd.ABResponse.BrokerInfo + (*GAMResponse_AuthenticationMode)(nil), // 30: authd.GAMResponse.AuthenticationMode + (*IARequest_AuthenticationData)(nil), // 31: authd.IARequest.AuthenticationData } var file_authd_proto_depIdxs = []int32{ - 27, // 0: authd.ABResponse.brokers_infos:type_name -> authd.ABResponse.BrokerInfo + 29, // 0: authd.ABResponse.brokers_infos:type_name -> authd.ABResponse.BrokerInfo 0, // 1: authd.SBRequest.mode:type_name -> authd.SessionMode 9, // 2: authd.GAMRequest.supported_ui_layouts:type_name -> authd.UILayout - 28, // 3: authd.GAMResponse.authentication_modes:type_name -> authd.GAMResponse.AuthenticationMode + 30, // 3: authd.GAMResponse.authentication_modes:type_name -> authd.GAMResponse.AuthenticationMode 9, // 4: authd.SAMResponse.ui_layout_info:type_name -> authd.UILayout - 29, // 5: authd.IARequest.authentication_data:type_name -> authd.IARequest.AuthenticationData + 31, // 5: authd.IARequest.authentication_data:type_name -> authd.IARequest.AuthenticationData 21, // 6: authd.PasswdEntries.entries:type_name -> authd.PasswdEntry 23, // 7: authd.GroupEntries.entries:type_name -> authd.GroupEntry 25, // 8: authd.ShadowEntries.entries:type_name -> authd.ShadowEntry @@ -2018,24 +2123,28 @@ var file_authd_proto_depIdxs = []int32{ 1, // 22: authd.NSS.GetGroupEntries:input_type -> authd.Empty 19, // 23: authd.NSS.GetShadowByName:input_type -> authd.GetShadowByNameRequest 1, // 24: authd.NSS.GetShadowEntries:input_type -> authd.Empty - 4, // 25: authd.PAM.AvailableBrokers:output_type -> authd.ABResponse - 3, // 26: authd.PAM.GetPreviousBroker:output_type -> authd.GPBResponse - 7, // 27: authd.PAM.SelectBroker:output_type -> authd.SBResponse - 10, // 28: authd.PAM.GetAuthenticationModes:output_type -> authd.GAMResponse - 12, // 29: authd.PAM.SelectAuthenticationMode:output_type -> authd.SAMResponse - 14, // 30: authd.PAM.IsAuthenticated:output_type -> authd.IAResponse - 1, // 31: authd.PAM.EndSession:output_type -> authd.Empty - 1, // 32: authd.PAM.SetDefaultBrokerForUser:output_type -> authd.Empty - 21, // 33: authd.NSS.GetPasswdByName:output_type -> authd.PasswdEntry - 21, // 34: authd.NSS.GetPasswdByUID:output_type -> authd.PasswdEntry - 22, // 35: authd.NSS.GetPasswdEntries:output_type -> authd.PasswdEntries - 23, // 36: authd.NSS.GetGroupByName:output_type -> authd.GroupEntry - 23, // 37: authd.NSS.GetGroupByGID:output_type -> authd.GroupEntry - 24, // 38: authd.NSS.GetGroupEntries:output_type -> authd.GroupEntries - 25, // 39: authd.NSS.GetShadowByName:output_type -> authd.ShadowEntry - 26, // 40: authd.NSS.GetShadowEntries:output_type -> authd.ShadowEntries - 25, // [25:41] is the sub-list for method output_type - 9, // [9:25] is the sub-list for method input_type + 27, // 25: authd.NSS.DisableUser:input_type -> authd.DisableUserRequest + 28, // 26: authd.NSS.EnableUser:input_type -> authd.EnableUserRequest + 4, // 27: authd.PAM.AvailableBrokers:output_type -> authd.ABResponse + 3, // 28: authd.PAM.GetPreviousBroker:output_type -> authd.GPBResponse + 7, // 29: authd.PAM.SelectBroker:output_type -> authd.SBResponse + 10, // 30: authd.PAM.GetAuthenticationModes:output_type -> authd.GAMResponse + 12, // 31: authd.PAM.SelectAuthenticationMode:output_type -> authd.SAMResponse + 14, // 32: authd.PAM.IsAuthenticated:output_type -> authd.IAResponse + 1, // 33: authd.PAM.EndSession:output_type -> authd.Empty + 1, // 34: authd.PAM.SetDefaultBrokerForUser:output_type -> authd.Empty + 21, // 35: authd.NSS.GetPasswdByName:output_type -> authd.PasswdEntry + 21, // 36: authd.NSS.GetPasswdByUID:output_type -> authd.PasswdEntry + 22, // 37: authd.NSS.GetPasswdEntries:output_type -> authd.PasswdEntries + 23, // 38: authd.NSS.GetGroupByName:output_type -> authd.GroupEntry + 23, // 39: authd.NSS.GetGroupByGID:output_type -> authd.GroupEntry + 24, // 40: authd.NSS.GetGroupEntries:output_type -> authd.GroupEntries + 25, // 41: authd.NSS.GetShadowByName:output_type -> authd.ShadowEntry + 26, // 42: authd.NSS.GetShadowEntries:output_type -> authd.ShadowEntries + 1, // 43: authd.NSS.DisableUser:output_type -> authd.Empty + 1, // 44: authd.NSS.EnableUser:output_type -> authd.Empty + 27, // [27:45] is the sub-list for method output_type + 9, // [9:27] 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 @@ -2047,8 +2156,8 @@ func file_authd_proto_init() { return } file_authd_proto_msgTypes[8].OneofWrappers = []any{} - file_authd_proto_msgTypes[26].OneofWrappers = []any{} - file_authd_proto_msgTypes[28].OneofWrappers = []any{ + file_authd_proto_msgTypes[28].OneofWrappers = []any{} + file_authd_proto_msgTypes[30].OneofWrappers = []any{ (*IARequest_AuthenticationData_Challenge)(nil), (*IARequest_AuthenticationData_Wait)(nil), (*IARequest_AuthenticationData_Skip)(nil), @@ -2059,7 +2168,7 @@ func file_authd_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_authd_proto_rawDesc, NumEnums: 1, - NumMessages: 29, + NumMessages: 31, NumExtensions: 0, NumServices: 2, }, diff --git a/internal/proto/authd/authd.proto b/internal/proto/authd/authd.proto index df9158059f..27ef46e118 100644 --- a/internal/proto/authd/authd.proto +++ b/internal/proto/authd/authd.proto @@ -137,6 +137,9 @@ service NSS { rpc GetShadowByName(GetShadowByNameRequest) returns (ShadowEntry); rpc GetShadowEntries(Empty) returns (ShadowEntries); + + rpc DisableUser(DisableUserRequest) returns (Empty); + rpc EnableUser(EnableUserRequest) returns (Empty); } message GetPasswdByNameRequest{ @@ -195,3 +198,11 @@ message ShadowEntry { message ShadowEntries { repeated ShadowEntry entries = 1; } + +message DisableUserRequest{ + string name = 1; +} + +message EnableUserRequest{ + string name = 1; +} diff --git a/internal/proto/authd/authd_grpc.pb.go b/internal/proto/authd/authd_grpc.pb.go index 7f913a5970..7238558646 100644 --- a/internal/proto/authd/authd_grpc.pb.go +++ b/internal/proto/authd/authd_grpc.pb.go @@ -395,6 +395,8 @@ const ( NSS_GetGroupEntries_FullMethodName = "/authd.NSS/GetGroupEntries" NSS_GetShadowByName_FullMethodName = "/authd.NSS/GetShadowByName" NSS_GetShadowEntries_FullMethodName = "/authd.NSS/GetShadowEntries" + NSS_DisableUser_FullMethodName = "/authd.NSS/DisableUser" + NSS_EnableUser_FullMethodName = "/authd.NSS/EnableUser" ) // NSSClient is the client API for NSS service. @@ -409,6 +411,8 @@ type NSSClient interface { GetGroupEntries(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*GroupEntries, error) GetShadowByName(ctx context.Context, in *GetShadowByNameRequest, opts ...grpc.CallOption) (*ShadowEntry, error) GetShadowEntries(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*ShadowEntries, error) + DisableUser(ctx context.Context, in *DisableUserRequest, opts ...grpc.CallOption) (*Empty, error) + EnableUser(ctx context.Context, in *EnableUserRequest, opts ...grpc.CallOption) (*Empty, error) } type nSSClient struct { @@ -499,6 +503,26 @@ func (c *nSSClient) GetShadowEntries(ctx context.Context, in *Empty, opts ...grp return out, nil } +func (c *nSSClient) DisableUser(ctx context.Context, in *DisableUserRequest, opts ...grpc.CallOption) (*Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Empty) + err := c.cc.Invoke(ctx, NSS_DisableUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *nSSClient) EnableUser(ctx context.Context, in *EnableUserRequest, opts ...grpc.CallOption) (*Empty, error) { + cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) + out := new(Empty) + err := c.cc.Invoke(ctx, NSS_EnableUser_FullMethodName, in, out, cOpts...) + if err != nil { + return nil, err + } + return out, nil +} + // NSSServer is the server API for NSS service. // All implementations must embed UnimplementedNSSServer // for forward compatibility. @@ -511,6 +535,8 @@ type NSSServer interface { GetGroupEntries(context.Context, *Empty) (*GroupEntries, error) GetShadowByName(context.Context, *GetShadowByNameRequest) (*ShadowEntry, error) GetShadowEntries(context.Context, *Empty) (*ShadowEntries, error) + DisableUser(context.Context, *DisableUserRequest) (*Empty, error) + EnableUser(context.Context, *EnableUserRequest) (*Empty, error) mustEmbedUnimplementedNSSServer() } @@ -545,6 +571,12 @@ func (UnimplementedNSSServer) GetShadowByName(context.Context, *GetShadowByNameR func (UnimplementedNSSServer) GetShadowEntries(context.Context, *Empty) (*ShadowEntries, error) { return nil, status.Errorf(codes.Unimplemented, "method GetShadowEntries not implemented") } +func (UnimplementedNSSServer) DisableUser(context.Context, *DisableUserRequest) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method DisableUser not implemented") +} +func (UnimplementedNSSServer) EnableUser(context.Context, *EnableUserRequest) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method EnableUser not implemented") +} func (UnimplementedNSSServer) mustEmbedUnimplementedNSSServer() {} func (UnimplementedNSSServer) testEmbeddedByValue() {} @@ -710,6 +742,42 @@ func _NSS_GetShadowEntries_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } +func _NSS_DisableUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(DisableUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NSSServer).DisableUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: NSS_DisableUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NSSServer).DisableUser(ctx, req.(*DisableUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _NSS_EnableUser_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EnableUserRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(NSSServer).EnableUser(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: NSS_EnableUser_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(NSSServer).EnableUser(ctx, req.(*EnableUserRequest)) + } + return interceptor(ctx, in, info, handler) +} + // NSS_ServiceDesc is the grpc.ServiceDesc for NSS service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -749,6 +817,14 @@ var NSS_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetShadowEntries", Handler: _NSS_GetShadowEntries_Handler, }, + { + MethodName: "DisableUser", + Handler: _NSS_DisableUser_Handler, + }, + { + MethodName: "EnableUser", + Handler: _NSS_EnableUser_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "authd.proto", diff --git a/internal/services/nss/nss.go b/internal/services/nss/nss.go index bfa0adbc8e..f84f113c62 100644 --- a/internal/services/nss/nss.go +++ b/internal/services/nss/nss.go @@ -161,6 +161,40 @@ func (s Service) GetShadowEntries(ctx context.Context, req *authd.Empty) (*authd return &r, nil } +// DisableUser marks a user as disabled. +func (s Service) DisableUser(ctx context.Context, req *authd.DisableUserRequest) (*authd.Empty, error) { + if err := s.permissionManager.IsRequestFromRoot(ctx); err != nil { + return nil, err + } + + if req.GetName() == "" { + return nil, status.Error(codes.InvalidArgument, "no user name provided") + } + + if err := s.userManager.DisableUser(req.GetName()); err != nil { + return nil, err + } + + return &authd.Empty{}, nil +} + +// EnableUser marks a user as enabled. +func (s Service) EnableUser(ctx context.Context, req *authd.EnableUserRequest) (*authd.Empty, error) { + if err := s.permissionManager.IsRequestFromRoot(ctx); err != nil { + return nil, err + } + + if req.GetName() == "" { + return nil, status.Error(codes.InvalidArgument, "no user name provided") + } + + if err := s.userManager.EnableUser(req.GetName()); err != nil { + return nil, err + } + + return &authd.Empty{}, nil +} + // userPreCheck checks if the user exists in at least one broker. func (s Service) userPreCheck(ctx context.Context, username string) (pwent *authd.PasswdEntry, err error) { // Check if the user exists in at least one broker. diff --git a/internal/services/nss/nss_test.go b/internal/services/nss/nss_test.go index 7d0810ae92..88f69fa78d 100644 --- a/internal/services/nss/nss_test.go +++ b/internal/services/nss/nss_test.go @@ -256,6 +256,68 @@ func TestGetShadowEntries(t *testing.T) { } } +func TestDisablePasswd(t *testing.T) { + tests := map[string]struct { + sourceDB string + + username string + currentUserNotRoot bool + + wantErr bool + }{ + "Successfully_disable_user": {username: "user1"}, + + "Error_when_username_is_empty": {wantErr: true}, + "Error_when_user_does_not_exist": {username: "doesnotexist", wantErr: true}, + "Error_when_not_root": {username: "notroot", currentUserNotRoot: true, wantErr: true}, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + client := newNSSClient(t, tc.sourceDB, tc.currentUserNotRoot) + + _, err := client.DisableUser(context.Background(), &authd.DisableUserRequest{Name: tc.username}) + if tc.wantErr { + require.Error(t, err, "DisablePasswd should return an error, but did not") + return + } + require.NoError(t, err, "DisablePasswd should not return an error, but did") + }) + } +} + +func TestEnableUser(t *testing.T) { + tests := map[string]struct { + sourceDB string + + username string + currentUserNotRoot bool + + wantErr bool + }{ + "Successfully_enable_user": {username: "user1"}, + + "Error_when_username_is_empty": {wantErr: true}, + "Error_when_user_does_not_exist": {username: "doesnotexist", wantErr: true}, + "Error_when_not_root": {username: "notroot", currentUserNotRoot: true, wantErr: true}, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + if tc.sourceDB == "" { + tc.sourceDB = "disabled-user.db.yaml" + } + + client := newNSSClient(t, tc.sourceDB, tc.currentUserNotRoot) + + _, err := client.EnableUser(context.Background(), &authd.EnableUserRequest{Name: tc.username}) + if tc.wantErr { + require.Error(t, err, "EnableUser should return an error, but did not") + return + } + require.NoError(t, err, "EnableUser should not return an error, but did") + }) + } +} + func TestMockgpasswd(t *testing.T) { localgroupstestutils.Mockgpasswd(t) } diff --git a/internal/services/nss/testdata/disabled-user.db.yaml b/internal/services/nss/testdata/disabled-user.db.yaml new file mode 100644 index 0000000000..6b087dd778 --- /dev/null +++ b/internal/services/nss/testdata/disabled-user.db.yaml @@ -0,0 +1,49 @@ +users: + - name: user1 + uid: 1111 + gid: 11111 + gecos: |- + User1 gecos + On multiple lines + dir: /home/user1 + shell: /bin/bash + broker_id: broker-id + disabled: true + - name: user2 + uid: 2222 + gid: 22222 + gecos: User2 + dir: /home/user2 + shell: /bin/dash + broker_id: broker-id + - name: user3 + uid: 3333 + gid: 33333 + gecos: User3 + dir: /home/user3 + shell: /bin/zsh + broker_id: broker-id +groups: + - name: group1 + gid: 11111 + ugid: group1 + - name: group2 + gid: 22222 + ugid: group2 + - name: group3 + gid: 33333 + ugid: group3 + - name: commongroup + gid: 99999 + ugid: commongroup +users_to_groups: + - uid: 1111 + gid: 11111 + - uid: 2222 + gid: 22222 + - uid: 2222 + gid: 99999 + - uid: 3333 + gid: 33333 + - uid: 3333 + gid: 99999 diff --git a/internal/services/pam/pam.go b/internal/services/pam/pam.go index 306ac6dc2b..87aac0a961 100644 --- a/internal/services/pam/pam.go +++ b/internal/services/pam/pam.go @@ -138,6 +138,15 @@ func (s Service) SelectBroker(ctx context.Context, req *authd.SBRequest) (resp * lang = "C" } + userIsDisabled, err := s.userManager.IsUserDisabled(username) + if err != nil && !errors.Is(err, users.NoDataFoundError{}) { + return nil, fmt.Errorf("could not check if user %q is disabled: %w", username, err) + } + // Throw an error if the user trying to authenticate already exists in the database and is disabled + if err == nil && userIsDisabled { + return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("user %s is disabled", username)) + } + var mode string switch req.GetMode() { case authd.SessionMode_LOGIN: diff --git a/internal/services/pam/pam_test.go b/internal/services/pam/pam_test.go index 49db6a298e..f03dfac8c3 100644 --- a/internal/services/pam/pam_test.go +++ b/internal/services/pam/pam_test.go @@ -193,6 +193,7 @@ func TestSelectBroker(t *testing.T) { brokerID string username string sessionMode string + existingDB string currentUserNotRoot bool @@ -209,13 +210,24 @@ func TestSelectBroker(t *testing.T) { "Error_when_broker_does_not_exist": {username: "no broker", brokerID: "does not exist", wantErr: true}, "Error_when_broker_does_not_provide_a_session_ID": {username: "NS_no_id", wantErr: true}, "Error_when_starting_the_session": {username: "NS_error", wantErr: true}, + "Error_when_user_is_disabled": {username: "disabled", wantErr: true, existingDB: "cache-with-disabled-user.db"}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { t.Parallel() + cacheDir := t.TempDir() + if tc.existingDB != "" { + err := db.Z_ForTests_CreateDBFromYAML(filepath.Join(testutils.TestFamilyPath(t), tc.existingDB), cacheDir) + require.NoError(t, err, "Setup: could not create database from testdata") + } + + m, err := users.NewManager(users.DefaultConfig, cacheDir) + require.NoError(t, err, "Setup: could not create user manager") + t.Cleanup(func() { _ = m.Stop() }) + pm := newPermissionManager(t, tc.currentUserNotRoot) - client := newPamClient(t, nil, globalBrokerManager, &pm) + client := newPamClient(t, m, globalBrokerManager, &pm) switch tc.brokerID { case "": diff --git a/internal/services/pam/testdata/TestSelectBroker/cache-with-disabled-user.db b/internal/services/pam/testdata/TestSelectBroker/cache-with-disabled-user.db new file mode 100644 index 0000000000..b24324dcab --- /dev/null +++ b/internal/services/pam/testdata/TestSelectBroker/cache-with-disabled-user.db @@ -0,0 +1,16 @@ +users: + - name: TestSelectBroker/Error_when_user_is_disabled_separator_disabled + uid: 1111 + gid: 11111 + gecos: gecos for other user + dir: /home/disabled + shell: /bin/bash + broker_id: broker-id + disabled: true +groups: + - name: group1 + gid: 11111 + ugid: ugid +users_to_groups: + - uid: 1111 + gid: 11111 diff --git a/internal/services/testdata/golden/TestRegisterGRPCServices b/internal/services/testdata/golden/TestRegisterGRPCServices index 495f2a96f8..077495443c 100644 --- a/internal/services/testdata/golden/TestRegisterGRPCServices +++ b/internal/services/testdata/golden/TestRegisterGRPCServices @@ -1,5 +1,11 @@ authd.NSS: methods: + - name: DisableUser + isclientstream: false + isserverstream: false + - name: EnableUser + isclientstream: false + isserverstream: false - name: GetGroupByGID isclientstream: false isserverstream: false diff --git a/internal/users/db/db_test.go b/internal/users/db/db_test.go index 80433e01d8..067b9eacc5 100644 --- a/internal/users/db/db_test.go +++ b/internal/users/db/db_test.go @@ -462,6 +462,20 @@ func TestUpdateBrokerForUser(t *testing.T) { require.Error(t, err, "UpdateBrokerForUser for a nonexistent user should return an error") } +func TestUpdateDisabledFieldForUser(t *testing.T) { + t.Parallel() + + c := initDB(t, "one_user_and_group") + + // Update broker for existent user + err := c.UpdateDisabledFieldForUser("user1", true) + require.NoError(t, err, "UpdateDisabledFieldForUser for an existent user should not return an error") + + // Error when updating broker for nonexistent user + err = c.UpdateDisabledFieldForUser("nonexistent", false) + require.Error(t, err, "UpdateDisabledFieldForUser for a nonexistent user should return an error") +} + func TestRemoveDb(t *testing.T) { t.Parallel() diff --git a/internal/users/db/sql/create_schema.sql b/internal/users/db/sql/create_schema.sql index afecc22b81..179ba2f1aa 100644 --- a/internal/users/db/sql/create_schema.sql +++ b/internal/users/db/sql/create_schema.sql @@ -5,7 +5,8 @@ CREATE TABLE IF NOT EXISTS users ( gecos TEXT DEFAULT "", dir TEXT DEFAULT "", shell TEXT DEFAULT "/bin/bash", - broker_id TEXT DEFAULT "" + broker_id TEXT DEFAULT "", + disabled BOOLEAN DEFAULT FALSE ); CREATE UNIQUE INDEX "idx_user_name" ON users ("name"); diff --git a/internal/users/db/update.go b/internal/users/db/update.go index ab81a199c1..9d8c0e7e7a 100644 --- a/internal/users/db/update.go +++ b/internal/users/db/update.go @@ -165,3 +165,21 @@ func (m *Manager) UpdateBrokerForUser(username, brokerID string) error { return nil } + +// UpdateDisabledFieldForUser sets the Disabled field to a given value for a user. +func (m *Manager) UpdateDisabledFieldForUser(username string, disabled bool) error { + query := `UPDATE users SET disabled = ? WHERE name = ?` + res, err := m.db.Exec(query, disabled, username) + if err != nil { + return fmt.Errorf("failed to update disabled field for user: %w", err) + } + rowsAffected, err := res.RowsAffected() + if err != nil { + return fmt.Errorf("failed to get rows affected: %w", err) + } + if rowsAffected == 0 { + return NoDataFoundError{table: "users", key: username} + } + + return nil +} diff --git a/internal/users/db/users.go b/internal/users/db/users.go index 16aded9051..00e34ee7dc 100644 --- a/internal/users/db/users.go +++ b/internal/users/db/users.go @@ -10,9 +10,9 @@ import ( "github.com/ubuntu/authd/log" ) -const allUserColumns = "name, uid, gid, gecos, dir, shell, broker_id" -const publicUserColumns = "name, uid, gid, gecos, dir, shell, broker_id" -const allUserColumnsWithPlaceholders = "name = ?, uid = ?, gid = ?, gecos = ?, dir = ?, shell = ?, broker_id = ?" +const allUserColumns = "name, uid, gid, gecos, dir, shell, broker_id, disabled" +const publicUserColumns = "name, uid, gid, gecos, dir, shell, broker_id, disabled" +const allUserColumnsWithPlaceholders = "name = ?, uid = ?, gid = ?, gecos = ?, dir = ?, shell = ?, broker_id = ?, disabled = ?" // UserRow represents a user row in the database. type UserRow struct { @@ -25,6 +25,8 @@ type UserRow struct { // BrokerID specifies the broker the user last successfully authenticated with. BrokerID string `yaml:"broker_id,omitempty"` + + Disabled bool `yaml:"disabled,omitempty"` } // NewUserRow creates a new UserRow. @@ -49,7 +51,7 @@ func userByID(db queryable, uid uint32) (UserRow, error) { row := db.QueryRow(query, uid) var u UserRow - err := row.Scan(&u.Name, &u.UID, &u.GID, &u.Gecos, &u.Dir, &u.Shell, &u.BrokerID) + err := row.Scan(&u.Name, &u.UID, &u.GID, &u.Gecos, &u.Dir, &u.Shell, &u.BrokerID, &u.Disabled) if errors.Is(err, sql.ErrNoRows) { return UserRow{}, NoDataFoundError{key: strconv.FormatUint(uint64(uid), 10), table: "users"} } @@ -66,7 +68,7 @@ func (m *Manager) UserByName(name string) (UserRow, error) { row := m.db.QueryRow(query, name) var u UserRow - err := row.Scan(&u.Name, &u.UID, &u.GID, &u.Gecos, &u.Dir, &u.Shell, &u.BrokerID) + err := row.Scan(&u.Name, &u.UID, &u.GID, &u.Gecos, &u.Dir, &u.Shell, &u.BrokerID, &u.Disabled) if errors.Is(err, sql.ErrNoRows) { return UserRow{}, NoDataFoundError{key: name, table: "users"} } @@ -93,7 +95,7 @@ func allUsers(db queryable) ([]UserRow, error) { var users []UserRow for rows.Next() { var u UserRow - err := rows.Scan(&u.Name, &u.UID, &u.GID, &u.Gecos, &u.Dir, &u.Shell, &u.BrokerID) + err := rows.Scan(&u.Name, &u.UID, &u.GID, &u.Gecos, &u.Dir, &u.Shell, &u.BrokerID, &u.Disabled) if err != nil { return nil, fmt.Errorf("scan error: %w", err) } @@ -146,8 +148,8 @@ func userExists(db queryable, u UserRow) (bool, error) { // insertUser inserts a new user into the database. func insertUser(db queryable, u UserRow) error { log.Debugf(context.Background(), "Inserting user %v", u.Name) - query := fmt.Sprintf(`INSERT INTO users (%s) VALUES (?, ?, ?, ?, ?, ?, ?)`, allUserColumns) - _, err := db.Exec(query, u.Name, u.UID, u.GID, u.Gecos, u.Dir, u.Shell, u.BrokerID) + query := fmt.Sprintf(`INSERT INTO users (%s) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, allUserColumns) + _, err := db.Exec(query, u.Name, u.UID, u.GID, u.Gecos, u.Dir, u.Shell, u.BrokerID, u.Disabled) if err != nil { return fmt.Errorf("insert user error: %w", err) } @@ -158,7 +160,7 @@ func insertUser(db queryable, u UserRow) error { func updateUserByID(db queryable, u UserRow) error { log.Debugf(context.Background(), "Updating user %v", u.Name) query := fmt.Sprintf(`UPDATE users SET %s WHERE uid = ?`, allUserColumnsWithPlaceholders) - _, err := db.Exec(query, u.Name, u.UID, u.GID, u.Gecos, u.Dir, u.Shell, u.BrokerID, u.UID) + _, err := db.Exec(query, u.Name, u.UID, u.GID, u.Gecos, u.Dir, u.Shell, u.BrokerID, u.Disabled, u.UID) if err != nil { return fmt.Errorf("update user error: %w", err) } diff --git a/internal/users/manager.go b/internal/users/manager.go index 632cfc6ff6..c0a87b3fa2 100644 --- a/internal/users/manager.go +++ b/internal/users/manager.go @@ -334,6 +334,34 @@ func (m *Manager) UpdateBrokerForUser(username, brokerID string) error { return nil } +// DisableUser sets the Disabled field to true for the given user. +func (m *Manager) DisableUser(username string) error { + if err := m.db.UpdateDisabledFieldForUser(username, true); err != nil { + return err + } + + return nil +} + +// EnableUser sets the Disabled field to false for the given user. +func (m *Manager) EnableUser(username string) error { + if err := m.db.UpdateDisabledFieldForUser(username, false); err != nil { + return err + } + + return nil +} + +// IsUserDisabled returns true if the user with the given user name is disabled, false otherwise. +func (m *Manager) IsUserDisabled(username string) (bool, error) { + u, err := m.db.UserByName(username) + if err != nil { + return false, err + } + + return u.Disabled, nil +} + // UserByName returns the user information for the given user name. func (m *Manager) UserByName(username string) (types.UserEntry, error) { usr, err := m.db.UserByName(username) diff --git a/internal/users/manager_test.go b/internal/users/manager_test.go index 76fc9ac97f..b38cab9ee9 100644 --- a/internal/users/manager_test.go +++ b/internal/users/manager_test.go @@ -325,6 +325,98 @@ func TestUpdateBrokerForUser(t *testing.T) { } } +//nolint:dupl // This is not a duplicate test +func TestDisableUser(t *testing.T) { + tests := map[string]struct { + username string + + dbFile string + + wantErr bool + wantErrType error + }{ + "Successfully_disable_user": {}, + + "Error_if_user_does_not_exist": {username: "doesnotexist", wantErrType: db.NoDataFoundError{}}, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + // We don't care about the output of gpasswd in this test, but we still need to mock it. + _ = localgroupstestutils.SetupGPasswdMock(t, "empty.group") + + if tc.username == "" { + tc.username = "user1" + } + if tc.dbFile == "" { + tc.dbFile = "multiple_users_and_groups" + } + + dbDir := t.TempDir() + err := db.Z_ForTests_CreateDBFromYAML(filepath.Join("testdata", "db", tc.dbFile+".db.yaml"), dbDir) + require.NoError(t, err, "Setup: could not create database from testdata") + m := newManagerForTests(t, dbDir) + + err = m.DisableUser(tc.username) + + requireErrorAssertions(t, err, tc.wantErrType, tc.wantErr) + if tc.wantErrType != nil || tc.wantErr { + return + } + + got, err := db.Z_ForTests_DumpNormalizedYAML(userstestutils.GetManagerDB(m)) + require.NoError(t, err, "Created database should be valid yaml content") + + golden.CheckOrUpdate(t, got) + }) + } +} + +//nolint:dupl // This is not a duplicate test +func TestEnableUser(t *testing.T) { + tests := map[string]struct { + username string + + dbFile string + + wantErr bool + wantErrType error + }{ + "Successfully_enable_user": {}, + + "Error_if_user_does_not_exist": {username: "doesnotexist", wantErrType: db.NoDataFoundError{}}, + } + for name, tc := range tests { + t.Run(name, func(t *testing.T) { + // We don't care about the output of gpasswd in this test, but we still need to mock it. + _ = localgroupstestutils.SetupGPasswdMock(t, "empty.group") + + if tc.username == "" { + tc.username = "user1" + } + if tc.dbFile == "" { + tc.dbFile = "disabled_user" + } + + dbDir := t.TempDir() + err := db.Z_ForTests_CreateDBFromYAML(filepath.Join("testdata", "db", tc.dbFile+".db.yaml"), dbDir) + require.NoError(t, err, "Setup: could not create database from testdata") + m := newManagerForTests(t, dbDir) + + err = m.EnableUser(tc.username) + + requireErrorAssertions(t, err, tc.wantErrType, tc.wantErr) + if tc.wantErrType != nil || tc.wantErr { + return + } + + got, err := db.Z_ForTests_DumpNormalizedYAML(userstestutils.GetManagerDB(m)) + require.NoError(t, err, "Created database should be valid yaml content") + + golden.CheckOrUpdate(t, got) + }) + } +} + //nolint:dupl // This is not a duplicate test func TestUserByIDAndName(t *testing.T) { tests := map[string]struct { diff --git a/internal/users/testdata/db/disabled_user.db.yaml b/internal/users/testdata/db/disabled_user.db.yaml new file mode 100644 index 0000000000..a953e84b62 --- /dev/null +++ b/internal/users/testdata/db/disabled_user.db.yaml @@ -0,0 +1,18 @@ +users: + - name: user1 + uid: 1111 + gid: 11111 + gecos: |- + User1 gecos + On multiple lines + dir: /home/user1 + shell: /bin/bash + broker_id: broker-id + disabled: true +groups: + - name: group1 + gid: 11111 + ugid: "12345678" +users_to_groups: + - uid: 1111 + gid: 11111 diff --git a/internal/users/testdata/golden/TestDisableUser/Successfully_disable_user b/internal/users/testdata/golden/TestDisableUser/Successfully_disable_user new file mode 100644 index 0000000000..0e31b6a1bd --- /dev/null +++ b/internal/users/testdata/golden/TestDisableUser/Successfully_disable_user @@ -0,0 +1,64 @@ +users: + - name: user1 + uid: 1111 + gid: 11111 + gecos: |- + User1 gecos + On multiple lines + dir: /home/user1 + shell: /bin/bash + broker_id: broker-id + disabled: true + - name: user2 + uid: 2222 + gid: 22222 + gecos: User2 + dir: /home/user2 + shell: /bin/dash + broker_id: broker-id + - name: user3 + uid: 3333 + gid: 33333 + gecos: User3 + dir: /home/user3 + shell: /bin/zsh + broker_id: broker-id + - name: userwithoutbroker + uid: 4444 + gid: 44444 + gecos: userwithoutbroker + dir: /home/userwithoutbroker + shell: /bin/sh +groups: + - name: group1 + gid: 11111 + ugid: "12345678" + - name: group2 + gid: 22222 + ugid: "56781234" + - name: group3 + gid: 33333 + ugid: "34567812" + - name: group4 + gid: 44444 + ugid: "45678123" + - name: commongroup + gid: 99999 + ugid: "87654321" +users_to_groups: + - uid: 1111 + gid: 11111 + - uid: 1111 + gid: 99999 + - uid: 2222 + gid: 22222 + - uid: 2222 + gid: 99999 + - uid: 3333 + gid: 33333 + - uid: 3333 + gid: 99999 + - uid: 4444 + gid: 44444 + - uid: 4444 + gid: 99999 diff --git a/internal/users/testdata/golden/TestEnableUser/Successfully_enable_user b/internal/users/testdata/golden/TestEnableUser/Successfully_enable_user new file mode 100644 index 0000000000..77567897ae --- /dev/null +++ b/internal/users/testdata/golden/TestEnableUser/Successfully_enable_user @@ -0,0 +1,17 @@ +users: + - name: user1 + uid: 1111 + gid: 11111 + gecos: |- + User1 gecos + On multiple lines + dir: /home/user1 + shell: /bin/bash + broker_id: broker-id +groups: + - name: group1 + gid: 11111 + ugid: "12345678" +users_to_groups: + - uid: 1111 + gid: 11111