Compare commits

...

7 Commits

11 changed files with 170 additions and 78 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ image: buildtool/build-tools:${BUILDTOOLS_VERSION}
build: build:
stage: build stage: build
services: services:
- docker:dind - docker:${DOCKER_DIND_VERSION}
script: script:
- build - build
- push - push
+2
View File
@@ -10,8 +10,10 @@ updates:
schedule: schedule:
interval: "daily" interval: "daily"
open-pull-requests-limit: 20 open-pull-requests-limit: 20
rebase-strategy: none
- package-ecosystem: "docker" - package-ecosystem: "docker"
directory: "/" directory: "/"
schedule: schedule:
interval: "daily" interval: "daily"
open-pull-requests-limit: 20 open-pull-requests-limit: 20
rebase-strategy: none
+1
View File
@@ -0,0 +1 @@
18
+2
View File
@@ -0,0 +1,2 @@
*.yaml
*.yml
+9
View File
@@ -0,0 +1,9 @@
{
"semi": false,
"singleQuote": true,
"trailingComma": "none",
"arrowParens": "always",
"quoteProps": "as-needed",
"bracketSpacing": true,
"bracketSameLine": false
}
+17 -12
View File
@@ -3,47 +3,52 @@
> This server helps you to simulate auth0 server locally. So, you are able to use the `/tokeninfo` endpoint to verify your token. > This server helps you to simulate auth0 server locally. So, you are able to use the `/tokeninfo` endpoint to verify your token.
## Getting Started ## Getting Started
### Prerequisites
* Install [Node.js](http://nodejs.org)
* on OSX use [homebrew](http://brew.sh) `brew install node`
* on Windows use [chocolatey](https://chocolatey.org/) `choco install nodejs`
### Prerequisites
- Install [Node.js](http://nodejs.org)
- on OSX use [homebrew](http://brew.sh) `brew install node`
- on Windows use [chocolatey](https://chocolatey.org/) `choco install nodejs`
## Installing ## Installing
* `fork` this repo
* `clone` your fork - `fork` this repo
* `npm install` to install all dependencies - `clone` your fork
- `npm install` to install all dependencies
## Running the app ## Running the app
After you have installed all dependencies you can now run the app. After you have installed all dependencies you can now run the app.
Run `npm start` to start a local server. Run `npm start` to start a local server.
The port will be displayed to you as `http://0.0.0.0:3333` (or if you prefer IPv6, if you're using `express` server, then it's `http://[::1]:3333/`). The port will be displayed to you as `http://0.0.0.0:3333` (or if you prefer IPv6, if you're using `express` server, then it's `http://[::1]:3333/`).
## API Documentation ## API Documentation
### `GET` /token/:username ### `GET` /token/:username
Returns a token with the given user(username). This token can the be used by your application. Returns a token with the given user(username). This token can the be used by your application.
### `POST` /tokeninfo ### `POST` /tokeninfo
Returns the data of the token like the username. Returns the data of the token like the username.
**Body** **Body**
``` ```
{ {
"id_token": "your-token-kjasdf6ashasl..." "id_token": "your-token-kjasdf6ashasl..."
} }
``` ```
## Related Projects ## Related Projects
* [express-typescript-boilerplate](https://github.com/w3tecch/express-typescript-boilerplate) - Boilerplate for an restful express-apllication written in TypeScript
* [express-graphql-typescript-boilerplate](https://github.com/w3tecch/express-graphql-typescript-boilerplate) - A starter kit for building amazing GraphQL API's with TypeScript and express by @w3tecch
- [express-typescript-boilerplate](https://github.com/w3tecch/express-typescript-boilerplate) - Boilerplate for an restful express-apllication written in TypeScript
- [express-graphql-typescript-boilerplate](https://github.com/w3tecch/express-graphql-typescript-boilerplate) - A starter kit for building amazing GraphQL API's with TypeScript and express by @w3tecch
## License ## License
[MIT](/LICENSE) [MIT](/LICENSE)
--- ---
Made with ♥ by Gery Hirschfeld ([@GeryHirschfeld1](https://twitter.com/GeryHirschfeld1)) Made with ♥ by Gery Hirschfeld ([@GeryHirschfeld1](https://twitter.com/GeryHirschfeld1))
+84 -46
View File
@@ -14,8 +14,10 @@ const cert = require('./cert')
let issuer = process.env.ISSUER || 'localhost:3333' let issuer = process.env.ISSUER || 'localhost:3333'
let jwksOrigin = `https://${issuer}/` let jwksOrigin = `https://${issuer}/`
const audience = process.env.AUDIENCE || 'https://generic-audience' const audience = process.env.AUDIENCE || 'https://generic-audience'
const adminCustomClaim = process.env.ADMIN_CUSTOM_CLAIM || 'https://unbound.se/admin' const adminCustomClaim =
const emailCustomClaim = process.env.EMAIL_CUSTOM_CLAIM || 'https://unbound.se/email' process.env.ADMIN_CUSTOM_CLAIM || 'https://unbound.se/admin'
const emailCustomClaim =
process.env.EMAIL_CUSTOM_CLAIM || 'https://unbound.se/email'
const debug = Debug('app') const debug = Debug('app')
@@ -37,7 +39,6 @@ const addCustomClaims = (email, customClaims, token) => {
...claim ...claim
} }
}, token) }, token)
} }
const signToken = (token) => { const signToken = (token) => {
@@ -48,7 +49,8 @@ const signToken = (token) => {
} }
// Configure our small auth0-mock-server // Configure our small auth0-mock-server
app.options('*', cors(corsOpts)) app
.options('*', cors(corsOpts))
.use(cors()) .use(cors())
.use(bodyParser.json({ strict: false })) .use(bodyParser.json({ strict: false }))
.use(bodyParser.urlencoded({ extended: true })) .use(bodyParser.urlencoded({ extended: true }))
@@ -91,26 +93,31 @@ app.post('/oauth/token', (req, res) => {
} else if (req.body.code) { } else if (req.body.code) {
const code = req.body.code const code = req.body.code
const session = sessions[code] const session = sessions[code]
let accessToken = signToken(addCustomClaims(session.email, session.customClaims, { let accessToken = signToken(
iss: jwksOrigin, addCustomClaims(session.email, session.customClaims, {
aud: [audience], iss: jwksOrigin,
sub: 'auth0|' + session.email, aud: [audience],
iat: date, sub: 'auth0|' + session.email,
exp: date + 7200, iat: date,
azp: session.clientId exp: date + 7200,
})) azp: session.clientId
})
)
let idToken = signToken(addCustomClaims(session.email, session.customClaims, { let idToken = signToken(
iss: jwksOrigin, addCustomClaims(session.email, session.customClaims, {
aud: session.clientId, iss: jwksOrigin,
nonce: session.nonce, aud: session.clientId,
sub: 'auth0|' + session.email, nonce: session.nonce,
iat: date, sub: 'auth0|' + session.email,
exp: date + 7200, iat: date,
azp: session.clientId, exp: date + 7200,
name: 'Example Person', azp: session.clientId,
picture: 'https://cdn.playbuzz.com/cdn/5458360f-32ea-460e-a707-1a2d26760558/70bda687-cb84-4756-8a44-8cf735ed87b3.jpg' name: 'Example Person',
})) picture:
'https://cdn.playbuzz.com/cdn/5458360f-32ea-460e-a707-1a2d26760558/70bda687-cb84-4756-8a44-8cf735ed87b3.jpg'
})
)
debug('Signed token for ' + session.email) debug('Signed token for ' + session.email)
@@ -133,9 +140,12 @@ app.get('/token/:email', (req, res) => {
debug('No user was given!') debug('No user was given!')
return res.status(400).send('user is missing') return res.status(400).send('user is missing')
} }
const token = jwt.sign({ const token = jwt.sign(
user_id: 'auth0|' + req.params.email {
}, privateKey) user_id: 'auth0|' + req.params.email
},
privateKey
)
debug('Signed token for ' + req.params.email) debug('Signed token for ' + req.params.email)
res.json({ token }) res.json({ token })
}) })
@@ -160,7 +170,9 @@ app.post('/code', (req, res) => {
codeChallenge: req.body.codeChallenge, codeChallenge: req.body.codeChallenge,
customClaims: [claim] customClaims: [claim]
} }
res.redirect(`${req.body.redirect}?domain=${issuer}&code=${code}&state=${encodeURIComponent(state)}`) res.redirect(
`${req.body.redirect}?code=${code}&state=${encodeURIComponent(state)}`
)
}) })
app.get('/authorize', (req, res) => { app.get('/authorize', (req, res) => {
@@ -171,13 +183,26 @@ app.get('/authorize', (req, res) => {
const codeChallenge = req.query.code_challenge const codeChallenge = req.query.code_challenge
const prompt = req.query.prompt const prompt = req.query.prompt
const responseMode = req.query.response_mode const responseMode = req.query.response_mode
if (responseMode === 'query') {
const code = req.cookies['auth0']
const session = sessions[code]
if (session) {
session.nonce = nonce
session.state = state
session.codeChallenge = codeChallenge
sessions[codeChallenge] = session
res.redirect(`${redirect}?code=${codeChallenge}&state=${state}`)
return
}
}
if (prompt === 'none' && responseMode === 'web_message') { if (prompt === 'none' && responseMode === 'web_message') {
const code = req.cookies['auth0'] const code = req.cookies['auth0']
const session = sessions[code] const session = sessions[code]
session.nonce = nonce if (session) {
session.state = state session.nonce = nonce
session.codeChallenge = codeChallenge session.state = state
res.send(` session.codeChallenge = codeChallenge
res.send(`
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<body> <body>
@@ -195,13 +220,16 @@ app.get('/authorize', (req, res) => {
</script> </script>
</body> </body>
</html>`) </html>`)
} else { return
res.cookie('auth0', codeChallenge, { }
sameSite: 'None', }
secure: true,
httpOnly: true res.cookie('auth0', codeChallenge, {
}) sameSite: 'None',
res.send(` secure: true,
httpOnly: true
})
res.send(`
<html lang='en'> <html lang='en'>
<head> <head>
<meta charset='utf-8'> <meta charset='utf-8'>
@@ -242,11 +270,15 @@ app.get('/authorize', (req, res) => {
</body> </body>
</html> </html>
`) `)
}
}) })
app.get('/userinfo', (req, res) => { app.get('/userinfo', (req, res) => {
res.contentType('application/json').send(JSON.stringify({ picture: 'https://cdn.playbuzz.com/cdn/5458360f-32ea-460e-a707-1a2d26760558/70bda687-cb84-4756-8a44-8cf735ed87b3.jpg' })) res.contentType('application/json').send(
JSON.stringify({
picture:
'https://cdn.playbuzz.com/cdn/5458360f-32ea-460e-a707-1a2d26760558/70bda687-cb84-4756-8a44-8cf735ed87b3.jpg'
})
)
}) })
app.get('/v2/logout', (req, res) => { app.get('/v2/logout', (req, res) => {
@@ -254,9 +286,8 @@ app.get('/v2/logout', (req, res) => {
}) })
app.get('/.well-known/jwks.json', (req, res) => { app.get('/.well-known/jwks.json', (req, res) => {
res res.contentType('application/json').send(
.contentType('application/json') JSON.stringify({
.send(JSON.stringify({
keys: [ keys: [
{ {
alg: 'RS256', alg: 'RS256',
@@ -270,7 +301,8 @@ app.get('/.well-known/jwks.json', (req, res) => {
x5t: thumbprint x5t: thumbprint
} }
] ]
})) })
)
}) })
// This route returns the inside of a jwt-token. Your main application // This route returns the inside of a jwt-token. Your main application
@@ -297,7 +329,13 @@ app.post('/issuer', (req, res) => {
} }
issuer = req.body.issuer issuer = req.body.issuer
jwksOrigin = `https://${issuer}/` jwksOrigin = `https://${issuer}/`
const { privateKey: key, certDer: der, thumbprint: thumb, exponent: exp, modulus: mod } = cert(jwksOrigin) const {
privateKey: key,
certDer: der,
thumbprint: thumb,
exponent: exp,
modulus: mod
} = cert(jwksOrigin)
privateKey = key privateKey = key
certDer = der certDer = der
thumbprint = thumb thumbprint = thumb
@@ -324,7 +362,7 @@ app.post('/api/v2/tickets/password-change', (req, res) => {
}) })
}) })
app.use(function(req, res, next) { app.use(function (req, res, next) {
console.log('404', req.path) console.log('404', req.path)
res.status(404).send('error: 404 Not Found ' + req.path) res.status(404).send('error: 404 Not Found ' + req.path)
}) })
+1 -5
View File
@@ -43,11 +43,7 @@ const PUBLIC_KEY_PEM =
'HwIDAQAB\n' + 'HwIDAQAB\n' +
'-----END PUBLIC KEY-----\n' '-----END PUBLIC KEY-----\n'
const createCertificate = ({ const createCertificate = ({ publicKey, privateKey, jwksOrigin }) => {
publicKey,
privateKey,
jwksOrigin
}) => {
const cert = forge.pki.createCertificate() const cert = forge.pki.createCertificate()
cert.publicKey = publicKey cert.publicKey = publicKey
cert.serialNumber = '123' cert.serialNumber = '123'
+1 -1
View File
@@ -14,7 +14,7 @@ spec:
spec: spec:
containers: containers:
- name: auth0mock - name: auth0mock
image: registry.gitlab.com/unboundsoftware/shiny/auth0mock:${COMMIT} image: registry.gitlab.com/unboundsoftware/auth0mock:${COMMIT}
imagePullPolicy: "IfNotPresent" imagePullPolicy: "IfNotPresent"
resources: resources:
requests: requests:
+9 -3
View File
@@ -6,13 +6,16 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon ./app.js", "dev": "nodemon ./app.js",
"start": "node ./app.js" "start": "node ./app.js",
"lint:prettier": "prettier --check .",
"lint": "yarn lint:prettier",
"lintfix": "prettier --write --list-different ."
}, },
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"base64-url": "^2.3.3", "base64-url": "^2.3.3",
"body-parser": "^1.20.1", "body-parser": "^1.20.2",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"cookie-parser": "^1.4.6", "cookie-parser": "^1.4.6",
"cors": "^2.8.3", "cors": "^2.8.3",
@@ -22,7 +25,10 @@
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"node-forge": "^1.3.1", "node-forge": "^1.3.1",
"node-rsa": "^1.1.1", "node-rsa": "^1.1.1",
"nodemon": "^2.0.20", "nodemon": "^2.0.21",
"serve-favicon": "^2.4.2" "serve-favicon": "^2.4.2"
},
"devDependencies": {
"prettier": "^2.8.4"
} }
} }
+42 -9
View File
@@ -60,7 +60,7 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
body-parser@1.20.1, body-parser@^1.20.1: body-parser@1.20.1:
version "1.20.1" version "1.20.1"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668"
integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==
@@ -78,6 +78,24 @@ body-parser@1.20.1, body-parser@^1.20.1:
type-is "~1.6.18" type-is "~1.6.18"
unpipe "1.0.0" unpipe "1.0.0"
body-parser@^1.20.2:
version "1.20.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
dependencies:
bytes "3.1.2"
content-type "~1.0.5"
debug "2.6.9"
depd "2.0.0"
destroy "1.2.0"
http-errors "2.0.0"
iconv-lite "0.4.24"
on-finished "2.4.1"
qs "6.11.0"
raw-body "2.5.2"
type-is "~1.6.18"
unpipe "1.0.0"
brace-expansion@^1.1.7: brace-expansion@^1.1.7:
version "1.1.11" version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -171,10 +189,10 @@ content-disposition@0.5.4:
dependencies: dependencies:
safe-buffer "5.2.1" safe-buffer "5.2.1"
content-type@~1.0.4: content-type@~1.0.4, content-type@~1.0.5:
version "1.0.4" version "1.0.5"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
cookie-parser@^1.4.6: cookie-parser@^1.4.6:
version "1.4.6" version "1.4.6"
@@ -621,10 +639,10 @@ node-rsa@^1.1.1:
dependencies: dependencies:
asn1 "^0.2.4" asn1 "^0.2.4"
nodemon@^2.0.20: nodemon@^2.0.21:
version "2.0.20" version "2.0.21"
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.20.tgz#e3537de768a492e8d74da5c5813cb0c7486fc701" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.21.tgz#267edff25578da91075d6aa54346ef77ecb7b302"
integrity sha512-Km2mWHKKY5GzRg6i1j5OxOHQtuvVsgskLfigG25yTtbyfRGn/GNvIbRyOf1PSCKJ2aT/58TiuUsuOU5UToVViw== integrity sha512-djN/n2549DUtY33S7o1djRCd7dEm0kBnj9c7S9XVXqRUbuggN1MZH/Nqa+5RFQr63Fbefq37nFXAE9VU86yL1A==
dependencies: dependencies:
chokidar "^3.5.2" chokidar "^3.5.2"
debug "^3.2.7" debug "^3.2.7"
@@ -696,6 +714,11 @@ picomatch@^2.2.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==
prettier@^2.8.4:
version "2.8.4"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.4.tgz#34dd2595629bfbb79d344ac4a91ff948694463c3"
integrity sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==
process-nextick-args@~2.0.0: process-nextick-args@~2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa"
@@ -736,6 +759,16 @@ raw-body@2.5.1:
iconv-lite "0.4.24" iconv-lite "0.4.24"
unpipe "1.0.0" unpipe "1.0.0"
raw-body@2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
dependencies:
bytes "3.1.2"
http-errors "2.0.0"
iconv-lite "0.4.24"
unpipe "1.0.0"
readable-stream@^2.0.1: readable-stream@^2.0.1:
version "2.3.6" version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"