Clever / saml2

Node module to abstract away the complexities of the SAML protocol behind an easy to use interface.
Apache License 2.0
356 stars 164 forks source link

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

Closed adamgins closed 8 years ago

adamgins commented 8 years ago

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?

jefff commented 8 years ago

Based on the error you're getting, I'm guessing the claim rules you have set up with ADFS are not sending something that matches the requested NameID format which is causing ADFS to give up and throw an error. You could try changing the settings in ADFS, using a combination of 'Send LDAP Attribute as Claims' to send the email and then using 'Transform an Incoming Claim' to make that into an Email NameID. Or it may be easier to simply remove the nameid_format key from sp_options which would remove that requirement.

adamgins commented 8 years ago

@jefff thanks heaps... that definitely helped.

We now have it working from both IDP and SP initiated requests when on the intranet using the Send LDAP Attribute as Claims & Transform an Incoming Claim

However when going in via the internet via ADFS proxy we are seeing the following error:

s2at
2016-05-31 15:53:39+10:00Assert Error { [Error: SAML Response was not success!]
s2at
2016-05-31 15:53:39+10:00Assert Error 2 { 'urn:oasis:names:tc:SAML:2.0:status:Responder': [] }
s2at
2016-05-31 15:53:39+10:00 message: 'SAML Response was not success!',
s2at
2016-05-31 15:53:39+10:00 extra: { status: { 'urn:oasis:names:tc:SAML:2.0:status:Responder': [] } } }

Any ideas pls?

adamgins commented 8 years ago

Closing this. Thanks for the help and great package. I removed the optional params and it works.

cpurtlebaugh commented 7 years ago

Did you ever find a solution to your last post regarding the status:Responder err?