@webda/core
Version:
Expose API with Lambda
458 lines • 22.4 kB
JavaScript
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { suite, test } from "@testdeck/mocha";
import * as assert from "assert";
import { Authentication, WebdaError } from "...js";
import { WebdaTest } from "../test.js";
import { AuthenticationParameters } from "./authentication.js";
const validationUrl = /.*\/auth\/email\/callback\?email=([^&]+)&token=([^& ]+)(&user=([^ &]+))?/;
var userId;
let AuthenticationTest = class AuthenticationTest extends WebdaTest {
constructor() {
super(...arguments);
this.events = 0;
}
getUserStore() {
return this.authentication._userModel.store();
}
getIdentStore() {
return this.authentication._identModel.store();
}
async before() {
await super.before();
this.authentication = this.getService("Authentication");
this.userStore = this.getUserStore();
this.identStore = this.getIdentStore();
assert.notStrictEqual(this.userStore, undefined);
assert.notStrictEqual(this.identStore, undefined);
await this.userStore.__clean();
await this.identStore.__clean();
this.mailer = this.getService("DefinedMailer");
this.authentication.on("Authentication.Login", () => {
this.events++;
});
this.authentication.on("Authentication.Register", evt => {
this.events++;
// @ts-ignore
evt.user.test = "TESTOR";
});
this.mailer.sent = [];
}
async registerTest2(ctx) {
let executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
login: "Test2@Webda.io",
password: "testtest",
register: true
}, {
"Accept-Language": "en-GB,en;q=0.9,fr;q=0.8"
});
await ctx.newSession();
ctx.getExecutor().getParameters().email.postValidation = true;
await executor.execute(ctx);
}
async cov() {
this.authentication.addProvider("plop");
this.authentication.addProvider("plop");
this.authentication.addProvider("plop2");
let ctx = await this.newContext();
this.authentication._listAuthentications(ctx);
assert.strictEqual(ctx.getResponseBody(), JSON.stringify(["email", "plop", "plop2"]));
ctx.setPathParameters({ provider: "plop" });
this.authentication.getParameters().password.verifier = "VersionService";
this.authentication.computeParameters();
assert.strictEqual(await this.authentication.getPasswordRecoveryInfos("bouzouf"), undefined);
assert.strictEqual(this.authentication._passwordVerifier, this.getService("VersionService"));
let params = new AuthenticationParameters({});
assert.strictEqual(params.identModel, "Webda/Ident");
assert.strictEqual(params.userModel, "Webda/User");
assert.strictEqual(params.url, "/auth");
params = new AuthenticationParameters({
identModel: "id",
userModel: "us",
url: "/aaa"
});
assert.strictEqual(params.identModel, "id");
assert.strictEqual(params.userModel, "us");
assert.strictEqual(params.url, "/aaa");
this.authentication.getParameters().email = undefined;
assert.strictEqual(this.authentication.getUrl("./emails", ["POST"]), undefined);
let auth = new Authentication(this.webda, "auth", {
email: { mailer: "plop" }
});
assert.throws(() => auth.resolve(), /email authentication requires a Mailer service/);
}
async register() {
// By default service does not have postValidation enable
let ctx = await this.newContext();
this.events = 0;
// Should reject because it is login and not email
let executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
login: "test@Webda.io",
password: "testtest"
}, {
"Accept-Language": "en-GB,en;q=0.9,fr;q=0.8"
});
// User unknown without register parameter
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 404);
// Set register to true
executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
login: "test@Webda.io",
password: "testtest",
register: true
}, {
"Accept-Language": "en-GB,en;q=0.9,fr;q=0.8"
});
await ctx.newSession();
await executor.execute(ctx);
// Should not authentified as we need to check email
assert.strictEqual(ctx.getSession().identUsed, undefined);
// Email is sent
assert.strictEqual(this.mailer.sent.length, 1);
// Ident is created pending validation
let ident = await this.identStore.get("test@webda.io_email");
assert.strictEqual(ident, undefined);
// Not registered as postValidation is not set
ctx.getExecutor().getParameters().email.postValidation = true;
// With postValidation on the user will be create on first request
await this.registerTest2(ctx);
assert.strictEqual(this.events, 2); // Register + Login
userId = ctx.getSession().userId;
assert.notStrictEqual(ctx.getSession().userId, undefined);
assert.strictEqual(this.mailer.sent.length, 2);
let user = await this.userStore.get(ctx.getSession().userId);
assert.notStrictEqual(user, undefined);
assert.notStrictEqual(user.getPassword(), undefined);
assert.strictEqual(user.locale, "en");
assert.strictEqual(user.test, "TESTOR"); // Verify that the listener on Register has done something
// Now logout
executor = this.getExecutor(ctx, "test.webda.io", "DELETE", "/auth");
await executor.execute(ctx);
// Now validate first user
ctx.getExecutor().getParameters().email.postValidation = false;
assert.strictEqual(ctx.getSession().userId, undefined);
var match = this.mailer.sent[0].replacements.url.match(validationUrl);
assert.notStrictEqual(match, undefined);
assert.strictEqual(match[1], "test@webda.io");
executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
token: match[2],
password: "testtest",
login: match[1],
register: true,
add: "plop"
});
await executor.execute(ctx);
// Should create it with the data provided
assert.notStrictEqual(ctx.getSession().userId, undefined);
ident = await this.identStore.get(ctx.getSession().identUsed);
assert.strictEqual(ctx.getCurrentUserId(), ident.getUser());
// Email should be already validate
assert.notStrictEqual(ident._validation, undefined);
assert.strictEqual(this.mailer.sent.length, 2);
// Resend email
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/test2@webda.io/validate");
ctx.getSession().login(userId, "fake");
// Should be to soon to resend an email
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 429);
ident = await this.identStore.get("test2@webda.io_email");
ident._lastValidationEmail = 10;
await ident.save();
// Should be ok now to send an email
await executor.execute(ctx);
assert.strictEqual(this.mailer.sent.length, 3);
// Validate email for test2 now
match = this.mailer.sent[1].replacements.url.match(validationUrl);
assert.notStrictEqual(match, undefined);
assert.strictEqual(match[1], "test2@webda.io");
await ctx.newSession();
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/callback?email=" + match[1] + "&token=" + match[2]);
await executor.execute(ctx);
assert.strictEqual(ctx.statusCode, 302);
// Verify the skipEmailValidation parameter
this.events = 0;
await ctx.newSession();
executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
login: "test4@webda.io",
password: "testtest",
register: true
});
ctx.getExecutor().getParameters().email.postValidation = true;
ctx.getExecutor().getParameters().email.skipEmailValidation = true;
await executor.execute(ctx);
// No new email has been sent
assert.strictEqual(this.mailer.sent.length, 3);
assert.strictEqual(this.events, 2); // Register + Login
assert.notStrictEqual(ctx.getSession().userId, undefined);
// Register while logged-in should fail with 410
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 410);
}
async registerBadPassword() {
// By default a password of 8 is needed
var params = {
login: "testBad@Webda.io",
password: "test",
register: true
};
let ctx = await this.newContext(params);
let executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
login: "testBad@Webda.io",
register: true
}, {
"Accept-Language": "en-GB"
});
// Activate post validation
ctx.getExecutor().getParameters().email.postValidation = true;
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 400);
}
async me() {
let ctx = await this.newContext();
let executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/me");
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 404);
executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
login: "test5@webda.io",
password: "testtest",
register: true,
plop: "yep"
});
ctx.getExecutor().getParameters().email.postValidation = true;
await executor.execute(ctx);
// Get me on known user
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/me");
await executor.execute(ctx);
let user = JSON.parse(ctx.getResponseBody());
assert.strictEqual(user.plop, "yep");
assert.strictEqual(user.register, undefined);
assert.strictEqual(user.locale, "es-ES");
assert.notStrictEqual(user, undefined);
}
async login() {
let ctx = await this.newContext();
await this.registerTest2(ctx);
await ctx.newSession();
this.events = 0;
let executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
login: "test3@webda.io",
password: "testtest"
});
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 404);
assert.strictEqual(ctx.getSession().userId, undefined);
// As it has not been validate
ctx.getHttpContext().setBody({
login: "test2@webda.io",
password: "testtest"
});
ctx.reinit();
await ctx.newSession();
await executor.execute(ctx);
assert.strictEqual(this.events, 1); // Login
assert.notStrictEqual(ctx.getSession().userId, undefined);
// Verify ident type
let ident = await this.identStore.get(ctx.getSession().identUsed);
assert.strictEqual(ident._type, "email");
ctx.getHttpContext().setBody({
login: "test2@webda.io",
password: "bouzouf"
});
ctx.reinit();
await ctx.newSession();
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 403);
assert.strictEqual(ctx.getSession().userId, undefined);
assert.strictEqual(this.events, 1);
assert.strictEqual(await (await this.identStore.get("test2@webda.io_email"))._failedLogin, 1);
// Re log to reinit failedLogin
ctx.getHttpContext().setBody({
login: "test2@webda.io",
password: "testtest"
});
ctx.reinit();
await ctx.newSession();
await executor.execute(ctx);
assert.strictEqual(await (await this.identStore.get("test2@webda.io_email"))._failedLogin, 0);
}
async testPasswordRecovery() {
let tokenInfo;
let ctx = await this.newContext();
await this.registerTest2(ctx);
this.mailer.sent = [];
this.events = 0;
userId = ctx.getSession().userId;
await ctx.newSession();
tokenInfo = await this.authentication.getPasswordRecoveryInfos(userId, -10);
// Missing the body
let executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email/passwordRecovery", {
token: tokenInfo.token,
expire: 123,
password: "retesttest",
login: userId
});
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 403);
executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email/passwordRecovery", {
token: tokenInfo.token,
expire: tokenInfo.expire,
password: "retesttest",
login: "unknown"
});
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 403);
// Missing the body
ctx.getHttpContext().setBody({
token: tokenInfo.token,
expire: tokenInfo.expire,
password: "retesttest",
login: userId
});
ctx.reinit();
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 410);
tokenInfo = await this.authentication.getPasswordRecoveryInfos(userId);
// Missing the body
ctx.getHttpContext().setBody({ ...tokenInfo, login: userId, password: "a" });
ctx.reinit();
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 400);
// @ts-ignore
this.authentication._passwordVerifier = {
validate: async (p) => {
return p === "retesttest";
}
};
ctx.getHttpContext().setBody({ ...tokenInfo, login: userId, password: "anyotherpass" });
ctx.reinit();
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 400);
ctx.getHttpContext().setBody({ ...tokenInfo, login: userId, password: "retesttest" });
ctx.reinit();
await executor.execute(ctx);
// Should be update with password retest now
await ctx.newSession();
executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
login: "test2@webda.io",
password: "retesttest"
});
await executor.execute(ctx);
assert.notStrictEqual(ctx.getSession().userId, undefined);
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/test2@webda.io/recover");
await executor.execute(ctx);
assert.strictEqual(this.mailer.sent.length, 1);
assert.strictEqual(this.mailer.sent[0].to, "test2@webda.io");
assert.notStrictEqual(this.mailer.sent[0].replacements.infos, undefined);
assert.notStrictEqual(this.mailer.sent[0].replacements.infos.expire, undefined);
assert.notStrictEqual(this.mailer.sent[0].replacements.infos.token, undefined);
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 429);
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/test66@webda.io/recover");
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 404);
}
async addEmailToAccount() {
// Log in as test2
let ctx = await this.newContext();
await this.registerTest2(ctx);
this.mailer.sent = [];
let executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/newtest@webda.io/validate", {
login: "test2@webda.io",
password: "retesttest"
});
await executor.execute(ctx);
let ident = await this.identStore.get("newtest@webda.io_email");
assert.notStrictEqual(ident, undefined);
assert.strictEqual(ident._validation, undefined);
userId = ctx.getCurrentUserId();
var match = this.mailer.sent[0].replacements.url.match(validationUrl);
assert.notStrictEqual(match, undefined);
assert.strictEqual(match[1], "newtest@webda.io");
// Send another one on newtest2
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/newtest2@webda.io/validate", {
login: "test2@webda.io",
password: "retesttest"
});
await executor.execute(ctx);
var match2 = this.mailer.sent[1].replacements.url.match(validationUrl);
assert.notStrictEqual(match2, undefined);
assert.strictEqual(match2[1], "newtest2@webda.io");
// Try to validate with wrong email
ctx.getSession().userId = "anotheruser";
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/callback?email=" + match[1] + "&user=" + match[4]);
await assert.strictEqual(executor, undefined);
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/callback?email=" + match[1] + "&token=" + match[2] + "&user=" + match[4]);
await executor.execute(ctx);
assert.strictEqual(ctx.statusCode, 302);
assert.strictEqual(ctx.getResponseHeaders().Location, "/login-error?reason=badUser");
// Right user
ctx.getSession().userId = userId;
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/callback?email=" + match[1] + "&token=bouzouf" + "&user=" + match[4]);
await executor.execute(ctx);
assert.strictEqual(ctx.statusCode, 302);
assert.strictEqual(ctx.getResponseHeaders().Location, "/login-error?reason=badToken");
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/callback?email=" + match[1] + "&token=" + match[2] + "&user=" + match[4]);
await executor.execute(ctx);
assert.strictEqual(ctx.statusCode, 302);
assert.strictEqual(ctx.getResponseHeaders().Location, "https://webda.io/user.html?validation=email");
// Check ident is added to the user
ident = await this.identStore.get("newtest@webda.io_email");
assert.notStrictEqual(ident._validation, undefined);
// Verify exception if same user try to revalidate
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/newtest@webda.io/validate");
await assert.rejects(() => executor.execute(ctx), (err) => err.getResponseCode() === 412);
// Verify exception if different user try to validate
ctx.getSession().userId = "bouzouf";
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/newtest@webda.io/validate");
await assert.rejects(() => executor.execute(ctx), WebdaError.Conflict);
// Check register on validated email does not work
await ctx.newSession();
executor = this.getExecutor(ctx, "test.webda.io", "POST", "/auth/email", {
login: "newtest@webda.io",
password: "testtest",
register: true
});
await assert.rejects(() => executor.execute(ctx), WebdaError.Conflict);
// Validation with no user
await ctx.newSession();
executor = this.getExecutor(ctx, "test.webda.io", "GET", "/auth/email/callback?email=" + match2[1] + "&token=" + match2[2] + "&user=" + match2[4]);
await executor.execute(ctx);
assert.strictEqual(ctx.statusCode, 302);
assert.strictEqual(ctx.getResponseHeaders().Location, "https://webda.io/user.html?validation=email");
await this.identStore.delete("newtest2@webda.io_email", undefined, undefined, true);
await executor.execute(ctx);
assert.ok(await this.identStore.exists("newtest2@webda.io_email"));
}
async multipleCreate() {
await this.authentication.createUserWithIdent("email", "test@test.com");
await assert.rejects(() => this.authentication.createUserWithIdent("email", "test@test.com"), /Ident is already known/);
}
async redirectEmailRegister() {
let token = await this.authentication.generateEmailValidationToken(undefined, "test@webda.io");
let ctx = await this.newContext();
await this.execute(ctx, "test.webda.io", "GET", `/auth/email/callback?email=test@webda.io&token=${token}`);
assert.strictEqual(ctx.statusCode, 302);
assert.strictEqual(ctx.getResponseHeaders().Location, `https://webda.io/register.html?token=${token}&email=test@webda.io`);
}
};
__decorate([
test
], AuthenticationTest.prototype, "cov", null);
__decorate([
test("register")
], AuthenticationTest.prototype, "register", null);
__decorate([
test("register - bad password")
], AuthenticationTest.prototype, "registerBadPassword", null);
__decorate([
test("/me")
], AuthenticationTest.prototype, "me", null);
__decorate([
test("login")
], AuthenticationTest.prototype, "login", null);
__decorate([
test("passwordRecovery")
], AuthenticationTest.prototype, "testPasswordRecovery", null);
__decorate([
test("add email to existing account")
], AuthenticationTest.prototype, "addEmailToAccount", null);
__decorate([
test
], AuthenticationTest.prototype, "multipleCreate", null);
__decorate([
test
], AuthenticationTest.prototype, "redirectEmailRegister", null);
AuthenticationTest = __decorate([
suite
], AuthenticationTest);
//# sourceMappingURL=authentication.spec.js.map