Comparing version 0.8.1 to 1.0.0
// Generated by CoffeeScript 1.7.1 | ||
var IdentityProvider, SAMLError, ServiceProvider, XMLNS, async, certificate_to_keyinfo, check_saml_signature, check_status_success, create_authn_request, create_logout_request, create_logout_response, create_metadata, crypto, debug, decrypt_assertion, format_pem, get_name_id, get_session_index, get_status, parseString, parse_assertion_attributes, parse_authn_response, parse_logout_request, parse_response_header, pretty_assertion_attributes, sign_get_request, to_error, url, util, xmlbuilder, xmlcrypto, xmldom, xmlenc, zlib, _, | ||
var IdentityProvider, SAMLError, ServiceProvider, XMLNS, async, certificate_to_keyinfo, check_saml_signature, check_status_success, create_authn_request, create_logout_request, create_logout_response, create_metadata, crypto, debug, decrypt_assertion, format_pem, get_name_id, get_session_index, get_status, parseString, parse_assertion_attributes, parse_authn_response, parse_logout_request, parse_response_header, pretty_assertion_attributes, set_option_defaults, sign_request, to_error, url, util, xmlbuilder, xmlcrypto, xmldom, xmlenc, zlib, _, | ||
__hasProp = {}.hasOwnProperty, | ||
@@ -91,3 +91,3 @@ __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, | ||
create_metadata = function(issuer, assert_endpoint, signing_certificate, encryption_certificate) { | ||
create_metadata = function(entity_id, assert_endpoint, signing_certificate, encryption_certificate) { | ||
return xmlbuilder.create({ | ||
@@ -97,3 +97,3 @@ 'md:EntityDescriptor': { | ||
'@xmlns:ds': XMLNS.DS, | ||
'@entityID': issuer, | ||
'@entityID': entity_id, | ||
'md:SPSSODescriptor': [ | ||
@@ -170,3 +170,3 @@ { | ||
sign_get_request = function(saml_request, private_key, relay_state, response) { | ||
sign_request = function(saml_request, private_key, relay_state, response) { | ||
var action, data, relay_state_data, samlQueryString, saml_request_data, sigalg_data, sign; | ||
@@ -474,6 +474,4 @@ if (response == null) { | ||
parse_authn_response = function() { | ||
var allow_unencrypted, cb, decrypted_assertion, idp_certificates, saml_response, sp_private_key, user, _i; | ||
saml_response = arguments[0], sp_private_key = arguments[1], idp_certificates = arguments[2], allow_unencrypted = 5 <= arguments.length ? __slice.call(arguments, 3, _i = arguments.length - 1) : (_i = 3, []), cb = arguments[_i++]; | ||
allow_unencrypted = allow_unencrypted[0]; | ||
parse_authn_response = function(saml_response, sp_private_key, idp_certificates, allow_unencrypted, cb) { | ||
var decrypted_assertion, user; | ||
user = {}; | ||
@@ -548,18 +546,18 @@ decrypted_assertion = null; | ||
set_option_defaults = function(request_options, idp_options, sp_options) { | ||
return _.defaults({}, request_options, idp_options, sp_options); | ||
}; | ||
module.exports.ServiceProvider = ServiceProvider = (function() { | ||
function ServiceProvider(issuer, private_key, certificate) { | ||
this.issuer = issuer; | ||
this.private_key = private_key; | ||
this.certificate = certificate; | ||
function ServiceProvider(options) { | ||
this.create_metadata = __bind(this.create_metadata, this); | ||
this.create_logout_url = __bind(this.create_logout_url, this); | ||
this.create_login_url = __bind(this.create_login_url, this); | ||
this.create_logout_request_url = __bind(this.create_logout_request_url, this); | ||
this.entity_id = options.entity_id, this.private_key = options.private_key, this.certificate = options.certificate, this.assert_endpoint = options.assert_endpoint; | ||
this.shared_options = _.pick(options, "force_authn", "auth_context", "nameid_format", "sign_get_request", "allow_unencrypted_assertion"); | ||
} | ||
ServiceProvider.prototype.create_login_url = function() { | ||
var assert_endpoint, cb, id, identity_provider, options, relay_state, xml, _i, _ref; | ||
identity_provider = arguments[0], assert_endpoint = arguments[1], relay_state = 4 <= arguments.length ? __slice.call(arguments, 2, _i = arguments.length - 1) : (_i = 2, []), cb = arguments[_i++]; | ||
options = relay_state[1]; | ||
relay_state = relay_state[0]; | ||
_ref = create_authn_request(this.issuer, assert_endpoint, identity_provider.sso_login_url, options != null ? options.force_authn : void 0, options != null ? options.context : void 0, options != null ? options.nameid_format : void 0), id = _ref.id, xml = _ref.xml; | ||
ServiceProvider.prototype.create_login_request_url = function(identity_provider, options, cb) { | ||
var id, xml, _ref; | ||
options = set_option_defaults(options, identity_provider.shared_options, this.shared_options); | ||
_ref = create_authn_request(this.entity_id, this.assert_endpoint, identity_provider.sso_login_url, options.force_authn, options.auth_context, options.nameid_format), id = _ref.id, xml = _ref.xml; | ||
return zlib.deflateRaw(xml, (function(_this) { | ||
@@ -572,11 +570,11 @@ return function(err, deflated) { | ||
uri = url.parse(identity_provider.sso_login_url); | ||
if (options != null ? options.no_signature : void 0) { | ||
if (options.sign_get_request) { | ||
uri.query = { | ||
SAMLRequest: deflated.toString('base64') | ||
}; | ||
if (relay_state != null) { | ||
uri.query.RelayState = relay_state; | ||
if (options.relay_state != null) { | ||
uri.query.RelayState = options.relay_state; | ||
} | ||
} else { | ||
uri.query = sign_get_request(deflated.toString('base64'), _this.private_key, relay_state); | ||
uri.query = sign_request(deflated.toString('base64'), _this.private_key, options.relay_state); | ||
} | ||
@@ -588,8 +586,21 @@ return cb(null, url.format(uri), id); | ||
ServiceProvider.prototype.assert = function() { | ||
var cb, decrypted_assertion, get_request, identity_provider, options, request_body, response, saml_response, _i; | ||
identity_provider = arguments[0], request_body = arguments[1], get_request = 4 <= arguments.length ? __slice.call(arguments, 2, _i = arguments.length - 1) : (_i = 2, []), cb = arguments[_i++]; | ||
options = get_request[1]; | ||
get_request = get_request[0]; | ||
if (!(((request_body != null ? request_body.SAMLResponse : void 0) != null) || ((request_body != null ? request_body.SAMLRequest : void 0) != null))) { | ||
ServiceProvider.prototype.redirect_assert = function(identity_provider, options, cb) { | ||
options = _.extend(options, { | ||
get_request: true | ||
}); | ||
options = set_option_defaults(options, identity_provider.shared_options, this.shared_options); | ||
return this._assert(identity_provider, options, cb); | ||
}; | ||
ServiceProvider.prototype.post_assert = function(identity_provider, options, cb) { | ||
options = _.extend(options, { | ||
get_request: false | ||
}); | ||
options = set_option_defaults(options, identity_provider.shared_options, this.shared_options); | ||
return this._assert(identity_provider, options, cb); | ||
}; | ||
ServiceProvider.prototype._assert = function(identity_provider, options, cb) { | ||
var decrypted_assertion, response, saml_response, _ref, _ref1; | ||
if (!((((_ref = options.request_body) != null ? _ref.SAMLResponse : void 0) != null) || (((_ref1 = options.request_body) != null ? _ref1.SAMLRequest : void 0) != null))) { | ||
return setImmediate(cb, new Error("Request body does not contain SAMLResponse or SAMLRequest.")); | ||
@@ -603,4 +614,4 @@ } | ||
var raw; | ||
raw = new Buffer(request_body.SAMLResponse || request_body.SAMLRequest, 'base64'); | ||
if (get_request) { | ||
raw = new Buffer(options.request_body.SAMLResponse || options.request_body.SAMLRequest, 'base64'); | ||
if (options.get_request) { | ||
return zlib.inflateRaw(raw, cb_wf); | ||
@@ -626,3 +637,3 @@ } | ||
response.type = 'authn_response'; | ||
return parse_authn_response(saml_response, _this.private_key, identity_provider.certificates, options != null ? options.allow_unencrypted_assertion : void 0, cb_wf); | ||
return parse_authn_response(saml_response, _this.private_key, identity_provider.certificates, options.allow_unencrypted_assertion, cb_wf); | ||
case saml_response.getElementsByTagNameNS(XMLNS.SAMLP, 'LogoutResponse').length !== 1: | ||
@@ -648,7 +659,12 @@ if (!check_status_success(saml_response)) { | ||
ServiceProvider.prototype.create_logout_url = function() { | ||
var cb, identity_provider, name_id, relay_state, session_index, xml, _i; | ||
identity_provider = arguments[0], name_id = arguments[1], session_index = arguments[2], relay_state = 5 <= arguments.length ? __slice.call(arguments, 3, _i = arguments.length - 1) : (_i = 3, []), cb = arguments[_i++]; | ||
relay_state = relay_state[0]; | ||
xml = create_logout_request(this.issuer, name_id, session_index, identity_provider.sso_logout_url); | ||
ServiceProvider.prototype.create_logout_request_url = function(identity_provider, options, cb) { | ||
var xml; | ||
if (_.isString(identity_provider)) { | ||
identity_provider = { | ||
sso_logout_url: identity_provider, | ||
options: {} | ||
}; | ||
} | ||
options = set_option_defaults(options, identity_provider.shared_options, this.shared_options); | ||
xml = create_logout_request(this.entity_id, options.name_id, options.session_index, identity_provider.sso_logout_url); | ||
return zlib.deflateRaw(xml, (function(_this) { | ||
@@ -661,3 +677,12 @@ return function(err, deflated) { | ||
uri = url.parse(identity_provider.sso_logout_url); | ||
uri.query = sign_get_request(deflated.toString('base64'), _this.private_key, relay_state); | ||
if (options.sign_get_request) { | ||
uri.query = { | ||
SAMLRequest: deflated.toString('base64') | ||
}; | ||
if (options.relay_state != null) { | ||
uri.query.RelayState = options.relay_state; | ||
} | ||
} else { | ||
uri.query = sign_request(deflated.toString('base64'), _this.private_key, options.relay_state); | ||
} | ||
return cb(null, url.format(uri)); | ||
@@ -668,5 +693,12 @@ }; | ||
ServiceProvider.prototype.create_logout_response_url = function(in_response_to, logout_url, cb) { | ||
ServiceProvider.prototype.create_logout_response_url = function(identity_provider, options, cb) { | ||
var xml; | ||
xml = create_logout_response(this.issuer, in_response_to, logout_url); | ||
if (_.isString(identity_provider)) { | ||
identity_provider = { | ||
sso_logout_url: identity_provider, | ||
options: {} | ||
}; | ||
} | ||
options = set_option_defaults(options, identity_provider.shared_options, this.shared_options); | ||
xml = create_logout_response(this.entity_id, options.in_response_to, identity_provider.sso_logout_url); | ||
return zlib.deflateRaw(xml, (function(_this) { | ||
@@ -678,4 +710,13 @@ return function(err, deflated) { | ||
} | ||
uri = url.parse(logout_url); | ||
uri.query = sign_get_request(deflated.toString('base64'), _this.private_key, void 0, true); | ||
uri = url.parse(identity_provider.sso_logout_url); | ||
if (options.sign_get_request) { | ||
uri.query = { | ||
SAMLResponse: deflated.toString('base64') | ||
}; | ||
if (options.relay_state != null) { | ||
uri.query.RelayState = options.relay_state; | ||
} | ||
} else { | ||
uri.query = sign_request(deflated.toString('base64'), _this.private_key, options.relay_state, true); | ||
} | ||
return cb(null, url.format(uri)); | ||
@@ -686,4 +727,4 @@ }; | ||
ServiceProvider.prototype.create_metadata = function(assert_endpoint) { | ||
return create_metadata(this.issuer, assert_endpoint, this.certificate, this.certificate); | ||
ServiceProvider.prototype.create_metadata = function() { | ||
return create_metadata(this.entity_id, this.assert_endpoint, this.certificate, this.certificate); | ||
}; | ||
@@ -696,9 +737,8 @@ | ||
module.exports.IdentityProvider = IdentityProvider = (function() { | ||
function IdentityProvider(sso_login_url, sso_logout_url, certificates) { | ||
this.sso_login_url = sso_login_url; | ||
this.sso_logout_url = sso_logout_url; | ||
this.certificates = certificates; | ||
function IdentityProvider(options) { | ||
this.sso_login_url = options.sso_login_url, this.sso_logout_url = options.sso_logout_url, this.certificates = options.certificates; | ||
if (!_.isArray(this.certificates)) { | ||
this.certificates = [this.certificates]; | ||
} | ||
this.shared_options = _.pick(options, "force_authn", "sign_get_request", "allow_unencrypted_assertion"); | ||
} | ||
@@ -714,12 +754,13 @@ | ||
module.exports.format_pem = format_pem; | ||
module.exports.sign_get_request = sign_get_request; | ||
module.exports.sign_request = sign_request; | ||
module.exports.check_saml_signature = check_saml_signature; | ||
module.exports.check_status_success = check_status_success; | ||
module.exports.pretty_assertion_attributes = pretty_assertion_attributes; | ||
module.exports.decrypt_assertion = decrypt_assertion; | ||
module.exports.parse_response_header = parse_response_header; | ||
module.exports.parse_logout_request = parse_logout_request; | ||
module.exports.parse_assertion_attributes = parse_assertion_attributes; | ||
module.exports.get_name_id = get_name_id; | ||
module.exports.get_session_index = get_session_index; | ||
module.exports.pretty_assertion_attributes = pretty_assertion_attributes; | ||
module.exports.parse_assertion_attributes = parse_assertion_attributes; | ||
module.exports.set_option_defaults = set_option_defaults; | ||
} |
{ | ||
"name": "saml2-js", | ||
"version": "0.8.1", | ||
"version": "1.0.0", | ||
"description": "SAML 2.0 node helpers", | ||
@@ -5,0 +5,0 @@ "author": "Clever", |
315
README.md
@@ -1,102 +0,281 @@ | ||
# SAML2 Library | ||
# SAML2-js | ||
## Description | ||
[![Build Status](https://ci.ops.clever.com/api/badge/github.com/Clever/saml2/status.svg?branch=master)](https://ci.ops.clever.com/github.com/Clever/saml2) | ||
Takes care of the complexities of the SAML protocol and provides an easy interface for using it. Specifically, creating metadata.xml files, creating `AuthnRequest`s and parsing and validating `AuthnResponse`s. | ||
`saml2-js` is a node module that abstracts away the complexities of the SAML protocol behind an easy to use interface. | ||
This is exposed as both a series of functions that implement each step of the SAML protocol, and an Express middleware that creates the necessary endpoints for the metadata, the login and the assertion. | ||
## Usage | ||
## Installation | ||
Install with [npm](https://www.npmjs.com/). | ||
```bash | ||
npm install saml2-js | ||
npm install saml2-js --save | ||
``` | ||
## Expected Usage | ||
Include the SAML library. | ||
```coffee | ||
saml_lib = require('saml') | ||
```javascript | ||
var saml2 = require('saml2-js'); | ||
``` | ||
To use the saml library, we think in terms of service providers (e.g. Clever) and identity providers (e.g. partners that use ADFS). | ||
## Documentation | ||
```coffee | ||
sp = saml_lib.service_provider | ||
private_key : 'saml.pem' | ||
certificate : 'saml.crt' | ||
This library exports two constructors. | ||
idp = saml_lib.identity_provider | ||
sso_login_url : 'https://www.example.com/login' | ||
sso_logout_url : 'https://www.example.com/logout' | ||
certificate : 'adfs.crt' | ||
- [`ServiceProvider`](#ServiceProvider) - Represents a service provider that relies on a trusted [`IdentityProvider`](#IdentityProvider) for authentication and authorization in the SAML flow. | ||
- [`IdentityProvider`](#IdentityProvider) - Represents an online service that authenticates users in the SAML flow. | ||
``` | ||
<a name="note_options" /> | ||
**Note:** Some options can be set on the [SP](#ServiceProvider), [IdP](#IdentityProvider), 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](#IdentityProvider) which *overrides* [SP](#ServiceProvider). | ||
Upon creating at least one service provider and one identity provider, you can then create SAML requests between them. | ||
<a name="ServiceProvider" /> | ||
### ServiceProvider(options) | ||
Represents a service provider that relies on a trusted [`IdentityProvider`](#IdentityProvider) for authentication and authorization in the SAML flow. | ||
```coffee | ||
# -- REQUIRED -- | ||
# Returns a redirect URL, at which a user can login | ||
sp.create_login_url(idp, cb) | ||
#### Options | ||
An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) for more information on options. | ||
# Returns user object, if the login attempt was valid. | ||
sp.assert(idp, request_body, cb) | ||
- `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. | ||
- `force_authn` - (Boolean) - If true, forces re-authentication of users even if the user has a SSO session with the [IdP](#IdentityProvider). This can also be configured on the [IdP](#IdentityProvider) 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](#IdentityProvider) or on a per-method basis. | ||
- `allow_unencrypted_assertion` - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the [IdP](#IdentityProvider) or on a per-method basis. | ||
# -- OPTIONAL -- | ||
# Returns a redirect URL, at which a user is logged out. | ||
sp.create_logout_url(idp, cb) | ||
#### Returns the following functions | ||
- [`create_login_request_url(IdP, options, cb)`](#create_login_request_url) - Get a URL to initiate a login. | ||
- [`redirect_assert(IdP, options, cb)`](#redirect_assert) - Gets a SAML response object if the login attempt is valid, used for redirect binding. | ||
- [`post_assert(IdP, options, cb)`](#post_assert) - Gets a SAML response object if the login attempt is valid, used for post binding. | ||
- [`create_logout_request_url(IdP, options, cb)`](#create_logout_request_url)- Creates a SAML Request URL to initiate a user logout. | ||
- [`create_logout_response_url(IdP, options, cb)`](#create_logout_response_url) - Creates a SAML Response URL to confirm a successful [IdP](#IdentityProvider) initiated logout. | ||
- [`create_metadata()`](#create_metadata) - Returns the XML metadata used during the initial SAML configuration. | ||
# Returns XML containing service-provider parameters. | ||
# For use during initial SAML configuration | ||
sp.create_metadata(idp, cb) | ||
``` | ||
#### Example | ||
```javascript | ||
## Helper Methods | ||
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 | ||
} | ||
We will break each of the `service_provider` methods into minimal, testable methods. | ||
// Call service provider constructor with options | ||
var sp = new saml2.ServiceProvider(sp_options); | ||
```coffee | ||
... TODO ... | ||
parse_xml | ||
parse_assert | ||
createAuthRequest | ||
// Example use of service provider. | ||
// Call metadata to get XML metatadata used in configuration. | ||
var metadata = sp.create_metadata(); | ||
``` | ||
## Example: Express implementation using `saml-lib` | ||
#### Service provider function definitions | ||
Library users will need to implement the URL endpoints. For example, express endpoints might look like the following: | ||
<a name="create_login_request_url" /> | ||
##### create_login_request_url(IdP, options, cb) | ||
Get a URL to initiate a login. | ||
```coffee | ||
app.get "/metadata.xml", (request, response) -> | ||
sp.get_metadata idp, (err, metadata) -> | ||
return response.send 500, err if err? | ||
response.send 200, metadata | ||
Takes the following arguments: | ||
- `IdP` - [IdP](#IdentityProvider) | ||
- `options` - An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) for more information on options. | ||
- `relay_state` - SAML relay state. | ||
- `auth_context` - Specifies `AuthnContextClassRef`. This can also be configured on the [SP](#ServiceProvider). | ||
- `nameid_format` - Format for Name ID. This can also be configured on the [SP](#ServiceProvider). | ||
- `force_authn`- (Boolean) - If true, forces re-authentication of users even if the user has a SSO session with the [IdP](#IdentityProvider). This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). | ||
- `sign_get_request` - (Boolean) - If true, signs the request. This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). | ||
- `cb(error, login_url, request_id)` - Callback called with the login URL and ID of the request. | ||
app.get "/login", (request, response) -> | ||
sp.create_login_url idp, (err, login_url) -> | ||
return response.send 500, err if err? | ||
response.location login_url | ||
response.send 302, "Redirecting..." | ||
app.get "/logout", (request, response) -> | ||
sp.create_logout_url idp, (err, login_url) -> | ||
return response.send 500, err if err? | ||
response.location login_url | ||
response.send 302, "Redirecting..." | ||
<a name="redirect_assert" /> | ||
##### redirect_assert(IdP, options, cb) | ||
Gets a SAML response object if the login attempt is valid, used for redirect binding. | ||
app.post "/assert", (request, response) -> | ||
sp.assert idp, response.body, (err, user) -> | ||
response.send 500, err if err? | ||
response.send 200, "Hello #{user.email}!" | ||
Takes the following arguments: | ||
- `IdP` - [IdP](#IdentityProvider) | ||
- `options` - An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) 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](#IdentityProvider) or [SP](#ServiceProvider). | ||
- `cb(error, response)` - Callback called with the [request response](#assert_response). | ||
<a name="assert_response" /> | ||
Example of the SAML assert response returned: | ||
```javascript | ||
{ 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' ] } } } | ||
``` | ||
<a name="post_assert" /> | ||
##### post_assert(IdP, options, cb) | ||
Gets a SAML response object if the login attempt is valid, used for post binding. | ||
Takes the following arguments: | ||
- `IdP` - [IdP](#IdentityProvider) | ||
- `options` - An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) 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](#IdentityProvider) or [SP](#ServiceProvider). | ||
- `cb(error, response)` - Callback called with the [request response](#assert_response). | ||
<a name="create_logout_request_url" /> | ||
##### create_logout_request_url(IdP, options, cb) | ||
Creates a SAML Request URL to initiate a user logout. | ||
Takes the following arguments: | ||
- `IdP` - [IdP](#IdentityProvider). 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](#note_options) 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](#IdentityProvider) or [SP](#ServiceProvider). | ||
+ `sign_get_request` - (Boolean) - If true, signs the request. This can also be configured on the [IdP](#IdentityProvider) or [SP](#ServiceProvider). | ||
+ `relay_state` - SAML relay state. | ||
- `cb(error, request_url)` - Callback called with the logout request url. | ||
<a name="create_logout_response_url" /> | ||
##### create_logout_response_url(IdP, options, cb) | ||
Creates a SAML Response URL to confirm a successful [IdP](#IdentityProvider) initiated logout. | ||
Takes the following arguments: | ||
- `IdP` - [IdP](#IdentityProvider). 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](#note_options) 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](#IdentityProvider) or [SP](#ServiceProvider). | ||
+ `relay_state` - SAML relay state. | ||
- `cb(error, response_url)` - Callback called with the logout response url. | ||
<a name="create_metadata" /> | ||
##### create_metadata() | ||
Returns the XML metadata used during the initial SAML configuration. | ||
<a name="IdentityProvider" /> | ||
### IdentityProvider(options) | ||
Represents an online service that authenticates users in the SAML flow. | ||
Returns no functions, exists solely to be passed to an [SP](#ServiceProvider) function. | ||
#### Options | ||
An object that can contain the below options. All options are strings, unless specified otherwise. See [note](#note_options) 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](#IdentityProvider). This can also be configured on the [SP](#ServiceProvider) or on a per-method basis. | ||
- `sign_get_request` - (Boolean) - If true, signs the request. This can also be configured on the [[SP](#ServiceProvider) or on a per-method basis. | ||
- `allow_unencrypted_assertion` - (Boolean) - If true, allows unencrypted assertions. This can also be configured on the [SP](#ServiceProvider) or on a per-method basis. | ||
#### Example | ||
```javascript | ||
// 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); | ||
``` | ||
## Related Libraries | ||
## Example: Express implementation | ||
- https://github.com/siphon-io/node-saml2 | ||
- https://github.com/bozzltron/express-saml | ||
- https://github.com/bergie/passport-saml | ||
- https://github.com/auth0/node-saml | ||
- https://github.com/auth0/passport-wsfed-saml2 | ||
Library users will need to implement a set of URL endpoints, here is an example of [express](http://expressjs.com/) endpoints. | ||
```javascript | ||
var saml2 = require('saml2-js'); | ||
var fs = require('fs'); | ||
var express = require('express'); | ||
var app = express(); | ||
// 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.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); | ||
}); | ||
}); | ||
// 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 #{saml_response.user.name_id}!"); | ||
}); | ||
}); | ||
// 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); | ||
``` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
112717
25
702
1
282