Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ An object that can contain the below options. All options are strings, unless s
- `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.
- `login_hint` - (String) - The email used to populate automatically the login field. It's equivalent to the login_hint of open-id.

#### Returns the following functions
- [`create_login_request_url(IdP, options, cb)`](#create_login_request_url) - Get a URL to initiate a login.
Expand All @@ -77,6 +78,7 @@ An object that can contain the below options. All options are strings, unless s
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,
login_hint: 'me@mycompany.com',
allow_unencrypted_assertion: true
}

Expand Down Expand Up @@ -104,6 +106,7 @@ Takes the following arguments:
- `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).
- `login_hint` - (String) - The email used to populate automatically the login field. It's equivalent to the login_hint of open-id.
- `cb(error, login_url, request_id)` - Callback called with the login URL and ID of the request.


Expand Down
15 changes: 10 additions & 5 deletions lib/saml2.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class SAMLError extends Error

# Creates an AuthnRequest and returns it as a string of xml along with the randomly generated ID for the created
# request.
create_authn_request = (issuer, assert_endpoint, destination, force_authn, context, nameid_format) ->
create_authn_request = (issuer, login_hint, assert_endpoint, destination, force_authn, context, nameid_format) ->
if context?
context_element = { 'saml:AuthnContextClassRef': context.class_refs, '@Comparison': context.comparison }

Expand All @@ -41,7 +41,10 @@ create_authn_request = (issuer, assert_endpoint, destination, force_authn, conte
'@AssertionConsumerServiceURL': assert_endpoint
'@ProtocolBinding': 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'
'@ForceAuthn': force_authn
'saml:Issuer': issuer
'saml:Issuer': issuer,
'saml:Subject': {
'saml:NameID': login_hint
},
NameIDPolicy:
'@Format': nameid_format or 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified'
'@AllowCreate': 'true'
Expand Down Expand Up @@ -477,6 +480,8 @@ parse_authn_response = (saml_response, sp_private_keys, idp_certificates, allow_
if audiences?.length > 0
validAudience = _.find audiences, (audience) ->
audienceValue = audience.firstChild?.data?.trim()
if !audienceValue
return true
!_.isEmpty(audienceValue?.trim()) and (
(_.isRegExp(sp_audience) and sp_audience.test(audienceValue)) or
(_.isString(sp_audience) and sp_audience.toLowerCase() == audienceValue.toLowerCase())
Expand Down Expand Up @@ -528,7 +533,7 @@ module.exports.ServiceProvider =
#
# Rest of options can be set/overwritten by the identity provider and/or at function call.
constructor: (options) ->
{@entity_id, @private_key, @certificate, @assert_endpoint, @alt_private_keys, @alt_certs} = options
{@entity_id, @login_hint, @private_key, @certificate, @assert_endpoint, @alt_private_keys, @alt_certs} = options

options.audience ?= @entity_id
options.notbefore_skew ?= 1
Expand All @@ -549,7 +554,7 @@ module.exports.ServiceProvider =
create_login_request_url: (identity_provider, options, cb) ->
options = set_option_defaults options, identity_provider.shared_options, @shared_options

{ id, xml } = create_authn_request @entity_id, @assert_endpoint, identity_provider.sso_login_url, options.force_authn, options.auth_context, options.nameid_format
{ id, xml } = create_authn_request @entity_id, @login_hint, @assert_endpoint, identity_provider.sso_login_url, options.force_authn, options.auth_context, options.nameid_format
zlib.deflateRaw xml, (err, deflated) =>
return cb err if err?
try
Expand All @@ -572,7 +577,7 @@ module.exports.ServiceProvider =
create_authn_request_xml: (identity_provider, options) ->
options = set_option_defaults options, identity_provider.shared_options, @shared_options

{ id, xml } = create_authn_request @entity_id, @assert_endpoint, identity_provider.sso_login_url, options.force_authn, options.auth_context, options.nameid_format
{ id, xml } = create_authn_request @entity_id, @login_hint, @assert_endpoint, identity_provider.sso_login_url, options.force_authn, options.auth_context, options.nameid_format
return sign_authn_request(xml, @private_key, options)

# Returns:
Expand Down