Skip to content

feat: create a token for another user via cli #13424

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

Closed
wants to merge 4 commits into from

Conversation

Philip-21
Copy link

Pr fixes for #13160

Signed-off-by: Philip-21 <philipuzomaobiora@gmail.com>
@cdr-bot cdr-bot bot added the community Pull Requests and issues created by the community. label May 31, 2024
Copy link

github-actions bot commented May 31, 2024

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@Philip-21
Copy link
Author

I have read the CLA Document and I hereby sign the CLA

cdrcommunity added a commit to coder/cla that referenced this pull request May 31, 2024
Copy link
Member

@matifali matifali left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Philip-21, you must run make fmt to pass the fmt ci check. Also, please add tests to cover the newly added functionality.

@matifali matifali changed the title Cli Token creation feat: create a token for another user via cli May 31, 2024
Copy link
Member

@kylecarbs kylecarbs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution! Almost there, just a few minor things.

Comment on lines 82 to 116
// CreateTokenForUser allows an admin to create a token on behalf of another user.
func (c *Client) CreateTokenForUser(ctx context.Context, adminID, targetUserID string, req CreateTokenRequest) (GenerateAPIKeyResponse, error) {
isAdmin, err := c.isAdmin(ctx, adminID)
if err != nil {
return GenerateAPIKeyResponse{}, fmt.Errorf("admin check failed: %w", err)
}
if !isAdmin {
return GenerateAPIKeyResponse{}, fmt.Errorf("user %s is not an admin", adminID)
}
return c.CreateToken(ctx, targetUserID, req)
}

// isAdmin is a placeholder function to check if a user is an admin.
func (c *Client) isAdmin(ctx context.Context, userID string) (bool, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s/keys", userID), nil)
if err != nil {
return false, fmt.Errorf("unable to get user : %s", userID)
}
defer res.Body.Close()
if res.StatusCode > http.StatusCreated {
return false, ReadBodyAsError(res)
}
//extract roles, when the API returns roles from the response, ensuring system admin privileges
var roles []string
if err := json.NewDecoder(res.Body).Decode(&roles); err != nil {
return false, fmt.Errorf("failed to decode roles: %w", err)
}
for _, role := range roles {
if role == "admin" {
return true, nil
}
}
return false, nil
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API should return an error when the user does not have permissions to create keys for other users, so we shouldn't need to add any new codersdk functions.

cli/tokens.go Outdated
Comment on lines 73 to 75
// Otherwise, create a token for the current user
res, err := client.CreateToken(inv.Context(), codersdk.Me, codersdk.CreateTokenRequest{
Lifetime: tokenLifetime,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can actually keep this the same as it was before, but add a userID flag.

e.g.

userID := codersdk.Me
if user != "" {
  userID = user
}
// Use the `userID` instead of `codersdk.Me` in `client.CreateToken`.

@Philip-21
Copy link
Author

Thank you i will make changes

Signed-off-by: Philip-21 <philipuzomaobiora@gmail.com>
@Philip-21
Copy link
Author

Hey @kylecarbs from the changes i have made, i added another condition where a user doesnt have the permission to create a key for another user.
Also the changes i made in the token.go, is it fine ?

@matifali matifali requested a review from kylecarbs June 3, 2024 17:10
@Philip-21
Copy link
Author

@Philip-21, you must run make fmt to pass the fmt ci check. Also, please add tests to cover the newly added functionality.

Alright

@Philip-21
Copy link
Author

Hey @matifali i ran make fmt i got the below

fatal: No names found, cannot describe anything.
==> fmt/eslint
bash: line 3: pnpm: command not found
make: *** [Makefile:404: fmt/eslint] Error 127

@Philip-21
Copy link
Author

Now i have made changes in the createToken(), please i'm trying to figure out how i can specify the args
-u, --user string, $CODER_TOKEN_USER
Create the token on behalf of another user (Admin only)
So the CreateTokenForUser() works effectively.

@matifali
Copy link
Member

matifali commented Jun 4, 2024

Hey @matifali i ran make fmt i got the below

fatal: No names found, cannot describe anything. ==> fmt/eslint bash: line 3: pnpm: command not found make: *** [Makefile:404: fmt/eslint] Error 127

@Philip-21 Please ensure you have a working dev environment by following these instructions. I would advise using devcontainer or nix

Philip-21 added 2 commits June 6, 2024 07:33
Signed-off-by: Philip-21 <philipuzomaobiora@gmail.com>
Signed-off-by: Philip-21 <philipuzomaobiora@gmail.com>
@Philip-21
Copy link
Author

@matifali i ran after following the steps and using nix-shell to set up my dev environment, i ran
make fmt i got this error

          => fmt/terraform
          ==> fmt/shfmt
          ==> fmt/go
          go: downloading mvdan.cc/gofumpt v0.4.0
          go: downloading golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde
          go: downloading golang.org/x/sys v0.0.0-20220829200755-d48e67d00261
          go: downloading github.com/google/go-cmp v0.5.8
          go: downloading golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
          go: downloading golang.org/x/tools v0.1.12
          # internal/godebugs
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # internal/unsafeheader
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # internal/goos
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # internal/coverage/rtcov
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # internal/goarch
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # internal/goexperiment
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # unicode/utf8
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # internal/race
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # unicode
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # internal/itoa
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # math/bits
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # encoding
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # runtime/internal/syscall
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # sync/atomic
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # internal/cpu
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # runtime/internal/atomic
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # cmp
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # unicode/utf16
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # internal/goversion
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # container/list
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          # github.com/google/go-cmp/cmp/internal/flags
          compile: version "go1.22.0" does not match go tool version "go1.22.2"
          make: *** [Makefile:397: fmt/go] Error 1

it didnt finish executing

@matifali
Copy link
Member

@bpmct, could you get some eyes on this PR? I am away for the next few weeks.

@github-actions github-actions bot added the stale This issue is like stale bread. label Jun 18, 2024
@github-actions github-actions bot closed this Jun 22, 2024
@stirby
Copy link
Collaborator

stirby commented Jun 24, 2024

@kylecarbs can you take another look?

@stirby stirby reopened this Jun 24, 2024
@stirby stirby added cli Area: CLI and removed stale This issue is like stale bread. labels Jun 24, 2024
@github-actions github-actions bot added the stale This issue is like stale bread. label Jul 2, 2024
@github-actions github-actions bot closed this Jul 6, 2024
@stirby stirby reopened this Jul 26, 2024
Copy link
Member

@kylecarbs kylecarbs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome change! Just one minor comment.

Comment on lines +97 to +118
// isAdmin is a placeholder function to check if a user is an admin.
func (c *Client) isAdmin(ctx context.Context, userID string) (bool, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/users/%s/keys", userID), nil)
if err != nil {
return false, fmt.Errorf("unable to get user : %s", userID)
}
defer res.Body.Close()
if res.StatusCode > http.StatusCreated {
return false, ReadBodyAsError(res)
}
//extract roles, when the API returns roles from the response, ensuring system admin privileges
var roles []string
if err := json.NewDecoder(res.Body).Decode(&roles); err != nil {
return false, fmt.Errorf("failed to decode roles: %w", err)
}
for _, role := range roles {
if role == "admin" {
return true, nil
}
}
return false, nil
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't perform intermediary checks in our API package.

Ideally, our API returns a friendly error indicating that the user isn't an admin, which reduces the number of requests required as well.

@github-actions github-actions bot removed the stale This issue is like stale bread. label Jul 27, 2024
@github-actions github-actions bot added the stale This issue is like stale bread. label Aug 4, 2024
@github-actions github-actions bot closed this Aug 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cli Area: CLI community Pull Requests and issues created by the community. stale This issue is like stale bread.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants