Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement /api/runtimetoken in node server. Closes #2253 #2298

Merged
merged 2 commits into from
Feb 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,38 @@
"watchu": "nodemon .\\src\\nodemon-unix.json"
},
"dependencies": {
"applicationinsights": "^1.0.1",
"async": "^2.5.0",
"async-file": "^2.0.2",
"axios": "^0.16.2",
"body-parser": "^1.17.2",
"circular-json": "^0.4.0",
"compression": "^1.7.1",
"cookie-parser": "^1.4.3",
"cookie-session": "^2.0.0-beta.3",
"crypto": "^1.0.1",
"dotenv": "^4.0.0",
"express": "^4.15.3",
"express-session": "^1.15.3",
"jsonwebtoken": "^7.4.1",
"jsonwebtoken": "^8.1.1",
"morgan": "^1.8.2",
"pug": "^2.0.0-rc.2",
"uuid": "^3.1.0",
"dotenv": "^4.0.0",
"compression": "^1.7.1",
"cookie-session": "^2.0.0-beta.3",
"crypto": "^1.0.1",
"applicationinsights": "^1.0.1"
"uuid": "^3.1.0"
},
"devDependencies": {
"@types/async": "^2.0.40",
"@types/axios": "^0.14.0",
"@types/body-parser": "^1.16.4",
"@types/circular-json": "^0.4.0",
"@types/compression": "^0.0.35",
"@types/cookie-parser": "^1.3.30",
"@types/cookie-session": "^2.0.34",
"@types/express": "^4.0.36",
"@types/express-session": "^1.15.0",
"@types/jsonwebtoken": "^7.2.1",
"@types/jsonwebtoken": "^7.2.5",
"@types/morgan": "^1.7.32",
"@types/pug": "^2.0.4",
"@types/uuid": "^3.4.0",
"@types/compression": "^0.0.35",
"concurrently": "^3.5.0",
"del": "^3.0.0",
"gulp": "^3.9.1",
Expand All @@ -46,12 +47,11 @@
"gulp-merge-json": "^1.2.0",
"gulp-rename": "^1.2.2",
"gulp-resx2": "^1.0.1",
"gulp-token-replace": "^1.1.2",
"merge-stream": "^1.0.1",
"nodemon": "^1.11.0",
"run-sequence": "^2.2.0",
"ts-node": "^3.1.0",
"typescript": "^2.4.1",
"@types/cookie-session": "^2.0.34",
"gulp-token-replace": "^1.1.2"
"typescript": "^2.4.1"
}
}
89 changes: 89 additions & 0 deletions server/src/actions/linux-function-app.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Request, Response } from 'express';
import axios from 'axios';
import * as jwt from 'jsonwebtoken';
import * as safeJson from 'circular-json';
import * as crypto from 'crypto';
import { LogHelper } from '../logHelper';
import { constants } from '../constants';

export async function getLinuxRuntimeToken(req: Request, res: Response) {
const armId: string = req.params ? req.params[0] : '';
const siteName = armId.split('/').filter(i => !!i).pop() || '';
const getAppSettingsUrl = `${armId}/config/appsettings/list?api-version=${constants.AntaresAppSettingsApiVersion}`;
const updateAppSettingsUrl = `${armId}/config/appsettings?api-version=${constants.AntaresAppSettingsApiVersion}`;
const armToken = req.header('portal-token');

// get app settings
const appSettings = await getAppSettings(getAppSettingsUrl, armToken);
if (appSettings) {
const machineKey = appSettings['MACHINEKEY_DecryptionKey'];
const handleToken = (error: Error, token: string) => {
if (error) {
LogHelper.error('getRuntimeToken', error);
res.status(500).send(safeJson.stringify(error));
} else {
res.contentType('json').send(safeJson.stringify(token));
}
};

if (machineKey) {
getRuntimeToken(siteName, machineKey, handleToken);
} else {
const key = generateAESKey();
if (await addMachineDecryptionKey(updateAppSettingsUrl, armToken, appSettings, key)) {
getRuntimeToken(siteName, key, handleToken);
} else {
res.status(500);
}
}
} else {
res.status(500);
}
}

async function getAppSettings(url: string, token: string | undefined) {
try {
const response = await axios.post(`https://management.azure.com/${url}`, null, {
headers: {
Authorization: `Bearer ${token}`
}
});
return response.data.properties as { [key: string]: string };
} catch (err) {
LogHelper.error('error-get-appsettings', err);
return null;
}
}

function generateAESKey() {
return crypto.randomBytes(32).toString('hex').toUpperCase();
}

async function addMachineDecryptionKey(url: string, token: string | undefined, appSettings: { [key: string]: string }, key: string) {
try {
appSettings['MACHINEKEY_DecryptionKey'] = key;
await axios.put(`https://management.azure.com/${url}`, { properties: appSettings }, {
headers: {
Authorization: `Bearer ${token}`
}
});
return true;
} catch (error) {
LogHelper.error('update-appsettings', error);
return false;
}
}

function getRuntimeToken(siteName: string, key: string, callback: (err: Error, token: string) => void) {
const issuer = `https://${siteName}.scm.azurewebsites.net`;
const audience = `https://${siteName}.azurewebsites.net/azurefunctions`;
const notBefore = Math.floor(Date.now() / 1000) - 10; // not before now - 10 seconds for clock skew
const expires = Math.floor(Date.now() / 1000) + (10 * 60); // 10 minute token

jwt.sign({
iss: issuer,
aud: audience,
nbf: notBefore,
exp: expires
}, key, callback);
}
1 change: 1 addition & 0 deletions server/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export namespace constants {
}
export const templatesPath = '';
export const AntaresApiVersion = '2016-03-01';
export const AntaresAppSettingsApiVersion = '2015-08-01';
export const KeyvaultApiVersion = '2016-10-01';
export const KeyvaultUri = 'https://vault.azure.net';
export namespace oauthApis {
Expand Down
21 changes: 12 additions & 9 deletions server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import { staticConfig } from './config';
import { setupDeploymentCenter } from './deployment-center/deployment-center';
import { triggerFunctionAPIM } from './actions/apim';
import { NextFunction } from 'express';
import { getLinuxRuntimeToken } from './actions/linux-function-app';

const cookieSession = require('cookie-session');
const appInsights = require('applicationinsights');
if (process.env.aiInstrumentationKey) {
Expand Down Expand Up @@ -46,15 +48,15 @@ app
.use(bodyParser.urlencoded({ extended: true }))
.use(cookieParser())
.use(
cookieSession({
//This session cookie will live as long as the session and be used for authentication/security purposes
name: 'session',
keys: [process.env.SALT],
cookie: {
httpOnly: true,
secure: true
}
})
cookieSession({
//This session cookie will live as long as the session and be used for authentication/security purposes
name: 'session',
keys: [process.env.SALT],
cookie: {
httpOnly: true,
secure: true
}
})
);
const redirectToAcom = (req: express.Request, res: express.Response, next: NextFunction) => {
if (!req.query.trustedAuthority) {
Expand Down Expand Up @@ -97,6 +99,7 @@ app.get('/api/config', getConfig);
app.post('/api/proxy', proxy);
app.post('/api/passthrough', proxy);
app.post('/api/triggerFunctionAPIM', triggerFunctionAPIM);
app.get('/api/runtimetoken/*', getLinuxRuntimeToken)

setupDeploymentCenter(app);
// if are here, that means we didn't match any of the routes above including those for static content.
Expand Down
68 changes: 35 additions & 33 deletions server/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@
"@types/express-serve-static-core" "*"
"@types/serve-static" "*"

"@types/jsonwebtoken@^7.2.1":
version "7.2.1"
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-7.2.1.tgz#44a0282b48d242d0760eab0ce6cf570a62eabf96"
"@types/jsonwebtoken@^7.2.5":
version "7.2.5"
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-7.2.5.tgz#413159d570ec45fc3e7da7ea3f7bca6fb9300e72"
dependencies:
"@types/node" "*"

Expand Down Expand Up @@ -1804,10 +1804,6 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"

isemail@1.x.x:
version "1.2.0"
resolved "https://registry.yarnpkg.com/isemail/-/isemail-1.2.0.tgz#be03df8cc3e29de4d2c5df6501263f1fa4595e9a"

isexe@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
Expand All @@ -1826,15 +1822,6 @@ isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"

joi@^6.10.1:
version "6.10.1"
resolved "https://registry.yarnpkg.com/joi/-/joi-6.10.1.tgz#4d50c318079122000fe5f16af1ff8e1917b77e06"
dependencies:
hoek "2.x.x"
isemail "1.x.x"
moment "2.x.x"
topo "1.x.x"

js-beautify@~1.5.4:
version "1.5.10"
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.5.10.tgz#4d95371702699344a516ca26bf59f0a27bb75719"
Expand Down Expand Up @@ -1877,14 +1864,19 @@ jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"

jsonwebtoken@^7.4.1:
version "7.4.1"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-7.4.1.tgz#7ca324f5215f8be039cd35a6c45bb8cb74a448fb"
jsonwebtoken@^8.1.1:
version "8.1.1"
resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.1.1.tgz#b04d8bb2ad847bc93238c3c92170ffdbdd1cb2ea"
dependencies:
joi "^6.10.1"
jws "^3.1.4"
lodash.includes "^4.3.0"
lodash.isboolean "^3.0.3"
lodash.isinteger "^4.0.4"
lodash.isnumber "^3.0.3"
lodash.isplainobject "^4.0.6"
lodash.isstring "^4.0.1"
lodash.once "^4.0.0"
ms "^2.0.0"
ms "^2.1.1"
xtend "^4.0.1"

jsprim@^1.2.2:
Expand Down Expand Up @@ -2044,6 +2036,10 @@ lodash.escape@^3.0.0:
dependencies:
lodash._root "^3.0.0"

lodash.includes@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f"

lodash.isarguments@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a"
Expand All @@ -2052,7 +2048,19 @@ lodash.isarray@^3.0.0:
version "3.0.4"
resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"

lodash.isplainobject@^4.0.4:
lodash.isboolean@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6"

lodash.isinteger@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"

lodash.isnumber@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc"

lodash.isplainobject@^4.0.4, lodash.isplainobject@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"

Expand Down Expand Up @@ -2236,10 +2244,6 @@ minimist@^1.1.0, minimist@^1.2.0:
dependencies:
minimist "0.0.8"

moment@2.x.x:
version "2.18.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f"

morgan@^1.8.2:
version "1.8.2"
resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.8.2.tgz#784ac7734e4a453a9c6e6e8680a9329275c8b687"
Expand All @@ -2250,10 +2254,14 @@ morgan@^1.8.2:
on-finished "~2.3.0"
on-headers "~1.0.1"

ms@2.0.0, ms@^2.0.0:
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"

ms@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"

multipipe@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/multipipe/-/multipipe-0.1.2.tgz#2a8f2ddf70eed564dff2d57f1e1a137d9f05078b"
Expand Down Expand Up @@ -3221,12 +3229,6 @@ token-stream@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/token-stream/-/token-stream-0.0.1.tgz#ceeefc717a76c4316f126d0b9dbaa55d7e7df01a"

topo@1.x.x:
version "1.1.0"
resolved "https://registry.yarnpkg.com/topo/-/topo-1.1.0.tgz#e9d751615d1bb87dc865db182fa1ca0a5ef536d5"
dependencies:
hoek "2.x.x"

touch@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/touch/-/touch-1.0.0.tgz#449cbe2dbae5a8c8038e30d71fa0ff464947c4de"
Expand Down