mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
Implement Keep me logged in feature.
This commit is contained in:
parent
059c5936f5
commit
4c3b5cfbb3
|
@ -6,7 +6,8 @@ import Util = require("util");
|
||||||
import UserMessages = require("../../../../shared/UserMessages");
|
import UserMessages = require("../../../../shared/UserMessages");
|
||||||
|
|
||||||
export function validate(username: string, password: string,
|
export function validate(username: string, password: string,
|
||||||
redirectUrl: string, $: JQueryStatic): BluebirdPromise<string> {
|
keepMeLoggedIn: boolean, redirectUrl: string, $: JQueryStatic)
|
||||||
|
: BluebirdPromise<string> {
|
||||||
return new BluebirdPromise<string>(function (resolve, reject) {
|
return new BluebirdPromise<string>(function (resolve, reject) {
|
||||||
let url: string;
|
let url: string;
|
||||||
if (redirectUrl != undefined) {
|
if (redirectUrl != undefined) {
|
||||||
|
@ -17,13 +18,19 @@ export function validate(username: string, password: string,
|
||||||
url = Util.format("%s", Endpoints.FIRST_FACTOR_POST);
|
url = Util.format("%s", Endpoints.FIRST_FACTOR_POST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const data: any = {
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (keepMeLoggedIn) {
|
||||||
|
data.keepMeLoggedIn = "true";
|
||||||
|
}
|
||||||
|
|
||||||
$.ajax({
|
$.ajax({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
url: url,
|
url: url,
|
||||||
data: {
|
data: data
|
||||||
username: username,
|
|
||||||
password: password,
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.done(function (body: any) {
|
.done(function (body: any) {
|
||||||
if (body && body.error) {
|
if (body && body.error) {
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
export const USERNAME_FIELD_ID = "#username";
|
export const USERNAME_FIELD_ID = "#username";
|
||||||
export const PASSWORD_FIELD_ID = "#password";
|
export const PASSWORD_FIELD_ID = "#password";
|
||||||
export const SIGN_IN_BUTTON_ID = "#signin";
|
export const SIGN_IN_BUTTON_ID = "#signin";
|
||||||
|
export const KEEP_ME_LOGGED_IN_ID = "#keep_me_logged_in";
|
||||||
|
|
|
@ -15,13 +15,14 @@ export default function (window: Window, $: JQueryStatic,
|
||||||
function onFormSubmitted() {
|
function onFormSubmitted() {
|
||||||
const username: string = $(UISelectors.USERNAME_FIELD_ID).val() as string;
|
const username: string = $(UISelectors.USERNAME_FIELD_ID).val() as string;
|
||||||
const password: string = $(UISelectors.PASSWORD_FIELD_ID).val() as string;
|
const password: string = $(UISelectors.PASSWORD_FIELD_ID).val() as string;
|
||||||
|
const keepMeLoggedIn: boolean = $(UISelectors.KEEP_ME_LOGGED_IN_ID).is(":checked");
|
||||||
|
|
||||||
$("form").css("opacity", 0.5);
|
$("form").css("opacity", 0.5);
|
||||||
$("input,button").attr("disabled", "true");
|
$("input,button").attr("disabled", "true");
|
||||||
$(UISelectors.SIGN_IN_BUTTON_ID).text("Please wait...");
|
$(UISelectors.SIGN_IN_BUTTON_ID).text("Please wait...");
|
||||||
|
|
||||||
const redirectUrl = QueryParametersRetriever.get(Constants.REDIRECT_QUERY_PARAM);
|
const redirectUrl = QueryParametersRetriever.get(Constants.REDIRECT_QUERY_PARAM);
|
||||||
firstFactorValidator.validate(username, password, redirectUrl, $)
|
firstFactorValidator.validate(username, password, keepMeLoggedIn, redirectUrl, $)
|
||||||
.then(onFirstFactorSuccess, onFirstFactorFailure);
|
.then(onFirstFactorSuccess, onFirstFactorFailure);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,8 @@ describe("test FirstFactorValidator", function () {
|
||||||
const jqueryMock = JQueryMock.JQueryMock();
|
const jqueryMock = JQueryMock.JQueryMock();
|
||||||
jqueryMock.jquery.ajax.returns(postPromise);
|
jqueryMock.jquery.ajax.returns(postPromise);
|
||||||
|
|
||||||
return FirstFactorValidator.validate("username", "password", "http://redirect", jqueryMock.jquery as any);
|
return FirstFactorValidator.validate("username", "password", false,
|
||||||
|
"http://redirect", jqueryMock.jquery as any);
|
||||||
});
|
});
|
||||||
|
|
||||||
function should_fail_first_factor_validation(errorMessage: string) {
|
function should_fail_first_factor_validation(errorMessage: string) {
|
||||||
|
@ -27,7 +28,8 @@ describe("test FirstFactorValidator", function () {
|
||||||
const jqueryMock = JQueryMock.JQueryMock();
|
const jqueryMock = JQueryMock.JQueryMock();
|
||||||
jqueryMock.jquery.ajax.returns(postPromise);
|
jqueryMock.jquery.ajax.returns(postPromise);
|
||||||
|
|
||||||
return FirstFactorValidator.validate("username", "password", "http://redirect", jqueryMock.jquery as any)
|
return FirstFactorValidator.validate("username", "password", false,
|
||||||
|
"http://redirect", jqueryMock.jquery as any)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return BluebirdPromise.reject(new Error("First factor validation successfully finished while it should have not."));
|
return BluebirdPromise.reject(new Error("First factor validation successfully finished while it should have not."));
|
||||||
}, function (err: Error) {
|
}, function (err: Error) {
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
# Authelia minimal configuration #
|
# Authelia minimal configuration #
|
||||||
###############################################################
|
###############################################################
|
||||||
|
|
||||||
|
logs_level: debug
|
||||||
|
|
||||||
authentication_backend:
|
authentication_backend:
|
||||||
file:
|
file:
|
||||||
path: /etc/authelia/users_database.yml
|
path: /etc/authelia/users_database.yml
|
||||||
|
@ -9,6 +11,7 @@ authentication_backend:
|
||||||
session:
|
session:
|
||||||
secret: unsecure_session_secret
|
secret: unsecure_session_secret
|
||||||
domain: example.com
|
domain: example.com
|
||||||
|
inactivity: 30000
|
||||||
|
|
||||||
# Configuration of the storage backend used to store data and secrets. i.e. totp data
|
# Configuration of the storage backend used to store data and secrets. i.e. totp data
|
||||||
storage:
|
storage:
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { AuthenticationSession } from "../../types/AuthenticationSession";
|
||||||
import { IRequestLogger } from "./logging/IRequestLogger";
|
import { IRequestLogger } from "./logging/IRequestLogger";
|
||||||
|
|
||||||
const INITIAL_AUTHENTICATION_SESSION: AuthenticationSession = {
|
const INITIAL_AUTHENTICATION_SESSION: AuthenticationSession = {
|
||||||
|
keep_me_logged_in: false,
|
||||||
first_factor: false,
|
first_factor: false,
|
||||||
second_factor: false,
|
second_factor: false,
|
||||||
last_activity_datetime: undefined,
|
last_activity_datetime: undefined,
|
||||||
|
|
|
@ -43,6 +43,7 @@ describe("routes/firstfactor/post", function () {
|
||||||
redirect: "http://redirect.url"
|
redirect: "http://redirect.url"
|
||||||
},
|
},
|
||||||
session: {
|
session: {
|
||||||
|
cookie: {}
|
||||||
},
|
},
|
||||||
headers: {
|
headers: {
|
||||||
host: "home.example.com"
|
host: "home.example.com"
|
||||||
|
@ -66,6 +67,26 @@ describe("routes/firstfactor/post", function () {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("keep me logged in", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mocks.usersDatabase.checkUserPasswordStub.withArgs("username", "password")
|
||||||
|
.returns(BluebirdPromise.resolve({
|
||||||
|
emails: emails,
|
||||||
|
groups: groups
|
||||||
|
}));
|
||||||
|
req.body.keepMeLoggedIn = "true";
|
||||||
|
return FirstFactorPost.default(vars)(req as any, res as any);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set keep_me_logged_in session variable to true", function () {
|
||||||
|
Assert.equal(authSession.keep_me_logged_in, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set cookie maxAge to one year", function () {
|
||||||
|
Assert.equal(req.session.cookie.maxAge, 365 * 24 * 60 * 60 * 1000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it("should retrieve email from LDAP", function () {
|
it("should retrieve email from LDAP", function () {
|
||||||
mocks.usersDatabase.checkUserPasswordStub.withArgs("username", "password")
|
mocks.usersDatabase.checkUserPasswordStub.withArgs("username", "password")
|
||||||
.returns(BluebirdPromise.resolve([{ mail: ["test@example.com"] }]));
|
.returns(BluebirdPromise.resolve([{ mail: ["test@example.com"] }]));
|
||||||
|
|
|
@ -21,8 +21,16 @@ export default function (vars: ServerVariables) {
|
||||||
: BluebirdPromise<void> {
|
: BluebirdPromise<void> {
|
||||||
const username: string = req.body.username;
|
const username: string = req.body.username;
|
||||||
const password: string = req.body.password;
|
const password: string = req.body.password;
|
||||||
|
const keepMeLoggedIn: boolean = req.body.keepMeLoggedIn &&
|
||||||
|
req.body.keepMeLoggedIn === "true";
|
||||||
let authSession: AuthenticationSession;
|
let authSession: AuthenticationSession;
|
||||||
|
|
||||||
|
if (keepMeLoggedIn) {
|
||||||
|
// Stay connected for 1 year.
|
||||||
|
vars.logger.debug(req, "User requested to stay logged in for one year.");
|
||||||
|
req.session.cookie.maxAge = 365 * 24 * 60 * 60 * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
return BluebirdPromise.resolve()
|
return BluebirdPromise.resolve()
|
||||||
.then(function () {
|
.then(function () {
|
||||||
if (!username || !password) {
|
if (!username || !password) {
|
||||||
|
@ -41,6 +49,7 @@ export default function (vars: ServerVariables) {
|
||||||
"LDAP binding successful. Retrieved information about user are %s",
|
"LDAP binding successful. Retrieved information about user are %s",
|
||||||
JSON.stringify(groupsAndEmails));
|
JSON.stringify(groupsAndEmails));
|
||||||
authSession.userid = username;
|
authSession.userid = username;
|
||||||
|
authSession.keep_me_logged_in = keepMeLoggedIn;
|
||||||
authSession.first_factor = true;
|
authSession.first_factor = true;
|
||||||
const redirectUrl = req.query[Constants.REDIRECT_QUERY_PARAM] !== "undefined"
|
const redirectUrl = req.query[Constants.REDIRECT_QUERY_PARAM] !== "undefined"
|
||||||
// Fuck, don't know why it is a string!
|
// Fuck, don't know why it is a string!
|
||||||
|
|
|
@ -80,6 +80,7 @@ describe("routes/verify/get", function () {
|
||||||
describe("given different cases of session", function () {
|
describe("given different cases of session", function () {
|
||||||
it("should not be authenticated when second factor is missing", function () {
|
it("should not be authenticated when second factor is missing", function () {
|
||||||
return test_non_authenticated_401({
|
return test_non_authenticated_401({
|
||||||
|
keep_me_logged_in: false,
|
||||||
userid: "user",
|
userid: "user",
|
||||||
first_factor: true,
|
first_factor: true,
|
||||||
second_factor: false,
|
second_factor: false,
|
||||||
|
@ -91,6 +92,7 @@ describe("routes/verify/get", function () {
|
||||||
|
|
||||||
it("should not be authenticated when first factor is missing", function () {
|
it("should not be authenticated when first factor is missing", function () {
|
||||||
return test_non_authenticated_401({
|
return test_non_authenticated_401({
|
||||||
|
keep_me_logged_in: false,
|
||||||
userid: "user",
|
userid: "user",
|
||||||
first_factor: false,
|
first_factor: false,
|
||||||
second_factor: true,
|
second_factor: true,
|
||||||
|
@ -102,6 +104,7 @@ describe("routes/verify/get", function () {
|
||||||
|
|
||||||
it("should not be authenticated when userid is missing", function () {
|
it("should not be authenticated when userid is missing", function () {
|
||||||
return test_non_authenticated_401({
|
return test_non_authenticated_401({
|
||||||
|
keep_me_logged_in: false,
|
||||||
userid: undefined,
|
userid: undefined,
|
||||||
first_factor: true,
|
first_factor: true,
|
||||||
second_factor: false,
|
second_factor: false,
|
||||||
|
@ -113,6 +116,7 @@ describe("routes/verify/get", function () {
|
||||||
|
|
||||||
it("should not be authenticated when first and second factor are missing", function () {
|
it("should not be authenticated when first and second factor are missing", function () {
|
||||||
return test_non_authenticated_401({
|
return test_non_authenticated_401({
|
||||||
|
keep_me_logged_in: false,
|
||||||
userid: "user",
|
userid: "user",
|
||||||
first_factor: false,
|
first_factor: false,
|
||||||
second_factor: false,
|
second_factor: false,
|
||||||
|
@ -134,6 +138,7 @@ describe("routes/verify/get", function () {
|
||||||
mocks.accessController.isAccessAllowedMock.returns(false);
|
mocks.accessController.isAccessAllowedMock.returns(false);
|
||||||
|
|
||||||
return test_unauthorized_403({
|
return test_unauthorized_403({
|
||||||
|
keep_me_logged_in: false,
|
||||||
first_factor: true,
|
first_factor: true,
|
||||||
second_factor: true,
|
second_factor: true,
|
||||||
userid: "user",
|
userid: "user",
|
||||||
|
|
|
@ -25,7 +25,7 @@ function verify_inactivity(req: Express.Request,
|
||||||
: BluebirdPromise<void> {
|
: BluebirdPromise<void> {
|
||||||
|
|
||||||
// If inactivity is not specified, then inactivity timeout does not apply
|
// If inactivity is not specified, then inactivity timeout does not apply
|
||||||
if (!configuration.session.inactivity) {
|
if (!configuration.session.inactivity || authSession.keep_me_logged_in) {
|
||||||
return BluebirdPromise.resolve();
|
return BluebirdPromise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ export interface AuthenticationSession {
|
||||||
userid: string;
|
userid: string;
|
||||||
first_factor: boolean;
|
first_factor: boolean;
|
||||||
second_factor: boolean;
|
second_factor: boolean;
|
||||||
|
keep_me_logged_in: boolean;
|
||||||
last_activity_datetime: number;
|
last_activity_datetime: number;
|
||||||
identity_check?: {
|
identity_check?: {
|
||||||
challenge: string;
|
challenge: string;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user