mirror of
https://github.com/netzbegruenung/meteor-accounts-saml.git
synced 2024-05-01 03:14:52 +02:00
no message
This commit is contained in:
parent
0f43b45f49
commit
266dd12b36
48
.versions
48
.versions
|
@ -1,27 +1,29 @@
|
|||
accounts-base@1.2.17
|
||||
allow-deny@1.0.5
|
||||
accounts-base@1.3.1
|
||||
allow-deny@1.0.6
|
||||
autoupdate@1.3.12
|
||||
babel-compiler@6.18.2
|
||||
babel-compiler@6.19.4
|
||||
babel-runtime@1.0.1
|
||||
base64@1.0.10
|
||||
binary-heap@1.0.10
|
||||
blaze@2.3.2
|
||||
blaze-tools@1.0.10
|
||||
boilerplate-generator@1.0.11
|
||||
boilerplate-generator@1.1.1
|
||||
caching-compiler@1.1.9
|
||||
caching-html-compiler@1.0.7
|
||||
callback-hook@1.0.10
|
||||
check@1.2.5
|
||||
coffeescript@1.0.17
|
||||
ddp@1.2.5
|
||||
ddp-client@1.3.4
|
||||
ddp-common@1.2.8
|
||||
ddp@1.3.0
|
||||
ddp-client@2.0.0
|
||||
ddp-common@1.2.9
|
||||
ddp-rate-limiter@1.0.7
|
||||
ddp-server@1.3.14
|
||||
ddp-server@2.0.0
|
||||
deps@1.0.12
|
||||
diff-sequence@1.0.7
|
||||
ecmascript@0.7.3
|
||||
ecmascript-runtime@0.3.15
|
||||
ecmascript@0.8.1
|
||||
ecmascript-runtime@0.4.1
|
||||
ecmascript-runtime-client@0.4.3
|
||||
ecmascript-runtime-server@0.4.1
|
||||
ejson@1.0.13
|
||||
geojson-utils@1.0.10
|
||||
html-tools@1.0.11
|
||||
|
@ -29,14 +31,14 @@ htmljs@1.0.11
|
|||
http@1.2.12
|
||||
id-map@1.0.9
|
||||
jquery@1.11.10
|
||||
local-test:steffo:meteor-accounts-saml@0.0.10
|
||||
localstorage@1.0.12
|
||||
local-test:steffo:meteor-accounts-saml@0.0.13
|
||||
localstorage@1.1.0
|
||||
logging@1.1.17
|
||||
meteor@1.6.1
|
||||
minimongo@1.0.23
|
||||
modules@0.8.2
|
||||
modules-runtime@0.7.10
|
||||
mongo@1.1.17
|
||||
meteor@1.7.0
|
||||
minimongo@1.2.1
|
||||
modules@0.9.2
|
||||
modules-runtime@0.8.0
|
||||
mongo@1.1.19
|
||||
mongo-id@1.0.6
|
||||
npm-mongo@2.2.24
|
||||
observe-sequence@1.0.16
|
||||
|
@ -46,7 +48,7 @@ practicalmeteor:loglevel@1.2.0_2
|
|||
practicalmeteor:mocha@2.4.5_2
|
||||
practicalmeteor:mocha-core@0.1.4
|
||||
practicalmeteor:sinon@1.14.1_2
|
||||
promise@0.8.8
|
||||
promise@0.8.9
|
||||
random@1.0.10
|
||||
rate-limit@1.0.8
|
||||
reactive-var@1.0.11
|
||||
|
@ -54,15 +56,15 @@ reload@1.1.11
|
|||
retry@1.0.9
|
||||
routepolicy@1.0.12
|
||||
service-configuration@1.0.11
|
||||
spacebars@1.0.12
|
||||
spacebars-compiler@1.1.0
|
||||
steffo:meteor-accounts-saml@0.0.10
|
||||
spacebars@1.0.15
|
||||
spacebars-compiler@1.1.2
|
||||
steffo:meteor-accounts-saml@0.0.13
|
||||
templating@1.1.14
|
||||
templating-tools@1.1.1
|
||||
tmeasday:test-reporter-helpers@0.2.1
|
||||
tracker@1.1.3
|
||||
ui@1.0.11
|
||||
ui@1.0.13
|
||||
underscore@1.0.10
|
||||
url@1.1.0
|
||||
webapp@1.3.15
|
||||
webapp@1.3.17
|
||||
webapp-hashing@1.0.9
|
||||
|
|
|
@ -31,6 +31,10 @@ settings = {"saml":[{
|
|||
"privateKeyFile": "certs/mykey.pem", // path is relative to $METEOR-PROJECT/private
|
||||
"publicCertFile": "certs/mycert.pem", // eg $METEOR-PROJECT/private/certs/mycert.pem
|
||||
"dynamicProfile": true // set to true if we want to create a user in Meteor.users dynamically if SAML assertion is valid
|
||||
"identifierFormat": "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified", // Defaults to urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress
|
||||
"localProfileMatchAttribute": "telephoneNumber" // CAUTION: this will be mapped to profile.<localProfileMatchAttribute> attribute in Mongo if identifierFormat (see above) differs from urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress,
|
||||
"attributesSAML": {[telephoneNumber, sn, givenName, mail]}, // attrs from SAML attr statement, which will be used for local Meteor profile creation. Currently no real attribute mapping. If required use mapping on IdP side.
|
||||
|
||||
}]}
|
||||
|
||||
Meteor.settings = settings;
|
||||
|
|
19
package.js
19
package.js
|
@ -1,7 +1,7 @@
|
|||
Package.describe({
|
||||
name:"steffo:meteor-accounts-saml",
|
||||
summary: "SAML Login (SP) for Meteor. Works with OpenAM, OpenIDP and provides Single Logout.",
|
||||
version: "0.0.10",
|
||||
version: "0.0.13",
|
||||
git: "https://github.com/steffow/meteor-accounts-saml.git"
|
||||
});
|
||||
|
||||
|
@ -23,6 +23,8 @@ Package.onTest((api) => {
|
|||
|
||||
Npm.depends({
|
||||
"depd": "1.1.0",
|
||||
"xml-crypto": "0.9.0",
|
||||
"body-parser": "1.17.1",
|
||||
"bytes": "2.5.0",
|
||||
"content-type": "1.0.2",
|
||||
"debug": "2.6.3",
|
||||
|
@ -41,9 +43,8 @@ Npm.depends({
|
|||
"media-typer": "0.3.0",
|
||||
"mime-types": "2.1.15",
|
||||
"xml2js": "0.4.17",
|
||||
"body-parser": "1.17.1",
|
||||
"sax": "1.2.2",
|
||||
"xmlbuilder": "8.2.2",
|
||||
"xmlbuilder": "9.0.0",
|
||||
"ejs": "2.5.6",
|
||||
"async": "2.3.0",
|
||||
"lodash":"4.17.4",
|
||||
|
@ -52,7 +53,13 @@ Npm.depends({
|
|||
"xpath.js": "1.0.7",
|
||||
"xmldom": "0.1.27",
|
||||
"connect": "3.6.0",
|
||||
"querystring": "0.2.0",
|
||||
"xml-encryption": "0.10.0",
|
||||
"xml-crypto": "0.9.0"
|
||||
"querystring": "0.2.0"
|
||||
// "xml-encryption": "0.10.0"
|
||||
});
|
||||
|
||||
// Npm.depends({
|
||||
// "depd": "1.1.0",
|
||||
// "xml-crypto": "0.9.0",
|
||||
// "xmlbuilder": "9.0.0",
|
||||
// "xml2js": "0.4.17"
|
||||
// });
|
||||
|
|
325
saml_server.js
325
saml_server.js
|
@ -8,12 +8,12 @@ var bodyParser = Npm.require('body-parser')
|
|||
RoutePolicy.declare('/_saml/', 'network');
|
||||
|
||||
Meteor.methods({
|
||||
samlLogout: function (provider) {
|
||||
samlLogout: function(provider) {
|
||||
// Make sure the user is logged in before initiate SAML SLO
|
||||
if (!Meteor.userId()) {
|
||||
throw new Meteor.Error("not-authorized");
|
||||
}
|
||||
var samlProvider = function (element) {
|
||||
var samlProvider = function(element) {
|
||||
return (element.provider == provider)
|
||||
}
|
||||
providerConfig = Meteor.settings.saml.filter(samlProvider)[0];
|
||||
|
@ -63,37 +63,90 @@ Meteor.methods({
|
|||
}
|
||||
})
|
||||
|
||||
Accounts.registerLoginHandler(function (loginRequest) {
|
||||
Accounts.registerLoginHandler(function(loginRequest) {
|
||||
if (!loginRequest.saml || !loginRequest.credentialToken) {
|
||||
return undefined;
|
||||
}
|
||||
var loginResult = Accounts.saml.retrieveCredential(loginRequest.credentialToken);
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("RESULT :" + JSON.stringify(loginResult));
|
||||
console.log("RESULT :" + JSON.stringify(loginResult));
|
||||
}
|
||||
if (loginResult && loginResult.profile && loginResult.profile.email) {
|
||||
console.log("Profile: " + JSON.stringify(loginResult.profile.email));
|
||||
|
||||
if (loginResult && loginResult.profile && loginResult.profile.nameID) {
|
||||
console.log("Profile: " + JSON.stringify(loginResult.profile.nameID));
|
||||
var localProfileMatchAttribute;
|
||||
var localFindStructure;
|
||||
var nameIDFormat;
|
||||
// Default nameIDFormat is emailAddress
|
||||
if (!(Meteor.settings.saml[0].identifierFormat) || (Meteor.settings.saml[0].identifierFormat == "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")) {
|
||||
nameIDFormat = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress";
|
||||
} else {
|
||||
nameIDFormat = Meteor.settings.saml[0].identifierFormat;
|
||||
}
|
||||
|
||||
if (nameIDFormat == "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress" ) {
|
||||
// If nameID Format is emailAdress, we should not force 'email' as localProfileMatchAttribute
|
||||
localProfileMatchAttribute = "email";
|
||||
localFindStructure = "emails.address";
|
||||
profileOrEmail = "email";
|
||||
profileOrEmailValue = loginResult.profile.nameID;
|
||||
} else // any other nameID format
|
||||
// Check if Meteor.settings.saml[0].localProfileMatchAttribute has value
|
||||
// These values will be stored in profile substructure. They're NOT security relevant because profile isn't a safe place
|
||||
if (Meteor.settings.saml[0].localProfileMatchAttribute){
|
||||
profileOrEmail = "profile";
|
||||
profileOrEmailValue = {
|
||||
[Meteor.settings.saml[0].localProfileMatchAttribute] : loginResult.profile.nameID
|
||||
};
|
||||
localFindStructure = 'profile.' + Meteor.settings.saml[0].localProfileMatchAttribute;
|
||||
}
|
||||
var user = Meteor.users.findOne({
|
||||
'emails.address': loginResult.profile.email
|
||||
//profile[Meteor.settings.saml[0].localProfileMatchAttribute]: loginResult.profile.nameID
|
||||
[localFindStructure]: loginResult.profile.nameID
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
if (Meteor.settings.saml[0].dynamicProfile) {
|
||||
Accounts.createUser({
|
||||
email: loginResult.profile.email,
|
||||
password: "",
|
||||
username: loginResult.profile.nameID,
|
||||
profile: ""
|
||||
});
|
||||
user = Meteor.users.findOne({
|
||||
"emails.address": loginResult.profile.email
|
||||
});
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("Created new user");
|
||||
if (Meteor.settings.saml[0].dynamicProfile) {
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("User not found. Will dynamically create one with '" + Meteor.settings.saml[0].localProfileMatchAttribute + "' = " + loginResult.profile[Meteor.settings.saml[0].localProfileMatchAttribute])
|
||||
}
|
||||
Accounts.createUser({
|
||||
//email: loginResult.profile.email,
|
||||
password: "",
|
||||
username: loginResult.profile.nameID,
|
||||
[profileOrEmail]: profileOrEmailValue
|
||||
|
||||
//[Meteor.settings.saml[0].localProfileMatchAttribute]: loginResult.profile[Meteor.settings.saml[0].localProfileMatchAttribute]
|
||||
});
|
||||
user = Meteor.users.findOne({
|
||||
"username": loginResult.profile.nameID
|
||||
});
|
||||
// update user profile w attrs from SAML Attr Satement
|
||||
//Meteor.user.update(user, )
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("Profile for attributes: " + JSON.stringify(loginResult.profile));
|
||||
}
|
||||
var attributeNames = Meteor.settings.saml[0].attributesSAML;
|
||||
var meteorProfile = {};
|
||||
if (attributeNames) {
|
||||
attributeNames.forEach(function(attribute) {
|
||||
meteorProfile[attribute] = loginResult.profile[attribute];
|
||||
});
|
||||
}
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("Profile for Meteor: " + JSON.stringify(meteorProfile));
|
||||
}
|
||||
Meteor.users.update(user, {
|
||||
$set: {
|
||||
'profile': meteorProfile
|
||||
}
|
||||
});
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("Created new user");
|
||||
}
|
||||
} else {
|
||||
throw new Error("Could not find an existing user with supplied attribute '" + Meteor.settings.saml[0].localProfileMatchAttribute + "' and value:" + loginResult.profile[Meteor.settings.saml[0].localProfileMatchAttribute]);
|
||||
}
|
||||
} else {
|
||||
throw new Error("Could not find an existing user with supplied email " + loginResult.profile.email);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -122,6 +175,35 @@ Accounts.registerLoginHandler(function (loginRequest) {
|
|||
}
|
||||
});
|
||||
|
||||
if (loginResult.profile.uid) {
|
||||
Meteor.users.update({
|
||||
_id: user._id
|
||||
}, {
|
||||
$set: {
|
||||
// TBD this should be pushed, otherwise we're only able to SSO into a single IDP at a time
|
||||
'uid': loginResult.profile.uid
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var attributeNames = Meteor.settings.saml[0].attributesSAML;
|
||||
var meteorProfile = {};
|
||||
if (attributeNames) {
|
||||
attributeNames.forEach(function(attribute) {
|
||||
meteorProfile[attribute] = loginResult.profile[attribute];
|
||||
});
|
||||
}
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("Profile Update for Meteor: " + JSON.stringify(meteorProfile));
|
||||
}
|
||||
Meteor.users.update({
|
||||
_id: user._id
|
||||
}, {
|
||||
$set: {
|
||||
'profile': meteorProfile
|
||||
}
|
||||
});
|
||||
|
||||
//sending token along with the userId
|
||||
var result = {
|
||||
userId: user._id,
|
||||
|
@ -131,17 +213,17 @@ Accounts.registerLoginHandler(function (loginRequest) {
|
|||
return result
|
||||
|
||||
} else {
|
||||
throw new Error("SAML Profile did not contain an email address");
|
||||
throw new Error("SAML Assertion did not contain a proper SAML subject value");
|
||||
}
|
||||
});
|
||||
|
||||
Accounts.saml._loginResultForCredentialToken = {};
|
||||
|
||||
Accounts.saml.hasCredential = function (credentialToken) {
|
||||
Accounts.saml.hasCredential = function(credentialToken) {
|
||||
return _.has(Accounts.saml._loginResultForCredentialToken, credentialToken);
|
||||
}
|
||||
|
||||
Accounts.saml.retrieveCredential = function (credentialToken) {
|
||||
Accounts.saml.retrieveCredential = function(credentialToken) {
|
||||
// The credentialToken in all these functions corresponds to SAMLs inResponseTo field and is mandatory to check.
|
||||
var result = Accounts.saml._loginResultForCredentialToken[credentialToken];
|
||||
delete Accounts.saml._loginResultForCredentialToken[credentialToken];
|
||||
|
@ -151,15 +233,17 @@ Accounts.saml.retrieveCredential = function (credentialToken) {
|
|||
|
||||
|
||||
// Listen to incoming SAML http requests
|
||||
WebApp.connectHandlers.use(bodyParser.urlencoded({ extended: true })).use(function (req, res, next) {
|
||||
WebApp.connectHandlers.use(bodyParser.urlencoded({
|
||||
extended: true
|
||||
})).use(function(req, res, next) {
|
||||
// Need to create a Fiber since we're using synchronous http calls and nothing
|
||||
// else is wrapping this in a fiber automatically
|
||||
Fiber(function () {
|
||||
Fiber(function() {
|
||||
middleware(req, res, next);
|
||||
}).run();
|
||||
});
|
||||
|
||||
middleware = function (req, res, next) {
|
||||
middleware = function(req, res, next) {
|
||||
// Make sure to catch any exceptions because otherwise we'd crash
|
||||
// the runner
|
||||
try {
|
||||
|
@ -172,7 +256,7 @@ middleware = function (req, res, next) {
|
|||
if (!samlObject.actionName)
|
||||
throw new Error("Missing SAML action");
|
||||
|
||||
var service = _.find(Meteor.settings.saml, function (samlSetting) {
|
||||
var service = _.find(Meteor.settings.saml, function(samlSetting) {
|
||||
return samlSetting.provider === samlObject.serviceName;
|
||||
});
|
||||
|
||||
|
@ -180,102 +264,105 @@ middleware = function (req, res, next) {
|
|||
if (!service)
|
||||
throw new Error("Unexpected SAML service " + samlObject.serviceName);
|
||||
switch (samlObject.actionName) {
|
||||
case "metadata":
|
||||
_saml = new SAML(service);
|
||||
service.callbackUrl = Meteor.absoluteUrl("_saml/validate/" + service.provider);
|
||||
res.writeHead(200);
|
||||
res.write(_saml.generateServiceProviderMetadata(service.callbackUrl));
|
||||
res.end();
|
||||
//closePopup(res);
|
||||
break;
|
||||
case "logout":
|
||||
// This is where we receive SAML LogoutResponse
|
||||
_saml = new SAML(service);
|
||||
_saml.validateLogoutResponse(req.query.SAMLResponse, function (err, result) {
|
||||
if (!err) {
|
||||
var logOutUser = function (inResponseTo) {
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("Logging Out user via inResponseTo " + inResponseTo);
|
||||
}
|
||||
var loggedOutUser = Meteor.users.find({
|
||||
'services.saml.inResponseTo': inResponseTo
|
||||
}).fetch();
|
||||
if (loggedOutUser.length == 1) {
|
||||
case "metadata":
|
||||
_saml = new SAML(service);
|
||||
service.callbackUrl = Meteor.absoluteUrl("_saml/validate/" + service.provider);
|
||||
res.writeHead(200);
|
||||
res.write(_saml.generateServiceProviderMetadata(service.callbackUrl));
|
||||
res.end();
|
||||
//closePopup(res);
|
||||
break;
|
||||
case "logout":
|
||||
// This is where we receive SAML LogoutResponse
|
||||
_saml = new SAML(service);
|
||||
_saml.validateLogoutResponse(req.query.SAMLResponse, function(err, result) {
|
||||
if (!err) {
|
||||
var logOutUser = function(inResponseTo) {
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("Found user " + loggedOutUser[0]._id);
|
||||
console.log("Logging Out user via inResponseTo " + inResponseTo);
|
||||
}
|
||||
Meteor.users.update({
|
||||
_id: loggedOutUser[0]._id
|
||||
}, {
|
||||
$set: {
|
||||
"services.resume.loginTokens": []
|
||||
var loggedOutUser = Meteor.users.find({
|
||||
'services.saml.inResponseTo': inResponseTo
|
||||
}).fetch();
|
||||
if (loggedOutUser.length == 1) {
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("Found user " + loggedOutUser[0]._id);
|
||||
}
|
||||
});
|
||||
Meteor.users.update({
|
||||
_id: loggedOutUser[0]._id
|
||||
}, {
|
||||
$unset: {
|
||||
"services.saml": ""
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new Meteor.error("Found multiple users matching SAML inResponseTo fields");
|
||||
Meteor.users.update({
|
||||
_id: loggedOutUser[0]._id
|
||||
}, {
|
||||
$set: {
|
||||
"services.resume.loginTokens": []
|
||||
}
|
||||
});
|
||||
Meteor.users.update({
|
||||
_id: loggedOutUser[0]._id
|
||||
}, {
|
||||
$unset: {
|
||||
"services.saml": ""
|
||||
}
|
||||
});
|
||||
} else {
|
||||
throw new Meteor.error("Found multiple users matching SAML inResponseTo fields");
|
||||
}
|
||||
}
|
||||
|
||||
Fiber(function() {
|
||||
logOutUser(result);
|
||||
}).run();
|
||||
|
||||
|
||||
res.writeHead(302, {
|
||||
'Location': req.query.RelayState
|
||||
});
|
||||
res.end();
|
||||
} else {
|
||||
// TBD thinking of sth meaning full.
|
||||
}
|
||||
|
||||
Fiber(function () {
|
||||
logOutUser(result);
|
||||
}).run();
|
||||
|
||||
|
||||
res.writeHead(302, {
|
||||
'Location': req.query.RelayState
|
||||
});
|
||||
res.end();
|
||||
} else {
|
||||
// TBD thinking of sth meaning full.
|
||||
}
|
||||
})
|
||||
break;
|
||||
case "sloRedirect":
|
||||
var idpLogout = req.query.redirect
|
||||
res.writeHead(302, {
|
||||
// credentialToken here is the SAML LogOut Request that we'll send back to IDP
|
||||
'Location': idpLogout
|
||||
});
|
||||
res.end();
|
||||
break;
|
||||
case "authorize":
|
||||
service.callbackUrl = Meteor.absoluteUrl("_saml/validate/" + service.provider);
|
||||
service.id = samlObject.credentialToken;
|
||||
_saml = new SAML(service);
|
||||
_saml.getAuthorizeUrl(req, function (err, url) {
|
||||
if (err)
|
||||
throw new Error("Unable to generate authorize url");
|
||||
})
|
||||
break;
|
||||
case "sloRedirect":
|
||||
var idpLogout = req.query.redirect
|
||||
res.writeHead(302, {
|
||||
'Location': url
|
||||
// credentialToken here is the SAML LogOut Request that we'll send back to IDP
|
||||
'Location': idpLogout
|
||||
});
|
||||
res.end();
|
||||
});
|
||||
break;
|
||||
case "validate":
|
||||
_saml = new SAML(service);
|
||||
Accounts.saml.RelayState = req.body.RelayState;
|
||||
_saml.validateResponse(req.body.SAMLResponse, req.body.RelayState, function (err, profile, loggedOut) {
|
||||
if (err)
|
||||
throw new Error("Unable to validate response url: " + err);
|
||||
|
||||
var credentialToken = profile.inResponseToId || profile.InResponseTo || samlObject.credentialToken;
|
||||
if (!credentialToken)
|
||||
throw new Error("Unable to determine credentialToken");
|
||||
Accounts.saml._loginResultForCredentialToken[credentialToken] = {
|
||||
profile: profile
|
||||
break;
|
||||
case "authorize":
|
||||
service.callbackUrl = Meteor.absoluteUrl("_saml/validate/" + service.provider);
|
||||
service.id = samlObject.credentialToken;
|
||||
_saml = new SAML(service);
|
||||
_saml.getAuthorizeUrl(req, function(err, url) {
|
||||
if (err)
|
||||
throw new Error("Unable to generate authorize url");
|
||||
res.writeHead(302, {
|
||||
'Location': url
|
||||
});
|
||||
res.end();
|
||||
});
|
||||
break;
|
||||
case "validate":
|
||||
_saml = new SAML(service);
|
||||
if (Meteor.settings.debug) {
|
||||
console.log("Service: " + JSON.stringify(service));
|
||||
};
|
||||
closePopup(res);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unexpected SAML action " + samlObject.actionName);
|
||||
Accounts.saml.RelayState = req.body.RelayState;
|
||||
_saml.validateResponse(req.body.SAMLResponse, req.body.RelayState, function(err, profile, loggedOut) {
|
||||
if (err)
|
||||
throw new Error("Unable to validate response url: " + err);
|
||||
|
||||
var credentialToken = profile.inResponseToId || profile.InResponseTo || samlObject.credentialToken;
|
||||
if (!credentialToken)
|
||||
throw new Error("Unable to determine credentialToken");
|
||||
Accounts.saml._loginResultForCredentialToken[credentialToken] = {
|
||||
profile: profile
|
||||
};
|
||||
closePopup(res);
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unexpected SAML action " + samlObject.actionName);
|
||||
|
||||
}
|
||||
} catch (err) {
|
||||
|
@ -283,7 +370,7 @@ middleware = function (req, res, next) {
|
|||
}
|
||||
};
|
||||
|
||||
var samlUrlToObject = function (url) {
|
||||
var samlUrlToObject = function(url) {
|
||||
// req.url will be "/_saml/<action>/<service name>/<credentialToken>"
|
||||
if (!url)
|
||||
return null;
|
||||
|
@ -301,12 +388,12 @@ var samlUrlToObject = function (url) {
|
|||
credentialToken: splitPath[4]
|
||||
};
|
||||
if (Meteor.settings.debug) {
|
||||
console.log(result);
|
||||
console.log(result);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
var closePopup = function (res, err) {
|
||||
var closePopup = function(res, err) {
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'text/html'
|
||||
});
|
||||
|
|
|
@ -52,7 +52,7 @@ SAML.prototype.initialize = function(options) {
|
|||
|
||||
SAML.prototype.generateUniqueID = function() {
|
||||
const chars = 'abcdef0123456789';
|
||||
let uniqueID = '';
|
||||
let uniqueID = 'id-';
|
||||
for (let i = 0; i < 20; i++) {
|
||||
uniqueID += chars.substr(Math.floor((Math.random() * 15)), 1);
|
||||
}
|
||||
|
@ -485,24 +485,12 @@ SAML.prototype.generateServiceProviderMetadata = function(callbackUrl) {
|
|||
}
|
||||
}
|
||||
},
|
||||
'#list': [
|
||||
// this should be the set that the xmlenc library supports
|
||||
{
|
||||
'EncryptionMethod': {
|
||||
'@Algorithm': 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'
|
||||
}
|
||||
},
|
||||
{
|
||||
'EncryptionMethod': {
|
||||
'@Algorithm': 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'
|
||||
}
|
||||
},
|
||||
{
|
||||
'EncryptionMethod': {
|
||||
'@Algorithm': 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'
|
||||
}
|
||||
}
|
||||
]
|
||||
'EncryptionMethod': [
|
||||
// this should be the set that the xmlenc library supports
|
||||
{'@Algorithm': 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'},
|
||||
{'@Algorithm': 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'},
|
||||
{'@Algorithm': 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue