Versions: tip
from installer and current code in master
both exhibit the same behaviour.
TL;DR Writing an Ansible playbook to deploy DRP, in the following order:
- Download and install DRP Binaries
- Configure Service & Start
- Create user accounts
- Set passwords of created user accounts
- Delete rocketskates user
- Download and activate DRP content packs using newly created admin account
Expressed as shell commands, the relevant part is something like this:
drpcli users create '{"Name":"admin","Description":"Admin User","Roles":["superuser"],"Available":true}'
drpcli users password admin "password"
drpcli users destroy rocketskates
export RS_TOKEN=`drpcli users token admin | jq -r '.Token'`
drpcli contents create dev-library.json # Works
drpcli contents create drp-community-content.json # Fails
drpcli contents create ansible.json # Fails
...
It doesn't matter what order the contents create
lines are in, it always fails on the second line.
I built a local copy of dr-provision
from master
and added debug logging to frontend.userAuth()
, which shows that the userSecret
and grantorSecret
were changing between the first and second contents create
calls around here.
Checking this manually using drpcli users list
showed the user Secret
being updated as well.
I tracked this back to user.ChangePassword()
which modifies the Secret
whenever a users' password is changed, but does not appear to save it to the User
store at the same time.
Currently, the users password
call changes the PasswordHash
and the Secret
, but does not commit the new Secret
into the store (changing the Secret
happens after the User
is saved).
A token is then generated from this User
- either using the 'old' Secret
which had been previously persisted, or possibly the 'new' Secret
which is stored ephemerally in the existing User
object but not persisted to the backing store (not sure which one happens here).
The first content create
call (or some other consistently occurring action) then either:
- Causes the
User
to be reloaded from the store, invalidating any Token
s generated using the ephemeral Secret
, or
- Causes the ephemeral
User
to be saved to the store, invalidating any Token
s generated using the previously stored Secret
.
To test if this is the cause, I made the following change:
diff --git a/backend/user.go b/backend/user.go
index dea0cca1..da0cd801 100644
--- a/backend/user.go
+++ b/backend/user.go
@@ -95,9 +95,9 @@ func (u *User) ChangePassword(rt *RequestTracker, newPass string) error {
return err
}
u.PasswordHash = ph
- _, err = rt.Save(u)
// When a user changes their password, invalidate any previous cached auth tokens.
u.Secret = randString(16)
+ _, err = rt.Save(u)
return err
}
Which appears to fix the issue and causes a consistent Secret
to be returned and used for all runs of content create
.