-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add functionality to Enable/Disable users #782
base: main
Are you sure you want to change the base?
Conversation
@adombeck Does this look good? I see that the tests are failing on main branch as well. So I am hoping that it is not me. |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #782 +/- ##
==========================================
- Coverage 83.43% 79.08% -4.36%
==========================================
Files 83 102 +19
Lines 8689 10442 +1753
Branches 74 74
==========================================
+ Hits 7250 8258 +1008
- Misses 1111 1715 +604
- Partials 328 469 +141 ☔ View full report in Codecov by Sentry. |
internal/services/pam/pam.go
Outdated
@@ -138,6 +138,12 @@ func (s Service) SelectBroker(ctx context.Context, req *authd.SBRequest) (resp * | |||
lang = "C" | |||
} | |||
|
|||
// Throw an error if the user trying to authenticate already exists in cache and is disabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We use the term "database" instead of "cache" now (related: #775)
// Throw an error if the user trying to authenticate already exists in cache and is disabled | |
// Throw an error if the user trying to authenticate already exists in the database and is disabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed.
Hi @shiv-tyagi, yes this looks good, thanks! One small thing: I would prefer to have a |
There should also be a new test case "Error_when_user_is_disabled" in https://github.com/shiv-tyagi/authd/blob/fed39218cfcce6c23e80e0d02fe2a2d748d3d912/internal/brokers/manager_test.go#L187-L190. |
Oh and I don't think it makes sense to merge this before we have code which actually causes a user to be disabled (i.e. the command-line tool). If you still plan to work on that soon, feel free to repurpose this PR. Otherwise, I'll start working on that soon and would then cherry-pick your commits to a new branch. |
e6410f4
to
a7d839c
Compare
Sure. I will do that.
Noted.
Yes, I really intend to work on that. I will push my work soon :) |
internal/users/manager.go
Outdated
@@ -328,6 +328,16 @@ func (m *Manager) UpdateBrokerForUser(username, brokerID string) error { | |||
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) { | |||
usr, err := m.cache.UserByName(username) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
usr, err := m.cache.UserByName(username) | |
u, err := m.cache.UserByName(username) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. Thanks.
7183092
to
5e81b35
Compare
internal/services/pam/pam.go
Outdated
userIsDisabled, err := s.userManager.IsUserDisabled(username) | ||
if err == nil && userIsDisabled { | ||
return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("user %s is disabled", username)) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's handle unexpected errors here
userIsDisabled, err := s.userManager.IsUserDisabled(username) | |
if err == nil && userIsDisabled { | |
return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("user %s is disabled", username)) | |
} | |
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) | |
} | |
if err == nil && userIsDisabled { | |
return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("user %s is disabled", username)) | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for suggesting. I have incorporated this change.
5e81b35
to
54aae19
Compare
I rebased on main and resolved the conflicts caused by #779. |
7f1338f
to
fce5e88
Compare
I have finished the part till extending the GRPC API with new methods and adding unit tests for those. Now only the part of creating the CLI tool to call those methods remains. |
fce5e88
to
7208138
Compare
@adombeck I have added the initial implementation of the authctl tool. Please check if it looks good and provide any suggestions for me to proceed. This is my first time writing Go code, so I apologise if I made any rookie mistakes. I’ll be happy to fix them. Thanks in advance. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've got a few comments but the overall code style is good! Thanks a lot, @shiv-tyagi!
internal/users/manager_test.go
Outdated
wantErr bool | ||
wantErrType error | ||
}{ | ||
"Successfully_update_broker_for_user": {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test case is not named correctly
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry that was a copy and paste error. I should have been more careful. I have fixed this.
internal/users/manager_test.go
Outdated
wantErr bool | ||
wantErrType error | ||
}{ | ||
"Successfully_update_broker_for_user": {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, please update the test case name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed this.
// We don't care about the output of gpasswd in this test, but we still need to mock it. | ||
_ = localgroupstestutils.SetupGPasswdMock(t, "empty.group") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why we would need to mock gpasswd
in this test, but I also don't see why that's done in many of the other tests in this file which are unrelated to /etc/group
. I see that was introduced in fd10538, do you remember the reason, @denisonbarbosa?
internal/users/manager_test.go
Outdated
wantErr bool | ||
wantErrType error | ||
}{ | ||
"Successfully_update_broker_for_user": {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be a test case which uses testdata with a disabled user. Currently, it only tests enabling a user which was already enabled before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I am already doing that. Please see this.
internal/proto/authd/authd.proto
Outdated
rpc DisablePasswd(DisablePasswdRequest) returns (Empty); | ||
rpc EnablePasswd(EnablePasswdRequest) returns (Empty); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GetPasswd...
methods are named like that because they return an entry like the ones in the /etc/passwd
file. This analogy doesn't really apply to the disable/enable functionality, so let's name these methods DisableUser
and EnableUser
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
cmd/authctl/main.go
Outdated
|
||
func main() { | ||
if err := rootCmd.Execute(); err != nil { | ||
fmt.Fprintf(os.Stderr, "Error while executing authctl '%s'\n", err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Error while executing authctl" doesn't provide any useful info. Let's just print the error.
fmt.Fprintf(os.Stderr, "Error while executing authctl '%s'\n", err) | |
fmt.Fprintln(os.Stderr, err.Error()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
cmd/authctl/user/disable.go
Outdated
|
||
var DisableCmd = &cobra.Command{ | ||
Use: "disable", | ||
Short: "Disable a user to log in", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Disable a user to log in" is not a correct sentence. Also, I would like to convey that this can only disable users managed by authd (which is also an opportunity to at least implicitly tell users that the user accounts created by authd are managed separately from other user accounts on the system), so how about:
Short: "Disable a user to log in", | |
Short: "Disable a user managed by authd", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds better. Fixed that.
cmd/authctl/user/disable.go
Outdated
} | ||
|
||
client := authd.NewNSSClient(conn) | ||
_, err = client.EnablePasswd(context.Background(), &authd.EnablePasswdRequest{Name: args[0]}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's the wrong API method, you want to call DisablePasswd
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops. Sorry. I have fixed that.
cmd/authctl/user/disable.go
Outdated
conn, err := grpc.NewClient("unix://"+consts.DefaultSocketPath, grpc.WithTransportCredentials(insecure.NewCredentials())) | ||
|
||
if err != nil { | ||
return err | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick: no newline between function call and error handling. please also change that in the other occurrences in cmd/authctl/user/disable.go
and cmd/authctl/user/enable.go
.
conn, err := grpc.NewClient("unix://"+consts.DefaultSocketPath, grpc.WithTransportCredentials(insecure.NewCredentials())) | |
if err != nil { | |
return err | |
} | |
conn, err := grpc.NewClient("unix://"+consts.DefaultSocketPath, grpc.WithTransportCredentials(insecure.NewCredentials())) | |
if err != nil { | |
return err | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed this.
cmd/authctl/user/user.go
Outdated
|
||
var UserCmd = &cobra.Command{ | ||
Use: "user", | ||
Short: "Commands retaled to working with users", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Short: "Commands retaled to working with users", | |
Short: "Commands related to users", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done. Thanks.
This also adds tests for the same.
Thank you so much @adombeck for reviewing this. I have addressed all your suggestions. What next? How should I test it locally? |
As discussed in #640, this adds a property to the UserDB to mark a user enable/disabled. Before creating an authentication session in pam, we check if the user exists in the cache and is disabled.
This also adds the initial implementation of the authctl tool which can be used to enable/disable a user.