diff --git a/README.md b/README.md index 3c30d11..8f1f7e1 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ This is the official documentation for [Anvil Connect](https://github.com/anvilresearch/connect) and related projects. +## [Getting started](getting-started.md) + ## Support ### Chat with us diff --git a/augment.md b/augment.md deleted file mode 100644 index 74e95fb..0000000 --- a/augment.md +++ /dev/null @@ -1,12 +0,0 @@ -# Connect Augment -We'd like to support every language, every platform, and every application there is in the world. Unfortunately, that's not something that happens overnight. - -Below is a list of the pieces of software the Connect community wants to support as soon as possible. If there's one you'd like Connect to support, send a PR adding it to the list, and it will be registered as a priority for integration. - - diff --git a/clients.md b/clients.md index 82fc86a..4f8c40f 100644 --- a/clients.md +++ b/clients.md @@ -96,6 +96,76 @@ content-type: application/json ### REST API +### Registration permissions + +Anvil Connect can be configured for three types of client registration: `dynamic`, `token`, or `scoped`, each being more restrictive than the previous option. The default `client_registration` type is `scoped`. Trusted clients require additional scope to register. This can be configured with the `trusted_registration_scope` setting, which defaults to `realm`. + +#### Dynamic Client Registration + +With `client_registration` set to `dynamic`, any party can register a client with the authorization server. Optionally, a bearer token may be provided in the authorization header per RFC6750. If a valid access token is presented with a registration request, the client will be associated with the user represented by that token. + +```json +{ + // ... + "client_registration": "dynamic", + // ... +} +``` + +The following table indicates expected responses to *Dynamic Client Registration* requests. + +| trusted | w/token | w/scope | response | +|:-------:|:-------:|:-------:|----------:| +| | | | 201 | +| x | | | 403 | +| | x | | 201 | +| x | x | | 403 | +| x | x | x | 201 | +| | x | x | 201 | + + +#### Token-restricted Registration + +Client registration can be restricted so that a valid user access token is required by setting `client_registration` to `token`. In this case, any request without a token will fail. As with *Dynamic Client Registration*, in order to register a trusted client, the access token must have sufficient scope. + +```json +{ + // ... + "client_registration": "token", + // ... +} +``` + +| trusted | w/token | w/scope | response | +|:-------:|:-------:|:-------:|----------:| +| | | | 403 | +| x | | | 403 | +| | x | | 201 | +| x | x | | 403 | +| x | x | x | 201 | +| | x | x | 201 | + +#### Scoped Registration + +Third party registration can be restricted altogether with the `scoped` `client_registration` setting. In this case, all registration requires a prescribed `registration_scope`. + +```json +{ + // ... + "client_registration": "scoped", + // ... +} +``` + +| trusted | w/token | w/scope | response | +|:-------:|:-------:|:-------:|----------:| +| | | | 403 | +| x | | | 403 | +| | x | | 403 | +| x | x | | 403 | +| x | x | x | 201 | +| | x | x | 201 | + ## Client Properties #### redirect_uris diff --git a/getting-started.md b/getting-started.md new file mode 100644 index 0000000..7462ccd --- /dev/null +++ b/getting-started.md @@ -0,0 +1,250 @@ +## Getting Started + +### Requirements + +Anvil Connect works with the latest versions of [Node.js][nodejs] (0.12.x) or +[io.js][iojs] (3.x.x) and [Redis][redis] (3.0.x) and is tested on +[Debian][debian], [Ubuntu][ubuntu], [Alpine][alpine] Linux distributions, and +Mac OS X. + +The server and its dependencies can optionally run inside [Docker][docker] +containers. We recommend using Docker Compose, although it is not required. +[Installation instructions][docker-install] for Docker and related tools are +available on the Docker website. On Mac and Windows you can easily set up a +Docker environment using the [Docker Toolbox][docker-toolbox]. + +[nodejs]: https://nodejs.org +[iojs]: https://iojs.org +[redis]: http://redis.io +[debian]: https://www.debian.org +[ubuntu]: http://www.ubuntu.com +[alpine]: https://www.alpinelinux.org +[docker]: https://www.docker.com +[docker-install]: https://docs.docker.com/installation +[docker-toolbox]: https://www.docker.com/toolbox + + +### Initializing your project + +To get started with Anvil Connect, install the `anvil-connect-cli` package +globally using npm. + +```bash +$ npm install -g anvil-connect-cli +``` + +After this has completed successfully, you can generate all the files you'll +need to run your own custom auth server. + +First, make a new directory and `cd` into it. Then, run `nvl init`. + +``` +$ mkdir myauthserver +$ cd myauthserver +$ nvl init +``` + +This command will prompt you for some essential information and choices about +your deployment. + +With default options, `nv init` will generate all the files you +need to customize and run Anvil Connect, with or without Docker, Redis and +nginx, depending on your prompt selections. + +If you choose to use nginx, you'll also be prompted to create a new self-signed +SSL certificate. You can opt out of any of the components other than Anvil +Connect. + +```bash +# defaults to the name of the current directory +? What would you like to name your Connect instance? + +# FQDN of the auth server +# This can be localhost, an IP address, or a (sub)domain +? What (sub)domain will you use? connect.example.io + +# We recommend our default Docker setup, including +# support for running Anvil Connect, Redis, and nginx +# with Docker Compose. You can opt out of any or all +# of this if Docker isn't your cup of tea. +? Would you like to use Docker? Yes + +# We can generate a Redis configuration and optional +# Dockerfile. You can also configure Anvil Connect to +# run against any Redis instance available over the +# network. +? Would you like to run Redis? Yes + +# We recommend using nginx for SSL termination, load balancing, +# and caching of static assets. If you wish to employ other means +# answer "no". +? Would you like to run nginx? Yes + +# With nginx or without it, be sure to use SSL in production +? Would you like to create a self-signed SSL cert? Yes + +# If you opt "yes" to generating an SSL cert, you'll be +# prompted for the certificate subject information. +? Country Name (2 letter code) US +? State or Province Name (full name) South Dakota +? Locality Name (eg, city) Rapid City +? Organization Name (eg, company) Anvil Research, Inc +``` + +Once finished, you'll have a directory containing all the files needed to run +your auth server. + +We've structured the package so that you can customize your server without +having to maintain a fork. You can add your own static assets, customize views +(HTML templates), integrate custom auth protocols, manage project-specific +dependencies, and keep all this, along with your configuration files, under +version control using git. This setup makes upgrading Anvil Connect as simple +as changing the version number in `connect/package.json` in most cases. + + +## Run + +### Running locally + +A Redis instance needs to running locally or accessible over the network. Before you +can run Anvil Connect, you'll also need to install npm and bower dependencies. + +```bash +$ cd connect +$ npm install +$ bower install +``` + +You can run the server in `development` mode with: + +```bash +$ node server.js +``` + +This will use the `config/development.json` settings. To run in production mode, set +the `NODE_ENV` environment variable to `production`. + +```bash +$ NODE_ENV=production node server.js +``` + +When Anvil Connect starts for the first time, it will check to see whether or +not the Redis server at the configured hostname and port has any data inside and +whether or not it contains data from a valid Anvil Connect instance. + +If Anvil Connect detects any existing data in the database, and it is not from +an Anvil Connect instance, it will halt with the following error: + +``` +Redis already contains data, but it doesn't seem to be an Anvil Connect database. +If you are SURE it is, start the server with --no-db-check to skip this check. +``` + +If you are sure that there is no conflicting data in Redis, for example, +in the event that you may have edited Redis's data manually, start Anvil Connect +with the `--no-db-check` flag. + +```bash +$ node server.js --no-db-check +``` + + + +### Running in Docker Containers + +If you've opted to use Docker, Redis, and nginx, you should be ready to roll. +You can use Docker Compose to run a complete, production-ready set of +containers. + +First, you'll want to ensure a few things are in order. + +#### IP Address + +If you're running on Linux, Anvil Connect will be bound to localhost and/or the +IP of your computer/server. Once the containers are running, you should be able +to reach the service at `https://0.0.0.0`, `https://127.0.0.1`, or +`https://localhost`. + + +On Mac once you've installed the [Docker Toolbox][docker-toolbox] you can get +the IP address with the following command. + +```bash +$ docker-machine ip default +``` + +#### /etc/hosts + +To work with your Anvil Connect instance locally, it's a good idea to make an +entry in your `/etc/hosts` file. For example, on a Mac, you'll want to +associate the (sub)domain you provided the generator with the IP address of +your Docker host. + +```bash +192.168.99.100 connect.example.io +``` + +#### SSL Certificate + +When you ran `nv init`, you may have opted to generate a self-signed SSL +certificate. The files were created in the `nginx/certs` directory of this +project. If you did not opt to generate these files, you'll need to provide +your own `nginx.key` and `nginx.crt` files in the `nginx/certs` directory. + + +#### Start Anvil Connect with Docker Compose + +You can run these commands in the directory where you ran `nvl init`. + +```bash +$ docker-compose up -d +``` + +#### Stop + +``` +$ docker-compose stop [connect|nginx|redis] +``` + +#### Restart + +``` +$ docker-compose restart +``` + +#### View Logs + +If you're having trouble reaching the running Anvil Connect instance, you can +view the logs for each type of container with the following command. + +``` +$ docker-compose logs +``` + + +### Building Custom Containers + +By default, Docker Compose is configured to use images provided by Anvil +Research on Docker Hub. You can build images yourself by commenting out the +`image` property of a service in `docker-compose.yml` and uncommenting the +`build` property like so: + +```yaml +connect: + build: connect + #image: anvilresearch/connect + ... +``` + +While we highly recommend using the official images or provided Dockerfiles, +if necessary you can modify them to suit your requirements. You can also push +your own custom images to Docker Hub and use them to run Connect by referencing +them in the `image` property in `docker-compose.yml`. + +```yaml +connect: + #build: connect + image: /connect +``` + +### [Configuring the server](server/configuration.md) diff --git a/permissions.md b/permissions.md index 7b85d44..b40ddcb 100644 --- a/permissions.md +++ b/permissions.md @@ -7,75 +7,3 @@ ## Users ## Clients - -## Dynamic Registration - -Anvil Connect can be configured for three types of client registration: `dynamic`, `token`, or `scoped`, each being more restrictive than the previous option. The default `client_registration` type is `scoped`. Trusted clients require additional scope to register. This can be configured with the `trusted_registration_scope` setting, which defaults to `realm`. - -### Dynamic Client Registration - -With `client_registration` set to `dynamic`, any party can register a client with the authorization server. Optionally, a bearer token may be provided in the authorization header per RFC6750. If a valid access token is presented with a registration request, the client will be associated with the user represented by that token. - -```json -{ - // ... - "client_registration": "dynamic", - // ... -} -``` - -The following table indicates expected responses to *Dynamic Client Registration* requests. - -| trusted | w/token | w/scope | response | -|:-------:|:-------:|:-------:|----------:| -| | | | 201 | -| x | | | 403 | -| | x | | 201 | -| x | x | | 403 | -| x | x | x | 201 | -| | x | x | 201 | - - -### Token-restricted Registration - -Client registration can be restricted so that a valid user access token is required by setting `client_registration` to `token`. In this case, any request without a token will fail. As with *Dynamic Client Registration*, in order to register a trusted client, the access token must have sufficient scope. - -```json -{ - // ... - "client_registration": "token", - // ... -} -``` - -| trusted | w/token | w/scope | response | -|:-------:|:-------:|:-------:|----------:| -| | | | 403 | -| x | | | 403 | -| | x | | 201 | -| x | x | | 403 | -| x | x | x | 201 | -| | x | x | 201 | - -### Scoped Registration - -Third party registration can be restricted altogether with the `scoped` `client_registration` setting. In this case, all registration requires a prescribed `registration_scope`. - -```json -{ - // ... - "client_registration": "scoped", - // ... -} -``` - -| trusted | w/token | w/scope | response | -|:-------:|:-------:|:-------:|----------:| -| | | | 403 | -| x | | | 403 | -| | x | | 403 | -| x | x | | 403 | -| x | x | x | 201 | -| | x | x | 201 | - - diff --git a/protocols.md b/protocols.md new file mode 100644 index 0000000..0c639f9 --- /dev/null +++ b/protocols.md @@ -0,0 +1,72 @@ +## Protocols + +Out of the box, Anvil Connect supports authenticating users with local +passwords, OAuth 1.0, OAuth 2.0, OpenID, LDAP, and Active Directory. We call +these authentication methods "protocols". + +For each supported protocol, we implement a module that supports any compliant +provider. This way, there's no need to write OAuth 2.0 code to support a new +OAuth 2.0-based service. Within Anvil Connect, [providers](providers/) and +protocols work together to separate the differences between authentication +methods from the parts that remain the same. + +In addition to what we ship with Anvil Connect, it only takes a small amount of +code in your project to authenticate using virtually any other method. You can +customize your Connect instance to use additional providers and protocols by +creating special directories in your project and adding some JavaScript. + +### Adding protocols + +To add a new protocol, create a `connect/protocols` directory in your Anvil +Connect project and add a JavaScript file named for the protocol. The filename +should be a camel cased string. + +This new module should export a Passport strategy that has two extra functions +appended to it: `verifier` and `initialize`. You can use any virtually existing +Passport strategy as a starting point, or write your own from scratch. + + +```javascript +/** + * Dependencies + */ + +var Strategy = require('passport-ANYTHING').Strategy; + + +/** + * Verifier + */ + +function verifier (req, [?..,] done) { + // ... +}; + +Strategy.verifier = verifier; + + +/** + * Initialize + */ + +function initialize (provider, configuration) { + return new Strategy([...], verifier); +} + +Strategy.initialize = initialize; + + +/** + * Export + */ + +module.exports = strategy; +``` + +The verifier function is the callback that get's invoked by Passport once +authentication has completed. + +#### Verifier + +#### Initialize + diff --git a/providers/LDAP.md b/providers/LDAP.md new file mode 100644 index 0000000..cbffcdf --- /dev/null +++ b/providers/LDAP.md @@ -0,0 +1,128 @@ +## LDAP + +Because of LDAP's flexible nature, LDAP support is provided in the form of a +provider template which can be used to handle custom LDAP attribute to OpenID +Connect claim scenarios. A basic provider that inherits this template without +modification is provided for convenience. + +LDAP providers can be configured as follows: + +```json +{ + // ... + "providers": { + "LDAP": { + "url": "ldap://corp.example.com", + "bindDn": "cn=admin,dc=example,dc=com", + "bindCredentials": "pass1234", + "searchBase": "ou=people,dc=example,dc=com", + "searchFilter": "(cn={{username}})" + } + } +} +``` + +A [full list of configuration options][passport-ldapauth-config] is available +from the passport-ldapauth library. + +By default, LDAP attributes map to OpenID Connect claims as such: + +OpenID Connect claim | LDAP attribute +-------------------- | -------------- +id | dn +email | mail +name | cn +given\_name | givenName +family\_name | sn +phone\_number | telephoneNumber +address.formatted | postalAddress +address.street\_address | street +address.locality | l +address.region | st +address.postal\_code | postalCode +address.country | co + +To customize these mappings, simply create your own provider in the `providers` +folder of your Anvil Connect instance. For example: + +```js +module.exports = function(config) { + return { + id: 'MyLDAP', + name: 'Example Corp.', + templates: [ 'LDAP' ], + mapping: { + id: 'uid', + name: 'displayName' + }; +}; +``` + + +### Active Directory + +The expected configuration format for the Active Directory provider is as +follows: + +```json +{ + ... + "providers": { + "ActiveDirectory": { + "url": "ldaps://corp.example.com", + "domainDn": "dc=example,dc=com", + "tlsOptions": { + "ca": "/path/to/the/self/signed/ca-cert.cer" + } + } + } +} +``` + +Anvil Connect also provides the `ActiveDirectory` provider template in the event +that you may be working with several domains at a time or if you would like to +customize certain aspects of the AD provider, such as the name. + +Here's an example provider that uses the template: + +```javascript +module.exports = function(config) { + return { + id: 'examplecorpad', + name: 'Example Corporation', + templates: [ 'ActiveDirectory' ] + }; +}; +``` + +To configure this provider, you would use `examplecorpad` in place of +`ActiveDirectory` in your configuration. + +```json +{ + ... + "providers": { + "examplecorpad": { ... } + } +} +``` + + +### Groups + +The LDAP provider will synchronize the user's role membership in Anvil Connect +with their group membership in the domain. In order to take advantage of this +feature, each LDAP group for which you wish to enable synchronization must have +a respective role in Connect named after the fully-qualified distinguished name +(FQDN) of the group in the directory. + +For example, if there exists a group in the directory service with FQDN +`CN=Group 1,OU=Groups,DC=example,DC=com`, that group will only influence the +user's role membership if there also exists a role in Connect named +`CN=Group 1,OU=Groups,DC=example,DC=com`. You can create this role using the +`nv add role` command: + +```bash +nv add role '{ "name": "CN=Group 1,OU=Groups,DC=example,DC=com" }' +``` + diff --git a/providers/OAuth.md b/providers/OAuth.md new file mode 100644 index 0000000..428d172 --- /dev/null +++ b/providers/OAuth.md @@ -0,0 +1,16 @@ +## OAuth 1.0 + +OAuth 1.0 providers require `oauth_consumer_key` and `oauth_consumer_secret`. + + +```json +{ + //... + "providers": { + "twitter": { + "oauth_consumer_key": "Consumer Key (API Key)", + "oauth_consumer_secret": "Consumer Secret" + } + } +} +``` diff --git a/providers/OAuth2.md b/providers/OAuth2.md new file mode 100644 index 0000000..4d8dcee --- /dev/null +++ b/providers/OAuth2.md @@ -0,0 +1,103 @@ +## OAuth 2.0 + +Most OAuth 2.0 providers only require a `client_id` and `client_secret`. You can +obtain these by registering your app with the respective provider. + +```json +{ + // ... + "providers": { + "facebook": { + "client_id": "App ID", + "client_secret": "App Secret" + } + } +} +``` + +OAuth 2.0 supports a `scope` authorization parameter, and some providers use it +to restricted access to specific resources. You can set scope for a provider +using the `scope` property with an array of strings. See provider API +documentation for specifics. + +```json +{ + //... + "providers": { + "google": { + "client_id": "Client ID", + "client_secret": "Client secret", + "scope": [ + "https://www.googleapis.com/auth/userinfo.profile", + "https://www.googleapis.com/auth/userinfo.email" + ] + }, + "linkedin": { + "client_id": "Client ID", + "client_secret": "Client Secret", + "scope": [ + "r_basicprofile", + "r_fullprofile", + "r_emailaddress", + "r_network", + "r_contactinfo" + ] + } + } +} +``` + +### Creating a new OAuth 2.0 provider + +To integrate with a provider we don't support out of the box, you can create +your own provider definition in a custom `connect/providers` directory in your +project. You can use [officially supported provider definitions][supported-providers] +as examples. + +[supported-providers]: https://github.com/anvilresearch/connect/tree/master/providers + +``` +/** + * GitHub + */ + +module.exports = function (config) { + return { + id: 'github', + name: 'GitHub', + protocol: 'OAuth2', + url: 'https://github.com', + redirect_uri: config.issuer + '/connect/github/callback', + endpoints: { + authorize: { + url: 'https://github.com/login/oauth/authorize', + method: 'POST', + }, + token: { + url: 'https://github.com/login/oauth/access_token', + method: 'POST', + auth: 'client_secret_post' + }, + user: { + url: 'https://api.github.com/user', + method: 'GET', + auth: { + header: 'Authorization', + scheme: 'Bearer' + } + } + }, + separator: ',', + mapping: { + id: 'id', + email: 'email', + name: 'name', + website: 'blog', + preferredUsername: 'login', + profile: 'html_url', + picture: 'avatar_url', + } + }; +}; +``` + diff --git a/providers/Password.md b/providers/Password.md new file mode 100644 index 0000000..00e9b2f --- /dev/null +++ b/providers/Password.md @@ -0,0 +1,19 @@ +## Password authentication + +Local password authentication can be configured easily by adding a password +object to the providers section of your configuration files. + +Anvil Connect uses the mellt package to test password strength. You can +configure the minimum number of days required to crack a password with the +`daysToCrack` setting, which defaults to 14. + +```json +{ + // ... + "providers": { + "password": { + "daysToCrack": 21 + } + } +} +``` diff --git a/providers/README.md b/providers/README.md new file mode 100644 index 0000000..a33625b --- /dev/null +++ b/providers/README.md @@ -0,0 +1,122 @@ +## Providers + +A "provider" is a specific service providing authentication by means of a given +protocol. For example, Facebook, GitHub, and Dropbox are OAuth 2.0 providers. +They implement OAuth 2.0, and that's the protocol we use to interface with them +in the auth server. + +### Overview + +To add a new provider, create a `connect/providers` directory in your Anvil +Connect project and add a file named for the provider. The filename (not +including the .js extension) must be a valid JSON key since you'll be using it +in your configuration file. Let's say we want to add an OAuth 2.0 provider for +GitHub (although this provider is already supported). We'll create a file +called `connect/providers/github.js`. It should export a function that takes a +`config` argument which contains all settings for the server. + +``` +/** + * GitHub + */ + +module.exports = function (config) { + return { + id: 'github', + name: 'GitHub', + protocol: 'OAuth2', + // ... + // protocol specific properties + // ... + mapping: { + id: 'id', + email: 'email', + name: 'name', + website: 'blog', + preferredUsername: 'login', + profile: 'html_url', + picture: 'avatar_url', + } + }; +}; +``` + +When invoked, this function returns a simple JavaScript object containing all +the parameters needed by the corresponding protocol. + +#### id property + +The `id` property is used by the server to match a provider-specific +authorization request to this provider metadata. A good heuristic is to name +it the same as the filename (without the `.js` extension). + +#### protocol property + +The `protocol` property corresponds to the file name (sans extension) of the +protocol module you wish to use. Built in protocols you may wish to add a +provider for include `OAuth`, `OAuth2`, `OpenID`, `LDAP`, and +`ActiveDirectory`. If you add a [custom protocol](#?), use the basename of the +file for this value. + +#### mapping property + +The `mapping` property determines how user info from the provider gets mapped +into the OpenID Connect claims stored for each user inside Anvil Connect. On +the left are Anvil Connect user properties and on the right are property names +from the provider. You can reference nested properties using dot notation. +Given an object `{ info: { emails: { home: "foo@example.com" } } }`, your +mapping would contain `email: 'info.emails.home'`. The value side of a mapping +can also be a function, where the argument is the entire user info object from +the provider. + +#### amr claim + +The `amr` claim is a part of the [OpenID Connect specification][oidcimplicit] +which stands for Authentication Methods References. It determines which methods +of authentication were used during the authentication request. + +For example, if a user signs in with their e-mail and password, then one of the +values of the `amr` claim will be `pwd` for password authentication. If the user +also used two-factor authentication with a disposable token, then the `amr` +claim will be `[ 'mfa', 'pwd', 'otp' ]` for multi-factor authentication, +password authentication, and one-time password. + +Anvil Connect supports taking advantage of the `amr` claim given that it is +defined for a particular provider. You can also configure your own value for the +amr claim for a particular provider in the configuration file. + +We use, and recommend the use of, the [IETF amr values draft][ietfamrvalues] +as a starting point for choosing amr values. + +For example, to define an `amr` value of `ad` for authenticating with Active +Directory: + +```json +{ + // ... + "providers": { + "ActiveDirectory": { + "amr": "ad", + // ... + } + } +} +``` + +#### Contributing commonly used providers + +Contributing new OAuth and OAuth 2.0 providers is one of the easiest ways to +get involved with the open source project. While many custom providers may not +be suitable for inclusion in the core of Anvil Connect, we greatly appreciate +pull requests for those that are. + +### Creating and configuring providers + +Instructions for adding different types of providers are given throughout +this folder. + +- [Password](Password.md) +- [OAuth 2.0](OAuth2.md) +- [OAuth](OAuth.md) +- [LDAP and Active Directory](LDAP.md) + diff --git a/server.md b/server.md deleted file mode 100644 index d5490ae..0000000 --- a/server.md +++ /dev/null @@ -1,610 +0,0 @@ -# Server - - -## Get Started - -### Requirements - -Anvil Connect is built with the latest versions of [Node.js](https://nodejs.org/) (0.12.x) and [Redis](http://redis.io/) (3.0.x). You'll need these installed on your system before you can run the server. In light of the Node shakeup that resulted in the Node Foundation's creation, it should be noted that Connect will be updating as Node continues to evolve. - - -### Install -To install Connect, run the npm install command: - -```bash -$ npm install -g anvil-connect -``` - -> **Note:** Windows support hasn't been tested, but you must have Python 2.7 and Visual Studio, which are required for compiling parts of Connect. If you would like to help contribute to Windows support, let us [know](https://github.com/anvilresearch/connect/issues), and we'll be able to work together. - -After npm is finished installing Connect, you will have access to the Connect command line tool to start working on integrating Connect into your project. - - -### Initialize - -#### Generate deployment - -Once you have installed the CLI, make a new directory and initialize your project. - -```bash -$ mkdir path/to/project && cd path/to/project -$ nv init -``` - - - -This will generate a file tree in the **current** directory: - -```bash -├── .bowerrc -├── .git -├── .gitignore -├── Dockerfile -├── bower.json -├── config -│   ├── development.json -│   ├── keys -│   │   ├── private.pem -│   │   └── public.pem -│   └── production.json -├── package.json -├── public -│   ├── images -│   │   └── anvil.svg -│   ├── javascript -│   │   └── session.js -│   └── stylesheets -│   └── app.css -├── server.js -└── views - ├── authorize.jade - ├── session.jade - ├── signin.jade - └── signup.jade -``` - -`nv init` will also write to the console the next steps needed to finish Connect setup once the file tree has been created. - -Anvil Connect aims to be easily customizable. Using a deployment repository allows you to serve your own static assets, customize views (HTML templates), manage dependencies and keep your configuration under version control. It also makes upgrading Anvil Connect as simple as changing the version number in `package.json`. - -#### Install Dependencies - -Now you can install npm and bower dependencies, if you want to run Connect locally. - -```bash -$ npm install -$ bower install -``` - -#### Initializing the database - -In current versions of Anvil Connect, database initialization is handled by the -server at run-time. See [Run](#Run) for details. - -`nv migrate` has been deprecated. - -### Run -#### Environments - -#### Commands -There are two environments to run the Connect server in, `development`, and `production`. The development server is for local testing, setup, and development on Connect itself. The production environment should be used when deployed to a live environment. - -To run the authorization server in `development` mode, you can run the server by simply starting it: - -```bash -# The following are equivalent, any of them will start the development server -$ nv serve -$ node server.js -$ npm start -``` - -To run the server in production, set `NODE_ENV` to `production`: - -```bash -# The following are equivalent, any of them will start the production server -$ nv serve --production -$ node server.js -e production -$ NODE_ENV=production node server.js -``` - -When Anvil Connect starts for the first time, it will check to see whether or -not the Redis server at the configured hostname and port has any data inside and -whether or not it contains data from a valid Anvil Connect instance. - -If Anvil Connect detects any existing data in the database, and it is not from -an Anvil Connect instance, it will halt with the following error: - -``` -Redis already contains data, but it doesn't seem to be an Anvil Connect database. -If you are SURE it is, start the server with --no-db-check to skip this check. -``` - -If you are sure that there is no conflicting data in Redis, for example, -in the event that you may have edited Redis's data manually, start Anvil Connect -with the `--no-db-check` flag. - -```bash -$ node server.js --no-db-check -``` - - -## Configure - -### JSON files - -Anvil Connect loads its configuration from a JSON file in the `config` directory of the current working directory for the process. File names must match the `NODE_ENV` value. If `NODE_ENV` is not set, `config/development.json` will be loaded. - -### Key pairs - -If you generated a deployment repository with `nv init`, a new RSA key pair will be generated for you in `config/keys`. This pair of files is required for signing and verifying tokens. We recommend using the generated files. We have set up key generation to lower the barrier to entry, as it is a tedious, precise process to do by hand. - -If you want or need to provide your own RSA key pair, you can obtain it using OpenSSL and import them to the proper location, `config/keys/private.pem` for the private key and `config/keys/public.pem` for the public key. - -``` -$ cd PROJECT_ROOT -$ mkdir -p config/keys -$ openssl genrsa -out config/keys/private.pem 2048 -$ openssl rsa -pubout -in config/keys/private.pem -out config/keys/public.pem -``` - -### Server Settings - -##### issuer - -**Type:** string - -**Use:** URI used to identify issuer of authentication - -**Description:** Fully qualified base URI of the authorization server; e.g., https://accounts.anvil.io - - -##### port - -**Type:** integer - -**Use:** port # the Connect server is run under - -**Description:** An integer value representing the port the server will be bound to, unless a PORT environment variable is provided. Defaults to 3000. - -##### cookie_secret - -**Type:** string - -**Use:** signing cookies - -**Description:** A string used for signing cookies. When you initialize a project, this value is generated for each of your environments. Treat it as confidential and always use separate values for each project and environment. - -##### session_secret - -**Type:** string - -**Use:** signing session cookies - -**Description:** A string used for signing session ID cookies. When you initialize a project, this value is generated for each of your environments. Treat it as confidential and always use separate values for each project and environment. - -##### client_registration - -**Type:** string - options: `dynamic`, `token`, or `scoped` - -**Use:** Assigning the type of client registration Connect uses - -**Description:** Anvil Connect can be configured for three types of client registration: `dynamic`, `token`, or `scoped`, each being more restrictive than the previous option. The default `client_registration` type is `scoped`. For more details, see the section titled [Client Registration](#client-registration-1). - -##### trusted_registration_scope - -**Type:** string - options: `realm`, Connect operator's own registered scope(s) - -**Use:** signing session cookies - -**Description:** `trusted_registration_scope` signals if a client is trusted or not - trusted clients require additional scope to register. It defaults to `realm`. - - -### Providers - -The providers setting is an object containing settings for various authentication methods. - -```json -{ - // ... - "providers": { ... } -} -``` - -You can see all the natively supported providers in the [providers directory](https://github.com/anvilresearch/connect/tree/master/providers) in the Anvil Connect repository on GitHub. If you want to use an provider not listed there, you can easily add support in your instance by creating a simple configuration file in a providers directory in your project repository. - -#### amr claim - -The `amr` claim is a part of the [OpenID Connect specification][oidcimplicit] -which stands for Authentication Methods References. It determines which methods -of authentication were used during the authentication request. - -For example, if a user signs in with their e-mail and password, then one of the -values of the `amr` claim will be `pwd` for password authentication. If the user -also used two-factor authentication with a disposable token, then the `amr` -claim will be `[ 'mfa', 'pwd', 'otp' ]` for multi-factor authentication, -password authentication, and one-time password. - -Anvil Connect supports taking advantage of the `amr` claim given that it is -defined for a particular provider. You can also configure your own value for the -amr claim for a particular provider in the configuration file. - -We use, and recommend the use of, the [IETF amr values draft][ietfamrvalues] -as a starting point for choosing amr values. - -For example, to define an `amr` value of `ad` for authenticating with Active -Directory: - -```json -{ - // ... - "providers": { - "ActiveDirectory": { - "amr": "ad", - // ... - } - } -} -``` - -#### Password authentication - -To enable password authentication, add a `password` property to the `providers` object with a value of `true`. When set to true, `password` _requires_ login with username/password combination for the given providers every time they sign in. If set to `false`, the user will be able to sign in without authenticating with via username/password with the provider if as they are externally logged into that provider already. - -```json -{ - // ... - "providers": { - "password": true - } -} -``` - -#### OAuth 2.0 - -Most OAuth 2.0 providers only require a `client_id` and `client_secret`. You can obtain these by registering your app with the respective provider. - -```json -{ - // ... - "providers": { - "facebook": { - "client_id": "App ID", - "client_secret": "App Secret" - } - } -} -``` - -OAuth 2.0 supports a `scope` authorization parameter, and some providers use it to restricted access to specific resources. You can set scope for a provider using the `scope` property with an array of strings. See provider API documentation for specifics. - -```json -{ - //... - "providers": { - "google": { - "client_id": "Client ID", - "client_secret": "Client secret", - "scope": [ - "https://www.googleapis.com/auth/userinfo.profile", - "https://www.googleapis.com/auth/userinfo.email" - ] - }, - "linkedin": { - "client_id": "Client ID", - "client_secret": "Client Secret", - "scope": [ - "r_basicprofile", - "r_fullprofile", - "r_emailaddress", - "r_network", - "r_contactinfo" - ] - } - } -} -``` - -#### OAuth 1.0 - -OAuth 1.0 providers require `oauth_consumer_key` and `oauth_consumer_secret`. - - -```json -{ - //... - "providers": { - "twitter": { - "oauth_consumer_key": "Consumer Key (API Key)", - "oauth_consumer_secret": "Consumer Secret" - } - } -} -``` -#### LDAP - -Because of LDAP's flexible nature, LDAP support is provided in the form of a -provider template which can be used to handle custom LDAP attribute to OpenID -Connect claim scenarios. A basic provider that inherits this template without -modification is provided for convenience. - -LDAP providers can be configured as follows: - -```json -{ - // ... - "providers": { - "LDAP": { - "url": "ldap://corp.example.com", - "bindDn": "cn=admin,dc=example,dc=com", - "bindCredentials": "pass1234", - "searchBase": "ou=people,dc=example,dc=com", - "searchFilter": "(cn={{username}})" - } - } -} -``` - -A [full list of configuration options][passport-ldapauth-config] is available -from the passport-ldapauth library. - -By default, LDAP attributes map to OpenID Connect claims as such: - -OpenID Connect claim | LDAP attribute --------------------- | -------------- -id | dn -email | mail -name | cn -given\_name | givenName -family\_name | sn -phone\_number | telephoneNumber -address.formatted | postalAddress -address.street\_address | street -address.locality | l -address.region | st -address.postal\_code | postalCode -address.country | co - -To customize these mappings, simply create your own provider in the `providers` -folder of your Anvil Connect instance. For example: - -```js -module.exports = function(config) { - return { - id: 'MyLDAP', - name: 'Example Corp.', - templates: [ 'LDAP' ], - mapping: { - id: 'uid', - name: 'displayName' - }; -}; -``` - - -##### Active Directory - -The expected configuration format for the Active Directory provider is as follows: - -```json -{ - ... - "providers": { - "ActiveDirectory": { - "url": "ldaps://corp.example.com", - "domainDn": "dc=example,dc=com", - "tlsOptions": { - "ca": "/path/to/the/self/signed/ca-cert.cer" - } - } - } -} -``` - -Anvil Connect also provides the `ActiveDirectory` provider template in the event that you may be working with several domains at a time or if you would like to customize certain aspects of the AD provider, such as the name. - -Here's an example provider that uses the template: - -```javascript -module.exports = function(config) { - return { - id: 'examplecorpad', - name: 'Example Corporation', - templates: [ 'ActiveDirectory' ] - }; -}; -``` - -To configure this provider, you would use `examplecorpad` in place of `ActiveDirectory` in your configuration. - -```json -{ - ... - "providers": { - "examplecorpad": { ... } - } -} -``` - - -##### Groups - -The LDAP provider will synchronize the user's role membership in Anvil Connect with their group membership in the domain. In order to take advantage of this feature, each LDAP group for which you wish to enable synchronization must have a respective role in Connect named after the fully-qualified distinguished name (FQDN) of the group in the directory. - -For example, if there exists a group in the directory service with FQDN `CN=Group 1,OU=Groups,DC=example,DC=com`, that group will only influence the user's role membership if there also exists a role in Connect named `CN=Group 1,OU=Groups,DC=example,DC=com`. You can create this role using the `nv add role` command: - -```bash -nv add role '{ "name": "CN=Group 1,OU=Groups,DC=example,DC=com" }' -``` - - -### Configuring the mailer - -Anvil Connect uses [nodemailer](https://github.com/andris9/Nodemailer) for sending emails for the purposes of email verification, and other functionality which is to come. - -The configuration file (e.g. development.json, production.json) must have a mailer object on the top level. The options for this configuration object are identical as that of [nodemailer transports](https://github.com/andris9/Nodemailer#use-the-default-smtp-transport), with the exception of an additionally required `from` property. The `from` property defines what e-mail address and name Anvil Connect will use in sending e-mails. It must be in the form `Name `. - -```json -{ - "mailer": { - "from": "Hello World ", - "view_engine": "hogan", - "service": "Gmail", - "auth": { - "user": "test@gmail.com", - "pass": "test" - } - }, -} -``` - -### Configuring e-mail verification - -Anvil Connect supports verifying user e-mail addresses to ensure that the user has ownership/control over their registered address. By default, configuring the mailer will enable email verification server-wide, but not require it. - -When a user signs in or signs up using e-mail/password based authentication, their e-mail address is unverified at first. If the user signs in or signs up using a third-party provider, then Connect will inherit the `email_verified` claim if available. Otherwise, the user's e-mail address stays unverified. - -#### Flow - -1. **Email verification enabled, but not required** - The user is able to sign up for an account with Anvil Connect, and sign in to clients as they normally would, without interruption. However, when the user signs up for the first time, they receive an email asking them to verify their email address. -2. **Email verification enabled and required** - When the user signs up for the first time with an unverified e-mail address, they are redirected to a page that prompts them to check their e-mail for a verification e-mail message. They are also given the option on that page to resend the e-mail in the event that it hasn't made its way through. Until the user verifies their e-mail, they are unable to authenticate with any client. - -#### Configuring verification for the entire server - -```json -{ - "emailVerification": { - "enable": true, - "require": false - }, - ... -} -``` - -#### Configuring verification for specific providers - -```json -{ - "providers": { - "password": { - "emailVerification": { - "enable": true, - "require": false - } - } - } - ... -} -``` - - -### Redis - -Anvil Connect requires access to a Redis database and uses the default host and port for a local instance. To use a remote Redis server, provide url and auth parameters under the "redis" object in your config. - -```json -{ - // ... - "redis": { - "url": "redis://HOST:PORT", - "auth": "PASSWORD" - } -} -``` - -You can also provide a `db` setting (integer) if you want to use a different Redis database. By default, Redis is configured to support 16 databases (0 - 15). This can be configured in the `redis.conf` file for your Redis installation. - -```json -{ - // ... - "redis": { - "db": 3 - } -} -``` - -### Logger - -Anvil Connect uses [bucker](https://github.com/nlf/bucker) for logging. Any valid configuration parameters for bucker can be included in the "logger" parameter in your config file. For example: - -```json -{ - // ... - "logger": { - "console": { - "color": false - }, - "syslog": { - "host": "localhost", - "port": 514, - "facility": 18 - } - } -} -``` - - -### OpenID Metadata - -[OpenID Provider Metadata](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) default values can be overridden by defining them in the configuration file. Don't change these unless you know what you're doing. - - -## Customize - -### Views - -You can change the look and feel of Anvil Connect by editing the contents of the `views` directory in your project. There are four templates included in your views directory: `authorize`, `signin`, `signup`, and `session`. Connect works with any templating language supported by [consolidate.js](https://github.com/tj/consolidate.js). The `jade` templating language is used by default. You can configure your server to use a different templating language with the `view_engine` setting in your config files. - -#### Authorize - -The `authorize` view is the part of an OAuth 2.0 authorization flow that enables users to provide consent to an application to access some of their data. It is rendered when users authorize a third-party app. It is not displayed when authenticating `trusted` clients. - -#### Signin - -The `signin` view displays all configured user authentication options. - -#### Signup - -The `signup` view displays a signup form for local password authentication. - -#### Session - -This view is not intended to be visible to users. It gets loaded into a hidden iframe for clients that implement Single Sign-On using OpenID Connect Sessions. If you change it, be sure to leave the script references intact or this feature will not work correctly. - - - -#### Static Assets - -You can also add your own static assets to be served from the `public` directory at the root of your project. - -### E-mail templates - -E-mail templates are stored in the emails directory in the Connect root directory. The file extension matches the view engine to be used. The view engine can be configured by modifying the `view_engine` property on the `mailer` configuration object. Just as with views, any view engine supported by [consolidate.js](https://github.com/tj/consolidate.js) is supported by this property. By default, it is set to use [Hogan](https://github.com/twitter/hogan.js). - -#### E-mail verification - -The template for e-mail verification messages is `verifyEmail`. The template is provided with the provider name (`providerName`), verification URL (`verifyURL`), and user e-mail (`email`). - - - -## Deploy - - - -[oidcimplicit]: http://openid.net/specs/openid-connect-implicit-1_0.html -[ietfamrvalues]: http://tools.ietf.org/html/draft-jones-oauth-amr-values-00 -[passport-ldapauth-config]: https://github.com/vesse/node-ldapauth-fork/blob/master/lib/ldapauth.js#L22-L94 diff --git a/server/configuration.md b/server/configuration.md new file mode 100644 index 0000000..d655285 --- /dev/null +++ b/server/configuration.md @@ -0,0 +1,53 @@ +## Configuration + +### Server Settings + +Anvil Connect loads its configuration from a JSON file in the `config` +directory of the current working directory for the process. File names must +match the `NODE_ENV` value. If `NODE_ENV` is not set, `config/development.json` +will be loaded. + +Setting | Type | Default | Description +------- | ---- | ------- | ----------- +**issuer** | string | (none) | URI used to identify issuer of authentication +**port** | integer | 3000 | Port the Connect server is bound to +**cookie_secret** | string | (generated) | Secret string used to sign secure cookies +**session_secret** | string | (generated) | Secret string used to sign session ID cookies +**client_registration** | string | `scoped` | Type of client registration - `dynamic`, `token`, or `scoped` ([Explanation](../clients.md#registration)) +**trusted_registration_scope** | string | `realm` | Scope used to identify trusted clients. + + +### OpenID Metadata + +[OpenID Provider Metadata](http://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata) +default values can be overridden by defining them in the configuration file. +Don't change these unless you know what you're doing. + + + +### [Configuring Redis](redis.md) + +### [Configuring the mailer](mailer.md) + +### [Configuring the logger](logger.md) + +### Key pairs + +If you generated a deployment repository with `nv init`, a new RSA key pair +will be generated for you in `connect/config/keys`. This pair of files is +required for signing and verifying tokens. If the server does not find key +pairs when starting, it will attempt to generate them for you using the OpenSSL +package installed on your system. Mac and most Unix and Linux based systems +include OpenSSL by default. You can also [install it on Windows][ssl-windows]. + +[ssl-windows]: https://slproweb.com/products/Win32OpenSSL.html + +If you want to provide your own RSA key pair files, you can generate them +manually with OpenSSL. + +``` +$ cd PROJECT_ROOT +$ mkdir -p connect/config/keys +$ openssl genrsa -out connect/config/keys/private.pem 4096 +$ openssl rsa -pubout -in connect/config/keys/private.pem -out connect/config/keys/public.pem +``` diff --git a/server/customization.md b/server/customization.md new file mode 100644 index 0000000..d2081d9 --- /dev/null +++ b/server/customization.md @@ -0,0 +1,13 @@ +## Customization + +By default, Anvil Connect uses html templates, email templates and static +assets from inside the `anvil-connect` npm package. You can completely customize +the look and feel of Anvil Connect by overriding these files in the `views`, +`email`, and `public` directories in your project. + +To do this, simply copy the file you want to work with from +`node_modules/anvil-connect/[views|email|public]` into a corresponding directory +in your project and modify it however you want. When Anvil Connect runs, it will +use your custom files. + + diff --git a/server/email-verification.md b/server/email-verification.md new file mode 100644 index 0000000..8084250 --- /dev/null +++ b/server/email-verification.md @@ -0,0 +1,53 @@ +## Configuring e-mail verification + +Anvil Connect supports verifying user e-mail addresses to ensure that the user +has ownership/control over their registered address. By default, configuring the +mailer will enable email verification server-wide, but not require it. + +When a user signs in or signs up using e-mail/password based authentication, +their e-mail address is unverified at first. If the user signs in or signs up +using a third-party provider, then Connect will inherit the `email_verified` +claim if available. Otherwise, the user's e-mail address stays unverified. + +### Flow + +1. **Email verification enabled, but not required** + The user is able to sign up for an account with Anvil Connect, and sign in + to clients as they normally would, without interruption. However, when the + user signs up for the first time, they receive an email asking them to verify + their email address. +2. **Email verification enabled and required** + When the user signs up for the first time with an unverified e-mail address, + they are redirected to a page that prompts them to check their e-mail for a + verification e-mail message. They are also given the option on that page to + resend the e-mail in the event that it hasn't made its way through. Until the + user verifies their e-mail, they are unable to authenticate with any client. + +### Configuring verification for the entire server + +```json +{ + "emailVerification": { + "enable": true, + "require": false + }, + ... +} +``` + +### Configuring verification for specific providers + +```json +{ + "providers": { + "password": { + "emailVerification": { + "enable": true, + "require": false + } + } + } + ... +} +``` + diff --git a/server/logger.md b/server/logger.md new file mode 100644 index 0000000..568b2c8 --- /dev/null +++ b/server/logger.md @@ -0,0 +1,22 @@ +## Logger + +Anvil Connect uses [bucker](https://github.com/nlf/bucker) for logging. Any +valid configuration parameters for bucker can be included in the "logger" +parameter in your config file. For example: + +```json +{ + // ... + "logger": { + "console": { + "color": false + }, + "syslog": { + "host": "localhost", + "port": 514, + "facility": 18 + } + } +} +``` + diff --git a/server/mailer.md b/server/mailer.md new file mode 100644 index 0000000..8547701 --- /dev/null +++ b/server/mailer.md @@ -0,0 +1,26 @@ +## Configuring the mailer + +Anvil Connect uses [nodemailer](https://github.com/andris9/Nodemailer) for +sending emails for the purposes of email verification, and other functionality +which is to come. + +The configuration file (e.g. development.json, production.json) must have a +mailer object on the top level. The options for this configuration object are +identical as that of [nodemailer transports](https://github.com/andris9/Nodemailer#use-the-default-smtp-transport), +with the exception of an additionally required `from` property. The `from` +property defines what e-mail address and name Anvil Connect will use in sending +e-mails. It must be in the form `Name `. + +```json +{ + "mailer": { + "from": "Hello World ", + "view_engine": "hogan", + "service": "Gmail", + "auth": { + "user": "test@gmail.com", + "pass": "test" + } + }, +} +``` diff --git a/server/redis.md b/server/redis.md new file mode 100644 index 0000000..53b71af --- /dev/null +++ b/server/redis.md @@ -0,0 +1,33 @@ +## Redis + +Anvil Connect requires access to a Redis database and uses the default host and +port for a local instance. To use a remote Redis server, provide host, port, +and password parameters under the "redis" object in your config. + +```json +{ + // ... + "redis": { + "host": "HOST", + "port": "PORT", + "password": "PASSWORD" + } +} +``` + +Configuration options for Redis are identical to that of the +[supported options for ioredis][ioredis-options]. + +You can also provide a `db` setting (integer) if you want to use a different +Redis database. By default, Redis is configured to support 16 databases +(0 - 15). This can be configured in the `redis.conf` file for your Redis +installation. + +```json +{ + // ... + "redis": { + "db": 3 + } +} +```