All files / src/auth/resolvers AdfsCredentials.ts

97.5% Statements 39/40
83.33% Branches 5/6
100% Functions 5/5
97.5% Lines 39/40
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 1081x 1x 1x 1x 1x 1x 1x   1x 1x         1x 1x 1x     1x   1x     3x 3x   3x             3x             3x           3x   3x 3x   3x 2x             1x   1x     1x 1x 1x 1x 1x   1x   1x                 1x   1x             1x 1x 1x   1x                        
import * as Promise from 'bluebird';
import * as request from 'request-promise';
import * as url from 'url';
import * as _ from 'lodash';
import * as fs from 'fs';
import * as path from 'path';
import * as cookie from 'cookie';
import { IncomingMessage } from 'http';
import * as util from 'util';
let xmldoc: any = require('xmldoc');
 
import { IAuthResolver } from './../IAuthResolver';
import { IAdfsUserCredentials } from './../IAuthOptions';
import { IAuthResponse } from './../IAuthResponse';
import { Cache } from './../../utils/Cache';
import * as consts from './../../Consts';
import { AdfsHelper } from './../../utils/AdfsHelper';
import { SamlAssertion } from './../../utils/SamlAssertion';
 
export class AdfsCredentials implements IAuthResolver {
 
  private static CookieCache: Cache = new Cache();
  private _authOptions: IAdfsUserCredentials;
 
  constructor(private _siteUrl: string, _authOptions: IAdfsUserCredentials) {
    this._authOptions = _.extend<{}, IAdfsUserCredentials>({}, _authOptions);
 
    this._authOptions.username = this._authOptions.username
      .replace(/&/g, '&amp;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&apos;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;');
 
    this._authOptions.password = this._authOptions.password
      .replace(/&/g, '&amp;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&apos;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;');
 
    Iif (this._authOptions.domain !== undefined) {
      this._authOptions.username = `${this._authOptions.domain}\\${this._authOptions.username}`;
    }
  }
 
  public getAuth(): Promise<IAuthResponse> {
    let siteUrlParsed: url.Url = url.parse(this._siteUrl);
 
    let cacheKey: string = util.format('%s@%s', siteUrlParsed.host, this._authOptions.username);
    let cachedCookie: string = AdfsCredentials.CookieCache.get<string>(cacheKey);
 
    if (cachedCookie) {
      return Promise.resolve({
        headers: {
          'Cookie': cachedCookie
        }
      });
    }
 
    return AdfsHelper.getSamlAssertion(this._siteUrl, this._authOptions)
      .then(data => {
        return this.postTokenData(data);
      })
      .then(data => {
        let adfsCookie: string = this._authOptions.adfsCookie || consts.FedAuth;
        let notAfter: number = new Date(data[0]).getTime();
        let expiresIn: number = parseInt(((notAfter - new Date().getTime()) / 1000).toString(), 10);
        let response: IncomingMessage = data[1];
        let authCookie: string = adfsCookie + '=' + cookie.parse(response.headers['set-cookie'][0])[adfsCookie];
 
        AdfsCredentials.CookieCache.set(cacheKey, authCookie, expiresIn);
 
        return {
          headers: {
            'Cookie': authCookie
          }
        };
      });
  }
 
  private postTokenData(samlAssertion: SamlAssertion): Promise<[string, any]> {
    let tokenPostTemplate: Buffer = fs.readFileSync(path.join(__dirname, '..', '..', '..', 'templates', 'adfs_saml_token.tmpl'));
 
    let result: string = _.template(tokenPostTemplate.toString())({
      created: samlAssertion.notBefore,
      expires: samlAssertion.notAfter,
      relyingParty: this._authOptions.relyingParty,
      token: samlAssertion.value
    });
 
    let tokenXmlDoc: any = new xmldoc.XmlDocument(result);
    let siteUrlParsed: url.Url = url.parse(this._siteUrl);
    let rootSiteUrl = `${siteUrlParsed.protocol}//${siteUrlParsed.host}`;
 
    return Promise.all([samlAssertion.notAfter, request.post(`${rootSiteUrl}/_trust/`, {
      form: {
        'wa': 'wsignin1.0',
        'wctx': `${rootSiteUrl}/_layouts/Authenticate.aspx?Source=%2F`,
        'wresult': tokenXmlDoc.toString({ compressed: true })
      },
      resolveWithFullResponse: true,
      simple: false,
      strictSSL: false
    })]);
  }
}