Skip to content

Commit

Permalink
Merge pull request #17 from JbIPS/master
Browse files Browse the repository at this point in the history
Makes it compatible with Hapi 17
  • Loading branch information
molekilla authored Oct 18, 2018
2 parents 7268c6f + 842435f commit 49a5626
Show file tree
Hide file tree
Showing 12 changed files with 508 additions and 473 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ pids
*.pid
*.seed

# IDE
.*.sw*

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

Expand Down
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
A Hapi plugin that wraps passport-saml for SAML SSO (as SP)
with support for multiple strategies

**Version 2.0.0 is compatible with Hapi 17. For previous version, stay with 1.x.x**

## Current release
1.3.0
2.0.0

## Install

Expand Down Expand Up @@ -50,9 +52,12 @@ const samlOptions = {
// Assertion Response Hook
// Use this to add any specific props for your business
// or appending to existing cookie
onResponse: (profile) => {
const username = profile['urn:oid:2.5.4.4'];
return { ...profile, username };
// or make use of the RelayState
onResponse: (profile, request, h) => {
if(request.payload.RelayState)
return h.redirect(request.payload.RelayState);
else
return h.response();
},
}
}
Expand Down
61 changes: 39 additions & 22 deletions lib/SamlController.js
Original file line number Diff line number Diff line change
@@ -1,46 +1,63 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const Boom = require('boom');
/**
* Endpoint to retrieve metadata
* @function
* @param {Object} request - A Hapi Request
* @param {Object} reply - A Hapi Reply
* @param {Object} h - A Hapi response toolkit
*/
exports.getMetadata = (saml) => (request, reply) => {
return reply(saml.getSamlLib().generateServiceProviderMetadata(saml.props.decryptionCert)).type('application/xml');
exports.getMetadata = (saml) => (request, h) => {
const response = h.response(saml.getSamlLib().generateServiceProviderMetadata(saml.props.decryptionCert));
response.type('application/xml');
return response;
};
/**
* Assert endpoint for when login completes
* @function
* @param {Object} request - A Hapi Request
* @param {Object} reply - A Hapi Reply
* @param {Object} h - A Hapi response toolkit
*/
exports.assert = (saml, onAssertRes, onAssertReq, cookieName, samlCredsPropKey) => (request, reply) => {
exports.assert = (saml, onAssertRes, onAssertReq, cookieName, samlCredsPropKey) => (request, h) => __awaiter(this, void 0, void 0, function* () {
if (request.payload.SAMLRequest) {
// Implement your SAMLRequest handling here
if (onAssertReq) {
return onAssertReq(request, reply);
return onAssertReq(request, h);
}
return reply(500);
throw new Error('Invalid assertion request');
}
if (request.payload.SAMLResponse) {
// Handles SP use cases, e.g. IdP is external and SP is Hapi
saml.validatePostResponse(request.payload, (err, profile) => {
if (err !== null) {
if (err.message.indexOf('SAML assertion expired') > -1) {
return reply.redirect('/');
}
return reply(err.message).code(500);
}
try {
const profile = yield new Promise((resolve, reject) => {
saml.validatePostResponse(request.payload, (err, profile) => {
if (err)
reject(err);
else
resolve(profile);
});
});
if (onAssertRes) {
// the callback shall return the reply object after using it to redirect/response.
const replyFromCallback = onAssertRes(profile, request, reply).state(cookieName, profile);
if (replyFromCallback) {
return replyFromCallback.state(cookieName, profile);
}
return reply.state(cookieName, profile).code(200);
const replyFromCallback = onAssertRes(profile, request, h);
replyFromCallback.state(cookieName, { [samlCredsPropKey]: profile });
return replyFromCallback;
}
throw Boom.badImplementation('onAssert is missing');
}
catch (err) {
if (err.message.indexOf('SAML assertion expired') > -1) {
return h.redirect('/');
}
throw new Error('onAssert is missing');
});
throw Boom.unauthorized(err.message, 'saml');
}
}
};
});
47 changes: 28 additions & 19 deletions lib/SchemeAuthenticate.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,42 @@
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const Boom = require('boom');
exports.SchemeAuthenticate = (saml, settings, samlCredsPropKey) => (request, reply) => {
exports.SchemeAuthenticate = (saml, settings, samlCredsPropKey) => (request, h) => __awaiter(this, void 0, void 0, function* () {
const state = request.state;
let session = state[settings.cookie];
if (!session) {
saml.getSamlLib().getAuthorizeUrl({
headers: request.headers,
body: request.payload,
query: request.query
}, function (err, loginUrl) {
console.log(err);
if (err !== null) {
return reply().code(500);
}
session = {};
session.redirectTo = request.path;
return reply.redirect(loginUrl).state(settings.cookie, session);
const loginUrl = yield new Promise((resolve, reject) => {
saml.getSamlLib().getAuthorizeUrl({
headers: request.headers,
body: request.payload,
query: request.query
}, function (err, loginUrl) {
if (err)
reject(err);
else
resolve(loginUrl);
});
});
return;
session = {};
session.redirectTo = request.path;
h.state(settings.cookie, session);
return h.redirect(loginUrl).takeover();
}
if (session && session[samlCredsPropKey]) {
return reply.continue({
return h.authenticated({
credentials: session[samlCredsPropKey]
});
}
if (request.auth.mode === 'try') {
return reply(null, Boom.unauthorized('Not authenticated'));
throw Boom.unauthorized('Not authenticated');
}
const err = { error: 'Unauthorized' };
return reply(err, 'saml');
};
throw Boom.unauthorized('Unauthorized', 'saml');
});
2 changes: 1 addition & 1 deletion lib/SchemeImpl.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ exports.SchemeImpl = (saml, options, propKey, cookieName) => (server, settings)
password: settings.password,
isSecure: settings.isSecure !== false,
isHttpOnly: settings.isHttpOnly !== false,
// isSameSite: 'Strict',
isSameSite: settings.isSameSite || 'Strict',
ttl: settings.ttl
//domain: settings.domain,
//ignoreErrors: true,
Expand Down
7 changes: 3 additions & 4 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const SchemeImpl_1 = require("./SchemeImpl");
const DEFAULT_COOKIE = `hapi-passport-saml-cookie`;
const SAML_CREDENTIALS_PROP = 'profile';
const SCHEME_NAME = 'saml';
const register = (function (server, options, next) {
const register = (function (server, options) {
const hapiSaml = new HapiSaml_1.HapiSaml(options);
let cookieName = DEFAULT_COOKIE;
const samlCredsPropKey = options.config.cookieSamlCredentialPropKey || SAML_CREDENTIALS_PROP;
Expand Down Expand Up @@ -56,9 +56,8 @@ const register = (function (server, options, next) {
}
// config: hapiSamlOptions.routes.assert.config,
});
next();
});
register.attributes = {
exports.plugin = {
register,
pkg: require('../package.json')
};
exports.register = register;
Loading

0 comments on commit 49a5626

Please sign in to comment.