it's no longer needed to use stunnel ;-)master
parent
5e5005cf6b
commit
3f600c664f
@ -0,0 +1,21 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import * as fs from 'fs';
|
||||
import { GoogleLDAPAuth } from '../../src/auth/GoogleLDAPAuth';
|
||||
|
||||
describe('test google ldap auth', function() {
|
||||
this.timeout(10000);
|
||||
it('authenticate against ldap server', async () => {
|
||||
const auth = new GoogleLDAPAuth({
|
||||
base: 'dc=hokify,dc=com',
|
||||
tlsOptions: {
|
||||
key: fs.readFileSync('./ldap.gsuite.hokify.com.40567.key'),
|
||||
cert: fs.readFileSync('./ldap.gsuite.hokify.com.40567.crt')
|
||||
}
|
||||
});
|
||||
|
||||
const result = await auth.authenticate('username', 'password');
|
||||
|
||||
expect(result).to.equal(true);
|
||||
});
|
||||
});
|
@ -0,0 +1,18 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import { IMAPAuth } from '../../src/auth/IMAPAuth';
|
||||
|
||||
describe('test imap auth', () => {
|
||||
it('authenticate against imap server', async () => {
|
||||
const auth = new IMAPAuth({
|
||||
host: 'imap.gmail.com',
|
||||
port: 993,
|
||||
useSecureTransport: true,
|
||||
validHosts: ['gmail.com']
|
||||
});
|
||||
|
||||
const result = await auth.authenticate('username', 'password');
|
||||
|
||||
expect(result).to.equal(true);
|
||||
});
|
||||
});
|
@ -0,0 +1,23 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import * as fs from 'fs';
|
||||
import { LDAPAuth } from '../../src/auth/LDAPAuth';
|
||||
|
||||
describe('test ldap auth', function() {
|
||||
this.timeout(10000);
|
||||
it('authenticate against ldap server', async () => {
|
||||
const auth = new LDAPAuth({
|
||||
url: 'ldaps://ldap.google.com:636',
|
||||
base: 'dc=hokify,dc=com',
|
||||
tlsOptions: {
|
||||
servername: 'ldap.google.com',
|
||||
key: fs.readFileSync('./ldap.gsuite.hokify.com.40567.key'),
|
||||
cert: fs.readFileSync('./ldap.gsuite.hokify.com.40567.crt'),
|
||||
}
|
||||
});
|
||||
|
||||
const result = await auth.authenticate('username', 'password');
|
||||
|
||||
expect(result).to.equal(true);
|
||||
});
|
||||
});
|
@ -0,0 +1,18 @@
|
||||
import 'mocha';
|
||||
import { expect } from 'chai';
|
||||
import { SMTPAuth } from '../../src/auth/SMTPAuth';
|
||||
|
||||
describe('test smtp auth', () => {
|
||||
it('authenticate against smtp server', async () => {
|
||||
const auth = new SMTPAuth({
|
||||
host: 'smtp.gmail.com',
|
||||
port: 465,
|
||||
useSecureTransport: true,
|
||||
validHosts: ['gmail.com']
|
||||
});
|
||||
|
||||
const result = await auth.authenticate('username', 'password');
|
||||
|
||||
expect(result).to.equal(true);
|
||||
});
|
||||
});
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
|
||||
},
|
||||
"include": ["__tests__/*.ts", "*.ts", "../src/**/*.ts"]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,25 @@
|
||||
import * as NodeCache from 'node-cache';
|
||||
import { IAuthentication } from './types/Authentication';
|
||||
|
||||
/**
|
||||
* this is just a simple abstraction to provide
|
||||
* an application layer for caching credentials
|
||||
*/
|
||||
export class Authentication implements IAuthentication {
|
||||
cache = new NodeCache();
|
||||
|
||||
constructor(private authenticator: IAuthentication) {}
|
||||
|
||||
async authenticate(username: string, password: string): Promise<boolean> {
|
||||
const cacheKey = `usr:${username}|pwd:${password}`;
|
||||
const fromCache = this.cache.get(cacheKey) as undefined | boolean;
|
||||
if (fromCache !== undefined) {
|
||||
return fromCache;
|
||||
}
|
||||
|
||||
const authResult = await this.authenticator.authenticate(username, password);
|
||||
this.cache.set(cacheKey, authResult, 86400); // cache for one day
|
||||
|
||||
return authResult;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
import * as imaps from 'imap-simple';
|
||||
import { IAuthentication } from '../types/Authentication';
|
||||
|
||||
interface IIMAPAuthOptions {
|
||||
host: string;
|
||||
port?: number;
|
||||
useSecureTransport?: boolean;
|
||||
validHosts?: string[];
|
||||
}
|
||||
|
||||
export class IMAPAuth implements IAuthentication {
|
||||
private host: string;
|
||||
|
||||
private port = 143;
|
||||
|
||||
private useSecureTransport = false;
|
||||
|
||||
private validHosts?: string[];
|
||||
|
||||
constructor(config: IIMAPAuthOptions) {
|
||||
this.host = config.host;
|
||||
if (config.port !== undefined) {
|
||||
this.port = config.port;
|
||||
}
|
||||
if (config.useSecureTransport !== undefined) {
|
||||
this.useSecureTransport = config.useSecureTransport;
|
||||
}
|
||||
if (config.validHosts !== undefined) {
|
||||
this.validHosts = config.validHosts;
|
||||
}
|
||||
}
|
||||
|
||||
async authenticate(username: string, password: string) {
|
||||
if (this.validHosts) {
|
||||
const domain = username.split('@').pop();
|
||||
if (!domain || !this.validHosts.includes(domain)) {
|
||||
console.info('invalid or no domain in username', username, domain);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
let success = false;
|
||||
try {
|
||||
const connection = await imaps.connect({
|
||||
imap: {
|
||||
host: this.host,
|
||||
port: this.port,
|
||||
tls: this.useSecureTransport,
|
||||
user: username,
|
||||
password,
|
||||
tlsOptions: {
|
||||
servername: this.host // SNI (needs to be set for gmail)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
success = true;
|
||||
|
||||
connection.end();
|
||||
} catch (err) {
|
||||
console.error('imap auth failed', err);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
import * as LdapAuth from 'ldapauth-fork';
|
||||
import { IAuthentication } from '../types/Authentication';
|
||||
|
||||
interface ILDAPAuthOptions {
|
||||
/** ldap url
|
||||
* e.g. ldaps://ldap.google.com
|
||||
*/
|
||||
url: string;
|
||||
/** base DN
|
||||
* e.g. 'dc=hokify,dc=com', */
|
||||
base: string;
|
||||
/** tls options
|
||||
* e.g. {
|
||||
key: fs.readFileSync('ldap.gsuite.hokify.com.40567.key'),
|
||||
cert: fs.readFileSync('ldap.gsuite.hokify.com.40567.crt'),
|
||||
servername: 'ldap.google.com'
|
||||
} */
|
||||
tlsOptions?: any;
|
||||
/**
|
||||
* searchFilter
|
||||
*/
|
||||
searchFilter?: string;
|
||||
}
|
||||
|
||||
export class LDAPAuth implements IAuthentication {
|
||||
private ldap: LdapAuth;
|
||||
|
||||
constructor(options: ILDAPAuthOptions) {
|
||||
this.ldap = new LdapAuth({
|
||||
url: options.url,
|
||||
searchBase: options.base,
|
||||
tlsOptions: options.tlsOptions,
|
||||
searchFilter: options.searchFilter || '(uid={{username}})',
|
||||
reconnect: true
|
||||
});
|
||||
this.ldap.on('error', function(err) {
|
||||
console.error('LdapAuth: ', err);
|
||||
});
|
||||
}
|
||||
|
||||
async authenticate(username: string, password: string) {
|
||||
// console.log('AUTH', this.ldap);
|
||||
const authResult: boolean = await new Promise((resolve, reject) => {
|
||||
this.ldap.authenticate(username, password, function(err, user) {
|
||||
if (err) {
|
||||
resolve(false);
|
||||
console.error('ldap error', err);
|
||||
// reject(err);
|
||||
}
|
||||
if (user) resolve(user);
|
||||
else reject();
|
||||
});
|
||||
});
|
||||
|
||||
return !!authResult;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
import { SMTPClient } from 'smtp-client';
|
||||
import { IAuthentication } from '../types/Authentication';
|
||||
|
||||
interface ISMTPAuthOptions {
|
||||
host: string;
|
||||
port?: number;
|
||||
useSecureTransport?: boolean;
|
||||
validHosts?: string[];
|
||||
}
|
||||
|
||||
export class SMTPAuth implements IAuthentication {
|
||||
private host: string;
|
||||
|
||||
private port = 25;
|
||||
|
||||
private useSecureTransport = false;
|
||||
|
||||
private validHosts?: string[];
|
||||
|
||||
constructor(options: ISMTPAuthOptions) {
|
||||
this.host = options.host;
|
||||
|
||||
if (options.port !== undefined) {
|
||||
this.port = options.port;
|
||||
}
|
||||
|
||||
if (options.useSecureTransport !== undefined) {
|
||||
this.useSecureTransport = options.useSecureTransport;
|
||||
}
|
||||
|
||||
if (options.validHosts !== undefined) {
|
||||
this.validHosts = options.validHosts;
|
||||
}
|
||||
}
|
||||
|
||||
async authenticate(username: string, password: string) {
|
||||
if (this.validHosts) {
|
||||
const domain = username.split('@').pop();
|
||||
if (!domain || !this.validHosts.includes(domain)) {
|
||||
console.info('invalid or no domain in username', username, domain);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const s = new SMTPClient({
|
||||
host: this.host,
|
||||
port: this.port,
|
||||
secure: this.useSecureTransport,
|
||||
tlsOptions: {
|
||||
servername: this.host // SNI (needs to be set for gmail)
|
||||
}
|
||||
});
|
||||
|
||||
let success = false;
|
||||
try {
|
||||
await s.connect();
|
||||
await s.greet({ hostname: 'mx.domain.com' }); // runs EHLO command or HELO as a fallback
|
||||
await s.authPlain({ username, password }); // authenticates a user
|
||||
|
||||
success = true;
|
||||
|
||||
s.close(); // runs QUIT command
|
||||
} catch (err) {
|
||||
console.error('imap auth failed', err);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
import { IAuthentication } from '../types/Authentication';
|
||||
|
||||
interface IStaticAuthOtions {
|
||||
validCrentials: {
|
||||
username: string;
|
||||
password: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export class StaticAuth implements IAuthentication {
|
||||
private validCredentials: { username: string; password: string }[];
|
||||
|
||||
constructor(options: IStaticAuthOtions) {
|
||||
this.validCredentials = options.validCrentials;
|
||||
}
|
||||
|
||||
async authenticate(username: string, password: string) {
|
||||
return !!this.validCredentials.find(
|
||||
credential => credential.username === username && credential.password === password
|
||||
);
|
||||
}
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"*.js"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true
|
||||
}
|
||||
"extends": "./tsconfig.json",
|
||||
"include": ["src/**/*.ts", "*.js", "*.ts", "__tests__/**/*.ts"],
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in new issue