Skip to content

Commit

Permalink
Merge branch 'GPII-2338'
Browse files Browse the repository at this point in the history
* GPII-2338: (122 commits)
  GPII-2338: Updated .gitignore to ignore gpii-service build
  GPII-2338: Removed stutter
  GPII-2338: Ensuring a buffer is the correct size.
  GPII-2338: Referencing the exact os-service version
  GPII-2338: Referencing the released scoped os-service
  GPII-2338: Added test for sending Error objects over the pipe.
  GPII-2338: Referencing universal#master.
  GPII-2338: More config documentation.
  GPII-2338: fixed require to use scoped package.
  GPII-2338: Moved os-service into the correct place (gpii-service module)
  GPII-2338: added os-service reference
  GPII-2338: fixed universal reference
  GPII-4099: Fixed incorrect argument.
  GPII-4099: Configurable user id source.
  GPII-4099: Blocked user names configurable with wildcards
  GPII-2338: Only asserting process.exit once.
  GPII-4000: Made the blocked username check case-insensitive
  GPII-3988: Added support for environmental logins in the user listeners.
  GPII-4000: Blocking some local usernames from auto-login
  GPII-2338: Making the service always shutdown.
  ...
  • Loading branch information
amb26 committed Jan 8, 2020
2 parents be6abd1 + e06f500 commit b9c2a65
Show file tree
Hide file tree
Showing 46 changed files with 7,620 additions and 2 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/node_modules/
/gpii-service/node_modules/
.vagrant
package-lock.json
**/test/*.exe
Expand Down
3 changes: 2 additions & 1 deletion .nycrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
"include": [
"index.js",
"gpii/node_modules/*/*.js",
"gpii/node_modules/*/src/*.js"
"gpii/node_modules/*/src/*.js",
"service/src/*.js"
],
"exclude": [
"!**/node_modules/"
Expand Down
2 changes: 1 addition & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ module.exports = function (grunt) {
lintAll: {
sources: {
md: [ "./*.md","./gpii/*.md", "./settingsHelper/**/*.md"],
js: ["./gpii/**/*.js", "./tests/**/*.js", "./*.js"],
js: ["./gpii/**/*.js", "./tests/**/*.js", "./*.js", "./service/src/**/*.js", "./service/tests/**/*.js"],
json: ["./gpii/**/*.json", "./tests/**/*.json", "./settingsHelper/**/*.json", "./*.json"],
json5: ["./gpii/**/*.json5", "./tests/**/*.json5", "./*.json5"],
other: ["./.*"]
Expand Down
7 changes: 7 additions & 0 deletions gpii-service/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "eslint-config-fluid",
"env": {
"node": true,
"es6": true
}
}
192 changes: 192 additions & 0 deletions gpii-service/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
# GPII Windows Service

A Windows Service that starts the GPII process (and listeners) when the user logs on, restarts it when it stops
unexpectedly, and provides the ability to run high-privileged tasks.

## Testing

The service can be ran as a normal process, without installing it.

Start the service via `npm start`, and the service will start GPII, and restart GPII if it dies.

`npm run service-dev` will start the service in development mode. That is, without it spawning GPII and allowing new
GPII instances to connect later without any authentication.

In both cases, the service will be started as a normal process but running as Administrator. This may only work in
vagrant boxes where UAC is at the minimal level, otherwise the commands will need to be invoked from an elevated command
prompt.

### From gpii-windows

`npm start` from gpii-windows ensures the service is running (in development mode) before starting gpii. GPII only
requires the service to be running if it applies solutions that depend on it.

### Running as a Windows Service

In order to use the service related functionality, such as starting GPII at the start of a Windows session, the gpii
service needs to be installed and ran as a Windows Service. These need to be started from an elevated command prompt.

Install the service: `npm run service-install`. To install the service using a config that does not start GPII, and
allows later instances to connect, run `npm run service-install-dev`

Start the service: `npm run service-start`

Stop the service: `npm run service-stop`

Uninstall the service: `npm run service-uninstall`

### Logging

When the service is being ran as a Windows service, don't expect a console window. The log will be found in
`%ProgramData%\GPII\gpii-service.log` (`C:\ProgramData\GPII\gpii-service.log`). The service doesn't put the log in the
same directory as GPII, because that's in the directory belonging to a user profile and the server doesn't run as a
normal user.

## Configuration

### [service.json5](config/service.json5)

Production config, used when being ran as `gpii-service.exe`. Starts `./gpii-app.exe` and accepts a connection from only
that child process.

### [service.dev.json5](config/service.dev.json5)

Default development configuration, used when running the service from the source directory. This doesn't start a child
gpii process, but allows any process to connect to the pipe using a known name.

### [service.dev.child.json5](config/service.dev.child.json5)

Starts GPII, via `node ../gpii.js` and accepts a connection only that child process.


To specify the config file, use the `--config` option when running or installing the service.

### Config options

*service.json*: The deployed version is in [%gpii-app/provisioning/service.json5](https://github.com/GPII/gpii-app/tree/master/provisioning)
This gets installed in `c:\Program Files (x86)\Morphic\windows\service.json5`.

```json5
{
"processes": {
/* A process block */
"gpii": { // key doesn't matter
/* The command to invoke. Can be undefined, to just open a pipe. */
"command": "gpii-app.exe", // Starts gpii

/* Provide a pipe to the process. */
"ipc": "gpii", // The value will be used to determine internally what the pipe does (nothing special at the moment)

/* Restart the process if it terminates. */
"autoRestart": true,
},

/* Opens a pipe (\\.\pipe\gpii-gpii), without any authentication. */
"gpii-dev": {
"ipc": "gpii",
"noAuth": true
},

/* More processes */
"rfid-listener": {
"command": "../listeners/GPII_RFIDListener.exe",
"autoRestart": true
},
"usb-listener": {
"command": "../listeners/GPII_USBListener.exe",
"autoRestart": true
}
},
"logging": {
/* Log level: FATAL, ERROR, WARN, INFO, or DEBUG */
"level": "DEBUG"
},
// The file that contains the private site-specific information.
"secretFile": "%ProgramData%\\Morphic Credentials\\secret.txt"
}
```

*secret.json*: This gets installed by the Morphic Credentials Installer, at
`%ProgramData%\\Morphic Credentials\\secret.txt`. It contains private data which is specific to the deployment site.
[test-secret.json5](test-secret.json5) is used for development/testing.

```json5
{
// Unique identifier of the deployment site.
"site": "testing.gpii.net",
// The client credentials for GPII cloud.
"clientCredentials": {
"client_id": "example_id",
"client_secret": "exampleEps19vgFBOzH8AO9GnzDtN9PXNWWmb3nJ1"
},
// Entropy for generating a gpii key based on their account id.
"signKey": "exampleoFd2xBVrMOEbt5zCL7mZy7JOvsOOLT64y91sLKPfvKJYv0D69xTZRaqVLqXRPByUziyNz"
}
```

## Deployment

During the build process, gpii-app's Installer.ps1 will bundle the service into a standalone executable, and the
installer will put it in the same place as gpii-app.exe.

The installer will install and start the service.

## Command line options

`index.js` recognises the following command-line arguments

```
--install Install the Windows Service.
--serviceArgs=ARGS
Comma separated arguments to pass to the service (use with --install).
--uninstall Uninstall the Windows Service.
--service Only used when running as a service.
--config=FILE Specify the config file to use (default: service.json).
```


## Notes

## How it works

Services are slightly different to normal processes, the differences are handled by
[stegru/node-os-service#GPII-2338](https://github.com/stegru/node-os-service/tree/GPII-2338), which is a fork of
[node-os-service](https://github.com/stephenwvickers/node-os-service), where the service-related calls are made.

The service is started by Windows during the start up, then waits for a user to log in. (By listening for the
[SERVICE_CONTROL_SESSIONCHANGE](https://msdn.microsoft.com/library/windows/desktop/ms683241.aspx)
service control code).

When a user logs on, it starts the processes listed in [service-config.json](service-config.json) as that user and will
restart them if they die.

## Debugging

When installing the service, add the debug arguments using the `--nodeArgs`. For example:

```
node index.js --install --nodeArgs=--inspect-brk=0.0.0.0:1234
sc start gpii-service
```

Then quickly attach to the service, before Windows thinks it didn't start.

## IPC

### Client authentication

Initial research in [GPII-2399](https://issues.gpii.net/browse/GPII-2399).

* Service creates pipe and listens
* Service starts Child, passing pipe name in `GPII_SERVICE_PIPE` environment variable.
* pipe name isn't a secret - other processes see open pipes.
* Child connects to pipe
* Service creates an event
* [CreateEvent](https://msdn.microsoft.com/library/ms682396) (unnamed, so only the handle can be used to access it)
* [DuplicateHandle](https://msdn.microsoft.com/library/ms724251) creates another handle to the event that's tied to Child's process
* Service sends the Child's handle to the event through the pipe
* The handle isn't a secret - it's a number that's meaningless to any process other than Child.
* Client calls [SetEvent](https://msdn.microsoft.com/library/ms686211) on the handle.
* Only Child can signal that event
* Service detects the event's signal, access is granted.

14 changes: 14 additions & 0 deletions gpii-service/config/service.dev.child.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Development configuration, auto starts GPII.
{
"processes": {
"gpii": {
"command": "node ../gpii.js",
"ipc": "gpii",
"autoRestart": true
}
},
"logging": {
"level": "DEBUG"
},
"secretFile": "test-secret.json5"
}
14 changes: 14 additions & 0 deletions gpii-service/config/service.dev.json5
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Development configuration, opens a pipe and waits for GPII to connect.
{
"processes": {
"gpii": {
"ipc": "gpii",
// Allow any process to connect.
"noAuth": true
}
},
"logging": {
"level": "DEBUG"
},
"secretFile": "test-secret.json5"
}
Loading

0 comments on commit b9c2a65

Please sign in to comment.