screwdriver-api 8.0.173 → 8.0.175
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/server.js +14 -2
- package/package.json +1 -1
- package/plugins/auth/index.js +85 -4
- package/plugins/auth/login.js +12 -0
- package/plugins/auth/token.js +4 -1
- package/plugins/builds/token.js +3 -0
- package/plugins/pipelines/admins/get.js +7 -1
- package/plugins/pipelines/caches/request.js +4 -1
- package/plugins/pipelines/get.js +5 -0
- package/plugins/users/get.js +7 -1
package/lib/server.js
CHANGED
|
@@ -227,7 +227,13 @@ module.exports = async config => {
|
|
|
227
227
|
server.app.buildFactory.apiUri = server.info.uri;
|
|
228
228
|
server.app.buildFactory.tokenGen = (buildId, metadata, scmContext, expiresIn, scope = ['temporal']) =>
|
|
229
229
|
server.plugins.auth.generateToken(
|
|
230
|
-
server.plugins.auth.generateProfile({
|
|
230
|
+
server.plugins.auth.generateProfile({
|
|
231
|
+
username: buildId,
|
|
232
|
+
scmContext,
|
|
233
|
+
scope,
|
|
234
|
+
auth: { type: 'temporary' },
|
|
235
|
+
metadata
|
|
236
|
+
}),
|
|
231
237
|
expiresIn
|
|
232
238
|
);
|
|
233
239
|
server.app.buildFactory.executor.tokenGen = server.app.buildFactory.tokenGen;
|
|
@@ -236,7 +242,13 @@ module.exports = async config => {
|
|
|
236
242
|
server.app.jobFactory.apiUri = server.info.uri;
|
|
237
243
|
server.app.jobFactory.tokenGen = (username, metadata, scmContext, scope = ['user']) =>
|
|
238
244
|
server.plugins.auth.generateToken(
|
|
239
|
-
server.plugins.auth.generateProfile({
|
|
245
|
+
server.plugins.auth.generateProfile({
|
|
246
|
+
username,
|
|
247
|
+
scmContext,
|
|
248
|
+
scope,
|
|
249
|
+
auth: { type: 'temporary' },
|
|
250
|
+
metadata
|
|
251
|
+
})
|
|
240
252
|
);
|
|
241
253
|
server.app.jobFactory.executor.userTokenGen = server.app.jobFactory.tokenGen;
|
|
242
254
|
|
package/package.json
CHANGED
package/plugins/auth/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const boom = require('@hapi/boom');
|
|
3
4
|
const joi = require('joi');
|
|
4
5
|
const jwt = require('jsonwebtoken');
|
|
5
6
|
const { v4: uuidv4 } = require('uuid');
|
|
@@ -94,6 +95,64 @@ const authPlugin = {
|
|
|
94
95
|
async register(server, options) {
|
|
95
96
|
const pluginOptions = joi.attempt(options, AUTH_PLUGIN_SCHEMA, 'Invalid config for plugin-auth');
|
|
96
97
|
|
|
98
|
+
server.ext('onPostAuth', async (request, h) => {
|
|
99
|
+
const { tokenFactory } = request.server.app;
|
|
100
|
+
|
|
101
|
+
const permissionLevels = {
|
|
102
|
+
read: 1,
|
|
103
|
+
execute: 2,
|
|
104
|
+
write: 3,
|
|
105
|
+
all: 4
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const authSettings = request.route.settings.plugins ? request.route.settings.plugins.authorization : null;
|
|
109
|
+
|
|
110
|
+
if (!authSettings) {
|
|
111
|
+
return h.continue;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!request.auth.isAuthenticated) {
|
|
115
|
+
throw boom.unauthorized();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const credentials = request.auth.credentials;
|
|
119
|
+
|
|
120
|
+
if (!credentials.auth || credentials.auth.type !== 'api_token') {
|
|
121
|
+
return h.continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const apiTokenId = credentials.auth.apiTokenId;
|
|
125
|
+
|
|
126
|
+
if (!apiTokenId) {
|
|
127
|
+
throw boom.forbidden(`Your token is invalid`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const token = await tokenFactory.get({ id: apiTokenId });
|
|
131
|
+
|
|
132
|
+
if (!token) {
|
|
133
|
+
throw boom.forbidden(`Your token is invalid`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (token.expiresAt && new Date(token.expiresAt) < new Date()) {
|
|
137
|
+
throw boom.forbidden(`Your token is expired: token id ${apiTokenId}`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const actualPermission = credentials.permission || 'all';
|
|
141
|
+
const requiredPermission = authSettings.permission;
|
|
142
|
+
const actualPermissionLevel = permissionLevels[actualPermission];
|
|
143
|
+
const requiredPermissionLevel = permissionLevels[requiredPermission];
|
|
144
|
+
|
|
145
|
+
if (!requiredPermissionLevel) {
|
|
146
|
+
throw boom.badImplementation(`Invalid required permission: "${requiredPermission}"`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
if (!actualPermissionLevel || actualPermissionLevel < requiredPermissionLevel) {
|
|
150
|
+
throw boom.forbidden(`This endpoint requires "${requiredPermission}" permission`);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return h.continue;
|
|
154
|
+
});
|
|
155
|
+
|
|
97
156
|
/**
|
|
98
157
|
* Generates a profile for storage in cookie and jwt
|
|
99
158
|
* @method generateProfile
|
|
@@ -102,12 +161,22 @@ const authPlugin = {
|
|
|
102
161
|
* @param {String} config.scmUserId User ID in the SCM
|
|
103
162
|
* @param {String} config.scmContext Scm to which the person logged in belongs
|
|
104
163
|
* @param {Array} config.scope Scope for this profile (usually build or user)
|
|
164
|
+
* @param {Object} config.auth Authentication method information
|
|
165
|
+
* @param {Object} config.options Additional token options
|
|
105
166
|
* @param {Object} config.metadata Additional information to tag along with the login
|
|
106
167
|
* @return {Object} The profile to be stored in jwt and/or cookie
|
|
107
168
|
*/
|
|
108
169
|
server.expose('generateProfile', config => {
|
|
109
|
-
const { username, scmUserId, scmContext, scope, metadata } = config;
|
|
110
|
-
const profile = {
|
|
170
|
+
const { username, scmUserId, scmContext, scope, auth, options: profileOptions, metadata } = config;
|
|
171
|
+
const profile = {
|
|
172
|
+
username,
|
|
173
|
+
scmContext,
|
|
174
|
+
scmUserId,
|
|
175
|
+
scope,
|
|
176
|
+
auth,
|
|
177
|
+
...(profileOptions || {}),
|
|
178
|
+
...(metadata || {})
|
|
179
|
+
};
|
|
111
180
|
|
|
112
181
|
if (pluginOptions.jwtEnvironment) {
|
|
113
182
|
profile.environment = pluginOptions.jwtEnvironment;
|
|
@@ -228,7 +297,13 @@ const authPlugin = {
|
|
|
228
297
|
username: user.username,
|
|
229
298
|
scmUserId: scmUser.id,
|
|
230
299
|
scmContext: user.scmContext,
|
|
231
|
-
scope: ['user']
|
|
300
|
+
scope: ['user'],
|
|
301
|
+
auth: {
|
|
302
|
+
type: 'api_token',
|
|
303
|
+
apiTokenId: token.id,
|
|
304
|
+
apiTokenType: 'user'
|
|
305
|
+
},
|
|
306
|
+
...(token.options || {})
|
|
232
307
|
};
|
|
233
308
|
|
|
234
309
|
const scmDisplayName = scm.getDisplayName({ scmContext: profile.scmContext });
|
|
@@ -256,7 +331,13 @@ const authPlugin = {
|
|
|
256
331
|
username: admin.username,
|
|
257
332
|
scmContext: pipeline.scmContext,
|
|
258
333
|
pipelineId: token.pipelineId,
|
|
259
|
-
scope: ['pipeline']
|
|
334
|
+
scope: ['pipeline'],
|
|
335
|
+
auth: {
|
|
336
|
+
type: 'api_token',
|
|
337
|
+
apiTokenId: token.id,
|
|
338
|
+
apiTokenType: 'pipeline'
|
|
339
|
+
},
|
|
340
|
+
...(token.options || {})
|
|
260
341
|
};
|
|
261
342
|
}
|
|
262
343
|
if (!profile) {
|
package/plugins/auth/login.js
CHANGED
|
@@ -35,6 +35,12 @@ function addGuestRoute(config) {
|
|
|
35
35
|
const profile = request.server.plugins.auth.generateProfile({
|
|
36
36
|
username,
|
|
37
37
|
scope: ['user', 'guest'],
|
|
38
|
+
auth: {
|
|
39
|
+
type: 'temporary'
|
|
40
|
+
},
|
|
41
|
+
options: {
|
|
42
|
+
permission: 'read'
|
|
43
|
+
},
|
|
38
44
|
metadata: {}
|
|
39
45
|
});
|
|
40
46
|
|
|
@@ -92,6 +98,12 @@ function addOAuthRoutes(config) {
|
|
|
92
98
|
scmUserId,
|
|
93
99
|
scmContext,
|
|
94
100
|
scope: ['user'],
|
|
101
|
+
auth: {
|
|
102
|
+
type: 'oauth'
|
|
103
|
+
},
|
|
104
|
+
options: {
|
|
105
|
+
permission: 'all'
|
|
106
|
+
},
|
|
95
107
|
metadata: {}
|
|
96
108
|
});
|
|
97
109
|
const scmDisplayName = await userFactory.scm.getDisplayName({ scmContext });
|
package/plugins/auth/token.js
CHANGED
|
@@ -45,7 +45,10 @@ module.exports = () => ({
|
|
|
45
45
|
profile = request.server.plugins.auth.generateProfile({
|
|
46
46
|
username: request.params.buildId,
|
|
47
47
|
scmContext: pipeline.scmContext,
|
|
48
|
-
scope: ['build', 'impersonated']
|
|
48
|
+
scope: ['build', 'impersonated'],
|
|
49
|
+
auth: {
|
|
50
|
+
type: 'temporary'
|
|
51
|
+
}
|
|
49
52
|
});
|
|
50
53
|
profile.token = request.server.plugins.auth.generateToken(profile);
|
|
51
54
|
|
package/plugins/builds/token.js
CHANGED
|
@@ -44,7 +44,13 @@ module.exports = () => ({
|
|
|
44
44
|
const profile = request.server.plugins.auth.generateProfile({
|
|
45
45
|
username: admin.username,
|
|
46
46
|
scmContext: admin.scmContext,
|
|
47
|
-
scope: ['user']
|
|
47
|
+
scope: ['user'],
|
|
48
|
+
auth: {
|
|
49
|
+
type: 'temporary'
|
|
50
|
+
},
|
|
51
|
+
options: {
|
|
52
|
+
permission: 'all'
|
|
53
|
+
}
|
|
48
54
|
});
|
|
49
55
|
|
|
50
56
|
admin.userToken = request.server.plugins.auth.generateToken(profile);
|
package/plugins/pipelines/get.js
CHANGED
|
@@ -17,6 +17,11 @@ module.exports = () => ({
|
|
|
17
17
|
strategies: ['token'],
|
|
18
18
|
scope: ['user', 'build', 'pipeline']
|
|
19
19
|
},
|
|
20
|
+
plugins: {
|
|
21
|
+
authorization: {
|
|
22
|
+
permission: 'read'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
20
25
|
|
|
21
26
|
handler: async (request, h) => {
|
|
22
27
|
const { canAccessPipeline } = request.server.plugins.pipelines;
|
package/plugins/users/get.js
CHANGED
|
@@ -42,7 +42,13 @@ module.exports = () => ({
|
|
|
42
42
|
const profile = request.server.plugins.auth.generateProfile({
|
|
43
43
|
username: user.username,
|
|
44
44
|
scmContext: user.scmContext,
|
|
45
|
-
scope: ['user']
|
|
45
|
+
scope: ['user'],
|
|
46
|
+
auth: {
|
|
47
|
+
type: 'temporary'
|
|
48
|
+
},
|
|
49
|
+
options: {
|
|
50
|
+
permission: 'all'
|
|
51
|
+
}
|
|
46
52
|
});
|
|
47
53
|
|
|
48
54
|
user.userToken = request.server.plugins.auth.generateToken(profile);
|