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
(eitherSTUDENT
,FACULTY
orSTAFF
) - Job title:
req.user.user_field_job_title
(e.g. mine comes up asLECTURER
) - Last name:
req.user.last_name
- First name:
req.user.first_name
- Given name:
req.user.given_name
- Email:
req.user.email