Less restrictive email handler - replace gmail with generic

pull/181/head
Dylan Smith 2017-10-25 19:28:56 +11:00
parent 5570ac3d84
commit c62b85e37d
19 changed files with 82 additions and 64 deletions

View File

@ -203,11 +203,13 @@ notifier:
# filesystem: # filesystem:
# filename: /tmp/authelia/notification.txt # filename: /tmp/authelia/notification.txt
# Use your gmail account to send the notifications. You can use an app password. # Use your email account to send the notifications. You can use an app password.
# gmail: # List of valid services can be found here: https://nodemailer.com/smtp/well-known/
# email:
# username: user@example.com # username: user@example.com
# password: yourpassword # password: yourpassword
# sender: admin@example.com # sender: admin@example.com
# service: gmail
# Use a SMTP server for sending notifications # Use a SMTP server for sending notifications
smtp: smtp:

View File

@ -178,11 +178,13 @@ storage:
# registration or a TOTP registration. # registration or a TOTP registration.
# Use only an available configuration: filesystem, gmail # Use only an available configuration: filesystem, gmail
notifier: notifier:
# Use your gmail account to send the notifications. You can use an app password. # Use your email account to send the notifications. You can use an app password.
# gmail: # List of valid services can be found here: https://nodemailer.com/smtp/well-known/
# email:
# username: user@example.com # username: user@example.com
# password: yourpassword # password: yourpassword
# sender: admin@example.com # sender: admin@example.com
# service: gmail
# Use a SMTP server for sending notifications # Use a SMTP server for sending notifications
smtp: smtp:

View File

@ -71,15 +71,15 @@ export default class Server {
displayableUserConfiguration.ldap.password = STARS; displayableUserConfiguration.ldap.password = STARS;
displayableUserConfiguration.session.secret = STARS; displayableUserConfiguration.session.secret = STARS;
if (displayableUserConfiguration.notifier && displayableUserConfiguration.notifier.gmail) if (displayableUserConfiguration.notifier && displayableUserConfiguration.notifier.email)
displayableUserConfiguration.notifier.gmail.password = STARS; displayableUserConfiguration.notifier.email.password = STARS;
if (displayableUserConfiguration.notifier && displayableUserConfiguration.notifier.smtp) if (displayableUserConfiguration.notifier && displayableUserConfiguration.notifier.smtp)
displayableUserConfiguration.notifier.smtp.password = STARS; displayableUserConfiguration.notifier.smtp.password = STARS;
displayableAppConfiguration.ldap.password = STARS; displayableAppConfiguration.ldap.password = STARS;
displayableAppConfiguration.session.secret = STARS; displayableAppConfiguration.session.secret = STARS;
if (displayableAppConfiguration.notifier && displayableAppConfiguration.notifier.gmail) if (displayableAppConfiguration.notifier && displayableAppConfiguration.notifier.email)
displayableAppConfiguration.notifier.gmail.password = STARS; displayableAppConfiguration.notifier.email.password = STARS;
if (displayableAppConfiguration.notifier && displayableAppConfiguration.notifier.smtp) if (displayableAppConfiguration.notifier && displayableAppConfiguration.notifier.smtp)
displayableAppConfiguration.notifier.smtp.password = STARS; displayableAppConfiguration.notifier.smtp.password = STARS;

View File

@ -66,10 +66,11 @@ interface SessionCookieConfiguration {
redis?: SessionRedisOptions; redis?: SessionRedisOptions;
} }
export interface GmailNotifierConfiguration { export interface EmailNotifierConfiguration {
username: string; username: string;
password: string; password: string;
sender: string; sender: string;
service: string;
} }
export interface SmtpNotifierConfiguration { export interface SmtpNotifierConfiguration {
@ -86,7 +87,7 @@ export interface FileSystemNotifierConfiguration {
} }
export interface NotifierConfiguration { export interface NotifierConfiguration {
gmail?: GmailNotifierConfiguration; email?: EmailNotifierConfiguration;
smtp?: SmtpNotifierConfiguration; smtp?: SmtpNotifierConfiguration;
filesystem?: FileSystemNotifierConfiguration; filesystem?: FileSystemNotifierConfiguration;
} }

View File

@ -54,19 +54,19 @@ function validateStorage(storage: any) {
} }
function validateNotifier(notifier: NotifierConfiguration) { function validateNotifier(notifier: NotifierConfiguration) {
const ERROR = "Notifier must be either 'filesystem', 'gmail' or 'smtp'"; const ERROR = "Notifier must be either 'filesystem', 'email' or 'smtp'";
if (!notifier) if (!notifier)
return []; return [];
const errors = validateUnknownKeys("notifier", notifier, ["filesystem", "gmail", "smtp"]); const errors = validateUnknownKeys("notifier", notifier, ["filesystem", "email", "smtp"]);
if (errors.length > 0) if (errors.length > 0)
return errors; return errors;
if (notifier && notifier.filesystem && notifier.gmail && notifier.smtp) if (notifier && notifier.filesystem && notifier.email && notifier.smtp)
return [ERROR]; return [ERROR];
if (notifier && !notifier.filesystem && !notifier.gmail && !notifier.smtp) if (notifier && !notifier.filesystem && !notifier.email && !notifier.smtp)
return [ERROR]; return [ERROR];
return []; return [];

View File

@ -2,14 +2,14 @@
import * as BluebirdPromise from "bluebird"; import * as BluebirdPromise from "bluebird";
import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier"; import { AbstractEmailNotifier } from "../notifiers/AbstractEmailNotifier";
import { GmailNotifierConfiguration } from "../configuration/Configuration"; import { EmailNotifierConfiguration } from "../configuration/Configuration";
import { IMailSender } from "./IMailSender"; import { IMailSender } from "./IMailSender";
export class GMailNotifier extends AbstractEmailNotifier { export class EMailNotifier extends AbstractEmailNotifier {
private mailSender: IMailSender; private mailSender: IMailSender;
private sender: string; private sender: string;
constructor(options: GmailNotifierConfiguration, mailSender: IMailSender) { constructor(options: EmailNotifierConfiguration, mailSender: IMailSender) {
super(); super();
this.mailSender = mailSender; this.mailSender = mailSender;
this.sender = options.sender; this.sender = options.sender;

View File

@ -1,7 +1,7 @@
import { IMailSender } from "./IMailSender"; import { IMailSender } from "./IMailSender";
import { SmtpNotifierConfiguration, GmailNotifierConfiguration } from "../configuration/Configuration"; import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/Configuration";
export interface IMailSenderBuilder { export interface IMailSenderBuilder {
buildGmail(options: GmailNotifierConfiguration): IMailSender; buildEmail(options: EmailNotifierConfiguration): IMailSender;
buildSmtp(options: SmtpNotifierConfiguration): IMailSender; buildSmtp(options: SmtpNotifierConfiguration): IMailSender;
} }

View File

@ -3,7 +3,7 @@ import { IMailSenderBuilder } from "./IMailSenderBuilder";
import { MailSender } from "./MailSender"; import { MailSender } from "./MailSender";
import Nodemailer = require("nodemailer"); import Nodemailer = require("nodemailer");
import NodemailerSmtpTransport = require("nodemailer-smtp-transport"); import NodemailerSmtpTransport = require("nodemailer-smtp-transport");
import { SmtpNotifierConfiguration, GmailNotifierConfiguration } from "../configuration/Configuration"; import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../configuration/Configuration";
export class MailSenderBuilder implements IMailSenderBuilder { export class MailSenderBuilder implements IMailSenderBuilder {
private nodemailer: typeof Nodemailer; private nodemailer: typeof Nodemailer;
@ -12,15 +12,15 @@ export class MailSenderBuilder implements IMailSenderBuilder {
this.nodemailer = nodemailer; this.nodemailer = nodemailer;
} }
buildGmail(options: GmailNotifierConfiguration): IMailSender { buildEmail(options: EmailNotifierConfiguration): IMailSender {
const gmailOptions = { const emailOptions = {
service: "gmail", service: options.service,
auth: { auth: {
user: options.username, user: options.username,
pass: options.password pass: options.password
} }
}; };
return new MailSender(gmailOptions, this.nodemailer); return new MailSender(emailOptions, this.nodemailer);
} }
buildSmtp(options: SmtpNotifierConfiguration): IMailSender { buildSmtp(options: SmtpNotifierConfiguration): IMailSender {

View File

@ -4,16 +4,16 @@ import Nodemailer = require("nodemailer");
import { INotifier } from "./INotifier"; import { INotifier } from "./INotifier";
import { FileSystemNotifier } from "./FileSystemNotifier"; import { FileSystemNotifier } from "./FileSystemNotifier";
import { GMailNotifier } from "./GMailNotifier"; import { EMailNotifier } from "./EMailNotifier";
import { SmtpNotifier } from "./SmtpNotifier"; import { SmtpNotifier } from "./SmtpNotifier";
import { IMailSender } from "./IMailSender"; import { IMailSender } from "./IMailSender";
import { IMailSenderBuilder } from "./IMailSenderBuilder"; import { IMailSenderBuilder } from "./IMailSenderBuilder";
export class NotifierFactory { export class NotifierFactory {
static build(options: NotifierConfiguration, mailSenderBuilder: IMailSenderBuilder): INotifier { static build(options: NotifierConfiguration, mailSenderBuilder: IMailSenderBuilder): INotifier {
if ("gmail" in options) { if ("email" in options) {
const mailSender = mailSenderBuilder.buildGmail(options.gmail); const mailSender = mailSenderBuilder.buildEmail(options.email);
return new GMailNotifier(options.gmail, mailSender); return new EMailNotifier(options.email, mailSender);
} }
else if ("smtp" in options) { else if ("smtp" in options) {
const mailSender = mailSenderBuilder.buildSmtp(options.smtp); const mailSender = mailSenderBuilder.buildSmtp(options.smtp);

View File

@ -53,10 +53,11 @@ describe("test server configuration", function () {
base_dn: "dc=example,dc=com" base_dn: "dc=example,dc=com"
}, },
notifier: { notifier: {
gmail: { email: {
username: "user@example.com", username: "user@example.com",
password: "password", password: "password",
sender: "test@authelia.com" sender: "test@authelia.com",
service: "gmail"
} }
}, },
regulation: { regulation: {

View File

@ -34,10 +34,11 @@ describe("test config parser", function () {
}, },
logs_level: "debug", logs_level: "debug",
notifier: { notifier: {
gmail: { email: {
username: "user", username: "user",
password: "password", password: "password",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
} }
} }
}; };
@ -83,18 +84,20 @@ describe("test config parser", function () {
it("should get the notifier config", function () { it("should get the notifier config", function () {
const userConfig = buildYamlConfig(); const userConfig = buildYamlConfig();
userConfig.notifier = { userConfig.notifier = {
gmail: { email: {
username: "user", username: "user",
password: "pass", password: "pass",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
} }
}; };
const config = ConfigurationParser.parse(userConfig); const config = ConfigurationParser.parse(userConfig);
Assert.deepEqual(config.notifier, { Assert.deepEqual(config.notifier, {
gmail: { email: {
username: "user", username: "user",
password: "pass", password: "pass",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
} }
}); });
}); });

View File

@ -31,10 +31,11 @@ describe("test ldap configuration adaptation", function () {
}, },
logs_level: "debug", logs_level: "debug",
notifier: { notifier: {
gmail: { email: {
username: "user", username: "user",
password: "password", password: "password",
sender: "admin@example.com" sender: "admin@example.com",
service: "email"
} }
} }
}; };

View File

@ -28,7 +28,7 @@ describe("test validator", function () {
"data.regulation should have required property 'max_retries'", "data.regulation should have required property 'max_retries'",
"data.session should have required property 'secret'", "data.session should have required property 'secret'",
"Storage must be either 'local' or 'mongo'", "Storage must be either 'local' or 'mongo'",
"Notifier must be either 'filesystem', 'gmail' or 'smtp'" "Notifier must be either 'filesystem', 'email' or 'smtp'"
]); ]);
Assert.deepStrictEqual(Validator.isValid({ Assert.deepStrictEqual(Validator.isValid({
@ -67,10 +67,11 @@ describe("test validator", function () {
user: "user" user: "user"
}, },
notifier: { notifier: {
gmail: { email: {
username: "user@gmail.com", username: "user@gmail.com",
password: "pass", password: "pass",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
} }
}, },
regulation: { regulation: {

View File

@ -3,19 +3,19 @@ import BluebirdPromise = require("bluebird");
import Nodemailer = require("nodemailer"); import Nodemailer = require("nodemailer");
import Sinon = require("sinon"); import Sinon = require("sinon");
import { IMailSender } from "../../../src/lib/notifiers/IMailSender"; import { IMailSender } from "../../../src/lib/notifiers/IMailSender";
import { SmtpNotifierConfiguration, GmailNotifierConfiguration } from "../../../src/lib/configuration/Configuration"; import { SmtpNotifierConfiguration, EmailNotifierConfiguration } from "../../../src/lib/configuration/Configuration";
export class MailSenderBuilderStub implements IMailSenderBuilder { export class MailSenderBuilderStub implements IMailSenderBuilder {
buildGmailStub: Sinon.SinonStub; buildEmailStub: Sinon.SinonStub;
buildSmtpStub: Sinon.SinonStub; buildSmtpStub: Sinon.SinonStub;
constructor() { constructor() {
this.buildGmailStub = Sinon.stub(); this.buildEmailStub = Sinon.stub();
this.buildSmtpStub = Sinon.stub(); this.buildSmtpStub = Sinon.stub();
} }
buildGmail(options: GmailNotifierConfiguration): IMailSender { buildEmail(options: EmailNotifierConfiguration): IMailSender {
return this.buildGmailStub(options); return this.buildEmailStub(options);
} }
buildSmtp(options: SmtpNotifierConfiguration): IMailSender { buildSmtp(options: SmtpNotifierConfiguration): IMailSender {

View File

@ -3,20 +3,21 @@ import * as Assert from "assert";
import BluebirdPromise = require("bluebird"); import BluebirdPromise = require("bluebird");
import { MailSenderStub } from "../mocks/notifiers/MailSenderStub"; import { MailSenderStub } from "../mocks/notifiers/MailSenderStub";
import GMailNotifier = require("../../src/lib/notifiers/GMailNotifier"); import EMailNotifier = require("../../src/lib/notifiers/EMailNotifier");
describe("test gmail notifier", function () { describe("test email notifier", function () {
it("should send an email to given user", function () { it("should send an email to given user", function () {
const mailSender = new MailSenderStub(); const mailSender = new MailSenderStub();
const options = { const options = {
username: "user_gmail", username: "user_gmail",
password: "pass_gmail", password: "pass_gmail",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
}; };
mailSender.sendStub.returns(BluebirdPromise.resolve()); mailSender.sendStub.returns(BluebirdPromise.resolve());
const sender = new GMailNotifier.GMailNotifier(options, mailSender); const sender = new EMailNotifier.EMailNotifier(options, mailSender);
const subject = "subject"; const subject = "subject";
const url = "http://test.com"; const url = "http://test.com";
@ -33,11 +34,12 @@ describe("test gmail notifier", function () {
const options = { const options = {
username: "user_gmail", username: "user_gmail",
password: "pass_gmail", password: "pass_gmail",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
}; };
mailSender.sendStub.returns(BluebirdPromise.reject(new Error("Failed to send mail"))); mailSender.sendStub.returns(BluebirdPromise.reject(new Error("Failed to send mail")));
const sender = new GMailNotifier.GMailNotifier(options, mailSender); const sender = new EMailNotifier.EMailNotifier(options, mailSender);
const subject = "subject"; const subject = "subject";
const url = "http://test.com"; const url = "http://test.com";

View File

@ -14,15 +14,17 @@ describe("test MailSenderBuilder", function() {
createTransportStub.restore(); createTransportStub.restore();
}); });
it("should create a gmail mail sender", function() { it("should create a email mail sender", function() {
const mailSenderBuilder = new MailSenderBuilder(Nodemailer); const mailSenderBuilder = new MailSenderBuilder(Nodemailer);
mailSenderBuilder.buildGmail({ mailSenderBuilder.buildEmail({
username: "user_gmail", username: "user_gmail",
password: "pass_gmail", password: "pass_gmail",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
}); });
Assert.equal(createTransportStub.getCall(0).args[0].auth.user, "user_gmail"); Assert.equal(createTransportStub.getCall(0).args[0].auth.user, "user_gmail");
Assert.equal(createTransportStub.getCall(0).args[0].auth.pass, "pass_gmail"); Assert.equal(createTransportStub.getCall(0).args[0].auth.pass, "pass_gmail");
Assert.equal(createTransportStub.getCall(0).args[0].service, "gmail");
}); });
describe("build smtp mail sender", function() { describe("build smtp mail sender", function() {

View File

@ -4,23 +4,24 @@ import * as BluebirdPromise from "bluebird";
import * as assert from "assert"; import * as assert from "assert";
import { NotifierFactory } from "../../src/lib/notifiers/NotifierFactory"; import { NotifierFactory } from "../../src/lib/notifiers/NotifierFactory";
import { GMailNotifier } from "../../src/lib/notifiers/GMailNotifier"; import { EMailNotifier } from "../../src/lib/notifiers/EMailNotifier";
import { SmtpNotifier } from "../../src/lib/notifiers/SmtpNotifier"; import { SmtpNotifier } from "../../src/lib/notifiers/SmtpNotifier";
import { MailSenderBuilderStub } from "../mocks/notifiers/MailSenderBuilderStub"; import { MailSenderBuilderStub } from "../mocks/notifiers/MailSenderBuilderStub";
describe("test notifier factory", function () { describe("test notifier factory", function () {
let mailSenderBuilderStub: MailSenderBuilderStub; let mailSenderBuilderStub: MailSenderBuilderStub;
it("should build a Gmail Notifier", function () { it("should build a Email Notifier", function () {
const options = { const options = {
gmail: { email: {
username: "abc", username: "abc",
password: "password", password: "password",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
} }
}; };
mailSenderBuilderStub = new MailSenderBuilderStub(); mailSenderBuilderStub = new MailSenderBuilderStub();
assert(NotifierFactory.build(options, mailSenderBuilderStub) instanceof GMailNotifier); assert(NotifierFactory.build(options, mailSenderBuilderStub) instanceof EMailNotifier);
}); });
it("should build a SMTP Notifier", function () { it("should build a SMTP Notifier", function () {

View File

@ -52,10 +52,11 @@ describe("Private pages of the server must not be accessible without session", f
} }
}, },
notifier: { notifier: {
gmail: { email: {
username: "user@example.com", username: "user@example.com",
password: "password", password: "password",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
} }
} }
}; };

View File

@ -52,10 +52,11 @@ describe("Public pages of the server must be accessible without session", functi
find_time: 5 * 60 find_time: 5 * 60
}, },
notifier: { notifier: {
gmail: { email: {
username: "user@example.com", username: "user@example.com",
password: "password", password: "password",
sender: "admin@example.com" sender: "admin@example.com",
service: "gmail"
} }
} }
}; };