Skip to content
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

api: add gRPC endpoints for creating, updating and deleting passwords #649

Merged
merged 1 commit into from
Nov 1, 2016
Merged

api: add gRPC endpoints for creating, updating and deleting passwords #649

merged 1 commit into from
Nov 1, 2016

Conversation

rithujohn191
Copy link
Contributor

@rithujohn191 rithujohn191 commented Oct 28, 2016

closes #639

cc @ericchiang

Copy link
Contributor

@ericchiang ericchiang left a comment

Choose a reason for hiding this comment

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

Generally good to separate generated code from hand written code. It lets us review it easier. So the commit history should look like.

api: add gRPC endpoints for ...
api: regenerate protobuf code

As discussed, please address these comments then add a couple tests to server/api_test.go. Those can use the in memory storage found in storage/memory to test your implementation.

if req.NewHash != nil {
actual, err := bcrypt.Cost(req.NewHash)
if err != nil {
log.Printf("api: bcrypt.Cost, error: %s", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

This should return an error instead of logging it.

log.Printf("api: bcrypt.Cost, error: %s", err)
}
if actual < bcrypt.MinCost {
log.Printf("api: hash does not meet MinCost requirement: %d", bcrypt.MinCost)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above. Return an error instead of logging.

Also we don't want MinCost we probably want DefaultCost. Min is the absolute minimum allowed bcrypt cost, not the minimal secure cost.

}

updater := func(old storage.Password) (storage.Password, error) {
new := storage.Password{
Copy link
Contributor

Choose a reason for hiding this comment

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

new is a keyword. Generally not a good idea to assign to it.

Also don't create a new struct here, just modify old. There might be new Password fields added later that you'll zero otherwise. See example in #648.

return &api.UpdatePasswordResp{NotFound: true}, nil
}
log.Printf("api: failed to update password: %v", err)
return nil, err
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably want to use fmt.Errorf to add context as well. For example

return nil, fmt.Errorf("update password: %v", err)

return &api.DeletePasswordResp{NotFound: true}, nil
}
log.Printf("api: failed to delete password: %v", err)
return nil, err
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment as above, use fmt.Errorf

Copy link
Contributor

@ericchiang ericchiang left a comment

Choose a reason for hiding this comment

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

One comment. Other than that looks good. Please add tests.


p := storage.Password{
Email: req.Password.Email,
Hash: req.Password.Hash,
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably check the hash the same way we do in UpdatePassword. Maybe pull out that logic into a helper function and use it here too?

if req.Password == nil {
return nil, errors.New("no password supplied")
}
if req.Password.Hash != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

They have to provide a password. So if this is nil we should return an error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also the storage package doc recommends a cost value of at least 14. Where as DefaultCost = 10. Should I change the condition to check for a cost value of 14 instead?

return nil, errors.New("no password supplied")
}
if req.Password.Hash != nil {
err := checkCost(req.Password.Hash)
Copy link
Contributor

Choose a reason for hiding this comment

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

golang tip: You can define variables as part of an if statement and make this a bit more concise:

if err := checkCost(req.Password.Hash); err != nil {
    return nil, err
}

@rithujohn191
Copy link
Contributor Author

Changed storage package doc to have min cost value of 10 instead of 14.

@rithujohn191
Copy link
Contributor Author

All the unit tests passed:
[rjohn@e4-b3-18-d3-91-0e server]$ go test -v .
=== RUN TestCreatePassword
--- PASS: TestCreatePassword (0.08s)
=== RUN TestUpdatePassword
--- PASS: TestUpdatePassword (0.00s)
=== RUN TestDeletePassword
--- PASS: TestDeletePassword (0.00s)

"github.com/coreos/dex/storage/memory"
)

var s = memory.New()
Copy link
Contributor

Choose a reason for hiding this comment

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

Avoid global state. Please create this instead each test.

Copy link
Contributor

@ericchiang ericchiang Nov 1, 2016

Choose a reason for hiding this comment

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

Actually just combine these into one test that

  1. Creates a password.
  2. Updates the password.
  3. Deletes the password

Username: "test",
UserId: "test123",
}
hash, err := bcrypt.GenerateFromPassword([]byte("test1"), 10)
Copy link
Contributor

Choose a reason for hiding this comment

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

Generate this value beforehand instead of requiring each test run to compute a bcrypt.

For example, just use this instead:

// bcrypt hash of the value "test1" with cost 10
hash := []byte("$2a$10$XVMN/Fid.Ks4CXgzo8fpR.iU1khOMsP5g9xQeXuBm1wXjRX8pjUtO")

}
hash, err := bcrypt.GenerateFromPassword([]byte("test1"), 10)
if err != nil {
t.Errorf("Unable to generate password hash: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

t.Errorf doesn't actually stop the tests. You either need to return or use t.Fatalf


if _, err := serv.UpdatePassword(ctx, &req); err != nil {
t.Errorf("Unable to update password: %v", err)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

need to get the user after to ensure the new username was actually set.

}
}

func TestDeletePassword(t *testing.T) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I commented on this above, but two tests shouldn't ever be dependent on one another. If they are, it should probably just be one test :)

@rithujohn191
Copy link
Contributor Author

Unit test passed:
$ go test -v .
=== RUN TestPassword
--- PASS: TestPassword (0.00s)

// Attempts to create, update and delete a test Password
func TestPassword(t *testing.T) {
var s = memory.New()
var serv = NewAPI(s)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: var serv = ... is redundant, just use serv := ... instead.

@ericchiang
Copy link
Contributor

one last nit, other than that lgtm

@ericchiang ericchiang merged commit 90e613b into dexidp:dev Nov 1, 2016
@rithujohn191 rithujohn191 deleted the gRPC-endpoints branch November 1, 2016 21:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants