adding expiration to Nonce and making cookie secure and httpOnly
This commit is contained in:
Родитель
d9baeb3ced
Коммит
fcf764cc1b
|
@ -13,3 +13,28 @@ export function hashStateGuid(guid: string) {
|
||||||
hash.update(guid);
|
hash.update(guid);
|
||||||
return hash.digest("hex");
|
return hash.digest("hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function newNonceWithExpiration() {
|
||||||
|
const nonceExpiration = Date.now() + 1000 * 60;
|
||||||
|
return `${newGuid()}_${nonceExpiration}}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isNonceExpired(nonce: string) {
|
||||||
|
if (!nonce) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const expirationString = nonce.split("_")[1];
|
||||||
|
|
||||||
|
if (!expirationString) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const expirationParsed = parseInt(expirationString, 10);
|
||||||
|
|
||||||
|
if (isNaN(expirationParsed) || expirationParsed < Date.now()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import * as https from "https";
|
||||||
import * as querystring from "querystring";
|
import * as querystring from "querystring";
|
||||||
import { SWA_CLI_API_URI, SWA_CLI_APP_PROTOCOL } from "../../../core/constants";
|
import { SWA_CLI_API_URI, SWA_CLI_APP_PROTOCOL } from "../../../core/constants";
|
||||||
import { DEFAULT_CONFIG } from "../../../config";
|
import { DEFAULT_CONFIG } from "../../../config";
|
||||||
import { hashStateGuid } from "../../../core/utils/auth";
|
import { hashStateGuid, isNonceExpired } from "../../../core/utils/auth";
|
||||||
|
|
||||||
const getGithubAuthToken = function (codeValue: string, clientId: string, clientSecret: string) {
|
const getGithubAuthToken = function (codeValue: string, clientId: string, clientSecret: string) {
|
||||||
const data = querystring.stringify({
|
const data = querystring.stringify({
|
||||||
|
@ -401,6 +401,16 @@ const httpTrigger = async function (context: Context, request: http.IncomingMess
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isNonceExpired(nonce)) {
|
||||||
|
context.res = response({
|
||||||
|
context,
|
||||||
|
status: 401,
|
||||||
|
headers: { ["Content-Type"]: "text/plain" },
|
||||||
|
body: "Login timed out. Please try again.",
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const { clientIdSettingName, clientSecretSettingName } = customAuth?.identityProviders?.[providerName]?.registration || {};
|
const { clientIdSettingName, clientSecretSettingName } = customAuth?.identityProviders?.[providerName]?.registration || {};
|
||||||
|
|
||||||
if (!clientIdSettingName) {
|
if (!clientIdSettingName) {
|
||||||
|
@ -466,7 +476,8 @@ const httpTrigger = async function (context: Context, request: http.IncomingMess
|
||||||
name: "Nonce",
|
name: "Nonce",
|
||||||
value: "deleted",
|
value: "deleted",
|
||||||
path: "/",
|
path: "/",
|
||||||
HttpOnly: false,
|
secure: true,
|
||||||
|
httpOnly: true,
|
||||||
expires: new Date(1).toUTCString(),
|
expires: new Date(1).toUTCString(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -474,6 +485,8 @@ const httpTrigger = async function (context: Context, request: http.IncomingMess
|
||||||
value: clientPrincipal === null ? "deleted" : btoa(JSON.stringify(clientPrincipal)),
|
value: clientPrincipal === null ? "deleted" : btoa(JSON.stringify(clientPrincipal)),
|
||||||
domain: DEFAULT_CONFIG.host,
|
domain: DEFAULT_CONFIG.host,
|
||||||
path: "/",
|
path: "/",
|
||||||
|
secure: true,
|
||||||
|
httpOnly: true,
|
||||||
expires: clientPrincipal === null ? new Date(1).toUTCString() : new Date(Date.now() + 1000 * 60 * 60 * 8).toUTCString(),
|
expires: clientPrincipal === null ? new Date(1).toUTCString() : new Date(Date.now() + 1000 * 60 * 60 * 8).toUTCString(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { response } from "../../../core";
|
||||||
import * as http from "http";
|
import * as http from "http";
|
||||||
import { SWA_CLI_APP_PROTOCOL } from "../../../core/constants";
|
import { SWA_CLI_APP_PROTOCOL } from "../../../core/constants";
|
||||||
import { DEFAULT_CONFIG } from "../../../config";
|
import { DEFAULT_CONFIG } from "../../../config";
|
||||||
import { hashStateGuid, newGuid } from "../../../core/utils/auth";
|
import { hashStateGuid, newNonceWithExpiration } from "../../../core/utils/auth";
|
||||||
|
|
||||||
const httpTrigger = async function (context: Context, _request: http.IncomingMessage, customAuth?: SWAConfigFileAuth) {
|
const httpTrigger = async function (context: Context, _request: http.IncomingMessage, customAuth?: SWAConfigFileAuth) {
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
|
@ -43,7 +43,7 @@ const httpTrigger = async function (context: Context, _request: http.IncomingMes
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = newGuid();
|
const state = newNonceWithExpiration();
|
||||||
const hashedState = hashStateGuid(state);
|
const hashedState = hashStateGuid(state);
|
||||||
const redirectUri = `${SWA_CLI_APP_PROTOCOL}://${DEFAULT_CONFIG.host}:${DEFAULT_CONFIG.port}`;
|
const redirectUri = `${SWA_CLI_APP_PROTOCOL}://${DEFAULT_CONFIG.host}:${DEFAULT_CONFIG.port}`;
|
||||||
|
|
||||||
|
@ -60,6 +60,8 @@ const httpTrigger = async function (context: Context, _request: http.IncomingMes
|
||||||
value: btoa(state),
|
value: btoa(state),
|
||||||
domain: DEFAULT_CONFIG.host,
|
domain: DEFAULT_CONFIG.host,
|
||||||
path: "/",
|
path: "/",
|
||||||
|
secure: true,
|
||||||
|
httpOnly: true,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
status: 302,
|
status: 302,
|
||||||
|
|
Загрузка…
Ссылка в новой задаче