All files / src/sso connect.ts

78% Statements 39/50
70.83% Branches 17/24
100% Functions 1/1
78% Lines 39/50

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 1061x 1x               1x 1x   1x                   1x 1x 1x   1x 1x       1x       1x 1x 1x           1x     1x 1x 2x 2x   2x 1x 1x   2x 2x 2x 2x             2x 2x 1x     2x 2x 2x       1x 1x         1x 1x 1x                           1x 1x            
import { hexDump } from './misc';
import {
  sspi,
  UserCredential,
  SecurityContext,
  InitializeSecurityContextInput,
  AcceptSecurityContextInput,
  ServerSecurityContext,
} from '../../lib/api';
import { SSO } from './SSO';
import dbg from 'debug';
 
const debug = dbg('node-expose-sspi:connect');
 
/**
 * Retrieves SSO information from an explicit credential (login/password and domain).
 * The SSO information will be retrieved only if the credential
 * matches a local account or a domain account.
 *
 * @param {sspi.UserCredential} userCredential
 * @returns {SSO} the SSO object.
 */
export async function connect(userCredential: UserCredential): Promise<SSO> {
  const errorMsg = 'Error while building the security context';
  const badLoginPasswordError = new Error('Sorry. Logon denied.');
  try {
    const packageInfo = sspi.QuerySecurityPackageInfo('Negotiate');
    const clientCred = sspi.AcquireCredentialsHandle({
      packageName: 'Negotiate',
      authData: userCredential,
    });
    const serverCred = sspi.AcquireCredentialsHandle({
      packageName: 'Negotiate',
    });
 
    let serverSecurityContext!: ServerSecurityContext;
    let clientSecurityContext!: SecurityContext;
    const clientInput: InitializeSecurityContextInput = {
      credential: clientCred.credential,
      targetName: 'kiki',
      cbMaxToken: packageInfo.cbMaxToken,
    };
 
    const serverInput: AcceptSecurityContextInput = {
      credential: serverCred.credential,
    };
    let i = 0;
    while (true) {
      debug('i: ', i);
      i++;
 
      if (serverSecurityContext) {
        clientInput.SecBufferDesc = serverSecurityContext.SecBufferDesc;
        clientInput.contextHandle = clientSecurityContext?.contextHandle;
      }
      clientSecurityContext = sspi.InitializeSecurityContext(clientInput);
      debug('clientSecurityContext: ', clientSecurityContext);
      debug(hexDump(clientSecurityContext.SecBufferDesc.buffers[0]));
      Iif (
        clientSecurityContext.SECURITY_STATUS !== 'SEC_I_CONTINUE_NEEDED' &&
        clientSecurityContext.SECURITY_STATUS !== 'SEC_E_OK'
      ) {
        throw errorMsg;
      }
 
      serverInput.SecBufferDesc = clientSecurityContext.SecBufferDesc;
      if (serverSecurityContext) {
        serverInput.contextHandle = serverSecurityContext.contextHandle;
      }
 
      serverSecurityContext = sspi.AcceptSecurityContext(serverInput);
      debug('serverSecurityContext: ', serverSecurityContext);
      if (
        serverSecurityContext.SECURITY_STATUS !== 'SEC_I_CONTINUE_NEEDED' &&
        serverSecurityContext.SECURITY_STATUS !== 'SEC_E_OK'
      ) {
        Eif (serverSecurityContext.SECURITY_STATUS === 'SEC_E_LOGON_DENIED') {
          throw badLoginPasswordError;
        }
        throw errorMsg;
      }
 
      debug(hexDump(serverSecurityContext.SecBufferDesc.buffers[0]));
      Eif (serverSecurityContext.SECURITY_STATUS !== 'SEC_E_OK') {
        continue;
      }
      // we have the security context !!!
      debug('We have the security context !!!');
      break;
    }
 
    const sso = new SSO(serverSecurityContext.contextHandle, undefined);
    await sso.load();
    if (sso.user.name === 'Guest') {
      throw badLoginPasswordError;
    }
    return sso;
  } catch (e) {
    Eif (e === badLoginPasswordError) {
      throw e;
    }
    console.error('error', e);
    throw e;
  }
}