├── .gitignore ├── .gitmodules ├── .jsdoc-conf.json ├── .travis.yml ├── Dockerfile ├── README.md ├── package.json ├── scm-config-webauthn.json ├── scm-config.json └── test └── mainTest.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | docs 3 | .DS_Store 4 | npm-debug.log 5 | coverage 6 | fido2-server-demo.sublime-project 7 | fido2-server-demo.sublime-workspace 8 | package-lock.json 9 | *.log 10 | data 11 | *~ -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "webauthn-yubiclone"] 2 | path = webauthn-yubiclone 3 | url = https://github.com/apowers313/webauthn-yubiclone.git 4 | [submodule "fido2-swagger"] 5 | path = fido2-swagger 6 | url = https://github.com/apowers313/fido2-swagger 7 | -------------------------------------------------------------------------------- /.jsdoc-conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "opts": { 3 | "template": "./node_modules/ink-docstrap/template", 4 | "readme": "README.md", 5 | "encoding": "utf8", 6 | "destination": "./docs", 7 | "recurse": true 8 | }, 9 | "source": { 10 | "include": ".", 11 | "includePattern": "\\.js$", 12 | "excludePattern": "node_modules" 13 | }, 14 | "templates": { 15 | "systemName": "FIDO2 Server Demo", 16 | "copyright": "Copyright 2016, Adam Powers", 17 | "linenums": true, 18 | "theme": "cerulean" 19 | }, 20 | "plugins": [ 21 | "plugins/markdown" 22 | ] 23 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: true 2 | services: 3 | - docker 4 | cache: 5 | directories: 6 | - node_modules 7 | notifications: 8 | email: true 9 | language: node_js 10 | node_js: 11 | - '10' 12 | before_script: 13 | - 'curl -Lo travis_after_all.py https://git.io/vLSON' 14 | - npm prune 15 | - npm run docker:build:prod-canary 16 | - npm run docker:build:test-canary 17 | script: 18 | - npm run docker:test:canary 19 | after_success: 20 | - python travis_after_all.py 21 | - export $(cat .to_export_back) 22 | - npm run docker:login 23 | - npm run docker:release:canary 24 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # production app 2 | FROM node:10 as production 3 | LABEL maintainer="apowers@ato.ms" 4 | WORKDIR /usr/src/app 5 | COPY package.json scm-config.json /usr/src/app/ 6 | COPY webauthn-yubiclone/ /usr/src/app/webauthn-yubiclone/ 7 | # RUN npm install --only=production 8 | RUN npm install 9 | EXPOSE 8888 10 | EXPOSE 8443 11 | ENTRYPOINT ["npm", "start"] 12 | 13 | # dev / testing 14 | FROM node:10 as test 15 | LABEL maintainer="apowers@ato.ms" 16 | WORKDIR /usr/src/app 17 | COPY --from=production /usr/src/app/ /usr/src/app/ 18 | COPY test/ /usr/src/app/test/ 19 | # RUN npm install --only=development 20 | EXPOSE 8888 21 | EXPOSE 8443 22 | ENTRYPOINT ["npm", "test"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Waffle.io - Columns and their card count](https://badge.waffle.io/apowers313/fido2-server-demo.svg?columns=all)](https://waffle.io/apowers313/fido2-server-demo) 2 | 3 | Currently in beta. Good for demos and prototypes, but not production ready. 4 | 5 | ## Installation 6 | 7 | ### NPM 8 | ``` bash 9 | git clone --recursive https://github.com/apowers313/fido2-server-demo 10 | cd fido2-server-demo 11 | npm install 12 | npm start 13 | ``` 14 | 15 | Note: this has been developed and tested on MacOS X, and webauthn.org was running this server on Ubuntu Linux. It has not been tested on Windows -- please open [issues](https://github.com/apowers313/fido2-server-demo/issues) for Windows bugs. 16 | 17 | Note: this project uses `async` / `await` and requires node.js 7.6+. If you are running OpenSSH >1.1.0 (e.g. - Debian Buster), it requires node.js 10+. 18 | 19 | ### Docker 20 | There is also a Docker image available, which makes it much less likely that you will have configuration problems. Here are the instructions for using the Docker image. 21 | 22 | * Install [Docker for Windows](https://docs.docker.com/docker-for-windows/install/#start-docker-for-windows) or [Docker for Mac](https://www.docker.com/docker-mac) or use one of the [several other install options](https://docs.docker.com/install/). 23 | * run the command: `docker run -d -p 8888:8888 -p 8443:8443 apowers313/fido2-server:prod-canary` 24 | * open https://localhost:8443 25 | 26 | ## Configuration 27 | 28 | Edit `scm-config.json` to change ports, domains, and certificate paths. 29 | 30 | This a [simple-component-manager](https://github.com/apowers313/simple-component-manager) configuration file where each component is replaceable with one of a similar type (logger, user data store, cert manager, etc.). More components and documentation will be forthcoming. For now, hopefully things like changing ports and certificate paths are fairly obvious. 31 | 32 | ## Components 33 | 34 | The following components are used for this server: 35 | 36 | * [component-fido2](https://github.com/apowers313/component-fido2) (Also note that the core FIDO2 functionality is implemented in [fido2-lib](https://github.com/apowers313/fido2-lib)) 37 | * [component-uds-json](https://github.com/apowers313/component-uds-json) 38 | * [component-certs](https://github.com/apowers313/component-certs) 39 | * [component-web](https://github.com/apowers313/component-web) 40 | * [component-logger-winston](https://github.com/apowers313/component-logger-winston) 41 | 42 | ## Bugs / Help / Contributing 43 | 44 | If you find bugs or need help, open a GitHub issue. If you are so inspired, feel free to submit a pull request. Also feel free to just send a note saying that you're using the server and what you think of it -- it's nice to know when a project is being used. 45 | 46 | You can also find me on Twitter at [@apowers313](https://twitter.com/apowers313). 47 | 48 | ## Security Considerations 49 | 50 | This server does a number of things that shouldn't be done in a real server. These are for demonstration purposes and will be phased out over the next couple months: 51 | 52 | 1. Attestation is not currently required to be verified. If an authenticator doesn't have attestation, the registration will still be successful and a warning message will be logged. 53 | 2. This allows both User Presence (UP) and User Verification (UV) to be used for first-factor authentication. Typically only UV should be used for first-factor authentication, but given that U2F tokens are going to be the most commonly available authenticator in the short term, this server still allows UP-only authenticators to behave in a password-less fashion. 54 | 3. User accounts are wide open -- the session is not currently checked for previous authentication, so anyone can add any authenticator to any username. This is great for demos (and inspired by [demo.yubico.com/u2f](https://demo.yubico.com/u2f)) but not how things would work in the real world. This will change in the near future. 55 | 56 | ## Sponsor 57 | Note that while I used to be Technical Director for FIDO Alliance (and I am currently the Technical Advisor for FIDO Alliance), THIS PROJECT IS NOT ENDORSED OR SPONSORED BY FIDO ALLIANCE. 58 | 59 | Work for this project is supported by my consulting company: [WebAuthn Consulting](https://webauthn.consulting/). 60 | 61 | ## Other FIDO2 / WebAuthn Projects 62 | There are a number of other great FIDO2 and WebAuthn projects out there. I love all things FIDO2 and WebAuthn, so here's a list of other projects (Note: I'm not affiliated with any of these projects): 63 | 64 | ### Open Source Servers 65 | 66 | * [Google / Java](https://github.com/google/webauthndemo) 67 | * [MasterCard / Java (Spring)](https://github.com/Mastercard/fido2-rp-spring) 68 | * [Mozilla / JavaScript (Browser)](https://github.com/jcjones/webauthn.bin.coffee) 69 | * [FIDO Alliance / JavaScript](https://github.com/fido-alliance/webauthn-demo) 70 | * [cedarcode / Ruby](https://github.com/cedarcode/webauthn-ruby) 71 | * [abergs / .NET](https://github.com/abergs/fido2-net-lib) 72 | 73 | ### Open Source Clients 74 | 75 | * [apowers313 / JavaScript (Browser)](https://github.com/apowers313/webauthn-simple-app) 76 | 77 | ### Open Source CTAP2 78 | 79 | * [Yubico / C](https://developers.yubico.com/libfido2/) 80 | * [Yubico / Python](https://developers.yubico.com/python-fido2/) 81 | 82 | ### Open Access Servers 83 | 84 | * Duo: [webauthn.io](https://webauthn.io/) 85 | * Mozilla: [webauthn.bin.coffee](https://webauthn.bin.coffee/) 86 | * Yubico: [demo.yubico.com/webauthn](https://demo.yubico.com/webauthn) 87 | * watahani: [webauthn-tutorial-haniyama.now.sh](https://webauthn-tutorial-haniyama.now.sh/) 88 | 89 | If your project isn't listed here and you would like it to be, drop me a note and I would be happy to add it. 90 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fido2-server-demo", 3 | "version": "1.0.0", 4 | "description": "Examples and demo code for FIDO2 / WebAuthn servers", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha", 8 | "start": "scm", 9 | "docker:build:prod-canary": "docker build --target=production -t apowers313/fido2-server:prod-canary .", 10 | "docker:build:test-canary": "docker build --target=test -t apowers313/fido2-server:test-canary .", 11 | "docker:test:canary": "docker run apowers313/fido2-server:test-canary", 12 | "docker:build:release": "docker build --target=test -t apowers313/fido2-server:test . && docker run apowers313/fido2-server:test && docker build --target=production -t apowers313/fido2-server:latest .", 13 | "docker:test:canary": "docker run apowers313/fido2-server:test-canary", 14 | "docker:login": "echo \"$DOCKER_PASSWORD\" | docker login -u \"$DOCKER_USERNAME\" --password-stdin", 15 | "docker:release:canary": "docker push apowers313/fido2-server:test-canary && docker push apowers313/fido2-server:prod-canary", 16 | "docker:release": "docker push apowers313/fido2-server:test && docker push apowers313/fido2-server:latest" 17 | }, 18 | "keywords": [ 19 | "fido", 20 | "fido2", 21 | "webauthn", 22 | "server" 23 | ], 24 | "author": "Adam Powers", 25 | "license": "MIT", 26 | "repository": { 27 | "type": "git", 28 | "url": "git+https://github.com/apowers313/fido2-server-demo.git" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/apowers313/fido2-server-demo/issues", 32 | "email": "apowers@ato.ms" 33 | }, 34 | "devDependencies": { 35 | "chai": "^3.5.0", 36 | "gh-pages": "^0.12.0", 37 | "ink-docstrap": "^1.3.0", 38 | "istanbul": "^0.4.5", 39 | "istanbul-coveralls": "^1.0.3", 40 | "jsdoc": "^3.4.3", 41 | "mocha": "^2.5.3", 42 | "sinon": "^1.17.6" 43 | }, 44 | "dependencies": { 45 | "component-certs-static": "^1.0.1", 46 | "component-fido2": "^1.0.11", 47 | "component-logger-winston": "^1.0.1", 48 | "component-uds-json": "^1.0.3", 49 | "component-web": "^1.0.1", 50 | "simple-component-manager": "^1.0.4" 51 | }, 52 | "homepage": "https://github.com/apowers313/fido2-server-demo#readme", 53 | "directories": { 54 | "lib": "lib", 55 | "test": "test" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /scm-config-webauthn.json: -------------------------------------------------------------------------------- 1 | // scm-config for webauthn.org 2 | // 3 | // this is a JSON file that allows JavaScript-style comments 4 | { 5 | // setuid and setgid are only required if running with sudo 6 | // you can delete these lines and run without sudo if your http/https ports don't require special privledges 7 | "setuid": 1000, 8 | "setgid": 1000, 9 | "components": [{ 10 | "name": "http", 11 | "type": "generic", 12 | "package": "component-web", 13 | "pre-config": [{ 14 | // setting the port isn't technically required here, but is included for convenience 15 | "set-port": 80 16 | }], 17 | "post-config": [{ 18 | "set-redirect": { 19 | "destProtocol": "https", 20 | "destTemporary": false 21 | } 22 | }] 23 | }, { 24 | "name": "https", 25 | "type": "generic", 26 | "package": "component-web", 27 | "pre-config": [{ 28 | // setting the port isn't technically required here, but is included for convenience 29 | "set-port": 443, 30 | "set-https": true, 31 | "set-domain": "webauthn.org", 32 | "set-body-parser": "json", 33 | "set-enable-session": true 34 | }, { // demo UI for WebAuthn 35 | "add-static": { 36 | "path": "/", 37 | "dir": "webauthn-yubiclone" 38 | } 39 | }, { // serve up swagger UI 40 | "add-static": { 41 | "path": "/swagger", 42 | "dir": "fido2-swagger" 43 | } 44 | }] 45 | }, { 46 | "name": "cert-manager", 47 | "type": "generic", 48 | "package": "component-certs-static", 49 | "pre-config": [{ 50 | "set-cert-file": "/etc/letsencrypt/live/webauthn.org/cert.pem", 51 | "set-key-file": "/etc/letsencrypt/live/webauthn.org/privkey.pem" 52 | }] 53 | }, { 54 | "name": "fido2", 55 | "type": "generic", 56 | "package": "component-fido2", 57 | "pre-config": [{ 58 | "enable-dangerous-open-registration": true, 59 | "enable-dangerous-xmit-debug-info": true, 60 | "set-service-name": "WebAuthn.org" 61 | }] 62 | }, { 63 | "name": "uds", 64 | "type": "generic", 65 | "package": "component-uds-json" 66 | }, { 67 | "name": "logger", 68 | "type": "logger", 69 | "package": "component-logger-winston", 70 | "pre-config": [{ 71 | "set-level": "silly", 72 | "add-transport": [{ 73 | // log to the screen... 74 | "type": "console", 75 | "colorize": true 76 | }, { 77 | // ...and log to a file 78 | // see winston's npm page for more transport configuration options 79 | "type": "file", 80 | "filename": "scm.log" 81 | }] 82 | }] 83 | }] 84 | } -------------------------------------------------------------------------------- /scm-config.json: -------------------------------------------------------------------------------- 1 | // scm-config 2 | // 3 | // this is a JSON file that allows JavaScript-style comments 4 | { 5 | // setuid and setgid are only required if running with sudo 6 | // you can delete these lines and run without sudo if your http/https ports don't require special privledges 7 | // "setuid": 1, 8 | // "setgid": 1, 9 | "components": [{ 10 | "name": "http", 11 | "type": "generic", 12 | "package": "node_modules/component-web", 13 | "pre-config": [{ 14 | "set-port": 8888 15 | }], 16 | "post-config": [{ 17 | "set-redirect": { 18 | "destProtocol": "https", 19 | "destPort": 8443, 20 | "destTemporary": false 21 | } 22 | }] 23 | }, { 24 | "name": "https", 25 | "type": "generic", 26 | "package": "node_modules/component-web", 27 | "pre-config": [{ 28 | "set-port": 8443, 29 | "set-https": true, 30 | "set-domain": "localhost", 31 | "set-body-parser": "json", 32 | "set-enable-session": true 33 | }, { // demo UI for WebAuthn 34 | "add-static": { 35 | "path": "/", 36 | "dir": "webauthn-yubiclone" 37 | } 38 | }, { // serve up swagger UI 39 | "add-static": { 40 | "path": "/swagger", 41 | "dir": "fido2-swagger" 42 | } 43 | }] 44 | }, { 45 | "name": "cert-manager", 46 | "type": "generic", 47 | "package": "node_modules/component-certs-static", 48 | "pre-config": [{ 49 | "set-cert-file": "data/node_modules/component-certs-static/test/helpers/certs/cert.pem", 50 | "set-key-file": "data/node_modules/component-certs-static/test/helpers/certs/key.pem" 51 | }] 52 | }, { 53 | "name": "fido2", 54 | "type": "generic", 55 | "package": "node_modules/component-fido2", 56 | "pre-config": [{ 57 | "enable-dangerous-open-registration": true, 58 | "enable-dangerous-xmit-debug-info": true, 59 | "set-service-name": "WebAuthn.org" 60 | }] 61 | }, { 62 | "name": "uds", 63 | "type": "generic", 64 | "package": "node_modules/component-uds-json" 65 | }, { 66 | "name": "logger", 67 | "type": "logger", 68 | "package": "node_modules/component-logger-winston", 69 | "pre-config": [{ 70 | "set-level": "silly", 71 | "add-transport": [{ 72 | // log to the screen... 73 | "type": "console", 74 | "colorize": true 75 | }, { 76 | // ...and log to a file 77 | // see winston's npm page for more transport configuration options 78 | "type": "file", 79 | "filename": "scm.log" 80 | }] 81 | }] 82 | }] 83 | } -------------------------------------------------------------------------------- /test/mainTest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | const assert = require("chai").assert; 4 | const pkg = require("../package"); 5 | const path = require("path"); 6 | const { spawn } = require("child_process"); 7 | const nodeModulesDir = path.join(__dirname, "../node_modules"); 8 | 9 | function testPackage(pkgName) { 10 | it(`tests ${pkgName}`, async function() { 11 | this.timeout(300000); // eslint-disable-line no-invalid-this 12 | this.slow(300000); // eslint-disable-line no-invalid-this 13 | 14 | var pkgDir = path.join(nodeModulesDir, pkgName); 15 | console.log("pkgDir", pkgDir); 16 | // XXX: no guarantee that the devDependencies were installed unless we 'install' first 17 | await npmCmd(pkgDir, "install"); 18 | await npmCmd(pkgDir, "test"); 19 | }); 20 | } 21 | 22 | async function npmCmd(pkgDir, cmd) { 23 | // spawn npm to test 24 | var npmArgs = []; 25 | npmArgs.push(cmd); 26 | 27 | // spawn npm 28 | var npmPs = spawn("npm", npmArgs, { 29 | cwd: pkgDir 30 | }); 31 | 32 | npmPs.stdout.on("data", (data) => { 33 | process.stdout.write(data.toString()); 34 | }); 35 | 36 | npmPs.stderr.on("data", (data) => { 37 | process.stderr.write(data.toString()); 38 | }); 39 | 40 | return new Promise((resolve, reject) => { 41 | npmPs.on("close", (code) => { 42 | // console.log("npm finished with code:", code); 43 | if (code === 0) { 44 | return resolve(true); 45 | } 46 | reject(new Error("test failed with code: " + code)); 47 | }); 48 | }); 49 | } 50 | 51 | describe("fido-server-demo", function() { 52 | it("loaded pkg", function() { 53 | // test goes here 54 | assert.isObject(pkg); 55 | }); 56 | 57 | // test all packages 58 | for (let depPkg of Object.keys(pkg.dependencies)) { 59 | testPackage(depPkg); 60 | } 61 | }); 62 | --------------------------------------------------------------------------------