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 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({ username: buildId, scmContext, scope, metadata }),
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({ username, scmContext, scope, metadata })
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screwdriver-api",
3
- "version": "8.0.173",
3
+ "version": "8.0.175",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -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 = { username, scmContext, scmUserId, scope, ...(metadata || {}) };
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) {
@@ -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 });
@@ -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
 
@@ -58,6 +58,9 @@ module.exports = () => ({
58
58
  username: profile.username,
59
59
  scmContext: profile.scmContext,
60
60
  scope: ['build'],
61
+ auth: {
62
+ type: 'temporary'
63
+ },
61
64
  metadata: jwtInfo
62
65
  }),
63
66
  parseInt(buildTimeout, 10)
@@ -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);
@@ -40,7 +40,10 @@ async function invoke(request) {
40
40
  username,
41
41
  scmContext,
42
42
  scope: ['sdapi'],
43
- metadata: { pipelineId }
43
+ metadata: { pipelineId },
44
+ auth: {
45
+ type: 'temporary'
46
+ }
44
47
  })
45
48
  );
46
49
 
@@ -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;
@@ -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);