Fix failing second factor when no default redirection url set.
When no default redirection url was set, Duo push second factor was shown as failing even if authentication was successful.pull/343/head
parent
e3b6410e79
commit
81207b49ad
|
@ -5,14 +5,11 @@ import { triggerDuoPushAuth, triggerDuoPushAuthSuccess, triggerDuoPushAuthFailur
|
|||
export default async function(dispatch: Dispatch, redirectionUrl: string | null) {
|
||||
dispatch(triggerDuoPushAuth());
|
||||
try {
|
||||
const res = await AutheliaService.triggerDuoPush(redirectionUrl);
|
||||
const body = await res.json();
|
||||
if ('error' in body) {
|
||||
throw new Error(body['error']);
|
||||
}
|
||||
const body = await AutheliaService.triggerDuoPush(redirectionUrl);
|
||||
dispatch(triggerDuoPushAuthSuccess());
|
||||
return body;
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
dispatch(triggerDuoPushAuthFailure(err.message))
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import { Dispatch } from 'redux';
|
|||
import SecondFactorDuoPush, { StateProps, OwnProps, DispatchProps } from '../../../components/SecondFactorDuoPush/SecondFactorDuoPush';
|
||||
import FetchStateBehavior from '../../../behaviors/FetchStateBehavior';
|
||||
import TriggerDuoPushAuth from '../../../behaviors/TriggerDuoPushAuth';
|
||||
import RedirectionResponse from '../../../services/RedirectResponse';
|
||||
|
||||
|
||||
const mapStateToProps = (state: RootState): StateProps => ({
|
||||
|
@ -12,16 +13,16 @@ const mapStateToProps = (state: RootState): StateProps => ({
|
|||
});
|
||||
|
||||
async function redirectIfPossible(body: any) {
|
||||
if ('redirect' in body) {
|
||||
if (body && 'redirect' in body) {
|
||||
window.location.href = body['redirect'];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function handleSuccess(dispatch: Dispatch, res: Response, duration?: number) {
|
||||
async function handleSuccess(dispatch: Dispatch, body: RedirectionResponse | undefined, duration?: number) {
|
||||
async function handle() {
|
||||
const redirected = await redirectIfPossible(res);
|
||||
const redirected = await redirectIfPossible(body);
|
||||
if (!redirected) {
|
||||
await FetchStateBehavior(dispatch);
|
||||
}
|
||||
|
@ -35,9 +36,8 @@ async function handleSuccess(dispatch: Dispatch, res: Response, duration?: numbe
|
|||
}
|
||||
|
||||
async function triggerDuoPushAuth(dispatch: Dispatch, redirectionUrl: string | null) {
|
||||
const res = await TriggerDuoPushAuth(dispatch, redirectionUrl);
|
||||
if (!res) return;
|
||||
await handleSuccess(dispatch, res, 2000);
|
||||
const body = await TriggerDuoPushAuth(dispatch, redirectionUrl);
|
||||
await handleSuccess(dispatch, body, 1000);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch: Dispatch, ownProps: OwnProps): DispatchProps => {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import RemoteState from "../views/AuthenticationView/RemoteState";
|
||||
import u2fApi, { SignRequest } from "u2f-api";
|
||||
import Method2FA from "../types/Method2FA";
|
||||
import RedirectResponse from "./RedirectResponse";
|
||||
|
||||
class AutheliaService {
|
||||
static async fetchSafe(url: string, options?: RequestInit): Promise<Response> {
|
||||
|
@ -113,19 +114,28 @@ class AutheliaService {
|
|||
})
|
||||
}
|
||||
|
||||
static async triggerDuoPush(redirectionUrl: string | null): Promise<any> {
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
static async triggerDuoPush(redirectionUrl: string | null): Promise<RedirectResponse | undefined> {
|
||||
const headers: Record<string, string> = {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
if (redirectionUrl) {
|
||||
headers['X-Target-Url'] = redirectionUrl;
|
||||
}
|
||||
return this.fetchSafe('/api/duo-push', {
|
||||
const res = await this.fetchSafe('/api/duo-push', {
|
||||
method: 'POST',
|
||||
headers: headers,
|
||||
})
|
||||
});
|
||||
|
||||
if (res.status === 204) {
|
||||
return;
|
||||
}
|
||||
|
||||
const body = await res.json();
|
||||
if ('error' in body) {
|
||||
throw new Error(body['error']);
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
static async initiatePasswordResetIdentityValidation(username: string) {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
|
||||
export default interface RedirectResponse {
|
||||
redirect?: string;
|
||||
error?: string;
|
||||
}
|
|
@ -15,7 +15,8 @@ class AutheliaServerFromDist implements AutheliaServerInterface {
|
|||
|
||||
async start() {
|
||||
this.serverProcess = ChildProcess.spawn('./scripts/authelia-scripts serve ' + this.configPath, {
|
||||
shell: true
|
||||
shell: true,
|
||||
env: process.env,
|
||||
} as any);
|
||||
if (this.logInFile) {
|
||||
var logStream = fs.createWriteStream('/tmp/authelia-server.log', {flags: 'a'});
|
||||
|
|
|
@ -20,11 +20,19 @@ storage:
|
|||
local:
|
||||
path: /tmp/authelia/db
|
||||
|
||||
# The Duo Push Notification API configuration
|
||||
duo_api:
|
||||
hostname: duo.example.com
|
||||
integration_key: ABCDEFGHIJKL
|
||||
secret_key: abcdefghijklmnopqrstuvwxyz123456789
|
||||
|
||||
access_control:
|
||||
default_policy: bypass
|
||||
rules:
|
||||
- domain: 'public.example.com'
|
||||
policy: bypass
|
||||
- domain: 'secure.example.com'
|
||||
policy: two_factor
|
||||
|
||||
notifier:
|
||||
smtp:
|
|
@ -3,12 +3,16 @@ import { exec } from "../../helpers/utils/exec";
|
|||
import AutheliaServer from "../../helpers/context/AutheliaServer";
|
||||
import DockerEnvironment from "../../helpers/context/DockerEnvironment";
|
||||
|
||||
// required to query duo-api over https
|
||||
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0 as any;
|
||||
|
||||
const autheliaServer = new AutheliaServer(__dirname + '/config.yml');
|
||||
const dockerEnv = new DockerEnvironment([
|
||||
'docker-compose.yml',
|
||||
'example/compose/nginx/backend/docker-compose.yml',
|
||||
'example/compose/nginx/portal/docker-compose.yml',
|
||||
'example/compose/smtp/docker-compose.yml',
|
||||
'example/compose/duo-api/docker-compose.yml',
|
||||
])
|
||||
|
||||
async function setup() {
|
|
@ -0,0 +1,33 @@
|
|||
import { StartDriver, StopDriver } from "../../../helpers/context/WithDriver";
|
||||
import LoginAs from "../../../helpers/LoginAs";
|
||||
import VerifyIsSecondFactorStage from "../../../helpers/assertions/VerifyIsSecondFactorStage";
|
||||
import ClickOnLink from "../../../helpers/ClickOnLink";
|
||||
import VerifyIsUseAnotherMethodView from "../../../helpers/assertions/VerifyIsUseAnotherMethodView";
|
||||
import ClickOnButton from "../../../helpers/behaviors/ClickOnButton";
|
||||
import Request from 'request-promise';
|
||||
import VerifyIsAlreadyAuthenticatedStage from "../../../helpers/assertions/VerifyIsAlreadyAuthenticatedStage";
|
||||
|
||||
export default function() {
|
||||
before(async function() {
|
||||
this.driver = await StartDriver();
|
||||
|
||||
// Configure the fake API to return allowing response.
|
||||
await Request('https://duo.example.com/allow', {method: 'POST'});
|
||||
});
|
||||
|
||||
after(async function () {
|
||||
await StopDriver(this.driver);
|
||||
});
|
||||
|
||||
it('should send user to already authenticated page', async function() {
|
||||
await LoginAs(this.driver, "john", "password");
|
||||
await VerifyIsSecondFactorStage(this.driver);
|
||||
|
||||
await ClickOnLink(this.driver, 'Use another method');
|
||||
await VerifyIsUseAnotherMethodView(this.driver);
|
||||
await ClickOnButton(this.driver, 'Duo Push Notification');
|
||||
await VerifyIsAlreadyAuthenticatedStage(this.driver, 10000);
|
||||
|
||||
await ClickOnButton(this.driver, "Logout");
|
||||
});
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import AutheliaSuite from "../../helpers/context/AutheliaSuite";
|
||||
import { exec } from '../../helpers/utils/exec';
|
||||
import BypassPolicy from "./scenarii/BypassPolicy";
|
||||
import NoDefaultRedirectionUrl from "./scenarii/NoDefaultRedirectionUrl";
|
||||
|
||||
AutheliaSuite(__dirname, function() {
|
||||
this.timeout(10000);
|
||||
|
@ -10,4 +11,5 @@ AutheliaSuite(__dirname, function() {
|
|||
});
|
||||
|
||||
describe('Bypass policy', BypassPolicy);
|
||||
describe("No default redirection", NoDefaultRedirectionUrl);
|
||||
});
|
|
@ -87,18 +87,6 @@ regulation:
|
|||
ban_time: 900
|
||||
|
||||
notifier:
|
||||
# For testing purpose, notifications can be sent in a file
|
||||
# filesystem:
|
||||
# filename: /tmp/authelia/notification.txt
|
||||
|
||||
# Use your email account to send the notifications. You can use an app password.
|
||||
# List of valid services can be found here: https://nodemailer.com/smtp/well-known/
|
||||
## email:
|
||||
## username: user@example.com
|
||||
## password: yourpassword
|
||||
## sender: admin@example.com
|
||||
## service: gmail
|
||||
|
||||
# Use a SMTP server for sending notifications
|
||||
smtp:
|
||||
username: test
|
||||
|
|
|
@ -6,8 +6,6 @@ port: 9091
|
|||
|
||||
logs_level: debug
|
||||
|
||||
default_redirection_url: https://home.example.com:8080/
|
||||
|
||||
authentication_backend:
|
||||
file:
|
||||
path: ./test/suites/basic/users_database.test.yml
|
||||
|
@ -93,18 +91,6 @@ regulation:
|
|||
ban_time: 900
|
||||
|
||||
notifier:
|
||||
# For testing purpose, notifications can be sent in a file
|
||||
# filesystem:
|
||||
# filename: /tmp/authelia/notification.txt
|
||||
|
||||
# Use your email account to send the notifications. You can use an app password.
|
||||
# List of valid services can be found here: https://nodemailer.com/smtp/well-known/
|
||||
## email:
|
||||
## username: user@example.com
|
||||
## password: yourpassword
|
||||
## sender: admin@example.com
|
||||
## service: gmail
|
||||
|
||||
# Use a SMTP server for sending notifications
|
||||
smtp:
|
||||
username: test
|
||||
|
|
Loading…
Reference in New Issue