forked from mcguinness/saml-idp
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathidp-metadata.js
More file actions
119 lines (97 loc) · 3.84 KB
/
idp-metadata.js
File metadata and controls
119 lines (97 loc) · 3.84 KB
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
108
109
110
111
112
113
114
115
116
117
118
119
'use strict';
const util = require('util'),
request = require("request"),
xml2js = require('xml2js');
function getBindingLocation(serviceEl, bindingUri) {
var location;
if (serviceEl && serviceEl.length > 0) {
serviceEl.forEach((element, index, array) => {
if (element.$.Binding.toLowerCase() === bindingUri) {
location = element.$.Location;
}
});
}
return location;
};
function getFirstCert(keyEl) {
if (keyEl.KeyInfo &&
keyEl.KeyInfo.length === 1,
keyEl.KeyInfo[0].X509Data &&
keyEl.KeyInfo[0].X509Data.length === 1,
keyEl.KeyInfo[0].X509Data[0].X509Certificate &&
keyEl.KeyInfo[0].X509Data[0].X509Certificate.length === 1) {
return keyEl.KeyInfo[0].X509Data[0].X509Certificate[0]._;
}
}
function fetch(url) {
return new Promise((resolve, reject) => {
const metadata = { sso: {}, slo: {}, nameIdFormats: [], signingKeys: [] };
if (typeof url === 'undefined' || url === null) {
return resolve(metadata);
}
console.log('downloading IdP metadata from ' + url)
request.get(url, (err, resp, body) => {
if (err) {
console.log('unable to fetch metadata: ' + err.message);
return reject(err);
};
console.log();
console.log(body);
console.log();
const parserConfig = {
explicitRoot: true,
explicitCharkey: true,
tagNameProcessors: [xml2js.processors.stripPrefix]
},
parser = new xml2js.Parser(parserConfig),
nameIds = [];
parser.parseString(body, (err, docEl) => {
if (err) {
return reject(err);
}
if (docEl.EntityDescriptor) {
metadata.issuer = docEl.EntityDescriptor.$.entityID
if (docEl.EntityDescriptor.IDPSSODescriptor && docEl.EntityDescriptor.IDPSSODescriptor.length === 1) {
metadata.protocol = 'samlp';
let ssoEl = docEl.EntityDescriptor.IDPSSODescriptor[0];
metadata.signRequest = ssoEl.$.WantAuthnRequestsSigned;
ssoEl.KeyDescriptor.forEach((keyEl) => {
if (keyEl.$.use && keyEl.$.use.toLowerCase() !== 'encryption') {
metadata.signingKeys.push(getFirstCert(keyEl));
}
})
if (ssoEl.NameIDFormat) {
ssoEl.NameIDFormat.forEach((element, index, array) => {
if (element._) {
metadata.nameIdFormats.push(element._);
}
});
}
metadata.sso.redirectUrl = getBindingLocation(ssoEl.SingleSignOnService, 'urn:oasis:names:tc:saml:2.0:bindings:http-redirect');
metadata.sso.postUrl = getBindingLocation(ssoEl.SingleSignOnService, 'urn:oasis:names:tc:saml:2.0:bindings:http-post');
metadata.slo.redirectUrl = getBindingLocation(ssoEl.SingleLogoutService, 'urn:oasis:names:tc:saml:2.0:bindings:http-redirect');
metadata.slo.postUrl = getBindingLocation(ssoEl.SingleLogoutService, 'urn:oasis:names:tc:saml:2.0:bindings:http-post');
}
}
if (docEl.EntityDescriptor.RoleDescriptor) {
metadata.protocol = 'wsfed';
try {
let roleEl = docEl.EntityDescriptor.RoleDescriptor.find((el) => {
return el.$['xsi:type'].endsWith(':SecurityTokenServiceType');
});
metadata.sso.redirectUrl = roleEl.PassiveRequestorEndpoint[0].EndpointReference[0].Address[0]._
roleEl.KeyDescriptor.forEach((keyEl) => {
metadata.signingKeys.push(getFirstCert(keyEl));
})
} catch(e) {
console.log('unable to parse RoleDescriptor metadata', e);
}
}
return resolve(metadata);
});
});
});
}
module.exports = {
fetch: fetch
};