-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbroker-oidc-auth.guard.ts
165 lines (158 loc) · 5.28 KB
/
broker-oidc-auth.guard.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import {
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AuthGuard } from '@nestjs/passport';
import get from 'lodash.get';
import {
ALLOW_OWNER_METADATA_KEY,
AllowOwnerArgs,
} from '../allow-owner.decorator';
import { OAUTH2_CLIENT_MAP_GUID } from '../constants';
import { CollectionRepository } from '../persistence/interfaces/collection.repository';
import { GraphRepository } from '../persistence/interfaces/graph.repository';
import { PersistenceUtilService } from '../persistence/persistence-util.service';
import {
ALLOW_BODY_VALUE_METADATA_KEY,
AllowBodyValueArgs,
} from '../allow-body-value.decorator';
import { ROLES_METADATA_KEY } from '../roles.decorator';
import { ALLOW_EMPTY_EDGE_METADATA_KEY } from '../allow-empty-edges.decorator';
/**
* This guard will issue a HTTP unauthorized if the request is not authenticated.
* This guard should be used by Rest APIs. Caller is responsible for redirecting to login.
* This guard should not be used with end points that browsers directly access.
*/
@Injectable()
export class BrokerOidcAuthGuard extends AuthGuard(['oidc']) {
constructor(
private readonly collectionRepository: CollectionRepository,
private readonly graphRepository: GraphRepository,
private readonly util: PersistenceUtilService,
private readonly reflector: Reflector,
) {
super();
}
async canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
if (!request.isAuthenticated()) {
throw new UnauthorizedException();
}
const roles = this.reflector.get<string[]>(
ROLES_METADATA_KEY,
context.getHandler(),
);
if (
!roles ||
(request.user.userinfo.client_roles &&
roles.every((role) =>
request.user.userinfo.client_roles.includes(role),
))
) {
return true;
}
const allowBodyValues = this.reflector.get<AllowBodyValueArgs[]>(
ALLOW_BODY_VALUE_METADATA_KEY,
context.getHandler(),
);
if (
allowBodyValues &&
allowBodyValues.some(
(test) => get(request.body, test.path) === test.value,
)
) {
return true;
}
const emptyEdges = this.reflector.get<string[]>(
ALLOW_EMPTY_EDGE_METADATA_KEY,
context.getHandler(),
);
if (emptyEdges && request.body && request.body.target) {
const vertex = await this.graphRepository.getVertex(request.body.target);
const info = await this.graphRepository.getVertexInfo(
request.body.target,
);
if (
vertex &&
info.incoming === 0 &&
info.outgoing === 0 &&
emptyEdges.indexOf(vertex.collection) !== -1
) {
return true;
}
}
// Allow owners of graph operations to continue
const userUpstreamData = this.reflector.get<AllowOwnerArgs>(
ALLOW_OWNER_METADATA_KEY,
context.getHandler(),
);
if (!userUpstreamData) {
return false;
}
const graphId = userUpstreamData.graphIdFromParamKey
? request.params[userUpstreamData.graphIdFromParamKey]
: get(request.body, userUpstreamData.graphIdFromBodyPath);
const userGuid: string = get(request.user.userinfo, OAUTH2_CLIENT_MAP_GUID);
const permission: string = userUpstreamData.permission;
// Mask data alterations as owner to prevent priviledged changes
// console.log(userUpstreamData.permission);
// console.log(userUpstreamData.sudoMaskKey);
// console.log(request.query);
// console.log(request.params);
request.user.mask =
userUpstreamData.sudoMaskKey &&
request.query[userUpstreamData.sudoMaskKey] === 'true'
? 'sudo'
: permission;
const user = await this.collectionRepository.getCollectionByKeyValue(
'user',
'guid',
userGuid,
);
// console.log(`mask: ${request.user.mask}`);
if (userUpstreamData.graphObjectType === 'collection') {
const collection = userUpstreamData.graphObjectCollectionFromParamKey
? request.params[userUpstreamData.graphObjectCollectionFromParamKey]
: userUpstreamData.graphObjectCollection;
const targetCollection =
await this.collectionRepository.getCollectionById(collection, graphId);
if (!targetCollection) {
return false;
}
// console.log(permission);
// console.log(
// await this.util.testUserPermissions(
// user.vertex.toString(),
// targetCollection.vertex.toString(),
// permission,
// ),
// );
return await this.util.testUserPermissions(
user.vertex.toString(),
targetCollection.vertex.toString(),
permission,
);
} else if (userUpstreamData.graphObjectType === 'edge') {
const targetEdge = await this.graphRepository.getEdge(graphId);
// console.log(graphId);
// console.log(targetEdge);
if (!targetEdge) {
return false;
}
return await this.util.testUserPermissions(
user.vertex.toString(),
targetEdge.target.toString(),
permission,
);
} else if (userUpstreamData.graphObjectType === 'vertex') {
return await this.util.testUserPermissions(
user.vertex.toString(),
graphId,
permission,
);
}
return false;
}
}