Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@loopback/authorization

Package Overview
Dependencies
Maintainers
7
Versions
82
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@loopback/authorization - npm Package Compare versions

Comparing version 0.4.5 to 0.4.6

8

CHANGELOG.md

@@ -6,2 +6,10 @@ # Change Log

## [0.4.6](https://github.com/strongloop/loopback-next/compare/@loopback/authorization@0.4.5...@loopback/authorization@0.4.6) (2019-12-09)
**Note:** Version bump only for package @loopback/authorization
## [0.4.5](https://github.com/strongloop/loopback-next/compare/@loopback/authorization@0.4.4...@loopback/authorization@0.4.5) (2019-11-25)

@@ -8,0 +16,0 @@

14

dist/authorize-interceptor.js

@@ -18,6 +18,9 @@ "use strict";

};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const context_1 = require("@loopback/context");
const security_1 = require("@loopback/security");
const debugFactory = require("debug");
const debug_1 = __importDefault(require("debug"));
const authorize_1 = require("./decorators/authorize");

@@ -27,3 +30,3 @@ const keys_1 = require("./keys");

const util_1 = require("./util");
const debug = debugFactory('loopback:authorization:interceptor');
const debug = debug_1.default('loopback:authorization:interceptor');
let AuthorizationInterceptor = class AuthorizationInterceptor {

@@ -39,2 +42,3 @@ constructor(authorizers, options = {}) {

async intercept(invocationCtx, next) {
var _a, _b;
const description = debug.enabled ? invocationCtx.description : '';

@@ -45,4 +49,4 @@ let metadata = authorize_1.getAuthorizationMetadata(invocationCtx.target, invocationCtx.methodName);

}
metadata = metadata || this.options.defaultMetadata;
if (!metadata || (metadata && metadata.skip)) {
metadata = (metadata !== null && metadata !== void 0 ? metadata : this.options.defaultMetadata);
if (!metadata || ((_a = metadata) === null || _a === void 0 ? void 0 : _a.skip)) {
debug('Authorization is skipped for %s', description);

@@ -66,3 +70,3 @@ const result = await next();

debug('Security context for %s', description, authorizationCtx);
let authorizers = await loadAuthorizers(invocationCtx, metadata.voters || []);
let authorizers = await loadAuthorizers(invocationCtx, (_b = metadata.voters, (_b !== null && _b !== void 0 ? _b : [])));
let finalDecision = this.options.defaultDecision;

@@ -69,0 +73,0 @@ authorizers = authorizers.concat(this.authorizers);

@@ -42,3 +42,3 @@ "use strict";

const list = [];
const set = new Set(src || []);
const set = new Set((src !== null && src !== void 0 ? src : []));
if (target) {

@@ -45,0 +45,0 @@ for (const i of target) {

@@ -19,5 +19,6 @@ "use strict";

function createPrincipalFromUserProfile(user) {
return Object.assign(Object.assign({}, user), { name: user.name || user[security_1.securityId], type: 'USER' });
var _a;
return Object.assign(Object.assign({}, user), { name: (_a = user.name, (_a !== null && _a !== void 0 ? _a : user[security_1.securityId])), type: 'USER' });
}
exports.createPrincipalFromUserProfile = createPrincipalFromUserProfile;
//# sourceMappingURL=util.js.map
{
"name": "@loopback/authorization",
"version": "0.4.5",
"version": "0.4.6",
"description": "A LoopBack component for authorization support.",

@@ -25,12 +25,12 @@ "engines": {

"dependencies": {
"@loopback/context": "^1.24.0",
"@loopback/core": "^1.11.0",
"@loopback/security": "^0.1.8",
"@loopback/context": "^1.25.0",
"@loopback/core": "^1.12.0",
"@loopback/security": "^0.1.9",
"debug": "^4.1.1"
},
"devDependencies": {
"@loopback/build": "^2.1.0",
"@loopback/testlab": "^1.9.5",
"@loopback/build": "^3.0.0",
"@loopback/testlab": "^1.10.0",
"@types/debug": "^4.1.4",
"@types/node": "10.17.5",
"@types/node": "10.17.6",
"casbin": "^3.0.7"

@@ -55,3 +55,3 @@ },

},
"gitHead": "c111543a6139c5a2999930c593aabbbdf10a838e"
"gitHead": "89eb61bacaed75e6eb61ae6840cea266cb888659"
}
# @loopback/authorization
A LoopBack 4 component for authorization support.
A LoopBack 4 component for authorization support (Role based, Permission based,
Vote based)
## Overview
To read on key building blocks read through
[loopback authorization docs](https://loopback.io/doc/en/lb4/Loopback-component-authorization.html)
Authorization decides if a **subject** can perform specific **action** on an
**object**.
![Authorization](authorization.png)
### Role based
### Permission based
### Vote based
### Key building blocks
1. Decorate a method to describe:
- Permission (maps the method to an action on the protected resource)
- Type of the protected resource (such as `customer` or `order`)
- What action does the method represent (such as `changeEmail`, `createOrder`,
or `cancelOrder`)
- ACL (provides role based rules)
- allowedRoles
- deniedRoles
- Voters (supplies a list of function to vote on the decision)
2. Intercept a method invocation
- Build authorization context
- Subject (who) - from authentication
- Map principals to roles
- Inspect the target method for metadata - Permission, ACL, voters
- Run through voters/enforcers to make decisions
## Decision matrix
The final decision is controlled by voting results from authorizers and options
for the authorization component.
The following table illustrates the decision matrix with 3 voters and
corresponding options.
| Vote #1 | Vote # 2 | Vote #3 | Options | Final Decision |
| ------- | -------- | ------- | ------------------------ | -------------- |
| Deny | Deny | Deny | **any** | Deny |
| Allow | Allow | Allow | **any** | Allow |
| Abstain | Allow | Abstain | **any** | Allow |
| Abstain | Deny | Abstain | **any** | Deny |
| Deny | Allow | Abstain | {precedence: Deny} | Deny |
| Deny | Allow | Abstain | {precedence: Allow} | Allow |
| Allow | Abstain | Deny | {precedence: Deny} | Deny |
| Allow | Abstain | Deny | {precedence: Allow} | Allow |
| Abstain | Abstain | Abstain | {defaultDecision: Deny} | Deny |
| Abstain | Abstain | Abstain | {defaultDecision: Allow} | Allow |
The `options` is described as follows:
```ts
export interface AuthorizationOptions {
/**
* Default decision if all authorizers vote for ABSTAIN
*/
defaultDecision?: AuthorizationDecision.DENY | AuthorizationDecision.ALLOW;
/**
* Controls if Allow/Deny vote takes precedence and override other votes
*/
precedence?: AuthorizationDecision.DENY | AuthorizationDecision.ALLOW;
}
```
The authorization component can be configured with options:

@@ -121,50 +51,9 @@

Please note that `@authorize` can also be applied at class level for all methods
within the class. In the code below, `numOfViews` is protected with
`BasicStrategy` (inherited from the class level) while `hello` does not require
authorization (skipped by `@authorize.skip`).
## Extract common layer
```ts
@authorize({allow: ['ADMIN']})
export class MyController {
@get('/number-of-views')
numOfViews(): number {
return 100;
}
`@loopback/authentication` and `@loopback/authorization` share the client
information from the request. Therefore we have created another module,
`@loopback/security` with types/interfaces that describe the client, like
`principles`, `userProfile`, etc.
@authorize.skip()
@get('/hello')
hello(): string {
return 'Hello';
}
}
```
## Extract common layer(TBD)
`@loopback/authentication` and `@loopback/authorization` shares the client
information from the request. Therefore we need another module with
types/interfaces that describe the client, like `principles`, `userProfile`,
etc... A draft PR is created for this module: see branch
https://github.com/strongloop/loopback-next/tree/security/packages/security
Since the common module is still in progress, as the first release of
`@loopback/authorization`, we have two choices to inject a user in the
interceptor:
- `@loopback/authorization` requires `@loopback/authentication` as a dependency.
The interceptor injects the current user using
`AuthenticationBindings.CURRENT_USER`. Then we remove this dependency in the
common layer PR, two auth modules will depend on `@loopback/security`.
- This is what's been done in my refactor PR, `Principle` and `UserProfile`
are still decoupled, I added a convertor function to turn a user profile
into a principle.
- The interceptor injects the user using another key not related to
`@loopback/authentication`.(_Which means the code that injects the user stays
as it is in https://github.com/strongloop/loopback-next/pull/1205_). Then we
unify the user set and injection in the common layer PR: same as the 1st
choice, two auth modules will depend on `@loopback/security`.
## Related resources

@@ -171,0 +60,0 @@

@@ -21,3 +21,3 @@ // Copyright IBM Corp. 2019. All Rights Reserved.

import {SecurityBindings, UserProfile} from '@loopback/security';
import * as debugFactory from 'debug';
import debugFactory from 'debug';
import {getAuthorizationMetadata} from './decorators/authorize';

@@ -67,4 +67,4 @@ import {AuthorizationBindings, AuthorizationTags} from './keys';

}
metadata = metadata || this.options.defaultMetadata;
if (!metadata || (metadata && metadata.skip)) {
metadata = metadata ?? this.options.defaultMetadata;
if (!metadata || metadata?.skip) {
debug('Authorization is skipped for %s', description);

@@ -94,3 +94,3 @@ const result = await next();

invocationCtx,
metadata.voters || [],
metadata.voters ?? [],
);

@@ -97,0 +97,0 @@

@@ -81,3 +81,3 @@ // Copyright IBM Corp. 2019. All Rights Reserved.

const list: T[] = [];
const set = new Set<T>(src || []);
const set = new Set<T>(src ?? []);
if (target) {

@@ -84,0 +84,0 @@ for (const i of target) {

@@ -21,5 +21,5 @@ import {Principal, securityId, UserProfile} from '@loopback/security';

...user,
name: user.name || user[securityId],
name: user.name ?? user[securityId],
type: 'USER',
};
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc