Hypertopic / AAAforREST

An HTTP reverse proxy to bring authentication, authorization and accounting to RESTful applications
GNU Affero General Public License v3.0
6 stars 5 forks source link

Reset one's password #29

Open benel opened 9 years ago

benel commented 9 years ago

The general idea is to send an e-mail with a URI that cannot be forged.

A. Different options could be used in the URI to make it unforgeable:

  1. a document UUID (if there are no other way to create one or to list them),
  2. a hash of the login (or e-mail) salted with a secret,
  3. a true asymetric digital signature,
  4. a one-time token (e.g. UUID) added to the user document by an admin.

B. On CouchDB's side, the password can be reset either:

  1. by the user itself (which would be applicable for password reset only with proxyauth set up on CouchDB and if the proxy can check the unforgeable URI itself),
  2. by an administrator (which means that the service that checks the unforgeable URI should know the admin credential),
  3. by anonymous in admin party (not applicable).

For implementation simplicity (balanced with security), I would favor solution A.4+B.2. @franck-eyraud Do you think about other solutions or do you favor another one?

benel commented 9 years ago

@adeprez I will assign you to this feature as soon as you have joined the team.

franck-eyraud commented 9 years ago

I find your list quite exhaustive, I would probably not reach that many alternatives.

Some comments :

For me both A and B can be done by the proxy, so the whole password reset would be a "module" of AAAforRest. And we can avoid to store admin's credentials if we use the proxyauth (i.e. admin authenticated by proxyauth while storing UUID or new password).

Note that storing the password is a bit more complex for couchdb v1.0 and below (including cloudant) : it needs to be hashed client side. I suggest to specifically declare the incompatibility.

benel commented 9 years ago

@adeprez For A4 and B2, I've just tested if admin edits could be done from an _update function added to the _users database. But "Only admins can access design document actions for system databases".

So the only way to do edits with admin privileges will be from a node service that knows admin user credentials:

franck-eyraud commented 9 years ago

I just realized that to allow admin access through proxy authentication, it is required to use the X-Auth-CouchDB-Roles header (whatever the username) :

$ curl -H "X-Auth-CouchDB-UserName: admin" http://127.0.0.1:5984/_active_tasks                                         
{"error":"unauthorized","reason":"You are not a server admin."}
$ curl -H "X-Auth-CouchDB-UserName: whatever" -H "X-Auth-CouchDB-Roles: _admin" http://127.0.0.1:5984/_active_tasks
[]
benel commented 9 years ago

I just realized that to allow admin access through proxy authentication, it is required to use the X-Auth-CouchDB-Roles header (whatever the username) :

Indeed. That's why I used a different URI in my test 98fc4869ffe3e3b2395863d2e77f7fffc30cde3e.

benel commented 9 years ago

For your information, I am refactoring the registration feature (from CouchDB attachments to Node static server) so that integration will be easier with node services needed for this part.

benel commented 9 years ago

I just realized that to allow admin access through proxy authentication

Please note, that the client will not initiate admin requests. Only the reset services.

franck-eyraud commented 9 years ago

Please note, that the client will not initiate admin requests. Only the reset services.

Yes I know, but it is a way to allow the reset services to authenticate wihthout having the actual credentials in some config file.

Luwangel commented 9 years ago

We have designed some mockups to show how the authentication system will work. This system will be used on TraduXio and that's why we use it as demonstrator.

User's scenario

Step 1

First of all the user who wants to connect needs to open the login page.

Login page

Step 2

We consider now that he tries to connect and fails. He has definitely forgot his password and needs to recover it. To do that he has to click on the link Mot de passe oublié ? (Forgot password? in english). As a result a formular appears on a new page and he just has to fill the field "Email" and clicks on the button.

Mail page

Step 3

Then he receives a mail with a link to access to the reset formular. In this last page the user can choose a new one he will never forget (until the next reset).

Mail page

ammelanie-utt commented 9 years ago

To have the same mockups style as the register's one (https://github.com/Hypertopic/AAAforREST/issues/28) we made three new mockups with the same information as the ones above.

connexion v3 1

reset password v2

reset password2 v2

Luwangel commented 9 years ago

We can now consider the mockups as finished. However we don't know if the recipe tests are necessary for this functionality. They could be difficult to write because of the external mail. For this particular reason we can imagine a test in two parts.

Part A : reset the password

  1. Click on the "Forgot password" link
  2. Fill the formular with an email
  3. Generate the content of the email before sending it (don't forget to catch the generated content)
  4. Click on the reset link catched
  5. Set the new password
  6. Check the login

Part B (manual testing ?) : send the mail

  1. Test if the mail is really sent (after the first part occured)
  2. Compare the mail content with the content catcher in the part A
benel commented 6 years ago

@franck-eyraud I've seen that you implemented this feature in TraduXio. Great job!

Two questions:

franck-eyraud commented 6 years ago

Hi @benel!

I have to say that I wasn't aware of this description while developing that part in TraduXio.

The solution is currently more simple (maybe too simple and that could have security issue). In fact, the password is reset with a generated one by admin, like in B2, but the password is sent by email (the email being previously confirmed - using the A2 solution). So this is the way the unforgeable information is sent to the user. It is quite possible to adapt it to another of the above listed solution.

For your second question, yes it should be possible to reuse it in other software, or external service, at least I thought of it while writing it. It relies on a service which accesses the users database as admin.

benel commented 6 years ago

The solution is currently more simple

No problem. It can be enhanced later.

the password is sent by email

OK. And I suppose it is the same for account creation, right ?

it should be possible to reuse it in other software, or external service, at least I thought of it while writing it. It relies on a service which accesses the users database as admin.

I suppose there is one Web service and one poller to send e-mails, aren't they? Is the first piece of software implemented with Express.js? Is the second one using follow library?

franck-eyraud commented 6 years ago

OK. And I suppose it is the same for account creation, right ? No, the account is directly created in couchdb _users database, with password set by the user.

I suppose there is one Web service and one poller to send e-mails, aren't they? No, I avoided the web service by creating a "password reset request" doc in couchdb database. The poller catches it, sets the password, and send the email. It also monitors account creation, and validate the email address. But if a web service is already existing, it is probably better to use it.

Is the second one using follow library? Yes. Or to be more precise, it uses the couchdb-nano library, which encloses the follow one.

benel commented 6 years ago

No, the account is directly created in couchdb _users database, with password set by the user.

I've just tested account creation. When I read your answer, I didn't get that e-mail address is first "not confirmed" (but usable) then "confirmed" (after clicking on the received e-mail). It's nice.

benel commented 4 years ago

Out of scope of v2. Could be implemented in Porphyry and LaSuli (maybe through a reusable React component).