Coder Social home page Coder Social logo

saml2's Introduction

Maintenance Notice

This library is currently in maintenance mode. Until further notice, the primary directive is to handle bug reports and security issues with this library.

Any library alternatives and suggestions can be filed under an issue.

SAML2-js

CircleCI

saml2-js is a node module that abstracts away the complexities of the SAML protocol behind an easy to use interface. It achieves this this by helping you implement a service provider for the SAML protocol. It currently does not implement the features to act as an identity provider.

Usage

Install with npm.

  npm install saml2-js --save

Include the SAML library.

  var saml2 = require('saml2-js');

Documentation

This library exports two constructors.

  • ServiceProvider - Represents a service provider that relies on a trusted IdentityProvider for authentication and authorization in the SAML flow.
  • IdentityProvider - Represents an online service that authenticates users in the SAML flow.

Note: Some options can be set on the SP, IdP, and/or on a per-method basis. For the options that are set in multiple places, they are overridden in the following order: per-method basis overrides IdP which overrides SP.

Represents a service provider that relies on a trusted IdentityProvider for authentication and authorization in the SAML flow.

Options

An object that can contain the below options. All options are strings, unless specified otherwise. See note for more information on options.

  • entity_id - Required - Unique identifier for the service provider, often the URL of the metadata file.
  • private_key - Required - (PEM format string) - Private key for the service provider.
  • certificate - Required - (PEM format string) - Certificate for the service provider.
  • assert_endpoint - Required - URL of service provider assert endpoint.
  • alt_private_keys - (Array of PEM format strings) - Additional private keys to use when attempting to decrypt responses. Useful for adding backward-compatibility for old certificates after a rollover.
  • alt_certs - (Array of PEM format strings) - Additional certificates to expose in the SAML metadata. Useful for staging new certificates for rollovers.
  • audience - (String or RegExp) — If set, at least one of the <Audience> values within the <AudienceRestriction> condition of a SAML authentication response must match. Defaults to entity_id.
  • notbefore_skew - (Number) – To account for clock skew between IdP and SP, accept responses with a NotBefore condition ahead of the current time (according to our clock) by this number of seconds. Defaults to 1. Set it to 0 for optimum security but no tolerance for clock skew.
  • force_authn - (Boolean) - If true, forces re-authentication of users even if the user has a SSO session with the IdP. This can also be configured on the IdP or on a per-method basis.
  • auth_context - Specifies AuthnContextClassRef. This can also be configured on a per-method basis.
  • nameid_format - Format for Name ID. This can also be configured on a per-method basis.
  • sign_get_request - (Boolean) - If true, signs the request. This can also be configured on the IdP or on a per-method basis.
  • allow_unencrypted_assertion - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the IdP or on a per-method basis.

Returns the following functions

Example

  var sp_options = {
    entity_id: "https://sp.example.com/metadata.xml",
    private_key: fs.readFileSync("key-file.pem").toString(),
    certificate: fs.readFileSync("cert-file.crt").toString(),
    assert_endpoint: "https://sp.example.com/assert",
    force_authn: true,
    auth_context: { comparison: "exact", class_refs: ["urn:oasis:names:tc:SAML:1.0:am:password"] },
    nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",
    sign_get_request: false,
    allow_unencrypted_assertion: true
  }

  // Call service provider constructor with options
  var sp = new saml2.ServiceProvider(sp_options);

  // Example use of service provider.
  // Call metadata to get XML metatadata used in configuration.
  var metadata = sp.create_metadata();

Service provider function definitions

Get a URL to initiate a login.

Takes the following arguments:

  • IdP - IdP
  • options - An object that can contain the below options. All options are strings, unless specified otherwise. See note for more information on options.
    • relay_state - SAML relay state.
    • auth_context - Specifies AuthnContextClassRef. This can also be configured on the SP.
    • nameid_format - Format for Name ID. This can also be configured on the SP.
    • force_authn- (Boolean) - If true, forces re-authentication of users even if the user has a SSO session with the IdP. This can also be configured on the IdP or SP.
    • sign_get_request - (Boolean) - If true, signs the request. This can also be configured on the IdP or SP.
  • cb(error, login_url, request_id) - Callback called with the login URL and ID of the request.

Gets a SAML response object if the login attempt is valid, used for redirect binding.

Takes the following arguments:

  • IdP - IdP
  • options - An object that can contain the below options. All options are strings, unless specified otherwise. See note for more information on options.
    • request_body - (Object) - An object containing the parsed query string parameters. This object should contain the value for either a SAMLResponse or SAMLRequest.
    • allow_unencrypted_assertion - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the IdP or SP.
    • require_session_index - (Boolean) - If false, allow the assertion to be valid without a SessionIndex attribute on the AuthnStatement node.
  • cb(error, response) - Callback called with the request response.
Example of the SAML assert response returned:
{ response_header:
   { id: '_abc-1',
     destination: 'https://sp.example.com/assert',
     in_response_to: '_abc-2' },
  type: 'authn_response',
  user:
   { name_id: 'nameid',
     session_index: '_abc-3',
     attributes:
      { 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname': [ 'Test' ] } } }

Gets a SAML response object if the login attempt is valid, used for post binding.

Takes the following arguments:

  • IdP - IdP
  • options - An object that can contain the below options. All options are strings, unless specified otherwise. See note for more information on options.
    • request_body - (Object) - An object containing the parsed query string parameters. This object should contain the value for either a SAMLResponse or SAMLRequest.
    • allow_unencrypted_assertion - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the IdP or SP.
    • require_session_index - (Boolean) - If false, allow the assertion to be valid without a SessionIndex attribute on the AuthnStatement node.
    • audience - (String or RegExp) — If set, at least one of the <Audience> values within the <AudienceRestriction> condition of a SAML authentication response must match. Defaults to entity_id.
    • notbefore_skew - (Number) – To account for clock skew between IdP and SP, accept responses with a NotBefore condition ahead of the current time (according to our clock) by this number of seconds. Defaults to 1. Set it to 0 for optimum security but no tolerance for clock skew.
  • cb(error, response) - Callback called with the request response.

Creates a SAML Request URL to initiate a user logout.

Takes the following arguments:

  • IdP - IdP. Note: Can pass sso_logout_url instead of IdP.
  • options - An object that can contain the below options. All options are strings, unless specified otherwise. See note for more information on options.
    • name_id - Format for Name ID. This can also be configured on a per-method basis.
    • session_index - Session index to use for creating logout request.
    • allow_unencrypted_assertion - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the IdP or SP.
    • sign_get_request - (Boolean) - If true, signs the request. This can also be configured on the IdP or SP.
    • relay_state - SAML relay state.
  • cb(error, request_url) - Callback called with the logout request url.

Creates a SAML Response URL to confirm a successful IdP initiated logout.

Takes the following arguments:

  • IdP - IdP. Note: Can pass sso_logout_url instead of IdP.
  • options - An object that can contain the below options. All options are strings, unless specified otherwise. See note for more information on options.
    • in_response_to - The ID of the request that this is in response to. Should be checked against any sent request IDs.
    • sign_get_request - (Boolean) - If true, signs the request. This can also be configured on the IdP or SP.
    • relay_state - SAML relay state.
  • cb(error, response_url) - Callback called with the logout response url.

Returns the XML metadata used during the initial SAML configuration.

Represents an online service that authenticates users in the SAML flow.

Returns no functions, exists solely to be passed to an SP function.

Options

An object that can contain the below options. All options are strings, unless specified otherwise. See note for more information on options.

  • sso_login_url - Required - Login url to use during a login request.
  • sso_logout_url - Required - Logout url to use during a logout request.
  • certificates - Required - (PEM format string or array of PEM format strings) - Certificate or certificates (array of certificate) for the identity provider.
  • force_authn - (Boolean) - If true, forces re-authentication of users even if the user has a SSO session with the IdP. This can also be configured on the SP or on a per-method basis.
  • sign_get_request - (Boolean) - If true, signs the request. This can also be configured on the [SP or on a per-method basis.
  • allow_unencrypted_assertion - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the SP or on a per-method basis.

Example

  // Initialize options object
  var idp_options = {
    sso_login_url: "https://idp.example.com/login",
    sso_logout_url: "https://idp.example.com/logout",
    certificates: [fs.readFileSync("cert-file1.crt").toString(), fs.readFileSync("cert-file2.crt").toString()],
    force_authn: true,
    sign_get_request: false,
    allow_unencrypted_assertion: false
  };

  // Call identity provider constructor with options
  var idp = new saml2.IdentityProvider(idp_options);

  // Example usage of identity provider.
  // Pass identity provider into a service provider function with options and a callback.
  sp.post_assert(idp, {}, callback);

Example: Express implementation

Library users will need to implement a set of URL endpoints, here is an example of express endpoints.

var saml2 = require('saml2-js');
var fs = require('fs');
var express = require('express');
var app = express();
// If you're using express <4.0:
// var bodyParser = require('body-parser');
// app.use(bodyParser.urlencoded({
//   extended: true
// }));
app.use(express.urlencoded());

// Create service provider
var sp_options = {
  entity_id: "https://sp.example.com/metadata.xml",
  private_key: fs.readFileSync("key-file.pem").toString(),
  certificate: fs.readFileSync("cert-file.crt").toString(),
  assert_endpoint: "https://sp.example.com/assert"
};
var sp = new saml2.ServiceProvider(sp_options);

// Create identity provider
var idp_options = {
  sso_login_url: "https://idp.example.com/login",
  sso_logout_url: "https://idp.example.com/logout",
  certificates: [fs.readFileSync("cert-file1.crt").toString(), fs.readFileSync("cert-file2.crt").toString()]
};
var idp = new saml2.IdentityProvider(idp_options);

// ------ Define express endpoints ------

// Endpoint to retrieve metadata
app.get("/metadata.xml", function(req, res) {
  res.type('application/xml');
  res.send(sp.create_metadata());
});

// Starting point for login
app.get("/login", function(req, res) {
  sp.create_login_request_url(idp, {}, function(err, login_url, request_id) {
    if (err != null)
      return res.send(500);
    res.redirect(login_url);
  });
});

// Variables used in login/logout process
var name_id, session_index;

// Assert endpoint for when login completes
app.post("/assert", function(req, res) {
  var options = {request_body: req.body};
  sp.post_assert(idp, options, function(err, saml_response) {
    if (err != null)
      return res.send(500);

    // Save name_id and session_index for logout
    // Note:  In practice these should be saved in the user session, not globally.
    name_id = saml_response.user.name_id;
    session_index = saml_response.user.session_index;

    res.send("Hello #{name_id}! session_index: #{session_index}.");
  });
});

// Starting point for logout
app.get("/logout", function(req, res) {
  var options = {
    name_id: name_id,
    session_index: session_index
  };

  sp.create_logout_request_url(idp, options, function(err, logout_url) {
    if (err != null)
      return res.send(500);
    res.redirect(logout_url);
  });
});

app.listen(3000);

saml2's People

Contributors

afumagalli avatar alsmola avatar andrewmaillet avatar azylman avatar bgveenstra avatar chad3814 avatar cozmo avatar danielsmedegaardbuus avatar ipam73 avatar jalleyne avatar jefff avatar johnhuangclever avatar kofi-clever avatar mcab avatar mgduk avatar mohit avatar nasa114 avatar nathanleiby avatar nishant-tomer avatar pjanuario avatar prime-time avatar raghavendhrak avatar renatoprime avatar rgarcia avatar samdecrock avatar sebreh avatar spanditcaa avatar targos avatar tobio avatar xavi- avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

saml2's Issues

HTTP-Redirect binding and SHA-256 with ADFS

According to https://stackoverflow.com/a/36032123/665632, "if you are sending the SAMLRequest as a query parameter (HTTP-Redirect binding), make sure you are using the SHA1 certificate for signing the AuthnRequest. Signing using the SHA256 certificate is not supported in HTTP-Redirect binding by ADFS."

In the code, it looks like signing is always done using SHA-256. So, what should we do if we want to use an HTTP-Redirect binding with ADFS and our existing SHA-256 certificate?

Bad attribute access when assertion contains empty AttributeValues

I noticed that OneLogin sends login assertions like this if there is no value for an attribute:

<saml:Attribute Name="NoValueAttr" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">
  <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string"/>
</saml:Attribute>

However, this causes an error when parsing attribute values. I am getting a TypeError: Cannot read property 'data' of undefined on this line. The attribute_value in question has a childNodes object of length 0. This can be fixed with a filter() to get rid of these empty attributes values, but since my knowledge of SAML is lacking, I wanted to make sure this was the right way to approach this problem.

Callback was already called error from async

const sp = new saml2.ServiceProvider(sso_options.sp_options);
const params = querystring.parse(event.body);

// Our field from the request.
const samlResponse = params['SAMLResponse'];

log.debug(samlResponse);
const req ={};
req.SAMLResponse = samlResponse;
const options = {request_body:req};
const idp = new saml2.IdentityProvider(sso_options.idp_options);
log.debug(options);
sp.post_assert(idp,options,function(err, assertionResponse){
if(err){
log.error(err);
throw(err);
} else {

log.debug(assertionResponse);
const userId = assertionResponse.user.name_id;
const firstName = assertionResponse.user.attributes.firstName[0];
const lastName = assertionResponse.user.attributes.lastName[0];
const email = assertionResponse.user.attributes.email[0];
const accessToken = auth.createAccessToken(userId,firstName,lastName,email,'User');

}})})

I get the below error after i receive the assertionResponse and see the log statement. It seems the callback is invoked before completion of the async calls. What could be the issue ?

2017-09-29T16:58:01.202Z 58dea4fa-a537-11e7-ac37-2b1c78b060d2 Error: Callback was already called.
at /var/task/node_modules/saml2-js/node_modules/async/dist/async.js:903:32
at /var/task/node_modules/saml2-js/lib-js/saml2.js:658:16
at nextTask (/var/task/node_modules/saml2-js/node_modules/async/dist/async.js:5297:14)
at next (/var/task/node_modules/saml2-js/node_modules/async/dist/async.js:5304:9)
at /var/task/node_modules/saml2-js/node_modules/async/dist/async.js:906:16
at /var/task/node_modules/saml2-js/lib-js/saml2.js:633:20
at nextTask (/var/task/node_modules/saml2-js/node_modules/async/dist/async.js:5297:14)
at next (/var/task/node_modules/saml2-js/node_modules/async/dist/async.js:5304:9)
at /var/task/node_modules/saml2-js/node_modules/async/dist/async.js:906:16
at /var/task/node_modules/saml2-js/lib-js/saml2.js:607:16

Process exit on PEM error

If the private key used to sign assertions is malformed (missing line-feeds or wrapped at the wrong column), saml2-js will cause the process to exit due to an uncaught exception:
Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
at Error (native)
at Sign.sign (crypto.js:283:26)
at sign_request (E:\RestAPI-Service\node_modules\saml2-js\lib-js\saml2.js:234:36)
at E:\RestAPI-Service\node_modules\saml2-js\lib-js\saml2.js:731:31
at DeflateRaw.onEnd (zlib.js:227:5)
at emitNone (events.js:91:20)
at DeflateRaw.emit (events.js:185:7)
at endReadableNT (_stream_readable.js:974:12)
at _combinedTickCallback (internal/process/next_tick.js:74:11)
at process._tickCallback (internal/process/next_tick.js:98:9)

I do not see this symptom when the same PEM is used for the HTTPS connection - the server object correct bubbles the exception up to the callback function. My expectation is that the error would bubble up to the callback.
Although I could capture uncaught exceptions, I would still have to exit the process because there would be no way to know if the process should continue to run.

Here is the sample code that is initiating the AuthnRequest:

return new Promise<string[]>((resolve, reject) => {
                sp.create_login_request_url(
                    idp,
                    {
                        relay_state: JSON.stringify({ sid: session.getId() }),
                    },
                    (error, login_url, request_id) => {
                        if (error) {
                            reject(error);
                        } else {
                            resolve([login_url, request_id]);
                        }
                    });
            })
            .then((loginData) => {

                    // redirect happens here
                }, (reason) => {
                    Logger.error('failed to create login URL, reason: ', reason);
                    return 500;
                })

Working example of an encrypted assertion?

Guys can you provide a sample for a working encrypted assertion?
The thing is, with allow_unencrypted_assertion: false, things work fine, but as soon as I add encryption, it fails with Expected 1 EncryptedAssertion; found 0.

Signed data did not contain a SAML Assertion! fails simple response

Testing with the example with Onelogin SAML Encrypted test connector, but fails with 'Signed data did not contain a SAML Assertion!'. I only needed to get the user email address to validate our application rule against. Quite new to SSO and managed to change

signed_dom = (new xmldom.DOMParser()).parseFromString(sn);

to

signed_dom = (new xmldom.DOMParser()).parseFromString(result);

which yields the expected behaviour after debugging as the result contained the assertion and email address. Am i missing a setting/param to make it work as intended with

signed_dom = (new xmldom.DOMParser()).parseFromString(sn);

great work putting this together!

Please append the body parser line in the Example: Express implementation

In the example, please also add 2 lines to add the body-parser, otherwise the req.body after logged in from IDP is always showing empty and thus results in not a SAML response error. We almost ended up struggling 2-3 hrs due to this.

var saml2 = require('saml2-js');
var fs = require('fs');
var express = require('express');
var app = express();

var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({
  extended: true
}));

Thanks,
Raghu

Misleading error message when no "private_key" is given.

Hi, when I "forget" the "private_key", the code complains with the following error:

`Expected 1 Assertion or 1 EncryptedAssertion; found 0``

However, when I look at the code, I see this:

decrypt_assertion saml_response, sp_private_keys, (err, result) ->
  return cb_wf null, result unless err?
  return cb_wf err, result unless allow_unencrypted
  assertion = saml_response.getElementsByTagNameNS(XMLNS.SAML, 'Assertion')
  unless assertion.length is 1
    return cb_wf new Error("Expected 1 Assertion or 1 EncryptedAssertion; found #{assertion.length}")
  cb_wf null, assertion[0].toString()

This tries to decrypt the SAML response with the given private key.

  1. When err == null, continue with the code by returning
  2. When allow_unencrypted == true, continue with the code by returning
  3. Search for the Assertion-element and when not found, complain that EncryptedAssertion is also not found. Wouldn't it be better to say No plain text Assertion found and no certificates given to decrypt the EncryptedAssertion?

SAML Consumer?

Just want to know if i understand this library correct.

I have an IDP (Azure AD) and want to do a SAML login from a pure client sided (no express) javascript in Browser app.
Something like doing the SAML redirect to the login page and grabbing (opt. validating) the SAML response form the IDP.

Is this possible with this library?

Expected 1 EncryptedAssertion; found 0.

I'm trying to implement this keeping the allow_unencrypted_assertions option to false.
I generated a certificate and private key pair and provided it to saml2.
After redirecting to asset I encounter this Error.

Expected 1 EncryptedAssertion; found 0.

An I missing something?

xml-encryption update to fix Jest bug

I was attempting to test some internal code I've built on top of this one in Jest, and importing saml2-js anywhere in the dependency tree causes this error when running Jest:

    TypeError: mods[i] is not a function

      at Object.module.exports (node_modules/node-forge/js/forge.js:41:14)
      at defineFunc (node_modules/node-forge/js/forge.js:47:10)
      at node_modules/node-forge/js/forge.js:90:14
      at define (node_modules/node-forge/js/forge.js:15:7)
      at define (node_modules/node-forge/js/forge.js:54:22)
      at node_modules/node-forge/js/forge.js:59:1
      at Object.<anonymous> (node_modules/node-forge/js/forge.js:92:3)

I've tracked this through a Jest issue to a fix in node-forge which is a dependency of xml-encryption, which is a dependency in this project.

Any chance we could get a version bump on that?

Thanks!

Install errors

I'm trying to get a look at the library to see if I can use it in a project and I'm getting install errors.

First I tried line one from the readme:

E:\Dev\Libraries\saml2-master>npm install saml2-js --save
npm ERR! Windows_NT 6.1.7601
npm ERR! argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "install" "saml2-js" "--save"
npm ERR! node v6.10.2
npm ERR! npm v3.10.10
npm ERR! code ENOSELF
npm ERR! Refusing to install saml2-js as a dependency of itself
npm ERR!
npm ERR! If you need help, you may report this error at:
npm ERR! https://github.com/npm/npm/issues
npm ERR! Please include the following file with any support request:
npm ERR! E:\Dev\Libraries\saml2-master\npm-debug.log

Then I tried just npm install to have it operate from package.json:

E:\Dev\Libraries\saml2-master>npm install
npm WARN deprecated [email protected]: Jade has been renamed to pug, please install the latest version of pug instead of jade
npm WARN deprecated [email protected]: graceful-fs v3.0.0 and before will fail on node releases >= v7.0. Please update to graceful-fs@^4.0.0 as soon as possible. Use 'npm ls graceful-fs' to find it in the tree.
npm WARN deprecated [email protected]: Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue

[email protected] prepublish E:\Dev\Libraries\saml2-master
make build

'make' is not recognized as an internal or external command,
operable program or batch file.

npm WARN [email protected] No license field.
npm ERR! Windows_NT 6.1.7601
npm ERR! argv "C:\Program Files\nodejs\node.exe" "C:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "install"
npm ERR! node v6.10.2
npm ERR! npm v3.10.10
npm ERR! code ELIFECYCLE
npm ERR! [email protected] prepublish: make build
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] prepublish script 'make build'.
npm ERR! Make sure you have the latest version of node.js and npm installed.
npm ERR! If you do, this is most likely a problem with the saml2-js package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! make build
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs saml2-js
npm ERR! Or if that isn't available, you can get their info via:
npm ERR! npm owner ls saml2-js
npm ERR! There is likely additional logging output above.

Is there some additional dependency I'm missing? I see a reference to 'make'. What 'make' is this?

TIA
Mike

Provide an option to sign request using key passphrase

Our current implementation requires the signing to be used with a passphrase.

samlQueryString.Signature = sign.sign({key: format_pem(private_key, 'PRIVATE KEY'), passphrase: 'mypassword'}, 'base64');

Is there any update to this in the near future

if sso_login_url contains ``?``, login request url can not be built

with SAML of google:

https://accounts.google.com/o/saml2/idp?idpid=[your_id]

the method url.format(uri) just ignore completely query object, if search exists in object uri, and returns the same url as sso_login_url

I've to parse the search field, and append to query object, then remove search in uri

the url.format works as intended in nodejs as cited in doc

 search will be used in place of query.

this special case should be handled in saml2's code.

Add debug

Quite useful to see a bit more information from the library at times (e.g. raw assertion, decrypted assertion).

Working with multiple idp's

Hi,
I would like to work with multiple idp's (configuration is based on user's email).
However, since the service is state-less - on the /assert enpoint of my service i need to call post_assert and pass the idp - is there some key (passing in the session) that can help me understand which idp should i call?

Deflating valid SAMLResponse fails with invalid code lengths set error from zlib

OS: MacOS Sierra 10.12.6
Node.js version: 8.9.4
NPM version: 5.6.0

I'm encountering the following error when I call redirect_assert:

invalid code lengths set
Error: invalid code lengths set
    at InflateRaw.zlibOnError (zlib.js:153:15)

Full error from the console:

{ Error: invalid code lengths set
    at InflateRaw.zlibOnError (zlib.js:153:15) errno: -3, code: 'Z_DATA_ERROR' }

The assertion is coming through encrypted from ADFS. The login was a success but for some reason, it can't be deflated by zlib. This is well outside my area of expertise, but I'm getting desperate. Is there anything I can do to get this thing working? I've already tried switching to samlify and that's a non-starter because it can't compile on my local or target system.

I can provide a sample for testing over a more private means of communication if needed

Question: Can this be used in Restify?

I notice this references use in Express, but I'm wondering if this can be used within a Restify server instead. Would this be possible or is it built for use in just Express?

Thanks.

Need additional custom field in AuthnRequest

Hi,

I need a way to (optionally) insert the following fields into the AuthnRequest:

<saml:Subject>
    <saml:NameID>jdoe</saml:NameID>
</saml:Subject>

I managed to achieve this locally by modifying directly the create_authn_request() in saml2.js.

Could you please help to guide me how to best proceed in order to have this change into your code base in this repo?

Thank you.

EncryptedAssertion problem

Hi, I try to do the SSO and can get the SAMLResponse in the req.body when perform method post /assert but there is an error like this: "Error: Expected 1 EncryptedAssertion; found 0". I use the example "Express implementation" in web page "https://www.npmjs.com/package/saml2-js". Please let me know if we have any idea for this problem.

Thanks

security scan failing

After scanning saml2-js module.

npm install saml2-js --save
npm install nsp --global
nsp check

Getting this issue:

screen shot 2017-01-03 at 10 46 43 am

Looks like its using outdated modules....

Update readme

The readme doesn't contain all the options and is a little out of date. Would be helpful to update it..

Failed to decrypt assertion with provided keys

I am working on a project implementing saml2-js. I currently have the following error coming up and I do not know what exactly it means. Can someone please help?

[Error: Failed to decrypt assertion with provided key(s): [ [Error: Decrypt failed: { [Error: Encrypted message length is invalid.] length: 256, expected: 257 }] ]]

I generated my cert and private key here: https://www.samltool.com/self_signed_certs.php

Give Values for Options

I am thinking of using saml2, however, there is one issue. How can we add values to the xml? For example:

 <saml2:Subject>
    <saml2:NameIDFormat="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">Customer_Id</saml2:NameID>
    <saml2:SubjectConfirmationMethod="urn:oasis:names:tc:SAML:2.0:cm:bearer"/>
  </saml2:Subject>

As one can see the NameIDFormat attribute within subject contains a Customer_Id within that. I think adding a way to add values and attributes would be very useful

signed login URL

There should be an option to sign the login request. Our ADFS and PingFederate clients usually enforce this.

Assert response empty

When authenticating with Azure AD, the login is successful but the request body on the assert response is empty.

Unsure if this is a fault with this library or with azure.

Shibboleth support?

Hi :)

I've successfully used saml2 to integrate with ADFS as well as Okta. ADFS automatically configures itself when given the metadata produced by saml2, which is superb :)

Next up I'd like to support Shibboleth as well, but I'm running into problems when trying to test against it using the metadata upload form at TestShib — I simply get the error The file you are attempting to upload is not valid metadata. Please correct any errors and try again..

Not a lot of info there, so I thought I'd try testing the XML against the XSD. This fails on the XSD end, and looks like it's due to some imports that fail...

I'll continue digging, but thought I'd raise the issue here as well, in case this is a known limitation or someone else has encountered this issue as well.

Cheers, and thanks for a great library!

Usage RelayState is not valid?

Hello -
I am using version: saml2-js 2.0.1.
I am getting this error when the serviceProvider object's post_assert function call --

{ [Error: SAML Response is not valid for this audience]
message: 'SAML Response is not valid for this audience',
extra: undefined }

when I have the relay_state in the options object.

Similar to the example (https://github.com/Clever/saml2#example-express-implementation), my post_assert function callback guts looks like:

function(err, saml_response) {
            if (err != null) {
                console.log('error in post assert');
                console.log(err);
                return res.send(500);
            }
            res.send(`Hello ${saml_response.user.name_id}!`);
}

My saml_response object looks like -- which i constructed -- i suspect there might be something wrong here:

{ SAMLResponse: 'some_valid_saml2_response',
  relay_state: 'some_valid_saml2_response' }

Here is the identity provider options object that I am sending.

// Create identity provider

var idp_options = {
    sso_login_url: https://myidp.com,
    sso_logout_url: "https://myidp.com/logout",
    certificates: ['abcd'],
    allow_unencrypted_assertion: true
};

in the sp.create function, i setting relay state in the options object (second arg).

 sp.create_login_request_url(idp, {relay_state: 'some-app-state'}, function(err, login_url, request_id) {
            if (err != null){

Am I not using the relay state properly? Please advise.

I should also point out -- when I do not have the relay state being sent, everything works just fine. So definitely there is something with the relay state -- usage or the saml2-js module's handling..

Is this repo still active?

There are a few PRs here that would be worth having merged and released, but haven't seen any other activity since Jan. Is this repo still active?

is "certificate" really required?

Hi,

In the SP, is "certificate" really required? Because I don't seem to need it to make a successful SAML authentication.

Cheers,
Sam

Update debug dependency for security vulnerability?

Hi there! We security scan our NodeJS repositories with https://snyk.io and it discovered a deep dependency of this module has a low severity DoS vulnerability.

./node_modules/.bin/snyk test
✗ Low severity vulnerability found on [email protected]
- desc: Regular Expression Denial of Service
- info: https://snyk.io/vuln/npm:ms:20151024
- from: [email protected] > [email protected] > [email protected] > [email protected]

It looks like the debug module updated to [email protected] with [email protected] released 2015-05-09. https://github.com/visionmedia/debug/blob/master/History.md

Would you be willing to update your debug dependency? Please let me know if you'd like me to help with upgrading or testing. Thanks!

Additional information about the [email protected] vulnerability from the link above:

Overview

The Regular expression Denial of Service (ReDoS) vulnerability exists in the ms package, affecting version 0.7.0 and below.

Details

ms is a milliseconds conversion utility, used to convert a time period string (i.e. "2 days", "1h") into milliseconds integer. The regular expression used by the function to parse the time is vulnerable to a denial of service attack, where extremely long strings passed to ms() can take a long time to process, subsequently blocking the event loop for that extended period.

"The Regular expression Denial of Service (ReDoS) is a Denial of Service attack, that exploits the fact that most Regular Expression implementations may reach extreme situations that cause them to work very slowly (exponentially related to input size). An attacker can then cause a program using a Regular Expression to enter these extreme situations and then hang for a very long time." 1

Remediation

Upgrade ms to version 0.7.1.

If direct dependency upgrade is not possible, use snyk wizard to patch this vulnerability.

References

https://nodesecurity.io/advisories/46
https://www.owasp.org/index.php/Regular_expression_Denial_of_Service_-_ReDoS

Can't decrypt assertion without a namespace

I have a SAML response looking like:

<samlp:Response
	xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
	xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ...>
        ...
   	<saml:Assertion
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xmlns:xs="http://www.w3.org/2001/XMLSchema" ...>
        ...
        </saml:Assertion>
</samlp:Response>

Because you search for assertions based on namespace: https://github.com/Clever/saml2/blob/master/lib/saml2.coffee#L306

AFAIK, according to the XML spec, if you put the namespace on the outer tag, you don't have to put it on the inner tag anymore. So the SAML response is valid and the assertion should be found regardless.

relay state

RelayState, if provided, should be part of the URL signature on logout/login requests

SessionIndex is optional

I think SessionIndex in the response is optional. But now get_session_index() throws an error if SessionIndex is missing

NameIDFormat not specified in metadata

When exporting SP metadata, md:NameIDFormat is not present in the xml even if it is defined for the ServiceProvider options.

My current understanding is that this should be present inside the md:SPSSODescriptor element.

signature check fails if whole response is signed

Google Apps for business has a SSO app you can add that is a SAML 2.0 IdP. Google doesn't sign just the assertion, it signs the whole response, so the signature check fails in saml2-js.

Google's xml has a <Reference> in the <Signature> that points to the id of the root tag, and xml-crypto looks like it correctly handles this; when I hacked saml2-js to check the whole doc instead of just the <Assertion> it passed.
zip of Google's SAML response

ignore_signature xml assertion problem

Hi,

been trying to use ignore_signature option like this:

var options = {request_body: body, ignore_signature: true};
sp.post_assert(idp, options, function(err, saml_response) { ... }

saml2-js returns this error:

Expected 1 Assertion; found 0

Problem seems to be in lib-js/saml2.js - parse_authn_response()

if (ignore_signature) {
    return cb_wf(null, (new xmldom.DOMParser()).parseFromString(result));
}

After little big of juggling this works:

if (ignore_signature) {
    return cb_wf(null, saml_response);
}

Looks like result is already xml 'Assertion', but it will try to get 'Assertion' again in get_name_id which gives error.

So, can you please tell me if I'm doing something wrong, because i can't test much on current infrastructure.

Thank you.

Is still happening: Error: SAML Assertion signature check failed! (checked 1 certificate(s))

2017-05-08T12:18:51.995668+00:00 app[web.1]: Error: SAML Assertion signature check failed! (checked 1 certificate(s))
2017-05-08T12:18:51.995688+00:00 app[web.1]:     at /app/node_modules/saml2-js/lib-js/saml2.js:633:20
2017-05-08T12:18:51.995689+00:00 app[web.1]:     at fn (/app/node_modules/saml2-js/node_modules/async/lib/async.js:746:34)
2017-05-08T12:18:51.995690+00:00 app[web.1]:     at /app/node_modules/saml2-js/node_modules/async/lib/async.js:1213:16
2017-05-08T12:18:51.995691+00:00 app[web.1]:     at /app/node_modules/saml2-js/node_modules/async/lib/async.js:166:37
2017-05-08T12:18:51.995691+00:00 app[web.1]:     at /app/node_modules/saml2-js/node_modules/async/lib/async.js:706:43
2017-05-08T12:18:51.995692+00:00 app[web.1]:     at /app/node_modules/saml2-js/node_modules/async/lib/async.js:167:37
2017-05-08T12:18:51.995693+00:00 app[web.1]:     at /app/node_modules/saml2-js/node_modules/async/lib/async.js:1209:30
2017-05-08T12:18:51.995693+00:00 app[web.1]:     at /app/node_modules/saml2-js/lib-js/saml2.js:607:16
2017-05-08T12:18:51.995694+00:00 app[web.1]:     at Timeout._onTimeout (/app/node_modules/saml2-js/lib-js/saml2.js:370:17)
2017-05-08T12:18:51.995695+00:00 app[web.1]:     at ontimeout (timers.js:380:14)
2017-05-08T12:18:51.995696+00:00 app[web.1]:     at tryOnTimeout (timers.js:244:5)
2017-05-08T12:18:51.995696+00:00 app[web.1]:     at Timer.listOnTimeout (timers.js:214:5)

Based on the issue here #34, this error seamed to be solved in 2015, but sadly I'm using "saml2-js": "1.11.0" and this is still happening 😟:

The code that I'm using goes like this:

let fs = require('fs');
let saml2 = require('saml2-js');
let express = require('express');
let environment_based_url = require(process.cwd() + '/helpers/environment_based_url');

let router = express.Router();

//
//	Service Provider Options
//
let sp_options = {
	entity_id: "Company_name",
	private_key: fs.readFileSync("./certificates/key.pem").toString(),
	certificate: fs.readFileSync("./certificates/cert.pem").toString(),
	assert_endpoint: environment_based_url() + "/sso/assertion"
};

//
//	Identity Provider Options
//
let idp_options = {
	sso_login_url: "https://accounts.google.com/o/saml2/idp?idpid=C026afnqm",
	sso_logout_url: "https://accounts.google.com/o/saml2/idp?idpid=C026afnqm",
	certificates: fs.readFileSync("./certificates/GoogleIDPCertificate.pem.txt").toString(),
	allow_unencrypted_assertion: true
};

//
//	This route will assert the request from Google
//
router.post('/', function(req, res, next) {

	//
	//	1.	Call service provider constructor with options
	//
	let sp = new saml2.ServiceProvider(sp_options);

	//
	//	2.	Call identity provider constructor with options
	//
	let idp = new saml2.IdentityProvider(idp_options);

	//
	//	3.	Pass the response that we got from the IDP
	//
	let options = {
		request_body: req.body
	};

	//
	//	4.	Check the response
	//
	sp.post_assert(idp, options, function(error, saml_response) {

		if(error)
		{
			return next(error);
		}

		//
		//	->	Display the response
		//
		res.send(saml_response);
		res.end()
	});

});

module.exports = router;

For testing I'm using Google SSO, and when I use the test URL that they provide I get this:

  1. Click... opens a new page with a list of Google accounts that I can choose from
  2. I select the one that I want to use
  3. I get redirected back to my assertion page
  4. The post data from Google gets through
  5. But Assertion check fails

I hope that someone can point to what I'm doing incorrectly, because I'm out of ideas.

ADFS 2 IDP originated req works, SP originated request does not work

HI, any examples of working with ADFS 2.0 pls?

I have the package working when started from the IDP... hit hits my `/assert' URL and all works well.

When I have a Service Providider initiated request it redirects to the IDP, the user logs in and then when it comes back to the /assert url it dies with:

Assert Error { [Error: SAML Response was not success!]
x8af
2016-05-30 16:46:11+10:00 message: 'SAML Response was not success!',
x8af
2016-05-30 16:46:11+10:00 extra: { status: { 'urn:oasis:names:tc:SAML:2.0:status:Requester': [Object] } } }
x8af
2016-05-30 16:46:11+10:00Assert Error 2 { 'urn:oasis:names:tc:SAML:2.0:status:Requester': [ 'urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy' ] }
snw7

Here's the code:

const saml2 = require('saml2-js');
const Fiber = require('fibers');
const bodyParser = require('body-parser');
const cookieParser = require('connect-cookies');


var sp_options = {
    entity_id: Meteor.absoluteUrl("metadata.xml"),
    private_key:  Assets.getText('saml/sp.key'),
    certificate: Assets.getText('saml/sp.crt'),
    assert_endpoint: Meteor.absoluteUrl("assert"),
    force_authn: true,
    nameid_format: "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress",
    sign_get_request: false,
    allow_unencrypted_assertion: true
}

// Call service provider constructor with options
var sp = new saml2.ServiceProvider(sp_options);

// Initialize options object
var idp_options = {
    sso_login_url: "https://<idp address>/adfs/ls",
    sso_logout_url: " https://<idp address>/adfs/ls/?wa=wsignout1.0",
    certificates: [Assets.getText('<idp cert >/.crt')],
    force_authn: true,
    sign_get_request: false,
    allow_unencrypted_assertion: true
};

// Call identity provider constructor with options
var idp = new saml2.IdentityProvider(idp_options);



WebApp.connectHandlers
    .use(bodyParser.urlencoded({ extended: false }))
    .use(cookieParser())
    .use('/metadata.xml', function (req, res, next) {

        res.writeHead(200, { 'Content-Type': 'application/xml'});
        res.end(sp.create_metadata());


    })
    .use('/loginsaml', function (req, res, next) {
        sp.create_login_request_url(idp, {}, function(err, login_url, request_id) {
            if (err != null)
                return res.send(500);
            res.writeHead(301, {'Location': login_url});
            res.end();
        });

    })
    .use('/assert',  function (req, res, next) {


        Fiber(function() {

            var options = {request_body: req.body};
            sp.post_assert(idp, options, function(err, saml_response) {
                if (err != null){
                    console.log("Assert Error", err);
                    console.log("Assert Error 2", err.extra.status);

                    return res.end("Ooops Assert issue!");

                }

                console.log(" saml_response",  saml_response)
                // Save name_id and session_index for logout
                // Note:  In practice these should be saved in the user session, not globally.
                var name_id = saml_response.user.name_id;
                var session_index = saml_response.user.session_index;

                //res.end("Hello " +  saml_response.user.name_id);
                console.log("SAML 1", saml_response.user.name_id.toLowerCase());
                Fiber(function() {
                    v// do some processing
                    } else {
                        userID = user._id;
                    }
                    console.log("SAML 5");
                    //redirect to signed in page

                }).run();


            });

        }).run();


    });

At the moment I removed / changed some of the params:

  auth_context: { comparison: "exact", class_refs: ["urn:oasis:names:tc:SAML:1.0:am:password"] },
    nameid_format: "urn:oasis:names:tc:SAML:2.0:nameid-format:transient",

At that point I got the following error similar error. Apologies I have lost the log file (as I restarted servers).

Any ideas pls?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.