Commit Graph

135 Commits

Author SHA1 Message Date
ebarault b9fbf51b27 Remote method /user/:id/verify
This commit adds:
- user.prototype.verify(verifyOptions, options, cb)
- remote method /user/:id/verify
- User.getVerifyOptions()

The remote method can be used to replay the sending of a user
identity/email verification message.

`getVerifyOptions()` can be fully customized programmatically
or partially customized using user model's `.settings.verifyOptions`

`getVerifyOptions()` is called under the hood when calling the
/user/:id/verify remote method

`getVerifyOptions()` can also be used to ease the building
of identity verifyOptions:

```js
var verifyOptions = {
  type: 'email',
  from: 'noreply@example.com'
  template: 'verify.ejs',
  redirect: '/',
  generateVerificationToken: function (user, options, cb) {
    cb('random-token');
  }
};

user.verify(verifyOptions);
```

NOTE: the `User.login()` has been modified to return the userId when
failing due to unverified identity/email. This userId can then be used
to call the /user/:id/verify remote method.
2017-04-26 19:05:41 +02:00
Miroslav Bajtoš c5ca2e1c2e
Implement more secure password flow
Improve the flow for setting/changing/resetting User password to make
it more secure.

 1. Modify `User.resetPassword` to create a token scoped to allow
    invocation of a single remote method: `User.setPassword`.

 2. Scope the method `User.setPassword` so that regular tokens created
    by `User.login` are not allowed to execute it.

For backwards compatibility, this new mode (flow) is enabled only
when User model setting `restrictResetPasswordTokenScope` is set to
`true`.

 3. Changing the password via `User.prototype.patchAttributes`
    (and similar DAO methods) is no longer allowed. Applications
    must call `User.changePassword` and ask the user to provide
    the current (old) password.

For backwards compatibility, this new mode (flow) is enabled only
when User model setting `rejectPasswordChangesViaPatchOrReplace` is set
to `true`.
2017-04-20 10:22:21 +02:00
Miroslav Bajtoš e27419086c
Add User.setPassword(id, new, cb)
Implement a new method for changing user password with password-reset
token but without the old password.

REST API

    POST /api/users/reset-password
    Authorization: your-password-reset-token-id
    Content-Type: application/json

    {"newPassword": "new-pass"}

JavaScript API

    User.setPassword(userId, newPassword[, cb])
    userInstance.setPassword(newPassword[, cb])

Note: the new REST endpoint is not protected by scopes yet, therefore
any valid access token can invoke it (similarly to how any valid access
token can change the password via PATCH /api/users/:id).
2017-04-20 10:18:49 +02:00
Miroslav Bajtoš 9c63abef52
Add missing tests for reset password flow 2017-04-18 13:01:14 +02:00
ebarault 912aad8b35 forwarding context options in user.verify
change original "options" argument to "verifyOptions"
adds ctx options argument as "options"
forward context "options" down to relevant downstream functions
review verifyOptions assertions
code cleaning
tests code cleaning
2017-04-11 17:54:45 +02:00
Miroslav Bajtoš c5145bdf34
Add support for scoped access tokens
Define a new property `AccessToken.scopes` to contain the list of
scopes granted to this access token.

Define a new remote method metadata `accessScopes` to contain a list
of scope name required by this method.

Define a special built-in scope name "DEFAULT" that's used when
a method/token does not provide any scopes. This allows access
tokens to grant access to both the default scope and any additional
custom scopes at the same time.

Modify the authorization algorithm to ensure that at least one
of the scopes required by a remote method is allowed by the scopes
granted to the requesting access token.

The "DEFAULT" scope preserve backwards compatibility because existing
remote methods with no `accessScopes` can be accessed by (existing)
access tokens with no `scopes` defined.

Impact on existing applications:

 - Database schema must be updated after upgrading the loopback version

 - If the application was already using a custom `AccessToken.scopes`
   property with a type different from an array, then the relevant code
   must be updated to work with the new type "array of strings".
2017-04-07 13:04:40 +02:00
Miroslav Bajtoš 94f267884f
Forward options in prepareForTokenInvalidation 2017-03-28 15:59:20 +02:00
Miroslav Bajtoš b550cdcf43
Check max password length in User.changePassword 2017-03-28 15:46:01 +02:00
Miroslav Bajtoš 27ed712528
Add User.changePassword(id, old, new, cb)
Implement a new method for changing user passwords the secure way.
The method requires the old password to be provided before a new
password can be used.

REST API:

    POST /api/users/change-password
    Authorization: your-token-id
    Content-Type: application/json

    {"oldPassword":"old-pass", "newPassword": "new-pass"}

JavaScript API:

    User.changePassword(userId, oldPassword, newPassword[, cb])

There is also an instance-level (prototype) method that can be used
from JavaScript:

    userInstance.changePassword(oldPassword, newPassword[, cb])
2017-03-24 11:01:04 +01:00
phairow 0969493ab7
Fix User.verify to convert uid to string
Applications using MongoDB connectors typically have `user.id`
property of type ObjectID.

This commit fixes the code building the verification URL to
correctly convert the user id value into string.
2017-03-08 16:03:53 +01:00
Hiran del Castillo a22b1e13f1
Pass options.verificationToken to templateFn
Enhance User.prototype.verify to pass the generated token
to the templating function in addition to other existing properties.

This allows application to build multiple URLs in the email template,
for example in order to provide a different URL for desktop and
mobile browsers.
2017-03-06 17:08:35 +01:00
Miroslav Bajtoš 79f441b9c4
Verify User and AccessToken relations at startup
Modify `app.enableAuth()` to verify that (custom) User and AccessToken
models have correctly configured their hasMany/belongsTo relations
and print a warning otherwise.
2017-03-03 10:18:58 +01:00
Miroslav Bajtoš 2cac589860
Fix access-token invalidation for missing relation
Fix the code invalidating access tokens on user email/password changes
to correctly handle the case when the relation
"AccessToken belongs to (subclassed) user" is not configured.
2017-02-23 12:56:13 +01:00
Miroslav Bajtoš ea05a2c4dc Fix creation of verification links
Fix User.prototype.verify to call `querystring.stringify` instead
of concatenating query-string components directly.

In particular, this fixes the bug where `options.redirect` containing
a hash fragment like `#/home?arg1=value1&arg2=value2` produced incorrect
URL, because the `redirect` value was not correctly encoded.
2017-02-06 12:39:21 +01:00
Eric 9fe084fffd Enable multiple user models
Allow LoopBack applications to configure multiple User models and share
the same AccessToken model.

To enable this feature:

1) In your custom AccessToken model:

 - add a new property "principalType" of type "string".
 - configure the relation "belongsTo user" as polymorphic,
   using "principalType" as the discriminator

2) In your User models:

 - Configure the "hasMany accessTokens" relation as polymorphic,
   using "principalType" as the discriminator

When creating custom Role and Principal instances, set your
User model's name as the value of "prinicipalType".
2017-02-02 09:42:30 +01:00
Miroslav Bajtoš 8f80aecc1f Preserve sessions on User.save() making no changes 2017-01-30 11:30:05 +01:00
Ritchie Martori d45c1ae7bb Fix logout to handle no or missing accessToken
Return 401 when the request does not provide any accessToken argument
or the token was not found.

Also simplify the implementation of the `logout` method to make only
a single database call (`deleteById`) instead of `findById` + `delete`.
2017-01-30 08:56:18 +01:00
Aris Kemper efd8237dc6 Fix User methods to use correct Primary Key
Do not use hard-coded "id" property name, call `idName()` to get the
name of the PK property.
2017-01-20 16:24:59 +01:00
João Ribeiro e63fea83f7 Fix User.resetPassword to call createAccessToken()
This allows User subclasses to override the algorithm used for building
one-time access tokens for password recovery.
2017-01-19 16:27:22 +01:00
Miroslav Bajtoš e17cc3d23a Preserve current session when invalidating tokens
Fix User model to preserve the current session (provided via
"options.accessToken") when invalidating access tokens after a change
of email or password property.
2017-01-16 10:08:30 +01:00
Miroslav Bajtoš 24bb15233d Clean up access-token-invalidation tests 2017-01-16 10:08:30 +01:00
Miroslav Bajtoš 70eecfab70 Upgrade eslint-config to 7.x 2017-01-06 12:12:35 +01:00
Bram Borggreve cddfb9c77d
Allow password reset request for users in realms 2017-01-05 09:47:18 -05:00
Miroslav Bajtoš 298635dad1 Merge pull request #2992 from DA-14/feature/resetPasswordRequest
Emit resetPasswordRequest event with options
2017-01-05 15:33:22 +01:00
박대선 d9ae32429b Fix false emailVerified on user model update
Yesterday, the loopback we are using in our system was upgraded
via npm, and since the upgrade, we noticed that every time
the user model updates, the emailVerified column would change to false.

I took a look and realized there might be an error in
https://github.com/strongloop/loopback/commit/eb640d8

The intent of the commit just mention is to make emailVerified false
when the email gets changed, but notice that ctx.data.email is null
on updates, so the condition is always met and emailVerified always
becomes false.

This commit fixes the issue just mentioned.
2016-12-23 14:04:44 +09:00
Miroslav Bajtoš 29a17f39d5 Invalidate AccessTokens on password change
Invalidate all existing sessions (delete all access tokens)
after user's password was changed.
2016-12-12 13:30:53 +01:00
Sergey Reus fa8bca8d6e Emit resetPasswordRequest event with options 2016-12-09 18:14:32 +02:00
Miroslav Bajtoš 5016703f21 Remove "options.template" from Email payload
Fix User.confirm to exclude "options.template" when sending the
confirmation email. Certain nodemailer transport plugins are rejecting
such requests.
2016-12-06 16:18:19 +01:00
Miroslav Bajtoš 1ec7cf0a37 Turn on "no-unused-expressions" rule for eslint
Fix unit-tests relying on property-based assertions to use function
calls instead, using "dirty-chai" to modify chai's property checkers.
2016-11-22 15:30:04 +01:00
Loay 06cb481c3f Update eslint to loopback config v5
Notable side-effects:
 - loopback no longer exports "caller" and "arguments" properties
 - kv-memory connector is now properly added to the connector registry
 - the file "test/support.js" was finally removed
2016-11-22 14:08:02 +01:00
Adrien Kiren 85da50cbc8 Add templateFn option to User#verify() 2016-11-14 16:22:10 +01:00
Loay eb640d8da0 Require verification after email change
When the User model is configured to require email verification,
then any change of the email address should trigger re-verification.
2016-11-09 13:06:25 +01:00
Dhaval Trivedi 4922f425fc adding check of string for case insensitive emails 2016-11-01 18:13:56 -04:00
Loay 5f5e874564 Validate non-email property partial update 2016-10-03 15:45:52 -04:00
David Cheung d544ae1bf8 Support uniqueness for realm users 2016-09-20 11:26:56 -04:00
Loay bcc2d99a95 Invalidate sessions after email change 2016-09-19 10:24:30 -04:00
Miroslav Bajtoš 21ff383eb3 Fix double-slash in confirmation URL
Fix the code building the URL used in the email-verification email
to prevent double-slash in the URL when e.g. restApiRoot is '/'.

Before:

  http://example.com//users/confirm?...

Now:

  http://example.com/users/confirm?...
2016-09-13 08:52:49 +02:00
Miroslav Bajtoš 92a5a08671 test/user: don't attach User model twice 2016-09-09 09:02:41 +02:00
Miroslav Bajtoš 9a75ee6f30 Rework email validation to use isemail
Drop hand-crafted RegExp in favour of a 3rd-party module that supports
RFC5321, RFC5322 and other relevant standards.
2016-09-06 14:09:00 +02:00
Loay 5567917c12 Allow resetPassword if emailVerified 2016-08-26 13:11:42 -04:00
Loay 7aebf0d132 Add bcrypt validation 2016-08-12 21:34:50 -04:00
Miroslav Bajtoš 7546ee531d Update dependencies to their latest versions 2016-08-03 16:17:58 +02:00
jannyHou 17a046d7a1 Increase timeout 2016-07-29 14:54:34 -04:00
Loay 0fa3327112 Fix test case error 2016-07-26 10:26:44 -04:00
Loay b53a22bfb3 Fix security issue 580 2016-07-22 17:48:57 -04:00
Loay ec51e833b6 Fix verificationToken bug 2016-06-17 10:21:59 -04:00
David Cheung ddb5327e64 Update tests for strong-error-handler
Fix rest-adapter related test case switching to strong-error-handler
Only affect the test-cases calling rest methods
2016-06-07 13:26:18 -04:00
David Cheung 817e76e424 Remove unused UserModel properties
- credentials
- challenges
- status
- created
- lastUpdated
2016-05-10 14:29:08 -04:00
Supasate Choochaisri 04e26fae5c Separate error-checking and next/done logic from other logic in the test suite
Signed-off-by: Supasate Choochaisri <supasate.c@gmail.com>
2016-05-05 11:12:48 +07:00
Ryan Graham 6964914bab
update copyright statements 2016-05-03 15:50:21 -07:00