@loopback/authorization
Version:
A LoopBack component for authorization support.
196 lines (181 loc) • 4.71 kB
text/typescript
// Copyright IBM Corp. and LoopBack contributors 2018,2020. All Rights Reserved.
// Node module: @loopback/authorization
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
import {BindingAddress, InvocationContext} from '@loopback/core';
import {Principal, Role} from '@loopback/security';
/**
* Built-in roles
*/
export const EVERYONE = '$everyone';
export const AUTHENTICATED = '$authenticated';
export const UNAUTHENTICATED = '$unauthenticated';
export const ANONYMOUS = '$anonymous';
/**
* Decisions for authorization
*/
export enum AuthorizationDecision {
/**
* Access allowed
*/
ALLOW = 'Allow',
/**
* Access denied
*/
DENY = 'Deny',
/**
* No decision
*/
ABSTAIN = 'Abstain',
}
/**
* Authorization metadata supplied via `@authorize` decorator
*/
export interface AuthorizationMetadata {
/**
* Roles that are allowed access
*/
allowedRoles?: string[];
/**
* Roles that are denied access
*/
deniedRoles?: string[];
/**
* Voters that help make the authorization decision
*/
voters?: (Authorizer | BindingAddress<Authorizer>)[];
/**
* Name of the resource, default to the method name
*/
resource?: string;
/**
* Define the access scopes
*/
scopes?: string[];
/**
* A flag to skip authorization
*/
skip?: boolean;
}
/**
* Request context for authorization
*/
export interface AuthorizationContext {
/**
* An array of principals identified for the request - it should come from
* authentication
*/
principals: Principal[];
/**
* An array of roles for principals
*/
roles: Role[];
/**
* An array of scopes representing granted permissions - usually come from
* access tokens
*/
scopes: string[];
/**
* An name for the target resource to be accessed, such as
* `OrderController.prototype.cancelOrder`
*/
resource: string;
/**
* Context for the invocation
*/
invocationContext: InvocationContext;
}
/**
* A function to decide if access to the target should be allowed or denied
*/
export type Authorizer<
T extends AuthorizationMetadata = AuthorizationMetadata,
> =
/**
* @param context: Context information for authorization
* @param metadata: Metadata representing requirements for authorization
*/
(
context: AuthorizationContext,
metadata: T,
) => Promise<AuthorizationDecision>;
/**
* Inspired by https://github.com/casbin/node-casbin
*/
export interface AuthorizationRequest {
/**
* The domain (realm/tenant)
*/
domain?: string;
/**
* The requestor that wants to access a resource.
*/
subject: string;
/**
* The resource that is going to be accessed.
*/
object: string;
/**
* The operation that the requestor performs on the resource.
*/
action: string;
}
/**
* An enforcer of authorization policies
*/
export interface Enforcer {
/**
* Extract the request from authorization context
* @param authorizationContext
*/
buildRequest(
authorizationContext: AuthorizationContext,
): Promise<AuthorizationRequest>;
/**
* Decide if the request can be granted access
* @param request
*/
enforce(request: AuthorizationRequest): Promise<AuthorizationDecision>;
}
/**
* The custom error class that describes the error thrown by
* the authorization module.
* Should be extracted to the common layer shared by authentication
* and authorization.
*/
export class AuthorizationError extends Error {
/**
* Machine readable code, can be understood by any clients
*/
code?: string;
/**
* The status code for HTTP requests
*/
statusCode?: number;
}
export interface AuthorizationOptions {
/**
* Default decision if all authorizers vote for ABSTAIN
* If not set, default to `AuthorizationDecision.DENY`
*/
defaultDecision?: AuthorizationDecision.DENY | AuthorizationDecision.ALLOW;
/**
* Controls if Allow/Deny vote takes precedence and override other votes.
* If not set, default to `AuthorizationDecision.DENY`.
*
* Once a vote matches the `precedence`, it becomes the final decision. The
* rest of votes will be skipped.
*/
precedence?: AuthorizationDecision.DENY | AuthorizationDecision.ALLOW;
/**
* Default authorization metadata if a method is not decorated with `@authorize`.
* If not set, no authorization will be enforced for those methods that are
* not associated with authorization metadata.
*/
defaultMetadata?: AuthorizationMetadata;
/**
* Default HTTP status code when the final decision is `AuthorizationDecision.DENY`.
* If not set, default to 403
*/
defaultStatusCodeForDeny?: number;
}