@entur-partner/permission-client-node
Advanced tools
Comparing version 3.0.3 to 3.1.0
@@ -312,3 +312,3 @@ declare module '@entur-partner/permission-client-node/ValueObjects' { | ||
declare module '@entur-partner/permission-client-node/version' { | ||
const _default: "3.0.3"; | ||
const _default: "3.1.0"; | ||
export default _default; | ||
@@ -315,0 +315,0 @@ |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
// This file is automatically generated by utils/UpdateVersionFile.cjs | ||
exports.default = '3.0.3'; | ||
exports.default = '3.1.0'; | ||
//# sourceMappingURL=version.js.map |
// This file is automatically generated by utils/UpdateVersionFile.cjs | ||
export default '3.0.3'; | ||
export default '3.1.0'; | ||
//# sourceMappingURL=version.js.map |
{ | ||
"name": "@entur-partner/permission-client-node", | ||
"version": "3.0.3", | ||
"version": "3.1.0", | ||
"author": "Entur AS", | ||
@@ -42,13 +42,13 @@ "contributors": [ | ||
"dependencies": { | ||
"axios": "^1.6.2", | ||
"axios": "^1.6.7", | ||
"jwt-decode": "^4.0.0" | ||
}, | ||
"devDependencies": { | ||
"@types/jest": "^29.5.8", | ||
"@types/jest": "^29.5.12", | ||
"@types/websocket": "^1.0.9", | ||
"@typescript-eslint/eslint-plugin": "^6.10.0", | ||
"@typescript-eslint/parser": "^6.10.0", | ||
"@typescript-eslint/eslint-plugin": "^7.0.1", | ||
"@typescript-eslint/parser": "^7.0.1", | ||
"audit-ci": "^6.6.1", | ||
"echo-cli": "^2.0.0", | ||
"eslint": "^8.53.0", | ||
"eslint": "^8.56.0", | ||
"eslint-config-prettier": "^9.0.0", | ||
@@ -58,7 +58,7 @@ "jest": "^29.7.0", | ||
"npm-dts": "^1.3.12", | ||
"prettier": "^3.0.3", | ||
"ts-jest": "^29.1.1", | ||
"prettier": "^3.2.5", | ||
"ts-jest": "^29.1.2", | ||
"ts-node-dev": "^2.0.0", | ||
"tsc-alias": "1.8.8", | ||
"typescript": "^5.2.2" | ||
"typescript": "^5.3.3" | ||
}, | ||
@@ -65,0 +65,0 @@ "files": [ |
257
README.md
# Permission Client for Node | ||
Permission Client is a Javascript module for Node and is an SDK for [Permission Store](https://bitbucket.org/enturas/permission-store) providing local cache of user permissions. | ||
A similar SDK also exists for Java called [Permission Client for Java](https://bitbucket.org/enturas/permission-client). | ||
Javascript modul som tilbyr en cache av bruker rettigheter fra Permission Store. | ||
Using Permission Client will help you satisfy Enturs Application Security Requirements related to Authorisation. | ||
If you have any questions about how to use Permission Store please use the Slack channel [#work-tilgangstyring](https://entur.slack.com/archives/C05MY64508L). | ||
## Oppsett for bruk | ||
### Basis | ||
Other more general questions related to authentication and/or authorization can be directed to [#talk-sikkerhet](https://entur.slack.com/archives/C02L04S142F). | ||
## Table of Contents | ||
[TOC] | ||
## Requirements | ||
#### Minimum requirements | ||
| Requirement | Functionality | Comment | | ||
|-----------------------|-----------------------------|---------------------------------------------------------------------------------------------------------| | ||
| ES2020 | All | Java 11 support is deprecated and Java 17 will be the minimum requirement from 01.03.2024. | | ||
#### Optional requirements | ||
| Requirement | Functionality | Comment | | ||
|------------------------------|-----------------|--------------------------------------------------------| | ||
| typescript | All | | | ||
| @stomp/stompjs + websocket | In Memory Cache | Used to save network traffic and faster refresh rates. | | ||
## Getting Started | ||
In this getting started guide we will describe how to set up a Node application with authorisation delivered by Permission Client for Node. | ||
Links to other frameworks and services that are mentioned/relevant for this guide: | ||
* [Express](https://expressjs.com/) | ||
* [Entur Partner](https://entur-partner.dev.entur.org/permission-admin) / [Permission Admin](https://bitbucket.org/enturas/permission-admin) | ||
* [Permission Store](https://bitbucket.org/enturas/permission-store) | ||
* [The DevOps Handbook](https://enturas.atlassian.net/wiki/spaces/ESP/pages/912392213/The+DevOps+Handbook) | ||
* [Application Security Requirements](https://enturas.atlassian.net/wiki/spaces/ESP/pages/3293511836/Application+Security+Requirements) | ||
* [Technical Platform Documentation](https://enturas.atlassian.net/wiki/spaces/ESP/pages/3649273997/Technical+Platform+Documentation) | ||
### Setup Express Application | ||
Permission Client for Node is provided as a standalone javascript module, but in this getting started guide we will be using it along with the Express framework. | ||
Verify your Express setup: | ||
* Check you have a running Express application. | ||
* Performs authentication and validated JWT. You can use [express-oauth2-jwt-bearer](https://auth0.com/docs/quickstart/backend/nodejs/interactive) or your favorite package. | ||
* Application has an internal/partner auth0 m2m client it can use. Note that internal clients can easily be provisioned for your project by enabling it in the app factory settings ([GoogleCloudApplication.md](https://bitbucket.org/enturas/tf-gcp-apps/src/master/docs/manifests/GoogleCloudApplication.md)). | ||
* Set up your test framework like [Jest](https://jestjs.io/). | ||
### Add Permission Client package | ||
```sh | ||
npm install @entur-partner/permission-client-node | ||
``` | ||
# alternativt yarn add auth0 @entur-partner/permission-client-node | ||
### Create permissions | ||
In this chapter we will show how to use Permission Client to secure a REST endpoint. | ||
Permissions for the application will be defined in typescript to be used in [Setup Permission Client for Node](#Setup Permission Client for Node) chapter. | ||
Permissions defined by applications must be in line with the guidelines described in Confluence [here](https://enturas.atlassian.net/wiki/spaces/TS/pages/1021935804/Utviklerdokumentasjon+-+Permission+Store#Retningslinjer). | ||
Here is an example file myPermissions.ts: | ||
```typescript | ||
import { ApplicationPermission, BusinessCapability } from '@entur-partner/permission-client-node' | ||
export const APPLICATION_PERMISSIONS : ApplicationPermission[] = []; | ||
// Define Business Capabilities | ||
export const OPERATION1_CREATE : BusinessCapability = {operation: 'operation1', access: 'OPPRETT'}; | ||
APPLICATION_PERMISSIONS.push(OPERATION1_CREATE); | ||
export const OPERATION1_READ : BusinessCapability = {operation: 'operation1', access: 'LES'}; | ||
APPLICATION_PERMISSIONS.push(OPERATION1_READ); | ||
// Define Responsibility Sets | ||
export const OPERATION2_READ : ApplicationPermission = {operation: 'operation2', access: 'LES', responsibilityType: 'name1.attributt1'}; | ||
APPLICATION_PERMISSIONS.push(OPERATION2_READ); | ||
``` | ||
### WebSocket | ||
Planlegger en å motta WebSocket push meldinger trengs følgende pakkener: | ||
```sh | ||
yarn add @stomp/stompjs websocket | ||
``` | ||
I tillegg trengs det å kjøre følgende ved oppstart av tjenesten: | ||
```js | ||
Object.assign(global, { WebSocket: require('websocket').w3cwebsocket }); | ||
``` | ||
## Eksempel på bruk ## | ||
### Setup Permission Client for Node | ||
Setup of Permission Client in your Node application involves initialisation of TokenFactory and AuthorizeCache. Here is an example: | ||
### TokenFactory ### | ||
Benyttes for å hente ut access tokens from Auth0 ved bruk av klient id og klient hemmelighet (Auth0 Clients) | ||
```typescript | ||
import {TokenOptions, TokenFactory} from '@entur-partner/permission-client-node' | ||
import { TokenOptions, TokenFactory } from '@entur-partner/permission-client-node' | ||
import { AuthorizeCacheType, Application, PermissionDeliverRepository } from '@entur-partner/permission-client-node' | ||
import PermissionClient from '@entur-partner/permission-client-node' | ||
import { APPLICATION_PERMISSIONS } from './myPermissions' | ||
// Define values for Auth0 internal client to be used when calling Permission Store | ||
const clientTokenOptions : TokenOptions = { | ||
domain: 'internal.dev.entur.org', | ||
clientId: '<clientId>', | ||
clientSecret: '<secret>', | ||
audience: 'https://api.dev.entur.io', | ||
refreshBeforeMinValidSeconds: 600 // getAccessToken() vil fornye token den retuner, når acess token er gyldig i mindre enn 10 minutter. | ||
domain: 'internal.dev.entur.org', // Changes to match environment. | ||
clientId: '<MNG_AUTH0_INT_CLIENT_ID>', // Client ID from Google Secret Manager. | ||
clientSecret: '<MNG_AUTH0_INT_CLIENT_SECRET>', // Client secret from Google Secret Manager. | ||
audience: 'https://api.dev.entur.io', // Changes to match environment. | ||
refreshBeforeMinValidSeconds: 600 // Refresh token when valid to is less than 10 minutter. | ||
} | ||
const accessTokenFactory = new TokenFactory(clientTokenOptions); | ||
// Eksempel bruk av TokenFactory | ||
const accessToken = await accessTokenFactory.getAccessToken(); | ||
``` | ||
### AuthorizeCache ### | ||
Ønsker en å sjekke hvilke rettigheter en bruker har i Permission Store benyttes PermissionClient. | ||
```typescript | ||
import {AuthorizeCacheType, Application, ApplicationPermission, PermissionDeliverRepository} from '@entur-partner/permission-client-node' | ||
import PermissionClient from '@entur-partner/permission-client-node' | ||
const application : Application = { | ||
name : 'TestApplication', | ||
refreshRate : 300 // Hvert 5 minutt sjekkes Permission Store for endringer | ||
name : 'MyApplication', // Name of this application. | ||
refreshRate : 300 // Refresh rate in seconds for in memory cache. | ||
} | ||
const permissionStoreUrl = new URL('https://api.dev.entur.io/permission-store/v1'); | ||
const repository = new PermissionDeliverRepository(application, accessTokenFactory, permissionStoreUrl); | ||
// Definerer rettigheter som benyttes av tjenesten | ||
const applicationpermissions : ApplicationPermission[] = []; | ||
applicationpermissions.push({operation: 'produkt', access: 'les'}); | ||
applicationpermissions.push({operation: 'produkt', access: 'les', responsibilityType: null}); | ||
applicationpermissions.push({operation: 'produkt', access: 'les', responsibilityType: 'produkt.organisation'}); | ||
applicationpermissions.push({operation: 'produkt', access: 'les', responsibilityType: 'produkt.id'}); | ||
let permissionClient: AuthorizeCache; | ||
const initPermissionClient = async () => { | ||
try { | ||
// TokenFactory will be used to get access tokens from Auth0 | ||
const accessTokenFactory = new TokenFactory(clientTokenOptions); | ||
const permissionStoreUrl = new URL('permission-store URL'); // for local development: https://api.dev.entur.io/permission-store/v1 | ||
const repository = new PermissionDeliverRepository(application, accessTokenFactory, permissionStoreUrl); | ||
permissionClient = await PermissionClient(AuthorizeCacheType.IN_MEMORY, APPLICATION_PERMISSIONS, repository); | ||
// Optional to use WebSocket when running in Google Kubernetes Engine (GKE) | ||
// const permissionClient = await PermissionClient(AuthorizeCacheType.IN_MEMORY, APPLICATION_PERMISSIONS, repository, { communicationType: CommunicationType.SocketJS }); | ||
permissionClient.setScheduleErrorHandler((error) => { | ||
logger.warning('PermissionClient scheduler failed', error); | ||
}); | ||
logger.info('PermissionClient initialized'); | ||
} catch (error) { | ||
logger.error('Failed to initialize PermissionClient', error); | ||
throw Error('Failed to initialize PermissionClient. Please make sure permission store cache configurations are correct and try again.'); | ||
} | ||
}; | ||
// Ved bruk at poll skriv følgende: | ||
const autorizeCache = await PermissionClient(AuthorizeCacheType.IN_MEMORY, applicationpermissions, repository); | ||
export { initPermissionClient, permissionClient }; | ||
``` | ||
// Optional for å benytte WebSocket. NB! Pass på at angitt permissionStoreUrl støtter WebSocket og ikke går via APIGEE | ||
// const autorizeCache = await PermissionClient(AuthorizeCacheType.IN_MEMORY, applicationpermissions, repository, { communicationType: CommunicationType.SocketJS }); | ||
## Permissions | ||
Defining and implementing permissions checks in the application is a central part of using Permission Client. Permission Client supports two types of permissions: | ||
// autorizeCache are ready to be used like: | ||
const hasBCAccess = autorizeCache.checkBusinessCapabilityPermission(authoritySubject, businessCapability); | ||
const hasRSAccess = autorizeCache.checkResponsibilitySetPermission(authoritySubject, responsibilitySet); | ||
const userPermissions = getPermissions(authoritySubject); | ||
* Business Capability | ||
* Responsibility Set | ||
Business Capability Permissions is typically used for securing REST endpoints. And Responsibility Permissions is a good candidate when you want you securely share data between partners. | ||
Permissions can be: | ||
* Restricted to a single or every organisation. | ||
* Restricted with the superuser flag. | ||
### Business Capability | ||
Business capability is a right typically used to control access to endpoints. | ||
Business Capability are defined in code and used when creating PermissionClient. Example: | ||
```typescript | ||
export const OPERATION_CREATE : BusinessCapability = {operation: 'operation', access: 'OPPRETT'}; | ||
``` | ||
## Bidrag til vidreutvikling ## | ||
### Responsibility Set | ||
Responsibility Set is a right designed to control access to data through permissions and agreements. | ||
This permission works similar to Business Capability, but in addition an agreement must be registered that the users organisation is allowed to access | ||
target data element. | ||
Clone modulen fra [Bitbucket](https://bitbucket.org/enturas/permission-client-node/src/master/) med: | ||
Responsibility Sets are defined in code and used when creating PermissionClient. Example: | ||
```typescript | ||
export const OPERATION_READ : ApplicationPermission = {operation: 'operation', access: 'LES', responsibilityType: 'name.attributt'}; | ||
``` | ||
## Agreement | ||
Agreements are used in tandem with responsibility sets to restrict access to data based on which organisation the user/client belongs to. I.e. an agreement is used to describe the relationship between an organisation and some data element. | ||
An application using Responsibility Sets will also normally maintain Agreements in its UI or delegates this to a related UI. | ||
Note: Agreements can only be changed by the same application that created it. | ||
To administrate agreements using Permission Client, applications can use the following methods on PermissionDeliverRepository: | ||
* async getAgreements(responsibilitySet: ResponsibilitySet): Promise<Agreement[]> | ||
* async storeAgreement(agreement: Agreement): Promise<void> | ||
* async deleteAgreement(agreementId: bigint): Promise<void> | ||
* async deleteObject(objectKey: ObjectKey): Promise<void> // Similar to deleteAgreement, difference that it will delete all Agreements related to one object. | ||
An Agreement is defined from: | ||
* operation | ||
* access | ||
* responsibilityType | ||
* responsibilityKey | ||
* organisationId | ||
## Cache types | ||
Permission Client for Node only supports one cache type: IN_MEMORY cache. | ||
### IN_MEMORY | ||
Cache type IN-MEMORY is for production. | ||
**Optional: Push notifications** | ||
When the application is running in one of the internal GKE environments (dev, tst/staging, prd), | ||
you can tell Permission Client to use Permission Store push notifications through websockets, | ||
rather than polling the Store directly at a regular interval. | ||
To do this, add websocket dependencies: | ||
```sh | ||
yarn add @stomp/stompjs websocket | ||
``` | ||
In addition, the following code needs to be run when starting the service: | ||
```typescript | ||
Object.assign(global, { WebSocket: require('websocket').w3cwebsocket }); | ||
``` | ||
And when you create PermissionClient pass the parameter ```typescript{ communicationType: CommunicationType.SocketJS }``` | ||
```typescript | ||
const permissionClient = await PermissionClient(AuthorizeCacheType.IN_MEMORY, APPLICATION_PERMISSIONS, repository, { communicationType: CommunicationType.SocketJS }); | ||
``` | ||
### LOCAL_TEST_CACHE | ||
LOCAL_TEST_CACHE is a cache type for running automatic tests. LOCAL_TEST_CACHE is not implemented for Permission Client for Node. It's expected that mock functionality in Jest will be used in automatic tests. | ||
## Miscellaneous | ||
### Get source | ||
Clone module from [Bitbucket](https://bitbucket.org/enturas/permission-client-node/src/master/) with: | ||
``` | ||
git clone https://<username>@bitbucket.org/enturas/permission-client-node.git | ||
``` | ||
Innstaller avhengigeter fra konsoll på roten av prosjektet: | ||
Install dependencies: | ||
``` | ||
@@ -83,3 +224,3 @@ npm install | ||
Enhetstester utviklet i [Jest](https://jestjs.io/) kjøres ned: | ||
Run [Jest](https://jestjs.io/) tests: | ||
``` | ||
@@ -89,4 +230,6 @@ npm test | ||
### Publisering | ||
Oppgrader versjon | ||
### Publishing | ||
Create a NPM user account on [https://www.npmjs.com/signup](https://www.npmjs.com/signup). Send your user to tech-lead in Entur Partner and ask to be added to [Entur Partner organisation](https://www.npmjs.com/org/entur-partner). | ||
Upgrade version with: | ||
``` | ||
@@ -96,7 +239,5 @@ npm version <major | minor | patch> | ||
Opprett en NPM user account på [https://www.npmjs.com/signup](https://www.npmjs.com/signup). Send brukeren din til tech-lead i Entur Partner og be om å bli lagt til i [Entur Partner organisation](https://www.npmjs.com/org/entur-partner). | ||
Publisering utføres ved å skrive: | ||
Publishing with: | ||
``` | ||
npm publish | ||
``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
153854
240
0
Updatedaxios@^1.6.7