Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

passport-saml

Package Overview
Dependencies
Maintainers
1
Versions
68
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

passport-saml - npm Package Compare versions

Comparing version 0.0.3 to 0.0.4

144

lib/passport-saml/saml.js

@@ -56,3 +56,3 @@ var zlib = require('zlib');

SAML.prototype.generateRequest = function (req) {
SAML.prototype.generateAuthorizeRequest = function (req) {
var id = "_" + this.generateUniqueID();

@@ -69,7 +69,10 @@ var instant = this.generateInstant();

var request =
"<samlp:AuthnRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\"" + id + "\" Version=\"2.0\" IssueInstant=\"" + instant + "\" ProtocolBinding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" AssertionConsumerServiceURL=\"" + callbackUrl + "\" Destination=\"" + this.options.entryPoint + "\">" +
"<samlp:AuthnRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\"" + id + "\" Version=\"2.0\" IssueInstant=\"" + instant +
"\" ProtocolBinding=\"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST\" AssertionConsumerServiceURL=\"" + callbackUrl + "\" Destination=\"" +
this.options.entryPoint + "\">" +
"<saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + this.options.issuer + "</saml:Issuer>\n";
if (this.options.identifierFormat) {
request += "<samlp:NameIDPolicy xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" Format=\"" + this.options.identifierFormat + "\" AllowCreate=\"true\"></samlp:NameIDPolicy>\n";
request += "<samlp:NameIDPolicy xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" Format=\"" + this.options.identifierFormat +
"\" AllowCreate=\"true\"></samlp:NameIDPolicy>\n";
}

@@ -85,5 +88,23 @@

SAML.prototype.getAuthorizeUrl = function (req, callback) {
SAML.prototype.generateLogoutRequest = function (req) {
var id = "_" + this.generateUniqueID();
var instant = this.generateInstant();
//samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
// ID="_135ad2fd-b275-4428-b5d6-3ac3361c3a7f" Version="2.0" Destination="https://idphost/adfs/ls/"
//IssueInstant="2008-06-03T12:59:57Z"><saml:Issuer>myhost</saml:Issuer><NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
//NameQualifier="https://idphost/adfs/ls/">myemail@mydomain.com</NameID<samlp:SessionIndex>_0628125f-7f95-42cc-ad8e-fde86ae90bbe
//</samlp:SessionIndex></samlp:LogoutRequest>
var request = "<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" "+
"xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\" ID=\""+id+"\" Version=\"2.0\" IssueInstant=\""+instant+
"\" Destination=\""+this.options.entryPoint + "\">" +
"<saml:Issuer xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">" + this.options.issuer + "</saml:Issuer>"+
"<saml:NameID Format=\""+req.user.nameIDFormat+"\">"+req.user.nameID+"</saml:NameID>"+
"</samlp:LogoutRequest>";
return request;
}
SAML.prototype.requestToUrl = function (request, operation, callback) {
var self = this;
var request = this.generateRequest(req);
zlib.deflateRaw(request, function(err, buffer) {

@@ -94,5 +115,11 @@ if (err) {

var base64 = buffer.toString('base64');
var target = self.options.entryPoint + '?'
var base64 = buffer.toString('base64');
var target = self.options.entryPoint + '?';
if (operation === 'logout') {
if (self.options.logoutUrl) {
target = self.options.logoutUrl + '?';
}
}
var samlRequest = {

@@ -110,4 +137,16 @@ SAMLRequest: base64

});
}
SAML.prototype.getAuthorizeUrl = function (req, callback) {
var request = this.generateAuthorizeRequest(req);
this.requestToUrl(request, 'authorize', callback);
};
SAML.prototype.getLogoutUrl = function(req, callback) {
var request = this.generateLogoutRequest(req);
this.requestToUrl(request, 'logout', callback);
}
SAML.prototype.certToPEM = function (cert) {

@@ -123,3 +162,3 @@ cert = cert.match(/.{1,64}/g).join('\n');

var doc = new xmldom.DOMParser().parseFromString(xml);
var signature = xmlCrypto.xpath.SelectNodes(doc, "/*/*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];
var signature = xmlCrypto.xpath.SelectNodes(doc, "//*[local-name(.)='Signature' and namespace-uri(.)='http://www.w3.org/2000/09/xmldsig#']")[0];
var sig = new xmlCrypto.SignedXml();

@@ -141,3 +180,5 @@ sig.keyInfoProvider = {

return parentElement['saml:' + elementName];
}
} else if (parentElement['samlp:'+elementName]) {
return parentElement['samlp:'+elementName];
}
return parentElement[elementName];

@@ -149,38 +190,75 @@ }

var xml = new Buffer(samlResponse, 'base64').toString('ascii');
var parser = new xml2js.Parser();
var parser = new xml2js.Parser({explicitRoot:true});
parser.parseString(xml, function (err, doc) {
// Verify signature
if (self.options.cert && !self.validateSignature(xml, self.options.cert)) {
return callback(new Error('Invalid signature'), null);
return callback(new Error('Invalid signature'), null, false);
}
var assertion = self.getElement(doc, 'Assertion');
if (!assertion) {
return callback(new Error('Missing SAML assertion'), null);
}
var response = self.getElement(doc, 'Response');
if (response) {
var assertion = self.getElement(response, 'Assertion');
if (!assertion) {
return callback(new Error('Missing SAML assertion'), null, false);
}
profile = {};
profile.issuer = self.getElement(assertion, 'Issuer');
profile = {};
var issuer = self.getElement(assertion[0], 'Issuer');
if (issuer) {
profile.issuer = issuer[0];
}
var attributeStatement = self.getElement(assertion, 'AttributeStatement');
var attributes = self.getElement(attributeStatement, 'Attribute');
attributes.forEach(function (attribute) {
var value = self.getElement(attribute, 'AttributeValue');
if (typeof value === 'string') {
profile[attribute['@'].Name] = value;
return;
var subject = self.getElement(assertion[0], 'Subject');
if (subject) {
var nameID = self.getElement(subject[0], 'NameID');
if (nameID) {
profile.nameID = nameID[0]["_"];
if (nameID[0]['$'].Format) {
profile.nameIDFormat = nameID[0]['$'].Format;
}
}
}
profile[attribute['@'].Name] = value['#'];
});
if (!profile.mail && profile['urn:oid:0.9.2342.19200300.100.1.3']) {
// See http://www.incommonfederation.org/attributesummary.html for definition of attribute OIDs
profile.mail = profile['urn:oid:0.9.2342.19200300.100.1.3'];
}
var attributeStatement = self.getElement(assertion[0], 'AttributeStatement');
if (!attributeStatement) {
return callback(new Error('Missing AttributeStatement'), null, false);
}
if (!profile.email && profile.mail) {
profile.email = profile.mail;
var attributes = self.getElement(attributeStatement[0], 'Attribute');
if (attributes) {
attributes.forEach(function (attribute) {
var value = self.getElement(attribute, 'AttributeValue');
if (typeof value[0] === 'string') {
profile[attribute['$'].Name] = value[0];
} else {
profile[attribute['$'].Name] = value[0]['_'];
}
});
}
if (!profile.mail && profile['urn:oid:0.9.2342.19200300.100.1.3']) {
// See http://www.incommonfederation.org/attributesummary.html for definition of attribute OIDs
profile.mail = profile['urn:oid:0.9.2342.19200300.100.1.3'];
}
if (!profile.email && profile.mail) {
profile.email = profile.mail;
}
callback(null, profile, false);
} else {
var logoutResponse = self.getElement(doc, 'LogoutResponse');
if (logoutResponse){
callback(null, null, true);
} else {
return callback(new Error('Unknown SAML response message'), null, false);
}
}
callback(null, profile);
});

@@ -187,0 +265,0 @@ };

@@ -31,3 +31,3 @@ var passport = require('passport');

this._saml.validateResponse(response, function (err, profile) {
this._saml.validateResponse(response, function (err, profile, loggedOut) {
if (err) {

@@ -37,2 +37,12 @@ return self.error(err);

if (loggedOut) {
if (self._saml.options.logoutRedirect) {
self.redirect(self._saml.options.logoutRedirect);
return;
} else {
self.redirect("/");
}
}
var verified = function (err, user, info) {

@@ -65,2 +75,6 @@ if (err) {

Strategy.prototype.logout = function(req, callback) {
this._saml.getLogoutUrl(req, callback);
};
module.exports = Strategy;
{
"name": "passport-saml",
"version": "0.0.3",
"version": "0.0.4",
"licenses": [{

@@ -22,3 +22,3 @@ "type": "MIT",

"zlib": "1.0.x",
"xml2js": "0.1.x",
"xml2js": "0.2.0",
"xml-crypto": "0.0.x",

@@ -25,0 +25,0 @@ "xmldom": "0.1.x"

@@ -6,4 +6,6 @@ Passport-SAML

The code is based on Michael Bosworth's [express-saml](https://github.com/bozzltron/express-saml) library.
The code was originally based on Michael Bosworth's [express-saml](https://github.com/bozzltron/express-saml) library.
Passport-SAML has been tested to work with both [SimpleSAMLphp](http://simplesamlphp.org/) based Identity Providers, and with [Active Directory Federation Services](http://en.wikipedia.org/wiki/Active_Directory_Federation_Services).
## Installation

@@ -64,1 +66,33 @@

```
## Security and signatures
Passport-SAML uses the HTTP Redirect Binding for its `AuthnRequest`s, and expects to receive the messages back via the HTTP POST binding.
Authentication requests sent by Passport-SAML can be signed using RSA-SHA1. To sign them you need to provide a private key in the PEM format via the `privateCert` configuration key. For example:
```javascript
privateCert: fs.readFileSync('./cert.pem', 'utf-8')
```
It is a good idea to validate the incoming SAML Responses. For this, you can provide the Identity Provider's certificate using the `cert` confguration key:
```javascript
cert: 'MIICizCCAfQCCQCY8tKaMc0BMjANBgkqh ... W=='
```
## Usage with Active Directory Federation Services
Here is a configuration that has been proven to work with ADFS:
```javascript
{
entryPoint: 'https://ad.example.net/adfs/ls/',
issuer: 'https://your-app.example.net/login/callback',
callbackUrl: 'https://your-app.example.net/login/callback',
cert: 'MIICizCCAfQCCQCY8tKaMc0BMjANBgkqh ... W==',
identifierFormat: null
}
```
Please note that ADFS needs to have a trust established to your service in order for this to work.
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc