-
Notifications
You must be signed in to change notification settings - Fork 57
/
Copy pathAdfsCredentials.ts
105 lines (87 loc) · 3.66 KB
/
AdfsCredentials.ts
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
import { request } from './../../config';
import * as url from 'url';
import * as cookie from 'cookie';
import template = require('lodash.template');
import { Response } from 'got';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const 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';
import { template as adfsSamlTokenTemplate } from './../../templates/AdfsSamlToken';
export class AdfsCredentials implements IAuthResolver {
private static CookieCache: Cache = new Cache();
private _authOptions: IAdfsUserCredentials;
constructor(private _siteUrl: string, _authOptions: IAdfsUserCredentials) {
this._authOptions = Object.assign({}, _authOptions);
this._authOptions.username = this._authOptions.username
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
this._authOptions.password = this._authOptions.password
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/</g, '<')
.replace(/>/g, '>');
if (this._authOptions.domain !== undefined) {
this._authOptions.username = `${this._authOptions.domain}\\${this._authOptions.username}`;
}
}
public getAuth(): Promise<IAuthResponse> {
const siteUrlParsed: url.Url = url.parse(this._siteUrl);
const cacheKey = `${siteUrlParsed.host}@${this._authOptions.username}@${this._authOptions.password}`;
const cachedCookie: string = AdfsCredentials.CookieCache.get<string>(cacheKey);
if (cachedCookie) {
return Promise.resolve({
headers: {
'Cookie': cachedCookie
}
});
}
return AdfsHelper.getSamlAssertion(this._authOptions)
.then((data: any) => {
return this.postTokenData(data);
})
.then(data => {
const adfsCookie: string = this._authOptions.adfsCookie || consts.FedAuth;
const notAfter: number = new Date(data[0]).getTime();
const expiresIn: number = parseInt(((notAfter - new Date().getTime()) / 1000).toString(), 10);
const response = data[1];
const authCookie: string = adfsCookie + '=' +
response.headers['set-cookie']
.map((cookieString: string) => cookie.parse(cookieString)[adfsCookie])
.filter((cookieString: string) => typeof cookieString !== 'undefined')[0];
AdfsCredentials.CookieCache.set(cacheKey, authCookie, expiresIn);
return {
headers: {
'Cookie': authCookie
}
};
});
}
private postTokenData(samlAssertion: SamlAssertion): Promise<[string, Response<string>]> {
const result: string = template(adfsSamlTokenTemplate)({
created: samlAssertion.notBefore,
expires: samlAssertion.notAfter,
relyingParty: this._authOptions.relyingParty,
token: samlAssertion.value
});
const tokenXmlDoc: any = new xmldoc.XmlDocument(result);
const siteUrlParsed: url.Url = url.parse(this._siteUrl);
const 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 })
}
})]);
}
}