LCOV - code coverage report
Current view: top level - src - auth.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 19 39 48.7 %
Date: 2024-07-30 12:54:47 Functions: 1 8 12.5 %

          Line data    Source code
       1             : // @ts-check
       2             : const
       3           1 :   { defaultTo, get, includes, isString, some } = require('lodash'),
       4           1 :   debug = require('debug')('auth'),
       5           1 :   passport = require('passport'),
       6           1 :   cookieSession = require('cookie-session'),
       7           1 :   { Issuer, Strategy } = require('openid-client');
       8             : 
       9             : /**
      10             :  * @typedef {import('express').Request} Request
      11             :  * @typedef {import('express').Response} Response
      12             :  * @typedef {import('express').NextFunction} NextFunction
      13             :  * @typedef {import('express').IRouter} IRouter
      14             :  */
      15             : 
      16             : /* to serialize info in session */
      17           1 : passport.serializeUser(function(user, done) {
      18           0 :   done(null, user);
      19             : });
      20             : 
      21           1 : passport.deserializeUser(function(user, done) {
      22           0 :   done(null, user);
      23             : });
      24             : 
      25             : /**
      26             :  * @param {string|string[]} role required role or list of roles (one of)
      27             :  * @param {Request} req incoming request
      28             :  * @param {Response} res outgoing reply
      29             :  * @param {NextFunction} next routing next callback
      30             :  */
      31             : function roleCheck(role, req, res, next) {
      32           0 :   const isStringRole = isString(role);
      33           0 :   const userRoles = get(req.user, 'cern_roles');
      34             : 
      35           0 :   if (!req.user) {
      36           0 :     debug('unauth user -> /auth');
      37           0 :     return res.redirect(defaultTo(req.baseUrl, '') + '/auth');
      38             :   }
      39           0 :   else if (isStringRole && includes(userRoles, role)) {
      40           0 :     return next();
      41             :   }
      42           0 :   else if (!isStringRole && some(role, (r) => includes(userRoles, r))) {
      43           0 :     return next();
      44             :   }
      45             :   else {
      46           0 :     debug('permission denied');
      47           0 :     return res.render('denied', { baseUrl: req.baseUrl, role });
      48             :   }
      49             : }
      50             : 
      51           1 : module.exports = {
      52             :   /**
      53             :    *
      54             :    * @param {IRouter} app
      55             :    * @param {AppServer.Config} config
      56             :    * @param {(user: any) => any} [loginCallback]
      57             :    */
      58             :   async register(app, config, loginCallback) {
      59           1 :     var basePath = get(config, 'basePath', '');
      60             : 
      61             :     const oidcIssuer =
      62           1 :       await Issuer.discover('https://auth.cern.ch/auth/realms/cern');
      63           1 :     const client = new oidcIssuer.Client({
      64             :       client_id: get(config, 'auth.clientID'), /* eslint-disable-line camelcase */
      65             :       client_secret: get(config, 'auth.clientSecret'), /* eslint-disable-line camelcase */
      66             :       redirect_uris: [ get(config, 'auth.callbackURL') ], /* eslint-disable-line camelcase */
      67             :       post_logout_redirect_uris: [ get(config, 'auth.logoutURL') ] /* eslint-disable-line camelcase */
      68             :     });
      69             : 
      70           1 :     passport.use('oidc', new Strategy({ client },
      71             :       /** @type {import('openid-client').StrategyVerifyCallbackUserInfo<any>} */
      72             :       function(tokenSet, userInfo, done) {
      73           0 :         debug('user authenticated: %s', get(userInfo, 'email'));
      74           0 :         const user = tokenSet.claims();
      75           0 :         done(null, user);
      76           0 :         if (loginCallback) {
      77           0 :           loginCallback(user);
      78             :         }
      79             :       }));
      80             : 
      81           1 :     app.use(cookieSession({
      82             :       name: 'oidc:auth.cern.ch',
      83             :       secret: get(config, 'auth.clientSecret', 'default'),
      84             :       path: get(config, 'basePath') || '/',
      85             :       signed: true,
      86             :       overwrite: true
      87             :     }));
      88           1 :     app.use(passport.initialize());
      89           1 :     app.use(passport.session());
      90           1 :     app.get('/auth', passport.authenticate('oidc'));
      91           1 :     app.get('/auth/callback', passport.authenticate('oidc', {
      92             :       successRedirect: basePath + '/',
      93             :       failureRedirect: basePath + '/auth'
      94             :     }));
      95           1 :     app.get('/auth/logout', function(req, res) {
      96           0 :       req.session = null;
      97           0 :       res.redirect(client.endSessionUrl());
      98             :     });
      99           1 :     app.get('/auth/me', function(req, res) { res.send(req.user); });
     100             :   },
     101             :   roleCheck: roleCheck
     102             : };

Generated by: LCOV version 1.16