Skip to content

Commit 1f576a3

Browse files
committed
Add back dynamically-generated-privileged
1 parent 8a7c6d5 commit 1f576a3

File tree

10 files changed

+230
-0
lines changed

10 files changed

+230
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
namespace advanced_security.dynamically_generated_privileged.sample_entities;
2+
3+
entity Entity1 {
4+
Attribute1 : String(100);
5+
Attribute2 : String(100)
6+
}
7+
8+
entity Entity2 {
9+
Attribute3 : String(100);
10+
Attribute4 : String(100)
11+
}

javascript/frameworks/cap/test/queries/bad-authn-authz/misused-privileged-user/dynamically-generated-privileged/dynamically-generated-privileged.expected

Whitespace-only changes.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bad-authn-authz/DefaultUserIsPrivileged/DynamicallyGeneratedPrivileged.ql
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"name": "@advanced-security/dynamically-generated-privileged",
3+
"version": "1.0.0",
4+
"dependencies": {
5+
"@sap/cds": "*",
6+
"express": "^4.17.1",
7+
"@cap-js/sqlite": "*"
8+
},
9+
"scripts": {
10+
"start": "cds serve",
11+
"watch": "cds watch"
12+
},
13+
"cds": {
14+
"requires": {
15+
"service-3": {
16+
"kind": "odata",
17+
"model": "@example/sample"
18+
},
19+
"auth": {
20+
"impl": "./srv/privileged-user.js"
21+
}
22+
}
23+
}
24+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const cds = require("@sap/cds");
2+
const app = require("express")();
3+
4+
cds.serve("all").in(app);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* 1. Creating a custom middleware that fulfills `req.user` */
2+
3+
const cds = require("@sap/cds");
4+
class CustomPrivilegedUser1 extends cds.User {
5+
is() {
6+
return true;
7+
}
8+
}
9+
module.exports = (req, res, next) => {
10+
req.user = new CustomPrivilegedUser1("privileged");
11+
next();
12+
};
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using { advanced_security.dynamically_generated_privileged.sample_entities as db_schema } from '../db/schema';
2+
3+
service Service1 @(path: '/service-1') {
4+
/* Unrestricted read access to anyone. */
5+
@(restrict: [ { grant: 'READ' } ])
6+
entity Service1Entity1 as projection on db_schema.Entity1 excluding { Attribute2 }
7+
8+
/* Read access only to users with access level greater than 2. */
9+
@(restrict: [ { grant: 'READ', to: '$user.level > 2' } ])
10+
entity Service1Entity2 as projection on db_schema.Entity1 excluding { Attribute1 }
11+
12+
/* API to talk to Service1. */
13+
action send1 (
14+
messageToPass : String
15+
) returns String;
16+
17+
/* API to talk to Service1. */
18+
action send2 (
19+
messageToPass : String
20+
) returns String;
21+
22+
/* API to talk to Service1. */
23+
action send3 (
24+
messageToPass : String
25+
) returns String;
26+
27+
/* API to talk to Service1. */
28+
action send4 (
29+
messageToPass : String
30+
) returns String;
31+
32+
/* API to talk to Service1. */
33+
action send5 (
34+
messageToPass : String
35+
) returns String;
36+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
const cds = require("@sap/cds");
2+
3+
class Service1 extends cds.ApplicationService {
4+
init() {
5+
// const Service2 = await cds.connect.to("service-2");
6+
// const { Service2Entity1, Service2Entity2 } = Service2.entities;
7+
8+
this.on("READ", "Service1Entity1", async (req) => {
9+
console.log(req.data.messageToPass);
10+
});
11+
12+
/*
13+
* FP: Service1 accessing its own entity that does not
14+
* require authorization, with a privileged user.
15+
*/
16+
this.on("send1", async (req) => {
17+
return this.tx(
18+
{ user: new cds.User.Privileged("privileged-user-1") },
19+
(tx) =>
20+
tx.run(
21+
SELECT.from`Service1.Service1Entity1` // Declared in service1.cds
22+
.where`Attribute1=${req.data.messageToPass}`
23+
)
24+
);
25+
});
26+
27+
/*
28+
* Error: Service1 accessing its own entity that requires
29+
* authorization, with a privileged user.
30+
*/
31+
this.on("send2", async (req) => {
32+
return this.tx(
33+
{ user: new cds.User.Privileged("privileged-user-2") },
34+
(tx) =>
35+
tx.run(
36+
SELECT.from`Service1.Service1Entity2` // Declared in service1.cds
37+
.where`Attribute2=${req.data.messageToPass}`
38+
)
39+
);
40+
});
41+
42+
/*
43+
* FP: Service1 accessing a local service's entity that does not
44+
* require authorization, with a privileged user.
45+
*/
46+
this.on("send3", async (req) => {
47+
return this.tx(
48+
{ user: new cds.User.Privileged("privileged-user-3") },
49+
(tx) =>
50+
tx.run(
51+
SELECT.from(Service2Entity1) // Declared in service2.cds
52+
.where`Attribute3=${req.data.messageToPass}`
53+
)
54+
);
55+
});
56+
57+
/*
58+
* Error: Service1 accessing a local service's entity that
59+
* requires authorization, with a privileged user.
60+
*/
61+
this.on("send4", async (req) => {
62+
const Service2 = await cds.connect.to("Service2");
63+
console.log(Service2);
64+
const { Service2Entity1 } = Service2.entities; // Service2Entity1 is undefined!
65+
console.log(Service2Entity1);
66+
return this.tx(
67+
{ user: new cds.User.Privileged("privileged-user-4") },
68+
(tx) =>
69+
tx.run(
70+
SELECT.from(Service2Entity1) // Declared in service2.cds
71+
.where`Attribute4=${req.data.messageToPass}`
72+
)
73+
);
74+
});
75+
76+
/*
77+
* Warning: Service1 accessing a remote service's entity whose
78+
* authorization requirements are unknown.
79+
*/
80+
this.on("send5", async (req) => {
81+
return this.tx(
82+
{ user: new cds.User.Privileged("privileged-user-5") },
83+
(tx) =>
84+
tx.run(
85+
SELECT.from`RemoteEntity` // Assume that it's declared in @example/sample
86+
.where`SomeAttribute=${req.data.messageToPass}`
87+
)
88+
);
89+
});
90+
}
91+
}
92+
93+
module.exports = Service1;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using { advanced_security.dynamically_generated_privileged.sample_entities as db_schema } from '../db/schema';
2+
3+
service Service2 @(path: '/service-2') {
4+
/* Unrestricted read access to anyone. */
5+
@(restrict: [ { grant: 'READ' } ])
6+
entity Service2Entity1 as projection on db_schema.Entity2 excluding { Attribute4 }
7+
8+
/* Read access only to users with access level greater than 2. */
9+
@(restrict: [ { grant: 'READ', to: '$user.level > 2' } ])
10+
entity Service2Entity2 as projection on db_schema.Entity2 excluding { Attribute4 }
11+
12+
/* API to talk to Service2. */
13+
action send5 (
14+
messageToPass: String
15+
) returns String;
16+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
const cds = require("@sap/cds");
2+
3+
class CustomPrivilegedUser2 extends cds.User {
4+
is() {
5+
return true;
6+
}
7+
}
8+
9+
module.exports = cds.service.impl(function () {
10+
this.on("send2", async (msg) => {
11+
/* 3. Creating a cds.User.Privileged directly */
12+
const user1 = new cds.User.Privileged("privileged1");
13+
this.tx({ user1 }, (tx) =>
14+
tx.run(
15+
INSERT.into("Service2Entity").entries({
16+
url: req._.req.url,
17+
user: req.user.id,
18+
data: msg.data.messageToPass,
19+
}),
20+
),
21+
);
22+
/* 4. Creating a custom privileged user directly */
23+
const user2 = new CustomPrivilegedUser2("privileged2");
24+
this.tx({ user2 }, (tx) =>
25+
tx.run(
26+
INSERT.into("Service2Entity").entries({
27+
url: req._.req.url,
28+
user: req.user.id,
29+
}),
30+
),
31+
);
32+
});
33+
});

0 commit comments

Comments
 (0)