All files / src/auth/resolvers AdfsCredentials.ts

35% Statements 14/40
0% Branches 0/6
0% Functions 0/5
35% Lines 14/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                                                                                                                                                                            
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;');
 
    if (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
    })]);
  }
}