1
0
mirror of https://github.com/0rangebananaspy/authelia.git synced 2024-09-14 22:47:21 +07:00
authelia/server/src/lib/IdentityCheckMiddleware.ts
Clement Michaud 97bfafb6eb [BREAKING] Flatten the ACL rules to enable some use cases.
With previous configuration format rules were not ordered between groups and
thus not predictable. Also in some cases `any` must have been a higher
precedence than `groups`. Flattening the rules let the user apply whatever
policy he can think of.

When several rules match the (subject, domain, resource), the first one is
applied.

NOTE: This commit changed the format for declaring ACLs. Be sure to update
your configuration file before upgrading.
2018-11-17 18:08:29 +01:00

139 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 fs = require("fs");
import ejs = require("ejs");
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 Identity = require("../../types/Identity");
import { IdentityValidationDocument }
from "./storage/IdentityValidationDocument";
const filePath = __dirname + "/../resources/email-template.ejs";
const email_template = fs.readFileSync(filePath, "utf8");
function createAndSaveToken(userid: string, challenge: string,
userDataStore: IUserDataStore): BluebirdPromise<string> {
const five_minutes = 4 * 60 * 1000;
const token = randomstring.generate({ length: 64 });
const that = this;
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.get(pre_validation_endpoint,
get_start_validation(handler, post_validation_endpoint, vars));
app.get(post_validation_endpoint,
get_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 get_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.identity_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.replyWithError401(req, res, vars.logger));
};
}
export function get_start_validation(handler: IdentityValidable,
postValidationEndpoint: string,
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) => {
const host = req.get("Host");
const link_url = util.format("https://%s%s?identity_token=%s", host,
postValidationEndpoint, 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) => {
handler.preValidationResponse(req, res);
return BluebirdPromise.resolve();
})
.catch(ErrorReplies.replyWithError401(req, res, vars.logger));
};
}