Skip to content

warden/groups: add a PUT method to overwrite members & some refactoring - #768

Closed
zepatrik wants to merge 5 commits into
ory:masterfrom
zepatrik:add-replace-warden-groups-members
Closed

zepatrik wants to merge 5 commits into
ory:masterfrom
zepatrik:add-replace-warden-groups-members

Conversation

@zepatrik

@zepatrik zepatrik commented Feb 7, 2018

Copy link
Copy Markdown
Member

There was no way to overwrite all group members meaning just sending the actual value, instead one had to keep track of changes or remove all members to add the new ones again.
Now a http PUT method allows to set the members array.

closes #745

There was no way to overwrite all group members meaning just sending the actual value, instead one had to keep track of changes or remove all members to add the new ones again.
Now a http PUT method allows to set the members array.
@zepatrik

zepatrik commented Feb 7, 2018

Copy link
Copy Markdown
Member Author

not quite ready to merge, just for review if I am doing it right

Comment thread warden/group/handler.go

if err := json.NewDecoder(r.Body).Decode(&g); err != nil {
h.H.WriteError(w, r, errors.WithStack(err))
if err := h.checkRequest(r, h.PrefixResource(GroupsResource), "create"); err != nil {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

isn't it better to always first check the request?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, maybe I was using g here for some reason which was why it was decoded first, but as it stands now the order can be reversed´the way you did it.

Comment thread warden/group/handler.go
if err := h.Manager.RemoveGroupMembers(id, m.Members); err != nil {
w.WriteHeader(http.StatusNoContent)
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

missing comment

Comment thread warden/group/manager_sql.go Outdated
return nil
}

func (m *SQLManager) applyInTransaction(requests ...func(tx *sqlx.Tx) error) error {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

check if rollbacks are correct

@zepatrik

zepatrik commented Feb 7, 2018

Copy link
Copy Markdown
Member Author

shouldn't this function (and the next one) be non capital because it is not checking the request at all, it is just a helper right?

@aeneasr

aeneasr commented Feb 7, 2018

Copy link
Copy Markdown
Member

shouldn't this function (and the next one) be non capital because it is not checking the request at all, it is just a helper right?

I'm not sure right now, I think they need to be upper case for swagger docs to work. I'd have to check, otherwise all of the handlers can be lower case.

@aeneasr aeneasr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks pretty solid so far!

Comment thread warden/group/handler.go Outdated
w.WriteHeader(http.StatusNoContent)
}

func (h *Handler) OverwriteGroupMembers(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would probably rename it to "UpdateGroup"

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I think I'm going for UpdateGroupMembers because the http PUT url is GroupsHandlerPath + "/:id/members" so only one group is affected, not all of them

Comment thread warden/group/handler.go

if err := json.NewDecoder(r.Body).Decode(&g); err != nil {
h.H.WriteError(w, r, errors.WithStack(err))
if err := h.checkRequest(r, h.PrefixResource(GroupsResource), "create"); err != nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes, maybe I was using g here for some reason which was why it was decoded first, but as it stands now the order can be reversed´the way you did it.

Comment thread warden/group/manager_sql.go Outdated
return nil
}

func (m *SQLManager) applyInTransaction(requests ...func(tx *sqlx.Tx) error) error {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

requests are really transactions, right?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

A transaction is a sequence of requests I would rather say.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

How about executors?

Comment thread warden/group/manager_sql.go Outdated

for _, req := range requests {
if err := req(tx); err != nil {
tx.Rollback()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If rollback fails, the error should be returned instead

if err := tx.Rollback(); err != nil {
  return err
}

Comment thread warden/group/manager_sql.go Outdated
}

func (m *SQLManager) OverwriteGroupMembers(group string, members []string) error {
if err := m.applyInTransaction(m.deleteGroup(group), m.createGroup(group), m.addGroupMembers(group, members)); err != nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this can be simplified to return m.ApplyIn...

Comment thread warden/group/manager_sql.go Outdated
return func(tx *sqlx.Tx) error {
for _, subject := range subjects {
if _, err := tx.Exec(m.DB.Rebind("DELETE FROM hydra_warden_group_member WHERE member=? AND group_id=?"), subject, group); err != nil {
if err := tx.Rollback(); err != nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

You have duplicate rollbacks here, let applyInTransaction handle rollbacks instead!

Comment thread warden/group/manager_sql.go Outdated
return func(tx *sqlx.Tx) error {
for _, subject := range subjects {
if _, err := tx.Exec(m.DB.Rebind("INSERT INTO hydra_warden_group_member (group_id, member) VALUES (?, ?)"), group, subject); err != nil {
if err := tx.Rollback(); err != nil {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Rollback is already covered by applyInTransaction

Comment thread warden/group/manager_sql.go Outdated
func (m *SQLManager) createGroup(group string) func(tx *sqlx.Tx) error {
return func(tx *sqlx.Tx) error {
if _, err := tx.Exec(m.DB.Rebind("INSERT INTO hydra_warden_group (id) VALUES (?)"), group); err != nil {
return err

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Normal errors do not have stack traces in go, to add a stack trace do return errors.WithStack(err)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Oh now I got it, I thought that errors.WithStack(err) just has to be called once to get the whole stacktrace.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Exactly, and it also needs to be called at the location which is the deepest in the stack trace and there only once - otherwise you'll overwrite the stack trace. This is a bit tricky unfortunately. The rule is that we wrap all errors coming from other libraries but don't wrap errors coming from our own. That way we ensure that traces are always as deep as possible in the stack.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

So this should be actually without a stacktrace?

Comment thread warden/group/manager_sql.go Outdated
func (m *SQLManager) deleteGroup(id string) func(tx *sqlx.Tx) error {
return func(tx *sqlx.Tx) error {
if _, err := tx.Exec(m.DB.Rebind("DELETE FROM hydra_warden_group WHERE id=?"), id); err != nil {
return err

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Normal errors do not have stack traces in go, to add a stack trace do return errors.WithStack(err)

Comment thread warden/group/manager_sql.go Outdated
if err := tx.Rollback(); err != nil {
return err
}
return err

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Normal errors do not have stack traces in go, to add a stack trace do return errors.WithStack(err)

@zepatrik

Copy link
Copy Markdown
Member Author

ready for review @arekkas

@aeneasr
aeneasr self-requested a review February 17, 2018 08:54

@aeneasr aeneasr left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Totally forgot about this one, have some questions. I'll check out the SQL implementation in more detail because the changes are a bit complex.

Comment thread warden/group/handler.go
// oauth2: hydra.warden.groups
//
// Responses:
// 204: emptyResponse

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

PUT requests typically don't return 204 responses but instead 200 + body. 204 is typically used for DELETE responses to aknowledge that the resource is gone

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I may not have changed everything correctly when copying the comments

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's also in the response, see w.WriteHeader(http.StatusNoContent)

return func(tx *sqlx.Tx) error {
_, err := tx.Exec(m.DB.Rebind("INSERT INTO hydra_warden_group (id) VALUES (?)"), group)

return errors.WithStack(err)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Not sure if this works for nil values? So if error is nil, does this return nil as well or not?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

https://godoc.org/github.com/pkg/errors#WithStack
I looked it up it works as expected

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Absolutely, it returns nil in that case: https://github.com/pkg/errors/blob/master/errors.go#L145

@aeneasr
aeneasr changed the base branch from master to 0.11 April 8, 2018 21:49
@aeneasr
aeneasr changed the base branch from 0.11 to master April 8, 2018 21:50
@aeneasr

aeneasr commented May 20, 2018

Copy link
Copy Markdown
Member

This is now tracked as ory/keto#10

@aeneasr aeneasr closed this May 20, 2018
aeneasr pushed a commit to ory/keto that referenced this pull request May 23, 2018
* transfer UpdateRoleMembers from ory/hydra#768 to keto

* fix tests by using right http method & correcting sql request

* Change behavior to overwrite the whole role instead of just the members.
+ small sql migration fix
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.

Add PUT method for /warden/groups/:id

2 participants