Deploy: The final application!

Here is what the index.js looks like:

const express = require("express"); const passport = require("passport"); const saml = require("passport-saml"); const session = require("express-session"); const bodyParser = require("body-parser"); const fs = require("fs"); const PbK = fs.readFileSync(__dirname + "/certs/cert.pem", "utf8"); const PvK = fs.readFileSync(__dirname + "/certs/key.pem", "utf8"); const JHU_SSO_URL = "https://idp.jh.edu/idp/profile/SAML2/Redirect/SSO"; const SP_NAME = "glacial-plateau-47269"; const BASE_URL = "https://glacial-plateau-47269.herokuapp.com"; // Setup SAML strategy const samlStrategy = new saml.Strategy( { // config options here entryPoint: JHU_SSO_URL, issuer: SP_NAME, callbackUrl: `${BASE_URL}/jhu/login/callback`, decryptionPvk: PvK, privateCert: PvK, }, (profile, done) => { return done(null, profile); } ); // Tell passport to use the samlStrategy passport.use("samlStrategy", samlStrategy); // Serialize and deserialize user for paqssport passport.serializeUser(function (user, done) { done(null, user); }); passport.deserializeUser(function (user, done) { done(null, user); }); // Initialize express. const app = express(); // Set up port. const port = process.env.PORT || 7000; // Middleware app.use(bodyParser.urlencoded({ extended: false })); app.use( session({ secret: "use-any-secret", resave: false, saveUninitialized: true }) ); app.use(passport.initialize({})); app.use(passport.session({})); // Set up homepage route app.get("/", (req, res) => { res.send("Test Home Page!"); }); // login route app.get( "/jhu/login", (req, res, next) => { next(); }, passport.authenticate("samlStrategy") ); // callback route app.post( "/jhu/login/callback", (req, res, next) => { next(); }, passport.authenticate("samlStrategy"), (req, res) => { // the user data is in req.user res.send(`welcome ${req.user.first_name}`); } ); // route to metadata app.get("/jhu/metadata", (req, res) => { res.type("application/xml"); res.status(200); res.send(samlStrategy.generateServiceProviderMetadata(PbK, PbK)); }); // Start the server. app.listen(port, () => { console.log(`Listening on http://localhost:${port}/`); });

I have deployed the app on Heroku and it is available at https://glacial-plateau-47269.herokuapp.com. Feel free to experiment with it:

  • Go to https://glacial-plateau-47269.herokuapp.com/jhu/login
  • It must redirect you to JHU SSO sign-in page
  • Enter your credential and login
  • It must redirect back to https://glacial-plateau-47269.herokuapp.com/jhu/login/callback
  • You must see a welcome message!

Assertion attributes

The IdP response includes a list of user attributes (assertions). You need to specify, in your correspondence with enterpriseauth@jhmi.edu, what attributes you need so they send it your way.

Here are some of the attributes you can receive (which will be accessible through req.user object in the callback route):

  • Username: req.user.username (your JHED ID)
  • Affiliation: req.user.user_field_affiliation (either STUDENT, FACULTY or STAFF)
  • Job title: req.user.user_field_job_title (e.g. mine comes up as LECTURER)
  • Last name: req.user.last_name
  • First name: req.user.first_name
  • Given name: req.user.given_name
  • Email: req.user.email