Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 0 additions & 104 deletions .tours/ams-cap-nodejs-bookshop.tour

This file was deleted.

24 changes: 11 additions & 13 deletions ams-cap-nodejs-bookshop/.cdsrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,31 +4,29 @@
"[development]": {
"kind": "mocked",
"users": {
"bob": {
"content-manager": {
"policies": [
"cap.admin",
"cap.Reader"
"cap.ContentManager"
]
},
"carol": {
"stock-manager": {
"policies": [
"local.Zealot"
"cap.StockManager"
]
},
"dave": {
"reader": {
"policies": [
"local.JuniorReader"
"cap.Reader"
]
},
"erin": {
"stock-manager-fiction": {
"policies": [
"local.BestsellerReader"
"local.StockManagerFiction"
]
},
"fred": {
"juniorReader": {
"policies": [
"local.Zealot",
"local.BestsellerReader"
"local.JuniorReader"
]
},
"technicalUser": {
Expand All @@ -49,7 +47,7 @@
},
"amsValueHelp": {
"policies": [
"cap.admin"
"cap.ContentManager"
],
"ias_apis": [
"AMS_ValueHelp"
Expand Down
38 changes: 26 additions & 12 deletions ams-cap-nodejs-bookshop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,9 @@ Refer to the [@sap/ams CAP integration guide](https://www.npmjs.com/package/@sap
- Authentication via SCI (`auth.kind = "ias"`)
- Authorization via AMS
- [Role](https://cap.cloud.sap/docs/guides/security/authorization#roles) Assignments
- Instance-based authorization with genre-based attribute filters
- Advanced filter conditions that exceed the capabilities of the standard [instance-based cds conditions](https://cap.cloud.sap/docs/guides/security/authorization#instance-based-auth)
- Principal propagation with API policies that further restrict access
- [Hybrid testing](https://cap.cloud.sap/docs/advanced/hybrid-testing) via `cds bind`
- Auto-Configuration for deployment via [cds add](https://cap.cloud.sap/docs/tools/cds-cli#cds-add)

Expand All @@ -43,24 +45,36 @@ DEBUG=ams cds watch # requires @sap/cds-dk installed globally

## Testing Locally
### Integration tests
You can look at the integration tests for the [`CatalogService`](./test/cat-service.test.js) and the [`AdminService`](./test/admin-service.test.js). They demonstrate the expected behavior of the application for mocked users with different combinations of authorization policies.
You can look at the integration tests for the [`CatalogService`](./test/cat-service.test.js), [`AdminService`](./test/admin-service.test.js), and [`AmsValueHelpService`](./test/vh-service.test.js). They demonstrate the expected behavior of the application for mocked users with different combinations of authorization policies.

Advanced AMS capabilities includes in the tests:
- **Filtered access**: The `juniorReader` can only access books in specific genres (Fairy Tale, Fantasy, Mystery)
- **Principal propagation**: The `principalPropagation` user demonstrates how API policies can further restrict access for user requests from external applications - combining JuniorReader policy (allows Fairy Tale, Fantasy, Mystery) of user with ReadCatalog API policy (excludes Mystery, Romance, Thriller, Dystopia) results in access to only Fantasy books

### Manual tests
To test the effect of changes, you can make manual requests against the server by authenticating via *Basic Auth* as one of the mocked users (and an empty password). In the [cds env configuration](./.cdsrc.json#L4), you can see and change the list of policies that is assigned to the mocked users.
To test the effect of changes, you can make manual requests against the server by authenticating via *Basic Auth* as one of the mocked users (and an empty password). In the [cds env configuration](./.cdsrc.json), you can see and change the list of policies that is assigned to the mocked users.

If the application was started in watch mode, get creative by making changes and observe the effects. Here's some ideas:

#### Create your own admin policy
- create a new admin policy in [adminPolicies.dcl](./ams/dcl/local/adminPolicies.dcl) with a different filter condition
- assign the policy to a user via the [cds env configuration](./.cdsrc.json#L4)
- validate it works as intended
- make a request to an entity that is filtered base on the attributes of the policy
- extend the unit tests

#### Extend the AMS annotations
- add more attribute filters via `ams.attributes` annotations
- extend the role policies in [basePolicies.dcl](./ams/dcl/cap/basePolicies.dcl) if the new AMS attribute is applicable for the existing roles
- [create an admin policy](#create-your-own-admin-policy) that filters a role based on this attribute
- Create a new policy in [adminPolicies.dcl](./ams/dcl/local/adminPolicies.dcl) with a different genre filter condition
- Assign the policy to a user via the [cds env configuration](./.cdsrc.json)
- Validate it works as intended
- Make a request to `/odata/v4/catalog/Books` as that user
- Verify only books matching the genre filter are returned
- Extend the unit tests to cover the new scenario

#### Extend the AMS attributes
- Add more attribute filters via `@ams.attributes` annotations in [authorization.cds](./srv/authorization.cds)
- Example: Add author-based filtering by mapping `Author: author.name`
- Extend the role policies in [basePolicies.dcl](./ams/dcl/cap/basePolicies.dcl) to additionally filter by the new attribute where it makes sense
- [Create a new admin policy](#create-your-own-policy) that filters a role based on this attribute
- Extend the [vh-service.js](./srv/vh-service.js) to return possible values for the new attribute

#### Test principal propagation
- Observe how the `principalPropagation` user's access is restricted by both the JuniorReader policy AND the ReadCatalog API policy
- Try creating different combinations of user policies and API policies to see how they interact
- The intersection of filters determines the final access rights

## Hybrid Testing
For [CAP Hybrid Testing](https://cap.cloud.sap/docs/advanced/hybrid-testing), you can `cds bind -2 <yourIdentityServiceInstance>` and start the application via
Expand Down
21 changes: 11 additions & 10 deletions ams-cap-nodejs-bookshop/ams/dcl/cap/basePolicies.dcl
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
POLICY "Reader" {
ASSIGN ROLE "Reader" WHERE
genre IS NOT RESTRICTED AND
description IS NOT RESTRICTED AND
stock IS NOT RESTRICTED;
POLICY StockManager {
ASSIGN ROLE ManageBooks WHERE Genre IS NOT RESTRICTED;
}

POLICY Inquisitor {
ASSIGN ROLE "Inquisitor" WHERE
description IS NOT RESTRICTED;
POLICY ContentManager {
ASSIGN ROLE ManageAuthors;
ASSIGN ROLE ManageBooks;
ASSIGN ROLE ValueHelpUser;
}

POLICY "admin" {
ASSIGN ROLE "admin";
POLICY Reader {
ASSIGN ROLE ReadBooks WHERE Genre IS NOT RESTRICTED;
}

POLICY "ValueHelpUser" {
ASSIGN ROLE "ValueHelpUser";
}
12 changes: 4 additions & 8 deletions ams-cap-nodejs-bookshop/ams/dcl/internal/apiPolicies.dcl
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
INTERNAL Policy AMS_ValueHelp {
USE cap.admin;
INTERNAL POLICY AMS_ValueHelp {
ASSIGN ROLE ValueHelpUser;
}

INTERNAL Policy ReadCatalog {
USE cap.Reader RESTRICT
genre IS NOT RESTRICTED,
description IS NOT RESTRICTED,
stock < 30;
INTERNAL POLICY ReadCatalog {
USE cap.Reader RESTRICT Genre NOT IN ('Mystery', 'Romance', 'Thriller', 'Dystopia');
}
19 changes: 4 additions & 15 deletions ams-cap-nodejs-bookshop/ams/dcl/local/adminPolicies.dcl
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
POLICY JuniorReader {
USE cap.Reader RESTRICT
genre IN ('Fantasy', 'Fairy Tale', 'Mystery'),
description IS NOT RESTRICTED,
stock IS NOT RESTRICTED;
}

POLICY BestsellerReader {
USE cap.Reader RESTRICT
genre IS NOT RESTRICTED,
description IS NOT RESTRICTED,
stock < 20;
POLICY StockManagerFiction {
USE cap.StockManager RESTRICT Genre IN ('Mystery', 'Fantasy');
}

POLICY Zealot {
USE cap.Inquisitor RESTRICT
description LIKE '%religious%references%';
POLICY JuniorReader {
USE cap.Reader RESTRICT Genre IN ('Fairy Tale', 'Fantasy', 'Mystery');
}
9 changes: 1 addition & 8 deletions ams-cap-nodejs-bookshop/ams/dcl/schema.dcl
Original file line number Diff line number Diff line change
@@ -1,15 +1,8 @@
// ---------------------------------HEADER_START-----------------------------------------------
// Generated from a CAP model by the SAP AMS Plugin (@sap/ams) 3.3.0
// hash of generated content: 760f88aa8521b7b516c368a517af58f0a55f37dfd0be60eb07c5d94cc2ea3efe
// ----------------------------------HEADER_END------------------------------------------------

SCHEMA {
@valueHelp: {
path: 'Genres',
valueField: 'name',
labelField: 'name'
}
genre: String,
description: String,
stock: Number
Genre: String
}
6 changes: 6 additions & 0 deletions ams-cap-nodejs-bookshop/db/aspects.cds
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using { sap.capire.bookshop.Genres } from './schema';

aspect media {
genre: Association to Genres;
stock: Integer;
}
5 changes: 3 additions & 2 deletions ams-cap-nodejs-bookshop/db/schema.cds
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
using { Currency, managed, sap } from '@sap/cds/common';
using { stocked, media } from '../srv/aspects';
using { media } from './aspects';
namespace sap.capire.bookshop;


entity Books : managed, media, stocked {
entity Books : managed, media {
key ID : Integer;
@mandatory title : localized String(111);
@mandatory author : Association to Authors;
descr: localized String(1111);
price : Decimal;
currency : Currency;
image : LargeBinary @Core.MediaType : 'image/png';
Expand Down
2 changes: 1 addition & 1 deletion ams-cap-nodejs-bookshop/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ams-cap-nodejs-bookshop",
"version": "2.2.0",
"version": "3.0.0",
"description": "A simple CAP project demonstrating the integration of AMS into CAP.",
"license": "UNLICENSED",
"private": true,
Expand Down
15 changes: 12 additions & 3 deletions ams-cap-nodejs-bookshop/srv/admin-service.cds
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
using { sap.capire.bookshop as my } from '../db/schema';
service AdminService @(requires:'admin', path: '/admin') {
using {sap.capire.bookshop as my} from '../db/schema';

service AdminService @(path: '/admin', requires: ['ManageAuthors', 'ManageBooks']) {

@(restrict: [
{ grant: ['READ'], to: 'ManageAuthors' },
{ grant: ['READ', 'WRITE'], to: 'ManageBooks' } ])
entity Books as projection on my.Books;

@(restrict: [
{ grant: ['READ', 'WRITE'], to: 'ManageAuthors' },
{ grant: ['READ'], to: 'ManageBooks' } ])
entity Authors as projection on my.Authors;
}
}
Loading