Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 060d9529bd | |||
|
8dc80e28cd
|
|||
| 94514bc627 | |||
| 34897e0015 | |||
| 86d4176015 | |||
| 68da5aa9a1 | |||
| f9743ca018 | |||
| b87a6002fd | |||
| 36dab87552 | |||
| f959811b68 | |||
| 39588214a6 | |||
|
8c7b44974f
|
|||
| afe64a31f9 | |||
|
45224547d6
|
|||
| d8aa7d2a89 | |||
| 72f3787dc6 | |||
| 2b62a7ed77 | |||
| 9500f5569d | |||
| 0a1f3eb4e4 | |||
| 7136bda3a8 | |||
| 790399edca | |||
| 6b1ea50aac | |||
| 5edd0801e4 | |||
| 5775cb6006 | |||
| 11ec56bae9 | |||
| 4ae4966ce9 | |||
|
9f40b06ce9
|
|||
| d300500da7 | |||
| 82f4604e6f | |||
| 04e402cdae | |||
| e6e1b1e348 | |||
| aaab5b2cd5 | |||
| 32af389b7b | |||
| f60af84b41 | |||
| 9cb454c32a | |||
| 8f31c1d717 | |||
| 277b64019c | |||
|
66f83fa70d
|
|||
| 01ccab5024 | |||
| 656b10bab9 | |||
| 366113bbf5 | |||
| dde5e91968 | |||
| 21ccdc6809 | |||
| b6b5673ea4 | |||
| b40c5b85e8 | |||
| 295636e444 | |||
| 5c7a189bf1 | |||
| 60ae679d87 | |||
| bc1dcdc8b4 | |||
| 81673c01eb | |||
| 0e883190d5 | |||
| bb29d2f2ad | |||
| 55374c395d | |||
| 8d94a8f8af | |||
| 3478ad0e5b | |||
|
b9a1c0b285
|
|||
| 3382e03305 | |||
| f97c03772b | |||
| 488d3a8b7f | |||
| a42c8c3251 | |||
| 411dd3d222 | |||
| acbea4996f | |||
| e0df0465aa | |||
| e7c4bfcdb7 | |||
| 041b66a54e | |||
| ce5467682e | |||
| 860b658fd8 | |||
| 5e0922d84f | |||
| ce35c1eb50 | |||
| 44047f88e4 | |||
| a9633e9079 | |||
| ef9654adfa | |||
| e99a340485 | |||
| d362203165 | |||
| afa1893f1a | |||
| 791a29d5b8 | |||
| d34a738b71 | |||
| 6e0bb8e1ca | |||
| c29f8be74c | |||
| 349989bb67 | |||
| d940a04d05 | |||
| 192929229f |
+2
-9
@@ -1,22 +1,15 @@
|
|||||||
include:
|
include:
|
||||||
- template: 'Workflows/MergeRequest-Pipelines.gitlab-ci.yml'
|
- template: 'Workflows/MergeRequest-Pipelines.gitlab-ci.yml'
|
||||||
|
- project: unboundsoftware/ci-templates
|
||||||
|
file: Release.gitlab-ci.yml
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- build
|
- build
|
||||||
|
|
||||||
variables:
|
|
||||||
DOCKER_HOST: tcp://docker:2376
|
|
||||||
DOCKER_TLS_CERTDIR: "/certs"
|
|
||||||
DOCKER_TLS_VERIFY: 1
|
|
||||||
DOCKER_CERT_PATH: "$DOCKER_TLS_CERTDIR/client"
|
|
||||||
DOCKER_DRIVER: overlay2
|
|
||||||
|
|
||||||
image: buildtool/build-tools:${BUILDTOOLS_VERSION}
|
image: buildtool/build-tools:${BUILDTOOLS_VERSION}
|
||||||
|
|
||||||
build:
|
build:
|
||||||
stage: build
|
stage: build
|
||||||
services:
|
|
||||||
- docker:${DOCKER_DIND_VERSION}
|
|
||||||
script:
|
script:
|
||||||
- build
|
- build
|
||||||
- push
|
- push
|
||||||
|
|||||||
@@ -1,19 +0,0 @@
|
|||||||
# To get started with Dependabot version updates, you'll need to specify which
|
|
||||||
# package ecosystems to update and where the package manifests are located.
|
|
||||||
# Please see the documentation for all configuration options:
|
|
||||||
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
||||||
|
|
||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: "npm"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
open-pull-requests-limit: 20
|
|
||||||
rebase-strategy: none
|
|
||||||
- package-ecosystem: "docker"
|
|
||||||
directory: "/"
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
open-pull-requests-limit: 20
|
|
||||||
rebase-strategy: none
|
|
||||||
+235
@@ -0,0 +1,235 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
|
## [0.1.4] - 2025-01-24
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(k8s)* Update labels to adhere to best practices
|
||||||
|
|
||||||
|
## [0.1.3] - 2024-12-18
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(deps)* Pin dependencies
|
||||||
|
- *(deps)* Update dependency express to v4.21.2
|
||||||
|
- *(deps)* Update dependency debug to v4.4.0
|
||||||
|
- *(deps)* Update dependency nodemon to v3.1.9
|
||||||
|
|
||||||
|
### 🚜 Refactor
|
||||||
|
|
||||||
|
- *(ci)* Remove unused Docker variables from config
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Update renovate configuration to disable auth0mock updates
|
||||||
|
- Remove Docker service from build stage configuration
|
||||||
|
|
||||||
|
## [0.1.2] - 2024-10-19
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(deps)* Update dependency cookie-parser to v1.4.7
|
||||||
|
- *(deps)* Update dependency express to v4.21.1
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Update Dockerfile to remove warnings
|
||||||
|
- Support issuer in openid-configuration
|
||||||
|
|
||||||
|
## [0.1.1] - 2024-10-05
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(deps)* Update dependency nodemon to v3.1.1
|
||||||
|
- *(deps)* Update dependency nodemon to v3.1.2
|
||||||
|
- *(deps)* Update dependency debug to v4.3.5
|
||||||
|
- *(deps)* Update dependency nodemon to v3.1.3
|
||||||
|
- *(deps)* Update dependency nodemon to v3.1.4
|
||||||
|
- *(deps)* Update dependency debug to v4.3.6
|
||||||
|
- *(deps)* Update dependency debug to v4.3.7
|
||||||
|
- *(deps)* Update dependency body-parser to v1.20.3
|
||||||
|
- *(deps)* Update dependency express to v4.20.0
|
||||||
|
- *(deps)* Update dependency express to v4.21.0
|
||||||
|
- *(deps)* Update dependency nodemon to v3.1.5
|
||||||
|
- *(deps)* Update dependency nodemon to v3.1.6
|
||||||
|
- *(deps)* Update dependency nodemon to v3.1.7
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Add release flow
|
||||||
|
|
||||||
|
## [0.1.0] - 2024-04-08
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Replace keystore handling with node-jose
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(deps)* Update dependency express to v4.19.1
|
||||||
|
- *(deps)* Update dependency express to v4.19.2
|
||||||
|
|
||||||
|
## [0.0.17] - 2024-03-11
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Support patching of user info
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- *(deps)* Update dependency express to v4.18.3
|
||||||
|
|
||||||
|
## [0.0.16] - 2023-06-01
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Initial users store
|
||||||
|
|
||||||
|
## [0.0.15] - 2023-05-31
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Return empty array
|
||||||
|
|
||||||
|
## [0.0.14] - 2023-05-31
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Remember created users
|
||||||
|
|
||||||
|
## [0.0.13] - 2023-05-02
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Add name and email to id token
|
||||||
|
|
||||||
|
## [0.0.12] - 2023-03-10
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Remove session on logout
|
||||||
|
|
||||||
|
## [0.0.11] - 2023-03-10
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Update image name to correct location
|
||||||
|
- Handle response mode query
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Use Docker DinD version from variable
|
||||||
|
- Change Dependabot rebase strategy
|
||||||
|
- Format code and add prettier
|
||||||
|
|
||||||
|
## [0.0.9] - 2022-04-28
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Add support for client id and secret tokens
|
||||||
|
|
||||||
|
## [0.0.8] - 2022-04-26
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Add dummy-implementation of management API
|
||||||
|
|
||||||
|
## [0.0.7] - 2022-04-26
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Use correct return-variable
|
||||||
|
|
||||||
|
## [0.0.6] - 2022-04-26
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Make sure thumbPrint is a string
|
||||||
|
|
||||||
|
### 💼 Other
|
||||||
|
|
||||||
|
- *(deps)* Bump express from 4.17.3 to 4.18.0
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Format code
|
||||||
|
|
||||||
|
## [0.0.5] - 2022-04-26
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Add custom claims to both id and access token
|
||||||
|
|
||||||
|
## [0.0.4] - 2022-04-26
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Add email custom claim
|
||||||
|
|
||||||
|
## [0.0.3] - 2022-04-26
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Add env-property for default issuer
|
||||||
|
|
||||||
|
## [0.0.2] - 2022-04-25
|
||||||
|
|
||||||
|
### 💼 Other
|
||||||
|
|
||||||
|
- *(deps)* Bump node from 17 to 18
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Change admin-handling
|
||||||
|
|
||||||
|
## [0.0.1] - 2022-04-19
|
||||||
|
|
||||||
|
### 🚀 Features
|
||||||
|
|
||||||
|
- Initial commit
|
||||||
|
- Updated to be compatible with Auth0 SPA which uses the 'Authorization Code Grant using Proof Key for Code Exchange (PKCE)' flow
|
||||||
|
- Add ENV-property for setting admin-role
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- Use correct envs
|
||||||
|
- Use commit rather than latest
|
||||||
|
- Package.json & yarn.lock to reduce vulnerabilities
|
||||||
|
- Package.json & yarn.lock to reduce vulnerabilities
|
||||||
|
- Pipeline
|
||||||
|
|
||||||
|
### 💼 Other
|
||||||
|
|
||||||
|
- *(deps)* Bump nodemon from 2.0.14 to 2.0.15
|
||||||
|
- *(deps)* Bump cookie-parser from 1.4.5 to 1.4.6
|
||||||
|
- *(deps)* Bump debug from 4.3.2 to 4.3.3
|
||||||
|
- *(deps)* Bump body-parser from 1.19.0 to 1.19.1
|
||||||
|
- *(deps)* Bump express from 4.17.1 to 4.17.2
|
||||||
|
- *(deps)* Bump node-forge from 0.10.0 to 1.0.0
|
||||||
|
- *(deps)* Bump node-forge from 1.0.0 to 1.1.0
|
||||||
|
- *(deps)* Bump node-forge from 1.1.0 to 1.2.0
|
||||||
|
- *(deps)* Bump node-forge from 1.2.0 to 1.2.1
|
||||||
|
- *(deps)* Bump body-parser from 1.19.1 to 1.19.2
|
||||||
|
- *(deps)* Bump https-localhost from 4.7.0 to 4.7.1
|
||||||
|
- *(deps)* Bump express from 4.17.2 to 4.17.3
|
||||||
|
- *(deps)* Bump debug from 4.3.3 to 4.3.4
|
||||||
|
- *(deps)* Bump node-forge from 1.2.1 to 1.3.0
|
||||||
|
- *(deps)* Bump node-forge from 1.3.0 to 1.3.1
|
||||||
|
- *(deps)* Bump body-parser from 1.19.2 to 1.20.0
|
||||||
|
|
||||||
|
### ⚙️ Miscellaneous Tasks
|
||||||
|
|
||||||
|
- Add triggering of acctest
|
||||||
|
- Add artifacts
|
||||||
|
- Update to latest build-tools
|
||||||
|
- Update to latest build-tools
|
||||||
|
- Add ingress
|
||||||
|
- Add CI workflows
|
||||||
|
- Use buildtools version from env
|
||||||
|
- Add dependabot config
|
||||||
|
- Remove dependabot-standalone
|
||||||
|
- Cleanup and remove acctest triggering
|
||||||
|
|
||||||
|
<!-- generated by git-cliff -->
|
||||||
+6
-6
@@ -1,12 +1,12 @@
|
|||||||
FROM node:20
|
FROM node:22@sha256:ae2f3d4cc65d251352eca01ba668824f651a2ee4d2a37e2efb22649521a483fd
|
||||||
ENV AUDIENCE "https://shiny.unbound.se"
|
ENV AUDIENCE="https://shiny.unbound.se"
|
||||||
ENV ORIGIN_HOST "auth0mock"
|
ENV ORIGIN_HOST="auth0mock"
|
||||||
ENV ORIGIN "https://auth0mock:3333"
|
ENV ORIGIN="https://auth0mock:3333"
|
||||||
EXPOSE 3333
|
EXPOSE 3333
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ADD package.json yarn.lock /app/
|
ADD package.json yarn.lock /app/
|
||||||
RUN yarn install --frozen-lockfile
|
RUN yarn install --frozen-lockfile
|
||||||
ADD app.js cert.js /app/
|
ADD *.js /app/
|
||||||
ADD public /app/public
|
ADD public /app/public
|
||||||
RUN mkdir -p /root/.config
|
RUN mkdir -p /root/.config
|
||||||
ENTRYPOINT yarn start
|
ENTRYPOINT ["yarn", "start"]
|
||||||
|
|||||||
@@ -22,6 +22,22 @@ 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/`).
|
||||||
|
|
||||||
|
## Initial users
|
||||||
|
|
||||||
|
Adding a JSON file with the following layout will populate the users store when starting:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"email@test.com": {
|
||||||
|
"given_name": "name",
|
||||||
|
"family_name": "family",
|
||||||
|
"user_id": "id"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
By default `./users.json` will be read but this can be overridden by setting the environment variable `USERS_FILE`.
|
||||||
|
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
### `GET` /token/:username
|
### `GET` /token/:username
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ const Debug = require('debug')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const cors = require('cors')
|
const cors = require('cors')
|
||||||
const bodyParser = require('body-parser')
|
const bodyParser = require('body-parser')
|
||||||
|
const jose = require('node-jose');
|
||||||
const favicon = require('serve-favicon')
|
const favicon = require('serve-favicon')
|
||||||
const cert = require('./cert')
|
const initialUsers = require('./users')
|
||||||
|
|
||||||
let issuer = process.env.ISSUER || 'localhost:3333'
|
const issuer = process.env.ISSUER || 'localhost:3333'
|
||||||
let jwksOrigin = `https://${issuer}/`
|
const jwksOrigin = `https://${issuer}/`
|
||||||
const audience = process.env.AUDIENCE || 'https://generic-audience'
|
const audience = process.env.AUDIENCE || 'https://generic-audience'
|
||||||
const adminCustomClaim =
|
const adminCustomClaim =
|
||||||
process.env.ADMIN_CUSTOM_CLAIM || 'https://unbound.se/admin'
|
process.env.ADMIN_CUSTOM_CLAIM || 'https://unbound.se/admin'
|
||||||
@@ -21,9 +22,10 @@ const emailCustomClaim =
|
|||||||
|
|
||||||
const debug = Debug('app')
|
const debug = Debug('app')
|
||||||
|
|
||||||
let { privateKey, certDer, thumbprint, exponent, modulus } = cert(jwksOrigin)
|
const keyStore = jose.JWK.createKeyStore()
|
||||||
|
keyStore.generate('RSA', 2048, { alg: 'RS256', use: 'sig' })
|
||||||
const users = {}
|
// let { privateKey, certDer, thumbprint, exponent, modulus } = cert(jwksOrigin)
|
||||||
|
const users = initialUsers(process.env.USERS_FILE || './users.json')
|
||||||
const sessions = {}
|
const sessions = {}
|
||||||
const challenges = {}
|
const challenges = {}
|
||||||
|
|
||||||
@@ -42,11 +44,12 @@ const addCustomClaims = (email, customClaims, token) => {
|
|||||||
}, token)
|
}, token)
|
||||||
}
|
}
|
||||||
|
|
||||||
const signToken = (token) => {
|
const signToken = async (token) => {
|
||||||
return jwt.sign(Buffer.from(JSON.stringify(token)), privateKey, {
|
const [key] = keyStore.all({ use: 'sig' })
|
||||||
algorithm: 'RS256',
|
const opt = { compact: true, jwk: key, fields: { typ: 'jwt' } }
|
||||||
keyid: thumbprint
|
return await jose.JWS.createSign(opt, key)
|
||||||
})
|
.update(JSON.stringify(token))
|
||||||
|
.final()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure our small auth0-mock-server
|
// Configure our small auth0-mock-server
|
||||||
@@ -60,10 +63,10 @@ app
|
|||||||
.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
|
.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
|
||||||
|
|
||||||
// This route can be used to generate a valid jwt-token.
|
// This route can be used to generate a valid jwt-token.
|
||||||
app.post('/oauth/token', (req, res) => {
|
app.post('/oauth/token', async (req, res) => {
|
||||||
let date = Math.floor(Date.now() / 1000)
|
const date = Math.floor(Date.now() / 1000)
|
||||||
if (req.body.grant_type === 'client_credentials' && req.body.client_id) {
|
if (req.body.grant_type === 'client_credentials' && req.body.client_id) {
|
||||||
let accessToken = signToken({
|
const accessToken = await signToken({
|
||||||
iss: jwksOrigin,
|
iss: jwksOrigin,
|
||||||
aud: [audience],
|
aud: [audience],
|
||||||
sub: 'auth0|management',
|
sub: 'auth0|management',
|
||||||
@@ -72,7 +75,7 @@ app.post('/oauth/token', (req, res) => {
|
|||||||
azp: req.body.client_id
|
azp: req.body.client_id
|
||||||
})
|
})
|
||||||
|
|
||||||
let idToken = signToken({
|
const idToken = await signToken({
|
||||||
iss: jwksOrigin,
|
iss: jwksOrigin,
|
||||||
aud: req.body.client_id,
|
aud: req.body.client_id,
|
||||||
sub: 'auth0|management',
|
sub: 'auth0|management',
|
||||||
@@ -94,7 +97,7 @@ 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(
|
const accessToken = await signToken(
|
||||||
addCustomClaims(session.email, session.customClaims, {
|
addCustomClaims(session.email, session.customClaims, {
|
||||||
iss: jwksOrigin,
|
iss: jwksOrigin,
|
||||||
aud: [audience],
|
aud: [audience],
|
||||||
@@ -105,7 +108,7 @@ app.post('/oauth/token', (req, res) => {
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
||||||
let idToken = signToken(
|
const idToken = await signToken(
|
||||||
addCustomClaims(session.email, session.customClaims, {
|
addCustomClaims(session.email, session.customClaims, {
|
||||||
iss: jwksOrigin,
|
iss: jwksOrigin,
|
||||||
aud: session.clientId,
|
aud: session.clientId,
|
||||||
@@ -294,26 +297,78 @@ app.get('/v2/logout', (req, res) => {
|
|||||||
res.redirect(req.query.returnTo)
|
res.redirect(req.query.returnTo)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.get('/.well-known/jwks.json', (req, res) => {
|
app.get('/.well-known/openid-configuration', (req, res) => {
|
||||||
|
debug('Fetching OpenID configuration')
|
||||||
res.contentType('application/json').send(
|
res.contentType('application/json').send(
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
keys: [
|
"issuer":
|
||||||
{
|
`${jwksOrigin}`,
|
||||||
alg: 'RS256',
|
"authorization_endpoint":
|
||||||
// e: 'AQAB',
|
`${jwksOrigin}authorize`,
|
||||||
e: exponent,
|
"token_endpoint":
|
||||||
kid: thumbprint,
|
`${jwksOrigin}oauth/token`,
|
||||||
kty: 'RSA',
|
"token_endpoint_auth_methods_supported":
|
||||||
n: modulus,
|
["client_secret_basic", "private_key_jwt"],
|
||||||
use: 'sig',
|
"token_endpoint_auth_signing_alg_values_supported":
|
||||||
x5c: [certDer],
|
["RS256"],
|
||||||
x5t: thumbprint
|
"userinfo_endpoint":
|
||||||
}
|
`${jwksOrigin}userinfo`,
|
||||||
]
|
"check_session_iframe":
|
||||||
|
`${jwksOrigin}check_session`,
|
||||||
|
"end_session_endpoint":
|
||||||
|
`${jwksOrigin}end_session`,
|
||||||
|
"jwks_uri":
|
||||||
|
`${jwksOrigin}.well-known/jwks.json`,
|
||||||
|
"registration_endpoint":
|
||||||
|
`${jwksOrigin}register`,
|
||||||
|
"scopes_supported":
|
||||||
|
["openid", "profile", "email", "address",
|
||||||
|
"phone", "offline_access"],
|
||||||
|
"response_types_supported":
|
||||||
|
["code", "code id_token", "id_token", "id_token token"],
|
||||||
|
"acr_values_supported":
|
||||||
|
[],
|
||||||
|
"subject_types_supported":
|
||||||
|
["public", "pairwise"],
|
||||||
|
"userinfo_signing_alg_values_supported":
|
||||||
|
["RS256", "ES256", "HS256"],
|
||||||
|
"userinfo_encryption_alg_values_supported":
|
||||||
|
["RSA-OAEP-256", "A128KW"],
|
||||||
|
"userinfo_encryption_enc_values_supported":
|
||||||
|
["A128CBC-HS256", "A128GCM"],
|
||||||
|
"id_token_signing_alg_values_supported":
|
||||||
|
["RS256", "ES256", "HS256"],
|
||||||
|
"id_token_encryption_alg_values_supported":
|
||||||
|
["RSA-OAEP-256", "A128KW"],
|
||||||
|
"id_token_encryption_enc_values_supported":
|
||||||
|
["A128CBC-HS256", "A128GCM"],
|
||||||
|
"request_object_signing_alg_values_supported":
|
||||||
|
["none", "RS256", "ES256"],
|
||||||
|
"display_values_supported":
|
||||||
|
["page", "popup"],
|
||||||
|
"claim_types_supported":
|
||||||
|
["normal", "distributed"],
|
||||||
|
"claims_supported":
|
||||||
|
["sub", "iss", "auth_time", "acr",
|
||||||
|
"name", "given_name", "family_name", "nickname",
|
||||||
|
"profile", "picture", "website",
|
||||||
|
"email", "email_verified", "locale", "zoneinfo",
|
||||||
|
"https://unbound.se/email", "https://unbound.se/admin"],
|
||||||
|
"claims_parameter_supported":
|
||||||
|
true,
|
||||||
|
"service_documentation":
|
||||||
|
"http://auth0/",
|
||||||
|
"ui_locales_supported":
|
||||||
|
["en-US"]
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.get('/.well-known/jwks.json', (req, res) => {
|
||||||
|
debug('Fetching JWKS')
|
||||||
|
res.contentType('application/json').send(keyStore.toJSON())
|
||||||
|
})
|
||||||
|
|
||||||
// This route returns the inside of a jwt-token. Your main application
|
// This route returns the inside of a jwt-token. Your main application
|
||||||
// should use this route to keep the auth0-flow
|
// should use this route to keep the auth0-flow
|
||||||
app.post('/tokeninfo', (req, res) => {
|
app.post('/tokeninfo', (req, res) => {
|
||||||
@@ -331,49 +386,44 @@ app.post('/tokeninfo', (req, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
app.post('/issuer', (req, res) => {
|
|
||||||
if (!req.body.issuer) {
|
|
||||||
debug('No issuer given in the body!')
|
|
||||||
return res.status(401).send('missing issuer')
|
|
||||||
}
|
|
||||||
issuer = req.body.issuer
|
|
||||||
jwksOrigin = `https://${issuer}/`
|
|
||||||
const {
|
|
||||||
privateKey: key,
|
|
||||||
certDer: der,
|
|
||||||
thumbprint: thumb,
|
|
||||||
exponent: exp,
|
|
||||||
modulus: mod
|
|
||||||
} = cert(jwksOrigin)
|
|
||||||
privateKey = key
|
|
||||||
certDer = der
|
|
||||||
thumbprint = thumb
|
|
||||||
exponent = exp
|
|
||||||
modulus = mod
|
|
||||||
debug('Issuer set to ' + req.body.issuer)
|
|
||||||
res.send('ok')
|
|
||||||
})
|
|
||||||
|
|
||||||
app.get('/api/v2/users-by-email', (req, res) => {
|
app.get('/api/v2/users-by-email', (req, res) => {
|
||||||
const email = req.query.email
|
const email = req.query.email
|
||||||
|
console.log('users', users)
|
||||||
const user = users[email]
|
const user = users[email]
|
||||||
if (user === undefined) {
|
if (user === undefined) {
|
||||||
res.json([{}])
|
res.json([])
|
||||||
} else {
|
} else {
|
||||||
res.json([
|
res.json([user])
|
||||||
user
|
|
||||||
])
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
app.patch('/api/v2/users/:userid', (req, res) => {
|
||||||
|
const email = req.params.userid.slice(6)
|
||||||
|
console.log('patching user with id', email)
|
||||||
|
const user = users[email]
|
||||||
|
if (!user) {
|
||||||
|
res.sendStatus(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
users[email] = {
|
||||||
|
email: email,
|
||||||
|
given_name: req.body.given_name || user.given_name,
|
||||||
|
family_name: req.body.family_name || user.family_name,
|
||||||
|
user_id: email,
|
||||||
|
picture: req.body.picture || user.picture
|
||||||
|
}
|
||||||
|
res.json({
|
||||||
|
user_id: `auth0|${email}`
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
app.post('/api/v2/users', (req, res) => {
|
app.post('/api/v2/users', (req, res) => {
|
||||||
const email = req.body.email
|
const email = req.body.email
|
||||||
users[email] = {
|
users[email] = {
|
||||||
"email": email,
|
email: email,
|
||||||
"given_name": "Given",
|
given_name: 'Given',
|
||||||
"family_name": "Last",
|
family_name: 'Last',
|
||||||
"user_id": email,
|
user_id: email
|
||||||
}
|
}
|
||||||
res.json({
|
res.json({
|
||||||
user_id: `auth0|${email}`
|
user_id: `auth0|${email}`
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
const base64url = require('base64-url')
|
|
||||||
const createHash = require('crypto').createHash
|
|
||||||
const forge = require('node-forge')
|
|
||||||
const NodeRSA = require('node-rsa')
|
|
||||||
|
|
||||||
const PRIVATE_KEY_PEM =
|
|
||||||
'-----BEGIN RSA PRIVATE KEY-----\n' +
|
|
||||||
'MIIEpAIBAAKCAQEApoocpO3bbUF6o8eyJlQCfwLahEsunWdVF++yOEyKu4Lp1j0m\n' +
|
|
||||||
'2j/P7iHOtxBAkjdM2X2oW3qO1mR0sIFefqnm93g0q2nRuYEoS+W3o6X50wjOVm8f\n' +
|
|
||||||
'r/tLqELzy5BoET0AQl7Axp1DNsb0HNOBcoIBt+xVY4I+k6uXJJJMzbgvahAgSLZ9\n' +
|
|
||||||
'RW0Z0WT+dCHZpZUj0nLxNXIPdci65Bw6IognqXHP6AwKZXpT6jCzjzq9uyHxVcud\n' +
|
|
||||||
'qw6j0kQw48/A5A6AN5fIVy1cKnd0sKdqRX1NUqVoiOrO4jaDB1IdLD+YmRE/JjOH\n' +
|
|
||||||
'sWIMElYCPxKqnsNo6VCslGX/ziinArHhqRBrHwIDAQABAoIBAHAdmpsN5iLvafjI\n' +
|
|
||||||
'f45+EBAhg6p8Uq102zx6CakNHniN8Y5hLL7RJtJRwDBNqKrGv93LUoQDRhXfGw+Y\n' +
|
|
||||||
'iF0NVIhVTF/5pU8VPGOcCr0JB96ilwZpWRPIQW7NZAMu/GBeiMYls/IB/TXrSnv9\n' +
|
|
||||||
'h6/nBfEkEXgkPqx7YA0m0L3NuV3U1lCY/LhBJY4Xvi0uRdqu3tTHXftehuPwC4UB\n' +
|
|
||||||
'42eJTWv/qLeOlkCdUUV4f7+dNaES88Vdhj6lu/BusnNhvnwHQik4dNwzPCGeP8NV\n' +
|
|
||||||
'5gaesWiNWFZuTURGKk1B65p5LzNPjsVT50RDuW8FnSZwIvNcohrX9ILPsmg/t0Kr\n' +
|
|
||||||
'ozcOksECgYEA4XWOK4twx5RG162zveRHqU7H9RBWSz7/PzM9Eob9vx/tC/b1YqBR\n' +
|
|
||||||
'VShk23vje19eNiYWAkxcpobIP4ek/0ZT8nHkJg8wl+J/hnXADcvwv2dKnoFnm5pn\n' +
|
|
||||||
'rTBUKc8R3wrSlAV8XQAtdnxsfFa5AOQJ6WFVI9AdfH3Iw8XZk4gIIPMCgYEAvRlY\n' +
|
|
||||||
'y80HnR3kwMOqY488V1qk41dmfNqa+YDL+zkPF1HhHI9VnK5BQuI7lyKJl984KwHu\n' +
|
|
||||||
'0gbwx3Wp4XkD5JUboEpl5LnaLsjEWemjTaQWdvJHPd5wkJ0m/jRQ2YeT4g2gFu4y\n' +
|
|
||||||
'Pi/pWkrzhnzQQVAmOdAm5Kj27LtDzp0lspw3uCUCgYEAw2YdvFGSgfZZW4147QeO\n' +
|
|
||||||
'sAbON+9bysUjdMPUl10VR/LEgA0d6MdnFfX3S13Y7tDdlvJ1OrKxzcWcgaru7ism\n' +
|
|
||||||
'kEXy5KVfiRNNUNx2gb6RvWEpA6zFfc9ZMXlkSAPlyjfX/1+tw/Bmdn0pjK2gk0wP\n' +
|
|
||||||
'5wtrPameFInzWPD9O+a2nM8CgYBZ6UhgNs+M9B7FTQOiLQPa4R2PfwobCXIwef4D\n' +
|
|
||||||
'KIE1bFgl1T02r2AWZi1BUkmr7ZXuVQ/xyx0HKbopm/mu4PruvxEtrPTB0/IQcleU\n' +
|
|
||||||
'XhXUXqRjFXXePOrCaaubkqxNCn95B67aBLvmk8awxn3a4DocuQ0VIgWuT+gQwIWh\n' +
|
|
||||||
'JEgWBQKBgQDKD+2Yh1/rUzu15lbPH0JSpozUinuFjePieR/4n+5CtEUxWJ2f0WeK\n' +
|
|
||||||
's4XWWf2qgUccjpiGju2UR840mgWROoZ8BfSTd5tg1F7bo0HMgu2hu0RIRpZcRhsA\n' +
|
|
||||||
'Cd0GrJvf1t0QIdDCXAy+RpgU1SLSq4Q6Lomc0WA5C5nBw9RKEUOV9A==\n' +
|
|
||||||
'-----END RSA PRIVATE KEY-----\n'
|
|
||||||
|
|
||||||
const PUBLIC_KEY_PEM =
|
|
||||||
'-----BEGIN PUBLIC KEY-----\n' +
|
|
||||||
'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApoocpO3bbUF6o8eyJlQC\n' +
|
|
||||||
'fwLahEsunWdVF++yOEyKu4Lp1j0m2j/P7iHOtxBAkjdM2X2oW3qO1mR0sIFefqnm\n' +
|
|
||||||
'93g0q2nRuYEoS+W3o6X50wjOVm8fr/tLqELzy5BoET0AQl7Axp1DNsb0HNOBcoIB\n' +
|
|
||||||
't+xVY4I+k6uXJJJMzbgvahAgSLZ9RW0Z0WT+dCHZpZUj0nLxNXIPdci65Bw6Iogn\n' +
|
|
||||||
'qXHP6AwKZXpT6jCzjzq9uyHxVcudqw6j0kQw48/A5A6AN5fIVy1cKnd0sKdqRX1N\n' +
|
|
||||||
'UqVoiOrO4jaDB1IdLD+YmRE/JjOHsWIMElYCPxKqnsNo6VCslGX/ziinArHhqRBr\n' +
|
|
||||||
'HwIDAQAB\n' +
|
|
||||||
'-----END PUBLIC KEY-----\n'
|
|
||||||
|
|
||||||
const createCertificate = ({ publicKey, privateKey, jwksOrigin }) => {
|
|
||||||
const cert = forge.pki.createCertificate()
|
|
||||||
cert.publicKey = publicKey
|
|
||||||
cert.serialNumber = '123'
|
|
||||||
const attrs = [
|
|
||||||
{
|
|
||||||
name: 'commonName',
|
|
||||||
value: `${jwksOrigin}`
|
|
||||||
}
|
|
||||||
]
|
|
||||||
cert.validity.notBefore = new Date()
|
|
||||||
cert.validity.notAfter = new Date()
|
|
||||||
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1)
|
|
||||||
cert.setSubject(attrs)
|
|
||||||
cert.setIssuer(attrs)
|
|
||||||
cert.sign(privateKey)
|
|
||||||
return forge.pki.certificateToPem(cert)
|
|
||||||
}
|
|
||||||
|
|
||||||
const getCertThumbprint = (certificate) => {
|
|
||||||
const shasum = createHash('sha1')
|
|
||||||
const der = Buffer.from(certificate).toString('binary')
|
|
||||||
shasum.update(der)
|
|
||||||
return shasum.digest('base64')
|
|
||||||
}
|
|
||||||
|
|
||||||
const createKeyPair = () => {
|
|
||||||
const privateKey = forge.pki.privateKeyFromPem(PRIVATE_KEY_PEM)
|
|
||||||
const publicKey = forge.pki.publicKeyFromPem(PUBLIC_KEY_PEM)
|
|
||||||
return {
|
|
||||||
privateKey,
|
|
||||||
publicKey
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const bnToB64 = (bn) => {
|
|
||||||
let hex = BigInt(bn).toString(16)
|
|
||||||
if (hex.length % 2) {
|
|
||||||
hex = '0' + hex
|
|
||||||
}
|
|
||||||
|
|
||||||
const bin = []
|
|
||||||
let i = 0
|
|
||||||
let d
|
|
||||||
let b
|
|
||||||
while (i < hex.length) {
|
|
||||||
d = parseInt(hex.slice(i, i + 2), 16)
|
|
||||||
b = String.fromCharCode(d)
|
|
||||||
bin.push(b)
|
|
||||||
i += 2
|
|
||||||
}
|
|
||||||
|
|
||||||
return Buffer.from(bin.join(''), 'binary').toString('base64')
|
|
||||||
}
|
|
||||||
|
|
||||||
const setup = (jwksOrigin) => {
|
|
||||||
const { privateKey, publicKey } = createKeyPair()
|
|
||||||
const certPem = createCertificate({
|
|
||||||
jwksOrigin,
|
|
||||||
privateKey,
|
|
||||||
publicKey
|
|
||||||
})
|
|
||||||
const certDer = forge.util.encode64(
|
|
||||||
forge.asn1
|
|
||||||
.toDer(forge.pki.certificateToAsn1(forge.pki.certificateFromPem(certPem)))
|
|
||||||
.getBytes()
|
|
||||||
)
|
|
||||||
const thumbprint = base64url.encode(getCertThumbprint(certDer))
|
|
||||||
|
|
||||||
const helperKey = new NodeRSA()
|
|
||||||
helperKey.importKey(forge.pki.privateKeyToPem(privateKey))
|
|
||||||
const { n: modulus, e: exponent } = helperKey.exportKey('components')
|
|
||||||
|
|
||||||
return {
|
|
||||||
privateKey: forge.pki.privateKeyToPem(privateKey),
|
|
||||||
certDer,
|
|
||||||
thumbprint: thumbprint.toString(),
|
|
||||||
exponent: bnToB64(exponent),
|
|
||||||
modulus: modulus.toString('base64')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = setup
|
|
||||||
+4
-4
@@ -6,11 +6,11 @@ spec:
|
|||||||
replicas: 1
|
replicas: 1
|
||||||
selector:
|
selector:
|
||||||
matchLabels:
|
matchLabels:
|
||||||
app: auth0mock
|
app.kubernetes.io/name: auth0mock
|
||||||
template:
|
template:
|
||||||
metadata:
|
metadata:
|
||||||
labels:
|
labels:
|
||||||
app: auth0mock
|
app.kubernetes.io/name: auth0mock
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- name: auth0mock
|
- name: auth0mock
|
||||||
@@ -36,10 +36,10 @@ kind: Service
|
|||||||
metadata:
|
metadata:
|
||||||
name: auth0mock
|
name: auth0mock
|
||||||
labels:
|
labels:
|
||||||
app: auth0mock
|
app.kubernetes.io/name: auth0mock
|
||||||
spec:
|
spec:
|
||||||
ports:
|
ports:
|
||||||
- port: 3333
|
- port: 3333
|
||||||
selector:
|
selector:
|
||||||
app: auth0mock
|
app.kubernetes.io/name: auth0mock
|
||||||
type: ClusterIP
|
type: ClusterIP
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
apiVersion: networking.k8s.io/v1beta1
|
apiVersion: networking.k8s.io/v1
|
||||||
kind: Ingress
|
kind: Ingress
|
||||||
metadata:
|
metadata:
|
||||||
name: auth0-ingress
|
name: auth0-ingress
|
||||||
|
|||||||
+11
-14
@@ -14,21 +14,18 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"base64-url": "^2.3.3",
|
"body-parser": "1.20.3",
|
||||||
"body-parser": "^1.20.2",
|
"cookie-parser": "1.4.7",
|
||||||
"buffer": "^6.0.3",
|
"cors": "2.8.5",
|
||||||
"cookie-parser": "^1.4.6",
|
"debug": "4.4.0",
|
||||||
"cors": "^2.8.3",
|
"express": "4.21.2",
|
||||||
"debug": "^4.3.4",
|
"https-localhost": "4.7.1",
|
||||||
"express": "^4.18.2",
|
"jsonwebtoken": "9.0.2",
|
||||||
"https-localhost": "^4.7.1",
|
"node-jose": "2.2.0",
|
||||||
"jsonwebtoken": "^9.0.0",
|
"nodemon": "3.1.9",
|
||||||
"node-forge": "^1.3.1",
|
"serve-favicon": "2.5.0"
|
||||||
"node-rsa": "^1.1.1",
|
|
||||||
"nodemon": "^2.0.22",
|
|
||||||
"serve-favicon": "^2.4.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"prettier": "^2.8.8"
|
"prettier": "3.4.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
|
"extends": [
|
||||||
|
"config:recommended"
|
||||||
|
],
|
||||||
|
"packageRules": [
|
||||||
|
{
|
||||||
|
"matchManagers": [
|
||||||
|
"kubernetes"
|
||||||
|
],
|
||||||
|
"matchPackageNames": [
|
||||||
|
"registry.gitlab.com/unboundsoftware/auth0mock"
|
||||||
|
],
|
||||||
|
"enabled": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
|
const setup = (usersFile) => {
|
||||||
|
let users = {}
|
||||||
|
if (fs.existsSync(usersFile)) {
|
||||||
|
console.log(`initial users file "${usersFile}" exists, reading`)
|
||||||
|
const read = fs.readFileSync(usersFile, { encoding: 'utf8', flag: 'r' })
|
||||||
|
users = JSON.parse(read)
|
||||||
|
for (let key of Object.keys(users)) {
|
||||||
|
users[key] = { ...users[key], email: key }
|
||||||
|
}
|
||||||
|
console.log('users:', users)
|
||||||
|
} else {
|
||||||
|
console.log(`initial users file "${usersFile}" missing`)
|
||||||
|
}
|
||||||
|
return users
|
||||||
|
}
|
||||||
|
module.exports = setup
|
||||||
Reference in New Issue
Block a user