Skip to content

Commit 0815e63

Browse files
committed
wip
1 parent 2668616 commit 0815e63

File tree

6 files changed

+404
-20
lines changed

6 files changed

+404
-20
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
// Example configuration using group-based access control
2+
module.exports = {
3+
// Use contextToGroups for group-based access control
4+
// Note: Cannot be used together with contextToRoles
5+
contextToGroups: async (context) => context.securityContext.auth?.groups || [],
6+
7+
canSwitchSqlUser: async () => true,
8+
9+
checkSqlAuth: async (req, user, password) => {
10+
if (user === 'analyst') {
11+
return {
12+
password,
13+
superuser: false,
14+
securityContext: {
15+
auth: {
16+
username: 'analyst',
17+
groups: ['analytics', 'reporting'],
18+
},
19+
},
20+
};
21+
}
22+
if (user === 'manager') {
23+
return {
24+
password,
25+
superuser: false,
26+
securityContext: {
27+
auth: {
28+
username: 'manager',
29+
groups: ['management', 'hr'],
30+
},
31+
},
32+
};
33+
}
34+
if (user === 'finance') {
35+
return {
36+
password,
37+
superuser: false,
38+
securityContext: {
39+
auth: {
40+
username: 'finance',
41+
groups: ['finance', 'accounting'],
42+
},
43+
},
44+
};
45+
}
46+
throw new Error(`User "${user}" doesn't exist`);
47+
}
48+
};
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// Example cube showing group-based access policies
2+
cube('Example', {
3+
sql_table: 'public.example',
4+
5+
data_source: 'default',
6+
7+
dimensions: {
8+
id: {
9+
sql: 'id',
10+
type: 'number',
11+
primary_key: true,
12+
},
13+
name: {
14+
sql: 'name',
15+
type: 'string',
16+
},
17+
department: {
18+
sql: 'department',
19+
type: 'string',
20+
},
21+
},
22+
23+
measures: {
24+
count: {
25+
type: 'count',
26+
},
27+
},
28+
29+
access_policy: [
30+
// Role-based policy (existing functionality)
31+
{
32+
role: 'admin',
33+
memberLevel: {
34+
includes: ['*'],
35+
},
36+
rowLevel: {
37+
allowAll: true,
38+
},
39+
},
40+
41+
// Group-based policy (new functionality) - single group
42+
{
43+
group: 'analytics',
44+
memberLevel: {
45+
includes: ['id', 'name', 'count'],
46+
},
47+
rowLevel: {
48+
filters: [
49+
{
50+
member: 'department',
51+
operator: 'equals',
52+
values: ['Analytics'],
53+
},
54+
],
55+
},
56+
},
57+
58+
// Groups-based policy (plural - preferred for multiple groups)
59+
{
60+
groups: ['finance', 'accounting'],
61+
memberLevel: {
62+
includes: ['id', 'name', 'department', 'count'],
63+
},
64+
rowLevel: {
65+
filters: [
66+
{
67+
member: 'department',
68+
operator: 'in',
69+
values: ['Finance', 'Accounting'],
70+
},
71+
],
72+
},
73+
},
74+
75+
// Manager role policy (separate from group-based policies)
76+
{
77+
role: 'manager',
78+
memberLevel: {
79+
includes: ['*'],
80+
},
81+
rowLevel: {
82+
filters: [
83+
{
84+
member: 'department',
85+
operator: 'equals',
86+
values: ['Management'],
87+
},
88+
],
89+
},
90+
},
91+
92+
// HR groups policy (using 'groups' with single value)
93+
{
94+
groups: 'hr',
95+
memberLevel: {
96+
includes: ['id', 'name', 'department', 'count'],
97+
},
98+
rowLevel: {
99+
filters: [
100+
{
101+
member: 'department',
102+
operator: 'equals',
103+
values: ['HR'],
104+
},
105+
],
106+
},
107+
},
108+
109+
// Default policy for users with no specific role/group
110+
{
111+
memberLevel: {
112+
includes: ['count'],
113+
},
114+
rowLevel: {
115+
filters: [
116+
{
117+
member: 'department',
118+
operator: 'equals',
119+
values: ['Public'],
120+
},
121+
],
122+
},
123+
},
124+
],
125+
});
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
// Example cube showing mixed role-based and group-based access policies
2+
// This demonstrates that contextToRoles and contextToGroups can coexist
3+
// but individual policies must use either role OR group, not both
4+
cube('MixedAccess', {
5+
sql_table: 'public.mixed_access',
6+
7+
data_source: 'default',
8+
9+
dimensions: {
10+
id: {
11+
sql: 'id',
12+
type: 'number',
13+
primary_key: true,
14+
},
15+
name: {
16+
sql: 'name',
17+
type: 'string',
18+
},
19+
department: {
20+
sql: 'department',
21+
type: 'string',
22+
},
23+
region: {
24+
sql: 'region',
25+
type: 'string',
26+
},
27+
},
28+
29+
measures: {
30+
count: {
31+
type: 'count',
32+
},
33+
},
34+
35+
access_policy: [
36+
// ✅ Role-based policy
37+
{
38+
role: 'admin',
39+
memberLevel: {
40+
includes: ['*'],
41+
},
42+
rowLevel: {
43+
allowAll: true,
44+
},
45+
},
46+
47+
// ✅ Another role-based policy
48+
{
49+
role: 'manager',
50+
memberLevel: {
51+
includes: ['*'],
52+
},
53+
rowLevel: {
54+
filters: [
55+
{
56+
member: 'region',
57+
operator: 'equals',
58+
values: () => COMPILE_CONTEXT.securityContext.region,
59+
},
60+
],
61+
},
62+
},
63+
64+
// ✅ Group-based policy (single group)
65+
{
66+
group: 'analytics',
67+
memberLevel: {
68+
includes: ['id', 'name', 'count'],
69+
},
70+
rowLevel: {
71+
filters: [
72+
{
73+
member: 'department',
74+
operator: 'equals',
75+
values: ['Analytics'],
76+
},
77+
],
78+
},
79+
},
80+
81+
// ✅ Group-based policy (multiple groups)
82+
{
83+
groups: ['finance', 'accounting'],
84+
memberLevel: {
85+
includes: ['id', 'name', 'department', 'count'],
86+
},
87+
rowLevel: {
88+
filters: [
89+
{
90+
member: 'department',
91+
operator: 'in',
92+
values: ['Finance', 'Accounting'],
93+
},
94+
],
95+
},
96+
},
97+
98+
// ❌ This would be invalid (mixing role and group in same policy):
99+
// {
100+
// role: 'manager',
101+
// group: 'hr',
102+
// memberLevel: { includes: ['*'] }
103+
// }
104+
105+
// Default policy for users without specific roles/groups
106+
{
107+
memberLevel: {
108+
includes: ['count'],
109+
},
110+
rowLevel: {
111+
filters: [
112+
{
113+
member: 'department',
114+
operator: 'equals',
115+
values: ['Public'],
116+
},
117+
],
118+
},
119+
},
120+
],
121+
});

0 commit comments

Comments
 (0)