Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #3377 from HSLdevcom/DT-3674
DT-3674: Fix sso callback
  • Loading branch information
optionsome committed Jul 3, 2020
2 parents 329c3b0 + d6a12bb commit 5d9c2f2
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 134 deletions.
26 changes: 23 additions & 3 deletions server/passport-openid-connect/Strategy.js
@@ -1,3 +1,4 @@
/* eslint-disable func-names */
/* eslint-disable no-console, strict, no-unused-vars, prefer-destructuring, consistent-return */

'use strict';
Expand Down Expand Up @@ -44,9 +45,10 @@ OICStrategy.prototype.init = function() {

OICStrategy.prototype.authenticate = function(req, opts) {
if (opts.callback) {
return this.callback(req, opts);
return this.callback(req);
}
const authurl = this.createAuthUrl(req.query['sso-token']);
const ssoToken = this.getSsoToken(req.headers.cookie);
const authurl = this.createAuthUrl(ssoToken);
this.redirect(authurl);
};

Expand All @@ -56,7 +58,7 @@ OICStrategy.prototype.getUserInfo = function() {
});
};

OICStrategy.prototype.callback = function(req, opts) {
OICStrategy.prototype.callback = function(req) {
return this.client
.authorizationCallback(this.config.redirect_uri, req.query, {
state: req.query.state,
Expand All @@ -77,6 +79,24 @@ OICStrategy.prototype.callback = function(req, opts) {
});
};

OICStrategy.prototype.getSsoToken = function(cookie) {
if (!cookie) {
return null;
}
const cookieObject = cookie.split(';').reduce(function(res, c) {
const [key, val] = c
.trim()
.split('=')
.map(decodeURIComponent);
try {
return Object.assign(res, { [key]: JSON.parse(val) });
} catch (e) {
return Object.assign(res, { [key]: val });
}
}, {});
return cookieObject.token;
};

OICStrategy.prototype.createAuthUrl = function(ssoToken) {
const params = {
response_type: 'code',
Expand Down
152 changes: 152 additions & 0 deletions server/passport-openid-connect/openidConnect.js
@@ -0,0 +1,152 @@
/* eslint-disable func-names */
const passport = require('passport');
const session = require('express-session');
const redis = require('redis');
const request = require('request');
const RedisStore = require('connect-redis')(session);
const LoginStrategy = require('./Strategy').Strategy;

export default function setUpOIDC(app, port) {
/* ********* Setup OpenID Connect ********* */
const devhost = '';
const callbackPath = '/oid_callback'; // connect callback path
// Use Passport with OpenId Connect strategy to authenticate users
const OIDCHost = process.env.OIDCHOST || 'https://hslid-dev.t5.fi';
const FavouriteHost =
process.env.FAVOURITE_HOST || 'https://dev-api.digitransit.fi/favourites';
const RedisHost = process.env.REDIS_HOST || 'localhost';
const RedisPort = process.env.REDIS_PORT || 6379;
const RedisKey = process.env.REDIS_KEY;
const RedisClient = RedisKey
? redis.createClient(RedisPort, RedisHost, {
auth_pass: RedisKey,
tls: { servername: RedisHost },
})
: redis.createClient(RedisPort, RedisHost);
const oic = new LoginStrategy({
issuerHost:
process.env.OIDC_ISSUER || `${OIDCHost}/.well-known/openid-configuration`,
client_id: process.env.OIDC_CLIENT_ID,
client_secret: process.env.OIDC_CLIENT_SECRET,
redirect_uri:
process.env.OIDC_CLIENT_CALLBACK ||
`http://localhost:${port}${callbackPath}`,
scope: 'openid profile',
});
passport.use(oic);
passport.serializeUser(LoginStrategy.serializeUser);
passport.deserializeUser(LoginStrategy.deserializeUser);
// Passport requires session to persist the authentication
app.use(
session({
secret: process.env.SESSION_SECRET || 'reittiopas_secret',
store: new RedisStore({
host: RedisHost,
port: RedisPort,
client: RedisClient,
ttl: 1000 * 60 * 60 * 24 * 365 * 10,
}),
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: process.env.NODE_ENV === 'production',
maxAge: 1000 * 60 * 60 * 24 * 365 * 10,
},
}),
);
// Initialize Passport
app.use(passport.initialize());
app.use(passport.session());

app.get('/', function(req, res, next) {
if (req.isAuthenticated) {
res.clearCookie('token');
}
next();
});

// Initiates an authentication request
// users will be redirected to hsl.id and once authenticated
// they will be returned to the callback handler below
app.get(
'/login',
passport.authenticate('passport-openid-connect', {
successReturnToOrRedirect: '/',
scope: 'profile',
}),
);
// Callback handler that will redirect back to application after successfull authentication
app.get(
callbackPath,
passport.authenticate('passport-openid-connect', {
callback: true,
successReturnToOrRedirect: `${devhost}/`,
failureRedirect: '/',
}),
);
app.get('/sso-callback', function(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.cookie('token', req.query['sso-token'], {
secure: process.env.NODE_ENV === 'production',
httpOnly: process.env.NODE_ENV === 'production',
maxAge: req.query['sso-validity'] * 1000 * 60,
});
res.status(200).send();
}
});
app.get('/logout', function(req, res) {
req.logout();
req.session.destroy(function() {
res.clearCookie('connect.sid');
res.redirect('/');
});
});
app.use('/api', function(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.sendStatus(401);
}
});
/* GET the profile of the current authenticated user */
app.get('/api/user', function(req, res) {
request.get(
`${OIDCHost}/openid/userinfo`,
{
auth: {
bearer: req.user.token.access_token,
},
},
function(err, response, body) {
if (!err) {
res.status(response.statusCode).send(body);
} else {
res.status(401).send('Unauthorized');
}
},
);
});

app.use('/api/user/favourites', function(req, res) {
request(
{
auth: {
bearer: req.user.token.access_token,
},
method: req.method,
url: `${FavouriteHost}/${req.user.data.sub}`,
body: JSON.stringify(req.body),
},
function(err, response, body) {
if (!err) {
res.status(response.statusCode).send(body);
} else {
res.status(404).send(body);
}
},
);
});
}
135 changes: 4 additions & 131 deletions server/server.js
Expand Up @@ -20,7 +20,6 @@ const proxy = require('express-http-proxy');
global.self = { fetch: global.fetch };

let Raven;
const devhost = '';

if (process.env.NODE_ENV === 'production' && process.env.SENTRY_SECRET_DSN) {
Raven = require('raven');
Expand Down Expand Up @@ -48,7 +47,6 @@ const express = require('express');
const expressStaticGzip = require('express-static-gzip');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const request = require('request');
const logger = require('morgan');
const { retryFetch } = require('../app/util/fetchUtils');
const config = require('../app/config').getConfiguration();
Expand All @@ -58,138 +56,13 @@ const port = config.PORT || 8080;
const app = express();

/* Setup functions */
function setUpOIDC() {
/* ********* Setup OpenID Connect ********* */
const callbackPath = '/oid_callback'; // connect callback path
// Use Passport with OpenId Connect strategy to authenticate users
const OIDCHost = process.env.OIDCHOST || 'https://hslid-dev.t5.fi';
const FavouriteHost =
process.env.FAVOURITE_HOST || 'https://dev-api.digitransit.fi/favourites';
const LoginStrategy = require('./passport-openid-connect/Strategy').Strategy;
const passport = require('passport');
const session = require('express-session');

const redis = require('redis');
const RedisStore = require('connect-redis')(session);
const RedisHost = process.env.REDIS_HOST || 'localhost';
const RedisPort = process.env.REDIS_PORT || 6379;
const RedisKey = process.env.REDIS_KEY;
const RedisClient = RedisKey
? redis.createClient(RedisPort, RedisHost, {
auth_pass: RedisKey,
tls: { servername: RedisHost },
})
: redis.createClient(RedisPort, RedisHost);
const oic = new LoginStrategy({
issuerHost:
process.env.OIDC_ISSUER || `${OIDCHost}/.well-known/openid-configuration`,
client_id: process.env.OIDC_CLIENT_ID,
client_secret: process.env.OIDC_CLIENT_SECRET,
redirect_uri:
process.env.OIDC_CLIENT_CALLBACK ||
`http://localhost:${port}${callbackPath}`,
scope: 'openid profile',
});
passport.use(oic);
passport.serializeUser(LoginStrategy.serializeUser);
passport.deserializeUser(LoginStrategy.deserializeUser);
function setUpOpenId() {
const setUpOIDC = require('./passport-openid-connect/openidConnect').default;
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(require('helmet')());
// Passport requires session to persist the authentication
app.use(
session({
secret: process.env.SESSION_SECRET || 'reittiopas_secret',
store: new RedisStore({
host: RedisHost,
port: RedisPort,
client: RedisClient,
ttl: 1000 * 60 * 60 * 24 * 365 * 10,
}),
resave: false,
saveUninitialized: false,
cookie: {
secure: process.env.NODE_ENV === 'production',
httpOnly: process.env.NODE_ENV === 'production',
maxAge: 1000 * 60 * 60 * 24 * 365 * 10,
},
}),
);
// Initialize Passport
app.use(passport.initialize());
app.use(passport.session());
// Initiates an authentication request
// users will be redirected to hsl.id and once authenticated
// they will be returned to the callback handler below
app.get(
'/login',
passport.authenticate('passport-openid-connect', {
successReturnToOrRedirect: '/',
scope: 'profile',
}),
);
// Callback handler that will redirect back to application after successfull authentication
app.get(
callbackPath,
passport.authenticate('passport-openid-connect', {
callback: true,
successReturnToOrRedirect: `${devhost}/`,
failureRedirect: '/',
}),
);
app.get('/logout', function(req, res) {
req.logout();
req.session.destroy(function() {
res.clearCookie('connect.sid');
res.redirect('/');
});
});
app.use('/api', function(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.sendStatus(401);
}
});
/* GET the profile of the current authenticated user */
app.get('/api/user', function(req, res, next) {
request.get(
`${OIDCHost}/openid/userinfo`,
{
auth: {
bearer: req.user.token.access_token,
},
},
function(err, response, body) {
if (!err) {
res.status(response.statusCode).send(body);
} else {
res.status(401).send('Unauthorized');
}
},
);
});

app.use('/api/user/favourites', function(req, res, next) {
request(
{
auth: {
bearer: req.user.token.access_token,
},
method: req.method,
url: `${FavouriteHost}/${req.user.data.sub}`,
body: JSON.stringify(req.body),
},
function(err, response, body) {
if (!err) {
res.status(response.statusCode).send(body);
} else {
res.status(404).send(body);
}
},
);
});
setUpOIDC(app, port);
}

function setUpStaticFolders() {
Expand Down Expand Up @@ -398,7 +271,7 @@ function startServer() {

/* ********* Init ********* */
if (process.env.OIDC_CLIENT_ID) {
setUpOIDC();
setUpOpenId();
}
setUpRaven();
setUpStaticFolders();
Expand Down

0 comments on commit 5d9c2f2

Please sign in to comment.