diff --git a/README.md b/README.md index 46fef65..f4f4675 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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 } @@ -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. diff --git a/lib/saml2.coffee b/lib/saml2.coffee index e625d8a..06c77a4 100644 --- a/lib/saml2.coffee +++ b/lib/saml2.coffee @@ -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 } @@ -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' @@ -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()) @@ -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 @@ -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 @@ -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: