Commit Graph

236 Commits

Author SHA1 Message Date
Moshe Malka 29c5f20d90
Fix ACL check to support model wildcard 2018-10-25 14:00:35 +02:00
lchaglla 2b7b0e1cc1
Add `options.preserveAccessTokens`
Add an option to preserve access tokens when email/password is changed.
2018-10-08 09:28:35 +02:00
virkt25 aaa1381964 fix: accessToken create default acl 2018-08-08 16:17:48 -04:00
virkt25 5ee731eafd chore: update deps + fix linting + .npmrc 2018-08-08 13:31:30 -04:00
mcitdev 37e57f6943
Fix crash in User model's "before delete" hook
Update User's "before delete" hook to take into account the case when
the related AccessToken model was not configured in the application
(attached to a datasource).
2018-06-29 14:51:41 +02:00
wolrajhti cc4fc2197f
fix bug in User.verify when confirm is disabled 2018-05-31 12:40:23 +02:00
Kevin Scroggins b2bc449e24 Add check for undefined user email in setter 2018-05-23 20:00:45 -04:00
Miroslav Bajtoš 2aead13f11
Fix isOwner() bug in multiple-principal setup
Fix the owner role resolver to correctly handle the case when a user
from one model (e.g. Seller) is accessing an instance of another
user-like model (e.g. Customer).
2018-05-18 15:36:59 +02:00
Miroslav Bajtoš c611bbbe04
Fix formatting issues reported by recent eslint 2018-03-05 10:03:59 +01:00
Raymond Feng d23ff84587
Merge pull request #3784 from zbarbuto/fix/user-status-code
Use statusCode prop for user errors
2018-01-31 15:16:27 -08:00
Zak Barbuto 50e2b49efe Use statusCode prop for user errors 2018-02-01 09:40:13 +10:30
Justin Ross 60750b4508
Update Copyright Years
Update copyright years to include 2018
2018-01-16 13:55:02 +01:00
Miroslav Bajtoš 73cc950b1b
Update eslint and eslint-config to latest 2017-12-12 09:33:15 +01:00
Miroslav Bajtoš 3996f56ab9
Fix "POST /change-password" for multi-user setup
Fix the code extracting current user id from the access token provided
in the HTTP request, to allow only access tokens created by the target
user models to execute the action.

This fixes the following security vulnerability:

* We have two user models, e.g. Admin and Customer

* We have an Admin instance and a Customer instance with the same
  id and the same password.

* The Customer can change Admin's password using their
  regular access token.
2017-10-27 09:47:07 +02:00
Miroslav Bajtoš 0a2a45512c
Fix "POST /reset-password" for multi-user setup
Fix the code extracting current user id from the access token provided
in the HTTP request, to allow only access tokens created by the target
user models to execute the action.

This fixes the following security vulnerability:

* A UserA with id 1 (for example), requires a resetToken1

* A UserB with the same id requires a resetToken2.

* Using resetToken2, use the UserAs/reset-password endpoint and change
  the password of UserA and/or vice-versa.
2017-10-19 13:29:08 +02:00
Miroslav Bajtoš d0a4941668
Fix handling of user verification options
- Fix `User.prototype.verify` to not modify properties of the supplied
   `verifyOptions` argument. This is needed to allow callers to supply
   the same options object to multiple calls of `verify`.

 - Fix `User.getVerifyOptions` to always return a new copy of the
   options object. This is needed to allow callers to modify the
   returned options object without affecting the result returned
   by subsequent calls of `getVerifyOptions`.
2017-10-09 13:42:22 +02:00
pierreclr e17132d061
Fix OWNER role to handle multiple relations
Fix the code resolving OWNER role to correctly handle the situation
where the target model has multiple "belongsTo" relations to the User
model.

Introduce a new model setting "ownerRelations" that enables the new
behavior. When "ownerRelations" is set to true, then all "belongsTo"
relations are considered as granting ownership. Alternatively,
"ownerRelations" can be set to an array of the relations which
are granting ownership.

For example, a document can "belongTo" an author and a reviewer,
but only the author is an owner, the reviewer is not. In this case,
"ownerRelations" should be set to "['author']".
2017-09-27 17:11:36 +02:00
Farid Neshat d2d8fabb16 Fix acl.resolvePermission for wildcard req
When acl.resolvePermission was called with a request containing a
wildcard, it would return the matching acl with lowest score instead of
higher.

Fixes #2153
2017-09-27 02:48:34 +02:00
Samuel Reed 44dd048036
fix(validatePassword): reword error message
Reword the error message returned when the password is too long
 - remove the plaintext password value, it looks very bad
 - include information about the maximum allowed length instead

Also add additional context to the error.
2017-08-16 14:57:57 +02:00
crandmck 9f8321ad61 Fix case of values per doc issue 2017-08-11 11:10:51 -07:00
Raymond Feng 69df11bb8e Refactor access token to make it extensible
1. Make it possible to reuse getIdForRequest()
2. Introduce a flag to control if oAuth2 bearer token should be base64
encoded
3. Promote resolve() to locate/validate access tokens by id
2017-05-02 10:55:51 -07:00
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
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
ebarault 8aa98a80ef Propagate authorized roles in remoting context
Adds an authorizedRoles object to remotingContext.args.options
which contains all the roles (static and dynamic) that are
granted to the user when performing a request through
strong-remoting to an app with authentication enabled.

The authorizedRoles object for example looks like:
{
  $everyone: true,
  $authenticated: true,
  myRole: true
}

NOTE: this pr also covers a number of jsdoc fixes as well
as refactoring in ACL.js and access-context.js
2017-03-20 12:29:33 +01:00
agriwebb build 3f4b5ece71
Allow custom properties of Change Model
Allow custom properties to be added to Change Model,
and make change filter customizable through mixins
to allow to add the custom property to the filter
used to look up relevant changes during change replication.
2017-03-09 08:58:42 +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š 01ce9b5f5a Merge pull request #3247 from strongloop/update-deps
Update runtime dependencies
2017-03-06 11:19:21 +01:00
Miroslav Bajtoš 8510982bea
Update runtime dependencies
- isemail@2
 - loopback-phase@3

Skip update of nodemailer because it changed the license to GPL-like one
2017-03-03 15:53:49 +01:00
Benjamin Schuster-Boeckler 4570626e9d
Fix context passing in OWNER role resolver 2017-02-24 12:28:30 +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
ebarault f0e70dd8a9 Fix Role.isOwner() for multiple user models
Fix `Role.isOwner()` to check both principalId and principalType.
This fixes a bug where users from different User model were treated
as owners as long as their user id was the same as owner's id.
2017-02-17 11:19:07 +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
ebarault ceceb44e78 Add promise support to built-in model RoleMapping 2017-02-01 09:51:43 +01:00
Miroslav Bajtoš c099d8c731 Merge pull request #3163 from ebarault/feature/promisify-acl
Add promise support to built-in model ACL
2017-01-31 14:54:26 +01:00
Miroslav Bajtoš dcb2f159ec Merge pull request #3160 from strongloop/fix/token-invalidation-on-save
Preserve sessions on User.save() making no changes
2017-01-31 14:38:48 +01:00
ebarault a63fad402e Add promise support to built-in model ACL 2017-01-31 14:09:43 +01:00
Miroslav Bajtoš 3b17a0cf5c Upgrade eslint config, fix linter errors 2017-01-31 13:44:32 +01:00
David Hernandez c072d0695d Add missing type to Role properties definition
Fix "created" and "modified" to be defined with type "date".
2017-01-30 11:37:33 +01:00
Miroslav Bajtoš 5fd79b14f4 Merge pull request #3146 from strongloop/feature/promisify-role
Promise-ify built-in Role model
2017-01-30 11:32:28 +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
Miroslav Bajtoš 0fd8f8af72 Promise-ify built-in Role model 2017-01-27 17:16:59 +01:00