mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
* Removal of the Redirect header sent by Authelia /api/verify endpoint. * Authelia does not consume Host header anymore but X-Forwarded-Proto and X-Forwarded-Host to compute the link sent in identity verification emails. * Authelia used Host header as the application name for U2F authentication but it's now using X-Forwarded-* headers.
137 lines
4.8 KiB
TypeScript
137 lines
4.8 KiB
TypeScript
import objectPath = require("object-path");
|
|
import randomstring = require("randomstring");
|
|
import BluebirdPromise = require("bluebird");
|
|
import util = require("util");
|
|
import Exceptions = require("./Exceptions");
|
|
import { IUserDataStore } from "./storage/IUserDataStore";
|
|
import Express = require("express");
|
|
import ErrorReplies = require("./ErrorReplies");
|
|
import { AuthenticationSessionHandler } from "./AuthenticationSessionHandler";
|
|
import { AuthenticationSession } from "../../types/AuthenticationSession";
|
|
import { ServerVariables } from "./ServerVariables";
|
|
import { IdentityValidable } from "./IdentityValidable";
|
|
import * as Constants from "../../../shared/constants";
|
|
|
|
import Identity = require("../../types/Identity");
|
|
import { IdentityValidationDocument }
|
|
from "./storage/IdentityValidationDocument";
|
|
import { OPERATION_FAILED } from "../../../shared/UserMessages";
|
|
import GetHeader from "./utils/GetHeader";
|
|
|
|
function createAndSaveToken(userid: string, challenge: string,
|
|
userDataStore: IUserDataStore): BluebirdPromise<string> {
|
|
|
|
const five_minutes = 4 * 60 * 1000;
|
|
const token = randomstring.generate({ length: 64 });
|
|
|
|
return userDataStore.produceIdentityValidationToken(userid, token, challenge,
|
|
five_minutes)
|
|
.then(function () {
|
|
return BluebirdPromise.resolve(token);
|
|
});
|
|
}
|
|
|
|
function consumeToken(token: string, challenge: string,
|
|
userDataStore: IUserDataStore)
|
|
: BluebirdPromise<IdentityValidationDocument> {
|
|
return userDataStore.consumeIdentityValidationToken(token, challenge);
|
|
}
|
|
|
|
export function register(app: Express.Application,
|
|
pre_validation_endpoint: string,
|
|
post_validation_endpoint: string,
|
|
handler: IdentityValidable,
|
|
vars: ServerVariables) {
|
|
|
|
app.post(pre_validation_endpoint,
|
|
post_start_validation(handler, vars));
|
|
app.post(post_validation_endpoint,
|
|
post_finish_validation(handler, vars));
|
|
}
|
|
|
|
function checkIdentityToken(req: Express.Request, identityToken: string)
|
|
: BluebirdPromise<void> {
|
|
if (!identityToken)
|
|
return BluebirdPromise.reject(
|
|
new Exceptions.AccessDeniedError("No identity token provided"));
|
|
return BluebirdPromise.resolve();
|
|
}
|
|
|
|
export function post_finish_validation(handler: IdentityValidable,
|
|
vars: ServerVariables)
|
|
: Express.RequestHandler {
|
|
|
|
return function (req: Express.Request, res: Express.Response)
|
|
: BluebirdPromise<void> {
|
|
|
|
let authSession: AuthenticationSession;
|
|
const identityToken = objectPath.get<Express.Request, string>(
|
|
req, "query.token");
|
|
vars.logger.debug(req, "Identity token provided is %s", identityToken);
|
|
|
|
return checkIdentityToken(req, identityToken)
|
|
.then(() => {
|
|
authSession = AuthenticationSessionHandler.get(req, vars.logger);
|
|
return handler.postValidationInit(req);
|
|
})
|
|
.then(() => {
|
|
return consumeToken(identityToken, handler.challenge(),
|
|
vars.userDataStore);
|
|
})
|
|
.then((doc: IdentityValidationDocument) => {
|
|
authSession.identity_check = {
|
|
challenge: handler.challenge(),
|
|
userid: doc.userId
|
|
};
|
|
handler.postValidationResponse(req, res);
|
|
return BluebirdPromise.resolve();
|
|
})
|
|
.catch(ErrorReplies.replyWithError200(req, res, vars.logger, OPERATION_FAILED));
|
|
};
|
|
}
|
|
|
|
export function post_start_validation(handler: IdentityValidable,
|
|
vars: ServerVariables)
|
|
: Express.RequestHandler {
|
|
return function (req: Express.Request, res: Express.Response)
|
|
: BluebirdPromise<void> {
|
|
let identity: Identity.Identity;
|
|
|
|
return handler.preValidationInit(req)
|
|
.then((id: Identity.Identity) => {
|
|
identity = id;
|
|
const email = identity.email;
|
|
const userid = identity.userid;
|
|
vars.logger.info(req, "Start identity validation of user \"%s\"",
|
|
userid);
|
|
|
|
if (!(email && userid))
|
|
return BluebirdPromise.reject(new Exceptions.IdentityError(
|
|
"Missing user id or email address"));
|
|
|
|
return createAndSaveToken(userid, handler.challenge(),
|
|
vars.userDataStore);
|
|
})
|
|
.then((token: string) => {
|
|
const scheme = GetHeader(req, Constants.HEADER_X_FORWARDED_PROTO);
|
|
const host = GetHeader(req, Constants.HEADER_X_FORWARDED_HOST);
|
|
const link_url = util.format("%s://%s/#%s?token=%s", scheme, host,
|
|
handler.destinationPath(), token);
|
|
vars.logger.info(req, "Notification sent to user \"%s\"",
|
|
identity.userid);
|
|
return vars.notifier.notify(identity.email, handler.mailSubject(),
|
|
link_url);
|
|
})
|
|
.then(() => {
|
|
handler.preValidationResponse(req, res);
|
|
return BluebirdPromise.resolve();
|
|
})
|
|
.catch(Exceptions.IdentityError, (err: Error) => {
|
|
vars.logger.error(req, err.message);
|
|
handler.preValidationResponse(req, res);
|
|
return BluebirdPromise.resolve();
|
|
})
|
|
.catch(ErrorReplies.replyWithError401(req, res, vars.logger));
|
|
};
|
|
}
|