Skip to content

Commit

Permalink
Added documentation for the projects. Renaming and some comment updat…
Browse files Browse the repository at this point in the history
…es to

go with it.
  • Loading branch information
tvrprasad committed Jan 28, 2017
1 parent 0066107 commit 046575e
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 7 deletions.
125 changes: 124 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,124 @@
# WORK IN PROGRESS. DO NOT CONSUME. REALLY. DON'T :)
# Client Side SSPI Authentication Module.

## Overview
SSPI is a Microsoft specific API that may be used by applications for
authenticated communications. This allows an application to use various
available security modules without changing the interface to the security
system. The actual security model is implemented by security packages installed
on the system. For more information, see [SSPI][].

Windows implementation of SSPI is in native code, making it available only for
C/C++ applications. sspi-client module provides a JavaScript interface for
applications that need to communicate with a server using SSPI. Primary
motivitation for building this module is to help implement Windows Integrated
Authentication in [Tedious][].

## API Documentation
Below is the API listing with brief optional descriptions. Refer to comments on
the corresponding functions and classes in code.
### sspi_client
#### SspiClient Class
This class has the core functionality implemented by the module.
##### constructor
```JavaScript
var sspiClient = new SspiClientApi.SspiClient(spn, securityPackage);
````
You may get __spn__ by invoking <code>makeSpn()</code> which takes an FQDN. If
you only have simple hostname or IP address, you may get FQDN by invoking
<code>getFqdn()</code> and then pass it to makeSpn.
##### getNextBlob
```JavaScript
SspiClient.getNextBlob(serverResponse, serverResponseBeginOffset, serverResponseLength, cb)
```
This function takes the server response and makes SSPI calls to get the client
response to send back to the server. You can use just this function to
implement client side SSPI based authentication. This will do initialization
if needed.
#### ensureInitialization
```JavaScript
ensureInitialization(cb);
```
Do initialization if needed.
#### getAvailableSspiPackageNames
```JavaScript
var availableSspiPackageNames = getAvailableSspiPackageNames();
```
Initialization must be completed before this function may be invoked.
#### getDefaultSspiPackageName
```JavaScript
var defaultPackageName = getDefaultSspiPackageName();
```
Initialization must be completed before this function may be invoked.
#### enableNativeDebugLogging
```JavaScript
enableNativeDebugging();
```
Logs detailed debug information from native code.
#### disableNativeDebugLogging
```JavaScript
disableNativeDebugLogging();
```
This together with <code>enableNativeDebugging</code> allows for enabling debug
logging for targeted sections of the application.
### fqdn
#### getFqdn
```JavaScript
getFqdn(hostidentifier, cb);
```
Resolves an IP address or hostname to an FQDN.
### make_spn
#### makeSpn
```JavaScript
var spn = makeSpn(serviceClassName, fqdn, instanceNameOrPort;
```
Puts together the parameters passed in return the Service Principal Name.
## Sample code
For a complete sample, see [Sample Code][].
## Developer Notes
This section has notes for developers to be able to build and run tests.
### Setup and Build
Install [NodeJS][]. Duh!
<code>npm install -g node-gyp</code>
git clone https://github.com/tvrprasad/sspi-client.git
cd sspi-client
npm install
### Run Tests
#### Setup
Copy [test_config.json][] to %USERPROFILE%\.sspi-client\test_config.json
Tweak the values in the file to have the right values for yoursetup. Should be
self-explanatory. This setup is needed for running both unit and integration
tests.
#### Unit Tests
npm run-script test
#### Integration Tests
Integration tests are currently manual but hopefully not too tedious. They test
the functionality end to end. These tests are in the directory
test\integration.
##### sspi_client_test.js
This test sets up a SSPI server and runs SSPI client to connect with it.
Follow instructions in [README_sspi_client_test.md][] to run this test.
##### sqlconnect_windows_integrated_auth.js
This test validates integration with Tedious by attempting to connect and run a
simple query for the following matrix:
1. Two instances of SQL Server, one local and one remote.
2. Supported SSPI protocols - negotiate, kerberos, ntlm.
3. TLS encryption on and off.

Follow instructions in [README_sqlconnect.md] to run this test.
##### sqlconnect_stress.js
This test validates integration with Tedious under stress by attempting to open
about 1000 connections in parallel and run a simple query on each connection,
again in parallel. The mix of connections is as below:
1. Two instances of SQL Server, one local and one remote.
2. Supported SSPI protocols - negotiate, kerberos, ntlm.
3. TLS encryption on and off.

Follow instructions in [README_sqlconnect.md] to run this test.

[SSPI]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa380493(v=vs.85).aspx "SSPI Windows"
[Tedious]: https://github.com/tediousjs/tedious "Node.js implementation of TDS protocol."
[Sample Code]: https://github.com/tvrprasad/sspi-client/blob/master/test/integration/sspi-client-test.js "Sample Code"
[NodeJS]: https://nodejs.org/en/download/current/ "NodeJS Download"
[test_config.json]: https://github.com/tvrprasad/sspi-client/blob/master/test/test_config.json "Test Configuration"
[README_sspi_client_test.md]: https://github.com/tvrprasad/sspi-client/blob/master/test/integration/README_sspi_client_test.md "README_sspi_client_test.md"
[README_sqlconnect.md]: https://github.com/tvrprasad/sspi-client/blob/master/test/integration/README_sqlconnect.md "README_sqlconnect.md"
3 changes: 3 additions & 0 deletions src_js/fqdn.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ function getFqdnForHostname(hostname, cb) {
}

// Handles IP address, hostname, localhost or FQDN.
//
// Signature of cb is:
// cb(err, fqdn)
function getFqdn(hostidentifier, cb) {
if (os.type() !== 'Windows_NT') {
throw new Error('Package currently not-supported on non-Windows platforms.');
Expand Down
2 changes: 1 addition & 1 deletion src_js/make_spn.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const os = require('os');

function makeSpn(serviceClassname, fqdn, instanceNameOrPort, cb) {
function makeSpn(serviceClassname, fqdn, instanceNameOrPort) {
if (os.type() !== 'Windows_NT') {
throw new Error('Package currently not-supported on non-Windows platforms.');
}
Expand Down
16 changes: 15 additions & 1 deletion src_js/sspi_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ let defaultSspiPackageName = 'Initialization not completed.';
class SspiClient {
// Creates an instance of the object in native code, which will invoke
// Windows SSPI calls.
//
// spn - Service principal of the destination server.
// securityPackage - Optional parameter specifying the security package.
// Should be one of 'negotiate', 'kerberos', 'ntlm'.
// If unspecified, the first supported security package
// from the above list will be used.
constructor(spn, securityPackage) {
if (os.type() !== 'Windows_NT') {
throw new Error('Package currently not-supported on non-Windows platforms.');
Expand Down Expand Up @@ -78,7 +84,7 @@ class SspiClient {
// Gets the next SSPI blob on the client side to send to the server as
// part of authentication negotiation.
//
// serverResponse - Buffer with SSPI response from the server.
// serverResponse - Buffer with SSPI response from the server. Null on first call.
// serverResponseBeginOffset - Offset within the buffer where the response begins.
// serverResponseLength - Length of response within the buffer.
//
Expand Down Expand Up @@ -216,6 +222,10 @@ function ensureInitialization(cb) {
}
}

// Initialization must be completed before invoking this function. Any calls to
// getNextBlob will complete initialization. Alternately, invoke
// ensureInitialization and wait for successful callback before invoking this
// function.
function getDefaultSspiPackageName() {
if (!initializeExecutionCompleted) {
throw new Error('Initialization not completed.');
Expand All @@ -224,6 +234,10 @@ function getDefaultSspiPackageName() {
return defaultSspiPackageName;
}

// Initialization must be completed before invoking this function. Any calls to
// getNextBlob will complete initialization. Alternately, invoke
// ensureInitialization and wait for successful callback before invoking this
// function.
function getAvailableSspiPackageNames() {
if (!initializeExecutionCompleted) {
throw new Error('Initialization not completed.');
Expand Down
54 changes: 54 additions & 0 deletions test/integration/README_sqlconnect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Tedious Integration Tests

## Setup sspi-client
Follow instructions under Setup and Build in [README.md][].

## Setup test configuration.
Follow instructions in [README.md][] to setup test_config.json with right
values and in the right location.

## Get Tedious bits.
Integrated Auth is not integrated into the master Tedious repository yet. Get
the bits with Integrated Auth as below:

1. git clone https://github.com/tvrprasad/tedious.git
2. cd tedious
3. git checkout windows-integrated-auth-draft
4. npm install

## Edit Paths.
sspi-client is not added to npm registry yet. So Tedious's package.json does
not have a dependency that pulls in sspi-client. We need to manually tweak
paths to get these tests to work.

### Tedious Paths In Tests
In sqlconnect_windows_integrated_auth.js and sqlconnect_stress.js, find the
following lines and tweak the relative paths to Tedious so they match the
location of Tedious on your machine.

```JavaScript
const Connection = require('../../../../src/tedious/src/tedious').Connection;
const Request = require('../../../../src/tedious/src/tedious').Request;
```

### sspi-client Paths in Tedious
In Tedious\src\connection.js, find the following lines and tweak the relative
paths to Tedious so they matche the location of Tedious on your machine.

```JavaScript
const SspiModuleSupported = require('../../sspi-client/src_js/index').ModuleSupported;
const SspiClientApi = require('../../sspi-client/src_js/index').SspiClientApi;
const Fqdn = require('../../sspi-client/src_js/index.js').Fqdn;
const MakeSpn = require('../../sspi-client/src_js/index.js').MakeSpn;
```

### Run Tests
These tests can take a few seconds.

<code>
node sqlconnect_stress.js

node sqlconnect_windows_integrated_auth.js
</code>

[README.md]: https://github.com/tvrprasad/sspi-client/blob/master/README.md "README.md"
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ This is a manual integration test. Below are the steps:
- Load sspi_test_server\sspi_test_server.sln in Visual Stuido and build.
- Open two console windows.
- Run sspi_test_server.exe you build above.
- Run 'node integration\sspi-client-test.js' in the other console window.
- Run 'node test\integration\sspi_client_test.js' in the other console window.

## Expected Output

Expand Down
File renamed without changes.
3 changes: 0 additions & 3 deletions test/integration/sspi-client-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,6 @@ const getFqdn = () => {
}

const spn = MakeSpn.makeSpn('MSSQLSvc', fqdn, 2000);
// const spn = 'redmond\\venktam';
// const spn = 'random string';
console.log('spn: ', spn);
console.log();
sspiClient = new SspiClientApi.SspiClient(spn);
canInvokeGetNextBlob = true;
Expand Down
6 changes: 6 additions & 0 deletions test/test_config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"localhostName": "<host1>",
"localhostFqdn": "<host1.a.b.com>",
"remoteHostName": "<host2>",
"remoteHostFqdn": "<host2.a.b.com>"
}
6 changes: 6 additions & 0 deletions test/utils/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ function getRemoteHostName() {
os.homedir() + '/.sspi-client/test_config.json', 'utf8')).remoteHostName;
}

function getRemoteHostFqdn() {
return JSON.parse(fs.readFileSync(
os.homedir() + '/.sspi-client/test_config.json', 'utf8')).remoteHostFqdn;
}

module.exports.getLocalhostName = getLocalhostName;
module.exports.getLocalhostFqdn = getLocalhostFqdn;
module.exports.getRemoteHostName = getRemoteHostName;
module.exports.getRemoteHostFqdn = getRemoteHostFqdn;

0 comments on commit 046575e

Please sign in to comment.