Merge pull request #344 from nightah/duo-additions

Capture IP address and Target URL in Duo 2FA request
pull/343/head
Clément Michaud 2019-03-27 10:47:23 +01:00 committed by GitHub
commit e3b6410e79
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 13 additions and 9 deletions

View File

@ -24,11 +24,11 @@ describe("routes/secondfactor/duo-push/Post", function() {
hostname: 'abc', hostname: 'abc',
integration_key: 'xyz', integration_key: 'xyz',
secret_key: 'secret', secret_key: 'secret',
} };
req = ExpressMock.RequestMock(); req = ExpressMock.RequestMock();
res = ExpressMock.ResponseMock(); res = ExpressMock.ResponseMock();
}) });
it("should raise authentication level of user", async function() { it("should raise authentication level of user", async function() {
const mock = Sinon.stub(DuoApi, "Client"); const mock = Sinon.stub(DuoApi, "Client");
@ -37,7 +37,7 @@ describe("routes/secondfactor/duo-push/Post", function() {
}); });
req.session.auth = { req.session.auth = {
userid: 'john' userid: 'john'
} };
Assert.equal(req.session.auth.authentication_level, undefined); Assert.equal(req.session.auth.authentication_level, undefined);
await Post(vars)(req, res as any); await Post(vars)(req, res as any);
@ -54,7 +54,7 @@ describe("routes/secondfactor/duo-push/Post", function() {
}); });
req.session.auth = { req.session.auth = {
userid: 'john' userid: 'john'
} };
vars.config.duo_api = undefined; vars.config.duo_api = undefined;
Assert.equal(req.session.auth.authentication_level, undefined); Assert.equal(req.session.auth.authentication_level, undefined);
@ -72,7 +72,7 @@ describe("routes/secondfactor/duo-push/Post", function() {
}); });
req.session.auth = { req.session.auth = {
userid: 'john' userid: 'john'
} };
Assert.equal(req.session.auth.authentication_level, undefined); Assert.equal(req.session.auth.authentication_level, undefined);
await Post(vars)(req, res as any); await Post(vars)(req, res as any);
@ -90,7 +90,7 @@ describe("routes/secondfactor/duo-push/Post", function() {
}); });
req.session.auth = { req.session.auth = {
userid: 'john' userid: 'john'
} };
Assert.equal(req.session.auth.authentication_level, undefined); Assert.equal(req.session.auth.authentication_level, undefined);
const promise = Post(vars)(req, res as any) const promise = Post(vars)(req, res as any)

View File

@ -6,6 +6,8 @@ import * as UserMessage from "../../../../../../shared/UserMessages";
import redirect from "../redirect"; import redirect from "../redirect";
import { Level } from "../../../authentication/Level"; import { Level } from "../../../authentication/Level";
import { DuoPushConfiguration } from "../../../configuration/schema/DuoPushConfiguration"; import { DuoPushConfiguration } from "../../../configuration/schema/DuoPushConfiguration";
import GetHeader from "../../../utils/GetHeader";
import { HEADER_X_TARGET_URL } from "../../../../../../shared/constants";
const DuoApi = require("@duosecurity/duo_api"); const DuoApi = require("@duosecurity/duo_api");
interface DuoResponse { interface DuoResponse {
@ -17,11 +19,13 @@ interface DuoResponse {
stat: "OK" | "FAIL"; stat: "OK" | "FAIL";
} }
function triggerAuth(username: string, config: DuoPushConfiguration): Promise<DuoResponse> { function triggerAuth(username: string, config: DuoPushConfiguration, req: Express.Request): Promise<DuoResponse> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
const clientIP = req.ip;
const targetURL = GetHeader(req, HEADER_X_TARGET_URL);
const client = new DuoApi.Client(config.integration_key, config.secret_key, config.hostname); const client = new DuoApi.Client(config.integration_key, config.secret_key, config.hostname);
const timer = setTimeout(() => reject(new Error("Call to duo push API timed out.")), 60000); const timer = setTimeout(() => reject(new Error("Call to duo push API timed out.")), 60000);
client.jsonApiCall("POST", "/auth/v2/auth", { username, factor: "push", device: "auto" }, (data: DuoResponse) => { client.jsonApiCall("POST", "/auth/v2/auth", { username, ipaddr: clientIP, factor: "push", device: "auto", pushinfo: `target%20url=${targetURL}`}, (data: DuoResponse) => {
clearTimeout(timer); clearTimeout(timer);
resolve(data); resolve(data);
}); });
@ -37,7 +41,7 @@ export default function(vars: ServerVariables) {
} }
const authSession = AuthenticationSessionHandler.get(req, vars.logger); const authSession = AuthenticationSessionHandler.get(req, vars.logger);
const authRes = await triggerAuth(authSession.userid, vars.config.duo_api); const authRes = await triggerAuth(authSession.userid, vars.config.duo_api, req);
if (authRes.response.result !== "allow") { if (authRes.response.result !== "allow") {
throw new Error("User denied access."); throw new Error("User denied access.");
} }