All files / src host-api.js

78.12% Statements 25/32
75% Branches 9/12
60% Functions 6/10
78.12% Lines 25/32

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114    1x 1x 1x                                       2x   2x   2x 1x   1x     1x   1x     1x       1x 1x   1x 1x 1x   1x   1x       1x                     4x                   2x           1x 1x   1x                                     1x                
'use strict'
 
const LogoutRequest = require('./handlers/logout-request')
const LoginConsentRequest = require('./handlers/login-consent-request')
const AuthResponseSent = require('./errors/auth-response-sent')
 
/**
 * Handles host-side authentication logic (this method is dependency injected
 * into the OIDC Provider instance).
 *
 * If the user is already authenticated (their user id is in the session),
 * simply sets the authRequest.subject property and returns the request.
 *
 * Otherwise, if not already authenticated, 302-redirects the user to the
 * /login endpoint.
 *
 * @param authRequest {AuthenticationRequest} Auth request object created inside
 *   an OIDC Provider in its /authorize endpoint handler.
 *
 * @throws {AuthResponseSent} If the user has been redirected to /login
 *
 * @return {AuthenticationRequest}
 */
function authenticate (authRequest) {
  const debug = authRequest.host.debug || console.log.bind(console)
 
  const webId = authenticatedUser(authRequest)
 
  if (webId) {
    debug('User is already authenticated as', webId)
 
    initSubjectClaim(authRequest, webId)
  } else {
    // User not authenticated, send them to login
    debug('User not authenticated, sending to /login')
 
    redirectToLogin(authRequest)
  }
 
  return authRequest
}
 
function redirectToLogin (authRequest) {
  console.log('Redirecting user to /login')
  console.log(authRequest.host)
 
  const queryString = new URLSearchParams(authRequest.req.query).toString()
  const loginUrl = `/login${queryString ? '?' + queryString : ''}`
  authRequest.subject = null
 
  authRequest.res.redirect(loginUrl)
 
  signalResponseSent()
}
 
function signalResponseSent () {
  throw new AuthResponseSent('User redirected to login')
}
 
/**
 * Extracts and returns the authenticated user from session, or null if none.
 *
 * @param authRequest {AuthenticationRequest}
 *
 * @return {string|null} Web ID of the authenticated user, or null
 */
function authenticatedUser (authRequest) {
  return authRequest.req.session.userId || null
}
 
/**
 * Initializes the authentication request's subject claim from session user id.
 *
 * @param authRequest {AuthenticationRequest} Auth request object created inside
 *   an OIDC Provider in its /authorize endpoint handler.
 */
function initSubjectClaim (authRequest, webId) {
  authRequest.subject = {
    _id: webId // put webId into the IDToken's subject claim
  }
}
 
function obtainConsent (authRequest) {
  const debug = authRequest.host.debug || console.error.bind(console)
  const skipConsent = false
 
  return LoginConsentRequest.handle(authRequest, skipConsent)
    .catch(error => {
      if (error instanceof AuthResponseSent) {
        throw error
      }
      debug('Error in auth Consent step: ', error)
    })
}
 
function logout (logoutRequest) {
  const debug = console.error.bind(console)
 
  return LogoutRequest.handle(logoutRequest.req, logoutRequest.res)
    .then(() => logoutRequest)
    .catch(error => {
      debug('Error in auth logout() step: ', error)
    })
}
 
module.exports = {
  authenticate,
  obtainConsent,
  logout,
  initSubjectClaim,
  authenticatedUser,
  redirectToLogin
}