npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@sap/ams

v1.16.0

Published

AMS client library for node.js

Downloads

1,360

Readme

@sap/ams

This is the Node.Js runtime library used to perform authorization checks in applications which authenticate users via the SAP Cloud Identity Services.

The module @sap/ams-dev provides the corresponding tooling support during application development.

As ADC (Authorization Decision Controller) the policy engine OPA (Open Policy Agent) is used.

Installation

Via public npmjs repository:

npm install @sap/ams

Usage examples

Basic allow request on resource salesOrders with action read:

const pdp = new PolicyDecisionPoint();
const attr = new Attributes();
attr.setAction("read")
	.setResource("salesOrders")
	.setPolicies(["sales.readAllSalesOrders"])
let isAllowedRead = await this.pdp.allow(attr);

Basic allowFilterClause request with unknown $env.$user:

const pdp = new PolicyDecisionPoint();
const attr = new Attributes();
attr.setAction("read")
	.setResource("salesOrders")
	.setPolicies(["sales.readAllSalesOrders"])
	.addUnknowns(AttributeName.common.APP, AttributeName.common.ENV);
const filterClause = await this.pdp.allowFilterClause(attr);

API Description

Attributes

The Attributes class (see doc/API/Attributes.md) wraps the input data for the OPA.
Internally a JSON object is created which could look approximately as follows:

{
	"$dcl": {
		"action":                "read",
		"resource":              "SalesOrder",
		"tenant":                "12345",
		"principal2policies":    ["zone_a","user_a"],
	},
	"$app": {
		"country": "DE"
	},
	"$env": {

	},
	"unknowns": [
		"$app.SalesID"
 	],
	 "ignores": [
		 "input[\"$dcl\"][\"resource\"]"
	]
}

An Attributes object can be defined as follows:

const attr = new Attributes()
	.setAction("read")
	.setPolicies(["ams.readAllSalesOrders"])
	.setResource("salesOrder")
	.setApp({"country": "DE"});

Note: Only principal2policies or policies can be set. The other one will be overridden.\

Policy Decision Point

The PolicyDecisionPoint or PDP (see doc/API/PolicyDecisionPoint.md) is responsible for communicating with OPA.

Per default, the URL of the OPA server is set to 127.0.0.1:8181. This URL can be set via the environment variable OPA_URL.
Alternatively, the URL can be passed to the constructor of the Policy Decision Point if a connection to multiple different OPA servers is desired.

AttributeName

AttributeName (see doc/API/AttributeName.md) is a special type to store unknown and ignore values.

Call

The Call class (see doc/API/Call.md) wraps a condition JSON returned from pdp.allowFilterClause().
In addition it wraps an enum Call.type:

{
	AND:         "and",
	OR:          "or",
	EQ:          "eq",
	GT:          "gt",
	...
}

The Call API contains functionalities which should make working with big condition results easier.
First the allowFilterClause condition is transformed into a Call object:

const filterClause = await pdp.allowFilterClause(attributes);
const call = Call.fromCondition(filterClause.condition);

In the most common cases one wants to transform the condition into a sql like statement.
Therefore a transform function has to be defined:

function transformToSQL(item) {
	if (Call.isCall(item)) {
		switch (item.getType()) {
		case Call.types.EQ: {
			const callChildren = [ "(", item.getArgument(0), " = ", item.getArgument(1), ")" ];
			return callChildren;
		}
		case Call.types.OR: {
			...
		}
		case Call.types.LT: {
			...
		}}
		...
	}
	else if (AttributeName.isAttributeName(item)) {
		return item.toString();
	}
}

This transform function will then be recursively applied on the Call object:

const sqlString = Call.transform(call, transformToSQL);

RolesProvider

An instance of the RolesProvider class can be used to evaluate the roles (or scopes) of a user based on policies of the following form:

GRANT <role> ON $SCOPES;

To get an Array<String> of a user's roles, call getRoles on a previously constructed instance of RolesProvider:

const pdp = new PolicyDecisionPoint();
const rp = new RolesProvider(pdp);
const principle = new Principle(app_tid, scim_id); // app_tid, scim_id taken from SAP Identity Service token

const roles = await rp.getRoles(principle);

Only one RolesProvider instance needs to be constructed and can be used to subsequently get the roles of different users.

RolesCache

A RolesProvider can use an optional RolesCache to improve the performance of subsequent role evaluations for the same user. It has the following configuration parameters:

  • TTL [ms] (time-to-live): the lifetime of cache entries. Specifies how long the cached roles of a given user are used without evaluating them again via the ADC. If set too high, administrative changes of a user's policy assignments or changes in policies might affect the application's behavior with a high delay which reduces overall security.
    Default: 1 minute
  • limit: maximum number of simultaneous cache entries. The cache follows a FIFO strategy: if necessary, the oldest cache entry is removed to make space for a new entry.
    Default: 10000

A RolesCache can be constructed and used by a RolesProvider as follows:

const rc = new RolesCache(10 * 60 * 1000, 1E6); // 10 min TTL and 100k users max
const rp = new RolesProvider(pdp).withRolesCache(rc);

RolesCache Sizing Guide

The memory consumed by the RolesCache can be estimated with the following formula:

Memory [Byte] = U*R*(2*S) + 84*U

U: #Users
R: #Roles per user
S: String length of role name

It is only an estimate and should be correct up to a factor of 2. Please use it only to get an understanding for the order of magnitude of the memory consumption. Use avg, min or max values of the input parameters to get a memory estimation for the scenario that is most important to you.

The following table gives a quick reference of expected memory consumption: | U (Users) | R (Roles) | S (String length) | Memory | |----------:|----------:|------------------:|-------:| | 1k | 10 | 20 | 1MB | | 1k | 50 | 30 | 3MB | | 10k | 10 | 20 | 5MB | | 100k | 15 | 20 | 70MB | | 100k | 50 | 10 | 100MB | | 100k | 50 | 30 | 300MB | | 1m | 25 | 20 | 1GB |

To compute a suitable user limit for your cache given a fixed amount of memory M, you can estimate it with the following formula:

$$U = \frac{M}{2 * R * S + 84}$$

Express Middleware

The authorization checks can be performed by the provided express middleware (see doc/API/Middleware.md).

For example, to restrict the /read endpoint to users with read authority:

const { middleware } = require('@sap/ams');

app.get("/read", [requireAuthentication, middleware.hasAuthority("read")], (req, res) => {
  res.send("User is allowed to read");
})

Note that the req object has to be extended with a tokenInfo object from @sap/xssec before calling hasAuthority.
This can be achieved by registering the middleware after the passport middleware of @sap/xssec.

If a middleware returns false or fails an error will be thrown otherwise the next handler is called.

CAP integration

This module provides a runtime plugin for CAP (Cloud Application Programming Model) applications which is documented in docs/CapIntegration.md.

Logging

The Node AMS library does no logging.
But theres's a guide on how to log Policy Decision Point results (see doc/Logging/LogPdp.md) and/or perform auditlogging (see doc/Logging/AuditLog.md).

Resources

Reporting Incidents

As registered SAP customers, report your issue in creating an incident for component BC-CP-CF-SEC-LIB on the SAP Support Portal

See also Getting Support in the SAP BTP documentation.

Open Source Legal Notices

SAP Cloud Identity 1.0