Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error "401 Authorization required" when querying methods involving relations #426

Closed
sam-artuso opened this issue Jul 31, 2014 · 40 comments
Closed
Labels

Comments

@sam-artuso
Copy link

I've recently migrated an application to LoopBack 2.0.

All my models require user authentication and have these ACLs:

    "acls": [
      {
        "accessType": "*",
        "permission": "DENY",
        "principalType": "ROLE",
        "principalId": "$everyone"
      },
      {
        "accessType": "READ",
        "permission": "ALLOW",
        "principalType": "ROLE",
        "principalId": "$authenticated"
      }
    ]

I have a model called issues. After logging in through the POST method /Users/login:

  • I don't have any problems when calling the GET method /issues. I get a list of issues as expected;
  • When I query a method involving a relation between two models (e.g. GET /issues/{id}/categories), I get the error 401 Authorization required. The same model used to work in Loopback 1.0.

Any clues?

@daankets
Copy link

I have the same issue. I also think the 401 Unauthorized is a wrong response. I am authenticated, so it should be 403 forbidden. I'm opening a new issue for that.

@gcirne
Copy link
Contributor

gcirne commented Aug 12, 2014

I think this has already been implemented: #301

@daankets
Copy link

This issue (#426) itself is not yet resolved. Defining an ACL on a relation property does not seem to work for me.
Replicate by defining a model, adding a relationship to it (for example many user to many group). Then DENY ALL on * for ROLE $everyone, and finally ALLOW READ/EXECUTE on for ROLE $authenticated. I consequently get access denied for these relationships.

@dagumak
Copy link

dagumak commented Aug 19, 2014

I am having the exact same issue! I spent a few hours digging through anything I can find, but I still couldnt get it to work!

@fabien
Copy link
Contributor

fabien commented Aug 19, 2014

@dagumak - can you post the ACL's you defined?

@dagumak
Copy link

dagumak commented Aug 19, 2014

@fabien I posted it here (#459 (comment)), but here it is:

{
  "name": "TestUser",
  "base": "User",
  "strict": true,
  "properties": {
    "username": {
      "type": "string",
      "required": true
    }
  },
  "validations": [],
  "relations": {
    "message": {
      "type": "hasMany",
      "model": "Message",
      "foreignKey": "userId"
    }  
  },
  "acls": [

  ],
  "methods": []
}

{
  "name": "Message",
  "base": "PersistedModel",
  "properties": {
    "type": {
      "type": "string",
      "required": true
    },
    "text": {
      "type": "string",
      "required": true
    }
  },
  "validations": [],
  "relations": {
    "testUser": {
      "type": "belongsTo",
      "model": "TestUser",
      "foreignKey": "userId"
    }
  },
  "acls": [
    {
      "principalType": "ROLE",
      "principalId": "$everyone",
      "permission": "ALLOW"
    }
  ],
  "methods": []
}

@fabien
Copy link
Contributor

fabien commented Aug 19, 2014

I think the core User ACL's are interfering with the ACL's you defined. I recall the following from one of my projects, which overrides all the ACL's:

TestUser.settings.acls = [ 
      { principalType: 'ROLE',
        principalId: '$everyone',
        permission: 'DENY' },
      { principalType: 'ROLE', // this is the important bit
        principalId: '$owner',
        permission: 'ALLOW' },
      { principalType: 'ROLE',
        principalId: '$everyone',
        permission: 'ALLOW',
        property: 'create' },
      { principalType: 'ROLE',
        principalId: '$owner',
        permission: 'ALLOW',
        property: 'deleteById' },
      { principalType: 'ROLE',
        principalId: '$everyone',
        permission: 'ALLOW',
        property: 'login' },
      { principalType: 'ROLE',
        principalId: '$everyone',
        permission: 'ALLOW',
        property: 'logout' },
      { principalType: 'ROLE',
        principalId: '$owner',
        permission: 'ALLOW',
        property: 'findById' },
      { principalType: 'ROLE',
        principalId: '$owner',
        permission: 'ALLOW',
        property: 'updateAttributes' },
      { principalType: 'ROLE',
        principalId: '$everyone',
        permission: 'ALLOW',
        property: 'confirm' }
    ]

@fabien
Copy link
Contributor

fabien commented Aug 19, 2014

@dagumak the very least you could do is trace your current TestUser.settings.acls to compare them.

@dagumak
Copy link

dagumak commented Aug 19, 2014

@fabien I feel silly for asking, but other than console log, how can I do that?

On Tue, Aug 19, 2014 at 11:32 PM, Fabien Franzen notifications@github.com
wrote:

@dagumak the very least you could do is trace your current TestUser.settings.acls to compare them.

Reply to this email directly or view it on GitHub:
#426 (comment)

@fabien
Copy link
Contributor

fabien commented Aug 19, 2014

@dagumak console.log is fine

@dagumak
Copy link

dagumak commented Aug 19, 2014

@fabien I am not very familiar with the framework yet, but where are the models loaded and a good place for me to console.log it?

@fabien
Copy link
Contributor

fabien commented Aug 19, 2014

You can put the following into a file at /server/boot/debug.js:

module.exports = function(app) {
  var TestUser = app.loopback.getModel('TestUser');
  console.log(TestUser.settings.acls);
};

@raymondfeng
Copy link
Member

You can run the application with DEBUG enabled:

$ DEBUG=loopback:security:* node .

Thanks,


Raymond Feng
Co-Founder and Architect @ StrongLoop, Inc.

StrongLoop makes it easy to develop APIs in Node, plus get DevOps capabilities like monitoring, debugging and clustering.

On Aug 19, 2014, at 8:29 AM, Fabien Franzen notifications@github.com wrote:

You can put the following into a file at /server/boot/debug.js:

module.exports = function(app) {
var TestUser = app.loopback.getModel('TestUser');
console.log(TestUser.settings.acls);
};

Reply to this email directly or view it on GitHub.

@dagumak
Copy link

dagumak commented Aug 19, 2014

@fabien Thanks a bunch! Here it is:

[ { principalType: 'ROLE',
    principalId: '$everyone',
    permission: 'DENY' },
  { principalType: 'ROLE',
    principalId: '$everyone',
    permission: 'ALLOW',
    property: 'create' },
  { principalType: 'ROLE',
    principalId: '$owner',
    permission: 'ALLOW',
    property: 'deleteById' },
  { principalType: 'ROLE',
    principalId: '$everyone',
    permission: 'ALLOW',
    property: 'login' },
  { principalType: 'ROLE',
    principalId: '$everyone',
    permission: 'ALLOW',
    property: 'logout' },
  { principalType: 'ROLE',
    principalId: '$owner',
    permission: 'ALLOW',
    property: 'findById' },
  { principalType: 'ROLE',
    principalId: '$owner',
    permission: 'ALLOW',
    property: 'updateAttributes' },
  { principalType: 'ROLE',
    principalId: '$everyone',
    permission: 'ALLOW',
    property: 'confirm' } ]

@SwadhyayStudios
Copy link

Is this resolved ? I am still having the same issue
The last thread doesn't help

@SwadhyayStudios
Copy link

[ { principalType: 'ROLE',
principalId: '$everyone',
permission: 'DENY' },
{ principalType: 'ROLE',
principalId: '$everyone',
permission: 'ALLOW',
property: 'create' },
{ principalType: 'ROLE',
principalId: '$owner',
permission: 'ALLOW',
property: 'deleteById' },
{ principalType: 'ROLE',
principalId: '$everyone',
permission: 'ALLOW',
property: 'login' },
{ principalType: 'ROLE',
principalId: '$everyone',
permission: 'ALLOW',
property: 'logout' },
{ principalType: 'ROLE',
principalId: '$owner',
permission: 'ALLOW',
property: 'findById' },
{ principalType: 'ROLE',
principalId: '$owner',
permission: 'ALLOW',
property: 'updateAttributes' },
{ principalType: 'ROLE',
principalId: '$everyone',
permission: 'ALLOW',
property: 'confirm' },
{ principalType: 'ROLE',
principalId: '$everyone',
permission: 'ALLOW',
property: 'resetPassword',
accessType: 'EXECUTE' },
{ accessType: '*',
principalType: 'ROLE',
principalId: '$everyone',
permission: 'ALLOW' } ]

@rubentorresbonet
Copy link

Something that helped me with ACL and relations is to run "DEBUG=loopback:security:* slc run" and then check the property it is trying to access.
At first I tried adding ACL to the "orders" property (since it was like /users/2/orders) but it seems like the ACL resolver tried to access this property: __get__orders.
I set that in my json acl file and it is working like a charm.

Example:
"acls": [
{
"accessType": "EXECUTE",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": "__get__orders"
}

@superkhau
Copy link
Contributor

Please create a test project on Github to reproduce the issue as per https://github.com/strongloop/loopback/wiki/Issues#bug-report

@LetsDoIt-
Copy link

@rubentorresbonet the acl that you defined with the property __get__orders is for which model?
Is it for the user model or for the orders model?

@rubentorresbonet
Copy link

@jdhiro
Copy link

jdhiro commented Aug 2, 2015

@rubentorresbonet Holy cow, that worked! I had to use the property __get__customer for a relationship named customer. Thanks!

DEBUG=loopback:security:* slc run really helped me understand what was happening with the ACLs.

This was on a subclassed user model. The full thing looks like this now:

{
  "name": "user",
  "base": "User",
  "idInjection": true,
  "properties": {},
  "validations": [],
  "relations": {
    "customer": {
      "type": "hasOne",
      "model": "Customer"
    }
  },
  "acls": [
    {
      "principalType": "ROLE",
      "principalId": "$owner",
      "permission": "ALLOW",
      "property": "__get__customer"
    }
  ],
  "methods": []
}

This can't possibly be the intended design.

@csvan
Copy link

csvan commented Sep 10, 2015

Agree with @jdhiro that from a design perspective, this is very uncomfortable. Would it not be better to introduce a single declaration in order to to set R/W/X privileges on a single relation, just as we can do for other built-in methods?

@csvan
Copy link

csvan commented Sep 10, 2015

By the way, the link to the documentation for accessing related models provided above is broken, the correct one is here:

https://docs.strongloop.com/display/public/LB/Accessing+related+models

@mike-aungsan
Copy link

I spent a few hours on this too. Doc is not clear. It should clearly mention that default is denied

@superkhau
Copy link
Contributor

@crandmck ^

@vnathalye
Copy link

While trying CoffeeShop example given at https://docs.strongloop.com/display/LB/Getting+started+part+II I'm getting 401 only while editing the review. I've the ACLs defined as given @ https://docs.strongloop.com/display/public/LB/Define+access+controls

So the following ACL entry is failing:

{
"accessType": "WRITE",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
}

If I change $owner to $authenticated, then I don't get 401. So there seems to be some problem in isOwner().
I've tried using DEBUG=loopback:security:* and it gives following output

loopback:security:access-context ---AccessContext--- +1ms
loopback:security:access-context principals: +3ms
loopback:security:access-context principal: {"type":"USER","id":"562a105037cfea381ac14fbb"} +2ms
loopback:security:access-context modelName Review +3ms
loopback:security:access-context modelId 562a105037cfea381ac14fbe +1ms
loopback:security:access-context property upsert +1ms
loopback:security:access-context method upsert +2ms
loopback:security:access-context accessType WRITE +1ms
loopback:security:access-context accessToken: +2ms
loopback:security:access-context id "EoEwOGWIWLNfw4DLgxf9ga2zCoFht974DgCccMFkQLmLrmnQJ64eHJidDIf4e8dh" +1ms
loopback:security:access-context ttl 1209600 +3ms
loopback:security:access-context getUserId() 562a105037cfea381ac14fbb +2ms
loopback:security:access-context isAuthenticated() true +3ms
loopback:security:role Custom resolver found for role $everyone +0ms
loopback:security:role isInRole(): $everyone +2ms
loopback:security:access-context ---AccessContext--- +1ms
loopback:security:access-context principals: +1ms
loopback:security:access-context principal: {"type":"USER","id":"562a105037cfea381ac14fbb"} +1ms
loopback:security:access-context modelName Review +2ms
loopback:security:access-context modelId 562a105037cfea381ac14fbe +1ms
loopback:security:access-context property upsert +1ms
loopback:security:access-context method upsert +3ms
loopback:security:access-context accessType WRITE +1ms
loopback:security:access-context accessToken: +1ms
loopback:security:access-context id "EoEwOGWIWLNfw4DLgxf9ga2zCoFht974DgCccMFkQLmLrmnQJ64eHJidDIf4e8dh" +2ms
loopback:security:access-context ttl 1209600 +2ms
loopback:security:access-context getUserId() 562a105037cfea381ac14fbb +2ms
loopback:security:access-context isAuthenticated() true +1ms
loopback:security:role Custom resolver found for role $everyone +1ms
loopback:security:role isInRole(): $owner +2ms
loopback:security:access-context ---AccessContext--- +1ms
loopback:security:access-context principals: +2ms
loopback:security:access-context principal: {"type":"USER","id":"562a105037cfea381ac14fbb"} +2ms
loopback:security:access-context modelName Review +2ms
loopback:security:access-context modelId 562a105037cfea381ac14fbe +2ms
loopback:security:access-context property upsert +1ms
loopback:security:access-context method upsert +1ms
loopback:security:access-context accessType WRITE +2ms
loopback:security:access-context accessToken: +1ms
loopback:security:access-context id "EoEwOGWIWLNfw4DLgxf9ga2zCoFht974DgCccMFkQLmLrmnQJ64eHJidDIf4e8dh" +2ms
loopback:security:access-context ttl 1209600 +2ms
loopback:security:access-context getUserId() 562a105037cfea381ac14fbb +1ms
loopback:security:access-context isAuthenticated() true +2ms
loopback:security:role Custom resolver found for role $owner +2ms
loopback:security:role isOwner(): Review 562a105037cfea381ac14fbe userId: 562a105037cfea381ac14fbb +2ms
loopback:security:role Model found: {"date":"2015-10-19T10:47:44.791Z","rating":5,"comments":"A very good coffee shop.","id":"562a105037cfea381ac14fbe","coffeeShopId":"562a105037cfea381ac14fb8","publisherId":"562a105037cfea381ac14fbb"} +5ms
loopback:security:role Checking relation reviewer to Reviewer: {"name":"reviewer","type":"belongsTo","modelFrom":"Review","keyFrom":"pulisherId","modelTo":"Reviewer","keyTo":"id","multiple":false} +4ms
loopback:security:acl The following ACLs were searched: +4ms
loopback:security:acl ---ACL--- +1ms
loopback:security:acl model Review +2ms
loopback:security:acl property * +1ms
loopback:security:acl principalType ROLE +1ms
loopback:security:acl principalId $everyone +1ms
loopback:security:acl accessType * +1ms
loopback:security:acl permission DENY +2ms
loopback:security:acl with score: +1ms 7495
loopback:security:acl ---ACL--- +1ms
loopback:security:acl model Review +1ms
loopback:security:acl property * +1ms
loopback:security:acl principalType ROLE +1ms
loopback:security:acl principalId $everyone +2ms
loopback:security:acl accessType READ +1ms
loopback:security:acl permission ALLOW +1ms
loopback:security:acl with score: +1ms -1
loopback:security:acl ---Resolved--- +1ms
loopback:security:access-context ---AccessRequest--- +1ms
loopback:security:access-context model Review +2ms
loopback:security:access-context property upsert +1ms
loopback:security:access-context accessType WRITE +1ms
loopback:security:access-context permission DENY +1ms
loopback:security:access-context isWildcard() false +2ms
loopback:security:access-context isAllowed() false +2ms

@crandmck
Copy link
Contributor

@mike-aungsan I added a note to https://docs.strongloop.com/display/LB/Accessing+related+models#Accessingrelatedmodels-note.
Please let me know if there's any issue with it.

@mike-aungsan
Copy link

@crandmck Many Thanks

@Amir-61 Amir-61 removed the triaging label Dec 23, 2015
@superkhau
Copy link
Contributor

Are you guys still running into issues? Can I close this?

@jdhiro
Copy link

jdhiro commented Feb 4, 2016

The design seems undesirable, but as long as the design is documented (and it looks like it is from @crandmck post), I don't see a problem closing it. I worked around it in my project -- no longer an immediate concern.

@superkhau
Copy link
Contributor

@jdhiro Sounds good. Please open a new issue if you guys are still running into issues. Better yet, submit a patch and we can go from there.

@gekko68
Copy link

gekko68 commented Feb 4, 2016

Yes - i do

sorry for this question but how do I enable the debug view ?

"You can run the application with DEBUG enabled:

$ DEBUG=loopback:security:* node . "

Thanks,

@superkhau
Copy link
Contributor

sorry for this question but how do I enable the debug view ?

What do you mean debug view? Run DEBUG=loopback:security:* node . when starting your loopback app.

@gekko68
Copy link

gekko68 commented Feb 5, 2016

Hi,
got it working. Thx. U just run the application DEBUG=loopback:security:* node . on commandline .

@emazzu
Copy link

emazzu commented Oct 26, 2017

somebody can help me ? with the same themes ?

@emazzu
Copy link

emazzu commented Oct 26, 2017

if somebody can help me, I send the problem !!!

@crandmck
Copy link
Contributor

https://loopback.io/doc/en/contrib/Reporting-issues.html#dont-use-an-issue-to-ask-a-question

@emazzu
Copy link

emazzu commented Oct 26, 2017

Execuse me, but on gitter nobody responds, and I cant resolve the problem, I dont know what I can do !!!

@princecharmx
Copy link

princecharmx commented Nov 3, 2017

@emazzu @crandmck , i think this problem has come again in the latest repo. @raymondfeng , please look into it. This exposes the security loophole for the app in production.
Refer this thread #3518

@princecharmx
Copy link

@emazzu , @crandmck @raymondfeng , this problem is only with custom access token. I reverted to loopback AccessToken model than it started working as intended.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests