Search code examples
aclloopbackjsstronglooploopback

Loopback ACL "Authorization Required"


I'm using Loopback3. I'm running into an issue with my ACL roles and I'm not sure what I did wrong. I want users in specific roles to be able to write data to the endpoint, and for some reason the user I have set up (which is in one of those roles) cannot write. I get an Authorization Required error.

I have 4 roles:

  • admin
  • internal
  • external
  • bot

For this endpoint, all authenticated users can read the data, but only admin, internal, and bot users can write data, and only admin users can delete data.

Here's how I've got my ACLs defined:

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

I have two users set up, one is a bot and one is an admin. When I do a POST request to the API for either user I get the 'Authorization Required' error, even when doing it from the explorer interface. I can do a GET with no problem, but a POST gets a failure.

If I remove all the "WRITE" acl's and replace them with this, doing a POST works.

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

So, I can make it happen, but I don't know why my custom roles are failing.

Edit: Here is how I created the users, since I don't actually have any kind of interface built yet.

module.exports = function (app) {
    let today = new Date();

    let admin = {
        name: 'admin',
        description: 'admin users',
        created: today.toJSON(),
        modified: today.toJSON()
    };

    let internal = {
        name: 'internal',
        description: 'Internal users',
        created: today.toJSON(),
        modified: today.toJSON()
    };

    let external = {
        name: 'external',
        description: 'external users',
        created: today.toJSON(),
        modified: today.toJSON()
    };

    let bot = {
        name: 'bot',
        description: 'robots',
        created: today.toJSON(),
        modified: today.toJSON()
    };

    let model = app.models.user;

    model.create([
        {username: 'bot', email: '[email protected]', password: 'test123'},
        {username: 'admin', email: '[email protected]', password: 'test123'},
        {username: 'iAdmin', email: '[email protected]', password: 'test123'},
        {username: 'eUser', email: '[email protected]', password: 'test123'},
    ], function(err, users) {
        if (err) throw err;

        app.models.Role.create(bot, function (err, botRole) {
            if (err) throw err;

            botRole.principals.create({principalType: app.models.RoleMapping.user, principalID: users[0].id}, function(err, principal) {
                if (err) throw err;
            });
        });

        app.models.Role.create(admin, function (err, adminRole) {
            if (err) throw err;

            adminRole.principals.create({principalType: app.models.RoleMapping.user, PrincipalID: users[1].id}, function(err, principal) {
                if (err) throw err;
            });
        });

        app.models.Role.create(admin, function (err, internalRole) {
            if (err) throw err;

            internalRole.principals.create({principalType: app.models.RoleMapping.user, PrincipalID: users[2].id}, function(err, principal) {
                if (err) throw err;
            });
        });

        app.models.Role.create(external, function (err, externalRole) {
            if (err) throw err;

            externalRole.principals.create({principalType: app.models.RoleMapping.user, PrincipalID: users[3].id}, function(err, principal) {
                if (err) throw err;
            });
        });
    });
};

Solution

  • The primary issues I was experiencing revolved around the following items:

    1. Use app.models.RoleMapping.USER instead of app.models.RoleMapping.user (which was changed in the codebase early on)

    2. Use principalId instead of principalID

    Since the rest of the ACLs had been removed from the application some time ago due to them not working, I can't state whether or not they were also contributing to the problems, but I will be adding them in over time making sure to use the correct permissions for LB3.