@boxyhq/saml-jackson 0.2.3-beta.231 → 0.2.3-beta.235
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/package.json +12 -4
- package/ nodemon.json +0 -12
- package/.dockerignore +0 -2
- package/.eslintrc.js +0 -18
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -27
- package/.github/ISSUE_TEMPLATE/config.yml +0 -5
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -43
- package/.github/pull_request_template.md +0 -31
- package/.github/workflows/codesee-arch-diagram.yml +0 -81
- package/.github/workflows/main.yml +0 -123
- package/_dev/docker-compose.yml +0 -37
- package/map.js +0 -1
- package/prettier.config.js +0 -4
- package/src/controller/api.ts +0 -225
- package/src/controller/error.ts +0 -13
- package/src/controller/oauth/allowed.ts +0 -22
- package/src/controller/oauth/code-verifier.ts +0 -11
- package/src/controller/oauth/redirect.ts +0 -12
- package/src/controller/oauth.ts +0 -334
- package/src/controller/utils.ts +0 -17
- package/src/db/db.ts +0 -100
- package/src/db/encrypter.ts +0 -38
- package/src/db/mem.ts +0 -128
- package/src/db/mongo.ts +0 -110
- package/src/db/redis.ts +0 -103
- package/src/db/sql/entity/JacksonIndex.ts +0 -43
- package/src/db/sql/entity/JacksonStore.ts +0 -43
- package/src/db/sql/entity/JacksonTTL.ts +0 -17
- package/src/db/sql/model/JacksonIndex.ts +0 -3
- package/src/db/sql/model/JacksonStore.ts +0 -8
- package/src/db/sql/sql.ts +0 -181
- package/src/db/store.ts +0 -49
- package/src/db/utils.ts +0 -26
- package/src/env.ts +0 -42
- package/src/index.ts +0 -84
- package/src/jackson.ts +0 -173
- package/src/read-config.ts +0 -29
- package/src/saml/claims.ts +0 -41
- package/src/saml/saml.ts +0 -233
- package/src/saml/x509.ts +0 -51
- package/src/test/api.test.ts +0 -270
- package/src/test/data/metadata/boxyhq.js +0 -6
- package/src/test/data/metadata/boxyhq.xml +0 -30
- package/src/test/data/saml_response +0 -1
- package/src/test/db.test.ts +0 -313
- package/src/test/oauth.test.ts +0 -362
- package/src/typings.ts +0 -167
- package/tsconfig.build.json +0 -6
- package/tsconfig.json +0 -26
package/README.md
CHANGED
@@ -357,7 +357,6 @@ To Do
|
|
357
357
|
Jackson currently supports the following databases.
|
358
358
|
|
359
359
|
- Postgres
|
360
|
-
- CockroachDB
|
361
360
|
- MySQL
|
362
361
|
- MariaDB
|
363
362
|
- MongoDB
|
@@ -381,7 +380,7 @@ The following options are supported and will have to be configured during deploy
|
|
381
380
|
| IDP_ENABLED (npm: idpEnabled) | Set to `true` to enable IdP initiated login for SAML. SP initiated login is the only recommended flow but you might have to support IdP login at times. | `false` |
|
382
381
|
| DB_ENGINE (npm: db.engine) | Supported values are `redis`, `sql`, `mongo`, `mem`. | `sql` |
|
383
382
|
| DB_URL (npm: db.url) | The database URL to connect to. For example `postgres://postgres:postgres@localhost:5450/jackson` | |
|
384
|
-
| DB_TYPE (npm: db.type) | Only needed when DB_ENGINE is `sql`. Supported values are `postgres`, `
|
383
|
+
| DB_TYPE (npm: db.type) | Only needed when DB_ENGINE is `sql`. Supported values are `postgres`, `mysql`, `mariadb`. | `postgres` |
|
385
384
|
| DB_TTL (npm: db.ttl) | TTL for the code, session and token stores (in seconds). | 300 |
|
386
385
|
| DB_CLEANUP_LIMIT (npm: db.cleanupLimit) | Limit cleanup of TTL entries to this number. | 1000 |
|
387
386
|
| DB_ENCRYPTION_KEY (npm: db.encryptionKey) | To encrypt data at rest specify a 32 character key. | |
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@boxyhq/saml-jackson",
|
3
|
-
"version": "0.2.3-beta.
|
3
|
+
"version": "0.2.3-beta.235",
|
4
4
|
"license": "Apache 2.0",
|
5
5
|
"description": "SAML 2.0 service",
|
6
6
|
"main": "dist/index.js",
|
@@ -25,7 +25,8 @@
|
|
25
25
|
"pre-loaded-db": "cross-env JACKSON_API_KEYS=secret PRE_LOADED_CONFIG='./_config' nodemon --config nodemon.json src/jackson.ts",
|
26
26
|
"test": "tap --ts --timeout=100 src/**/*.test.ts",
|
27
27
|
"dev-dbs": "docker-compose -f ./_dev/docker-compose.yml up -d",
|
28
|
-
"dev-dbs-destroy": "docker-compose -f ./_dev/docker-compose.yml down --volumes --remove-orphans"
|
28
|
+
"dev-dbs-destroy": "docker-compose -f ./_dev/docker-compose.yml down --volumes --remove-orphans",
|
29
|
+
"db:migration:generate": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js migration:generate --config ormconfig.js -n Initial"
|
29
30
|
},
|
30
31
|
"tap": {
|
31
32
|
"coverage-map": "map.js",
|
@@ -54,6 +55,8 @@
|
|
54
55
|
"xmlbuilder": "15.1.1"
|
55
56
|
},
|
56
57
|
"devDependencies": {
|
58
|
+
"@types/express": "^4.17.13",
|
59
|
+
"@types/node": "^16.11.17",
|
57
60
|
"@types/redis": "4.0.11",
|
58
61
|
"@types/sinon": "10.0.6",
|
59
62
|
"@types/tap": "15.0.5",
|
@@ -69,10 +72,15 @@
|
|
69
72
|
"sinon": "12.0.1",
|
70
73
|
"tap": "15.1.5",
|
71
74
|
"ts-node": "10.4.0",
|
72
|
-
"
|
75
|
+
"tsconfig-paths": "3.12.0",
|
76
|
+
"typescript": "4.5.4"
|
73
77
|
},
|
74
78
|
"lint-staged": {
|
75
79
|
"*.{js,ts}": "eslint --cache --fix",
|
76
80
|
"*.{js,ts,css,md}": "prettier --write"
|
77
|
-
}
|
81
|
+
},
|
82
|
+
"files": [
|
83
|
+
"dist",
|
84
|
+
"Dockerfile"
|
85
|
+
]
|
78
86
|
}
|
package/ nodemon.json
DELETED
package/.dockerignore
DELETED
package/.eslintrc.js
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
module.exports = {
|
2
|
-
env: {
|
3
|
-
es2021: true,
|
4
|
-
node: true,
|
5
|
-
},
|
6
|
-
parserOptions: {
|
7
|
-
ecmaVersion: 13,
|
8
|
-
sourceType: 'module',
|
9
|
-
},
|
10
|
-
root: true,
|
11
|
-
parser: '@typescript-eslint/parser',
|
12
|
-
plugins: ['@typescript-eslint'],
|
13
|
-
extends: [
|
14
|
-
'eslint:recommended',
|
15
|
-
'plugin:@typescript-eslint/recommended',
|
16
|
-
'prettier',
|
17
|
-
],
|
18
|
-
};
|
@@ -1,27 +0,0 @@
|
|
1
|
-
---
|
2
|
-
name: Bug report
|
3
|
-
about: Report any issues with the platform
|
4
|
-
title: ""
|
5
|
-
labels: bug
|
6
|
-
assignees: ""
|
7
|
-
---
|
8
|
-
|
9
|
-
Found a bug? Please fill out the sections below. 👍
|
10
|
-
|
11
|
-
### Issue Summary
|
12
|
-
|
13
|
-
A summary of the issue. This needs to be a clear detailed-rich summary.
|
14
|
-
|
15
|
-
### Steps to Reproduce
|
16
|
-
|
17
|
-
1. (for example) Went to ...
|
18
|
-
2. Clicked on...
|
19
|
-
3. ...
|
20
|
-
|
21
|
-
Any other relevant information. For example, why do you consider this a bug and what did you expect to happen instead?
|
22
|
-
|
23
|
-
### Technical details
|
24
|
-
|
25
|
-
- Browser version: You can use https://www.whatsmybrowser.org/ to find this out.
|
26
|
-
- Node.js version
|
27
|
-
- Anything else that you think could be an issue.
|
@@ -1,43 +0,0 @@
|
|
1
|
-
---
|
2
|
-
name: Feature request
|
3
|
-
about: Suggest a feature or idea
|
4
|
-
title: ""
|
5
|
-
labels: enhancement
|
6
|
-
assignees: ""
|
7
|
-
---
|
8
|
-
|
9
|
-
> Please check if your Feature Request has not been already raised in the [Discussions Tab](https://github.com/boxyhq/jackson/discussions), as we would like to reduce duplicates. If it has been already raised, simply upvote it 🔼.
|
10
|
-
|
11
|
-
### Is your proposal related to a problem?
|
12
|
-
|
13
|
-
<!--
|
14
|
-
Provide a clear and concise description of what the problem is.
|
15
|
-
For example, "I'm always frustrated when..."
|
16
|
-
-->
|
17
|
-
|
18
|
-
(Write your answer here.)
|
19
|
-
|
20
|
-
### Describe the solution you'd like
|
21
|
-
|
22
|
-
<!--
|
23
|
-
Provide a clear and concise description of what you want to happen.
|
24
|
-
-->
|
25
|
-
|
26
|
-
(Describe your proposed solution here.)
|
27
|
-
|
28
|
-
### Describe alternatives you've considered
|
29
|
-
|
30
|
-
<!--
|
31
|
-
Let us know about other solutions you've tried or researched.
|
32
|
-
-->
|
33
|
-
|
34
|
-
(Write your answer here.)
|
35
|
-
|
36
|
-
### Additional context
|
37
|
-
|
38
|
-
<!--
|
39
|
-
Is there anything else you can add about the proposal?
|
40
|
-
You might want to link to related issues here, if you haven't already.
|
41
|
-
-->
|
42
|
-
|
43
|
-
(Write your answer here.)
|
@@ -1,31 +0,0 @@
|
|
1
|
-
## What does this PR do?
|
2
|
-
|
3
|
-
<!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. -->
|
4
|
-
|
5
|
-
Fixes # (issue)
|
6
|
-
|
7
|
-
## Type of change
|
8
|
-
|
9
|
-
<!-- Please delete options that are not relevant. -->
|
10
|
-
|
11
|
-
- [ ] Bug fix (non-breaking change which fixes an issue)
|
12
|
-
- [ ] New feature (non-breaking change which adds functionality)
|
13
|
-
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
14
|
-
- [ ] This change requires a documentation update
|
15
|
-
|
16
|
-
## How should this be tested?
|
17
|
-
|
18
|
-
<!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration -->
|
19
|
-
|
20
|
-
- [ ] Test A
|
21
|
-
- [ ] Test B
|
22
|
-
|
23
|
-
## Checklist:
|
24
|
-
|
25
|
-
- [ ] My code follows the style guidelines of this project
|
26
|
-
- [ ] I have performed a self-review of my own code and corrected any misspellings
|
27
|
-
- [ ] I have commented my code, particularly in hard-to-understand areas
|
28
|
-
- [ ] I have made corresponding changes to the documentation
|
29
|
-
- [ ] My changes generate no new warnings
|
30
|
-
- [ ] I have added tests that prove my fix is effective or that my feature works
|
31
|
-
- [ ] New and existing unit tests pass locally with my changes
|
@@ -1,81 +0,0 @@
|
|
1
|
-
on:
|
2
|
-
push:
|
3
|
-
branches:
|
4
|
-
- main
|
5
|
-
pull_request_target:
|
6
|
-
types: [opened, synchronize, reopened]
|
7
|
-
|
8
|
-
name: CodeSee Map
|
9
|
-
|
10
|
-
jobs:
|
11
|
-
test_map_action:
|
12
|
-
runs-on: ubuntu-latest
|
13
|
-
continue-on-error: true
|
14
|
-
name: Run CodeSee Map Analysis
|
15
|
-
steps:
|
16
|
-
- name: checkout
|
17
|
-
id: checkout
|
18
|
-
uses: actions/checkout@v2
|
19
|
-
with:
|
20
|
-
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
21
|
-
ref: ${{ github.event.pull_request.head.ref }}
|
22
|
-
fetch-depth: 0
|
23
|
-
|
24
|
-
# codesee-detect-languages has an output with id languages.
|
25
|
-
- name: Detect Languages
|
26
|
-
id: detect-languages
|
27
|
-
uses: Codesee-io/codesee-detect-languages-action@latest
|
28
|
-
|
29
|
-
- name: Configure JDK 16
|
30
|
-
uses: actions/setup-java@v2
|
31
|
-
if: ${{ fromJSON(steps.detect-languages.outputs.languages).java }}
|
32
|
-
with:
|
33
|
-
java-version: '16'
|
34
|
-
distribution: 'zulu'
|
35
|
-
|
36
|
-
# CodeSee Maps Go support uses a static binary so there's no setup step required.
|
37
|
-
|
38
|
-
- name: Configure Node.js 14
|
39
|
-
uses: actions/setup-node@v2
|
40
|
-
if: ${{ fromJSON(steps.detect-languages.outputs.languages).javascript }}
|
41
|
-
with:
|
42
|
-
node-version: '14'
|
43
|
-
|
44
|
-
- name: Configure Python 3.x
|
45
|
-
uses: actions/setup-python@v2
|
46
|
-
if: ${{ fromJSON(steps.detect-languages.outputs.languages).python }}
|
47
|
-
with:
|
48
|
-
python-version: '3.x'
|
49
|
-
architecture: 'x64'
|
50
|
-
|
51
|
-
- name: Configure Ruby '3.x'
|
52
|
-
uses: ruby/setup-ruby@v1
|
53
|
-
if: ${{ fromJSON(steps.detect-languages.outputs.languages).ruby }}
|
54
|
-
with:
|
55
|
-
ruby-version: '3.0'
|
56
|
-
|
57
|
-
# CodeSee Maps Rust support uses a static binary so there's no setup step required.
|
58
|
-
|
59
|
-
- name: Generate Map
|
60
|
-
id: generate-map
|
61
|
-
uses: Codesee-io/codesee-map-action@latest
|
62
|
-
with:
|
63
|
-
step: map
|
64
|
-
github_ref: ${{ github.ref }}
|
65
|
-
languages: ${{ steps.detect-languages.outputs.languages }}
|
66
|
-
|
67
|
-
- name: Upload Map
|
68
|
-
id: upload-map
|
69
|
-
uses: Codesee-io/codesee-map-action@latest
|
70
|
-
with:
|
71
|
-
step: mapUpload
|
72
|
-
api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
|
73
|
-
github_ref: ${{ github.ref }}
|
74
|
-
|
75
|
-
- name: Insights
|
76
|
-
id: insights
|
77
|
-
uses: Codesee-io/codesee-map-action@latest
|
78
|
-
with:
|
79
|
-
step: insights
|
80
|
-
api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
|
81
|
-
github_ref: ${{ github.ref }}
|
@@ -1,123 +0,0 @@
|
|
1
|
-
# This is a basic workflow to help you get started with Actions
|
2
|
-
|
3
|
-
name: CI
|
4
|
-
|
5
|
-
# Controls when the workflow will run
|
6
|
-
on:
|
7
|
-
# Triggers the workflow on push or pull request events but only for the main branch
|
8
|
-
push:
|
9
|
-
branches:
|
10
|
-
- '*'
|
11
|
-
pull_request:
|
12
|
-
types: [opened, synchronize, reopened]
|
13
|
-
|
14
|
-
# Allows you to run this workflow manually from the Actions tab
|
15
|
-
workflow_dispatch:
|
16
|
-
|
17
|
-
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
18
|
-
jobs:
|
19
|
-
publish:
|
20
|
-
runs-on: ubuntu-latest
|
21
|
-
|
22
|
-
strategy:
|
23
|
-
matrix:
|
24
|
-
node-version: [16.x]
|
25
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
26
|
-
|
27
|
-
services:
|
28
|
-
postgres:
|
29
|
-
image: postgres:13
|
30
|
-
ports:
|
31
|
-
- 5432:5432
|
32
|
-
env:
|
33
|
-
POSTGRES_PASSWORD: ""
|
34
|
-
POSTGRES_HOST_AUTH_METHOD: "trust"
|
35
|
-
# Set health checks to wait until postgres has started
|
36
|
-
options: >-
|
37
|
-
--health-cmd pg_isready
|
38
|
-
--health-interval 10s
|
39
|
-
--health-timeout 5s
|
40
|
-
--health-retries 5
|
41
|
-
redis:
|
42
|
-
image: redis:6.2.5-alpine
|
43
|
-
ports:
|
44
|
-
- 6379:6379
|
45
|
-
mongo:
|
46
|
-
image: mongo:4.4.10
|
47
|
-
ports:
|
48
|
-
- 27017:27017
|
49
|
-
mysql:
|
50
|
-
image: mysql:5.7
|
51
|
-
ports:
|
52
|
-
- 3307:3306
|
53
|
-
env:
|
54
|
-
MYSQL_DATABASE: mysql
|
55
|
-
MYSQL_ROOT_PASSWORD: mysql
|
56
|
-
maria:
|
57
|
-
image: mariadb:10.4.22
|
58
|
-
ports:
|
59
|
-
- 3306:3306
|
60
|
-
env:
|
61
|
-
MARIADB_DATABASE: mysql
|
62
|
-
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: "yes"
|
63
|
-
|
64
|
-
steps:
|
65
|
-
- uses: actions/checkout@v2
|
66
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
67
|
-
uses: actions/setup-node@v2
|
68
|
-
with:
|
69
|
-
always-auth: true
|
70
|
-
node-version: ${{ matrix.node-version }}
|
71
|
-
registry-url: https://registry.npmjs.org
|
72
|
-
scope: '@boxyhq'
|
73
|
-
cache: 'npm'
|
74
|
-
- run: npm ci
|
75
|
-
- run: npm run test
|
76
|
-
- run: |
|
77
|
-
publishTag="latest"
|
78
|
-
if [[ "$GITHUB_REF" == *\/release ]]
|
79
|
-
then
|
80
|
-
echo "Release branch"
|
81
|
-
else
|
82
|
-
echo "Dev branch"
|
83
|
-
publishTag="beta"
|
84
|
-
versionSuffixTag="-beta.${GITHUB_RUN_NUMBER}"
|
85
|
-
sed "s/\(^[ ]*\"version\"\:[ ]*\".*\)\",/\1${versionSuffixTag}\",/" < package.json > package.json.new
|
86
|
-
mv package.json.new package.json
|
87
|
-
fi
|
88
|
-
npm publish --tag $publishTag --access public
|
89
|
-
env:
|
90
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
91
|
-
build:
|
92
|
-
needs: publish
|
93
|
-
runs-on: ubuntu-latest
|
94
|
-
|
95
|
-
steps:
|
96
|
-
- name: Check Out Repo
|
97
|
-
uses: actions/checkout@v2
|
98
|
-
|
99
|
-
- name: Get short SHA
|
100
|
-
id: slug
|
101
|
-
run: echo "::set-output name=sha7::$(echo ${GITHUB_SHA} | cut -c1-7)"
|
102
|
-
|
103
|
-
- name: Set up Docker Buildx
|
104
|
-
id: buildx
|
105
|
-
uses: docker/setup-buildx-action@v1
|
106
|
-
|
107
|
-
- name: Login to Docker Hub
|
108
|
-
uses: docker/login-action@v1
|
109
|
-
with:
|
110
|
-
username: ${{ secrets.DOCKER_HUB_USERNAME }}
|
111
|
-
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
112
|
-
|
113
|
-
- name: Build and push
|
114
|
-
id: docker_build
|
115
|
-
uses: docker/build-push-action@v2
|
116
|
-
with:
|
117
|
-
context: ./
|
118
|
-
file: ./Dockerfile
|
119
|
-
push: true
|
120
|
-
tags: ${{ github.repository }}:latest,${{ github.repository }}:${{ steps.slug.outputs.sha7 }}
|
121
|
-
|
122
|
-
- name: Image digest
|
123
|
-
run: echo ${{ steps.docker_build.outputs.digest }}
|
package/_dev/docker-compose.yml
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
# this file is a helper to run all the supported dbs locally, the data is ephemeral since no host volumes will be mounted
|
2
|
-
version: "3.6"
|
3
|
-
services:
|
4
|
-
postgres:
|
5
|
-
image: postgres:13
|
6
|
-
ports:
|
7
|
-
- "5432:5432"
|
8
|
-
restart: always
|
9
|
-
environment:
|
10
|
-
POSTGRES_PASSWORD: ""
|
11
|
-
POSTGRES_HOST_AUTH_METHOD: trust
|
12
|
-
redis:
|
13
|
-
image: redis:6.2.5-alpine
|
14
|
-
ports:
|
15
|
-
- "6379:6379"
|
16
|
-
restart: always
|
17
|
-
mongo:
|
18
|
-
image: mongo:4.4.10
|
19
|
-
ports:
|
20
|
-
- "27017:27017"
|
21
|
-
restart: always
|
22
|
-
mysql:
|
23
|
-
image: mysql:5.7
|
24
|
-
ports:
|
25
|
-
- "3307:3306"
|
26
|
-
restart: always
|
27
|
-
environment:
|
28
|
-
MYSQL_DATABASE: mysql
|
29
|
-
MYSQL_ROOT_PASSWORD: mysql
|
30
|
-
maria:
|
31
|
-
image: mariadb:10.4.22
|
32
|
-
ports:
|
33
|
-
- "3306:3306"
|
34
|
-
restart: always
|
35
|
-
environment:
|
36
|
-
MARIADB_DATABASE: mysql
|
37
|
-
MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: "yes"
|
package/map.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
module.exports = (test) => test.replace(/\.test\.js$/, '.js');
|
package/prettier.config.js
DELETED
package/src/controller/api.ts
DELETED
@@ -1,225 +0,0 @@
|
|
1
|
-
import crypto from 'crypto';
|
2
|
-
import { IdPConfig, ISAMLConfig, OAuth, Storable } from 'saml-jackson';
|
3
|
-
import * as dbutils from '../db/utils';
|
4
|
-
import saml from '../saml/saml';
|
5
|
-
import { JacksonError } from './error';
|
6
|
-
import { IndexNames } from './utils';
|
7
|
-
import x509 from '../saml/x509';
|
8
|
-
|
9
|
-
export class SAMLConfig implements ISAMLConfig {
|
10
|
-
private configStore: Storable;
|
11
|
-
|
12
|
-
constructor({ configStore }) {
|
13
|
-
this.configStore = configStore;
|
14
|
-
}
|
15
|
-
|
16
|
-
private _validateIdPConfig(body: IdPConfig): void {
|
17
|
-
const { rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product } =
|
18
|
-
body;
|
19
|
-
|
20
|
-
if (!rawMetadata) {
|
21
|
-
throw new JacksonError('Please provide rawMetadata', 400);
|
22
|
-
}
|
23
|
-
|
24
|
-
if (!defaultRedirectUrl) {
|
25
|
-
throw new JacksonError('Please provide a defaultRedirectUrl', 400);
|
26
|
-
}
|
27
|
-
|
28
|
-
if (!redirectUrl) {
|
29
|
-
throw new JacksonError('Please provide redirectUrl', 400);
|
30
|
-
}
|
31
|
-
|
32
|
-
if (!tenant) {
|
33
|
-
throw new JacksonError('Please provide tenant', 400);
|
34
|
-
}
|
35
|
-
|
36
|
-
if (!product) {
|
37
|
-
throw new JacksonError('Please provide product', 400);
|
38
|
-
}
|
39
|
-
}
|
40
|
-
|
41
|
-
public async create(body: IdPConfig): Promise<OAuth> {
|
42
|
-
const { rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product } =
|
43
|
-
body;
|
44
|
-
|
45
|
-
this._validateIdPConfig(body);
|
46
|
-
|
47
|
-
const idpMetadata = await saml.parseMetadataAsync(rawMetadata);
|
48
|
-
|
49
|
-
// extract provider
|
50
|
-
let providerName = extractHostName(idpMetadata.entityID);
|
51
|
-
if (!providerName) {
|
52
|
-
providerName = extractHostName(
|
53
|
-
idpMetadata.sso.redirectUrl || idpMetadata.sso.postUrl
|
54
|
-
);
|
55
|
-
}
|
56
|
-
|
57
|
-
idpMetadata.provider = providerName ? providerName : 'Unknown';
|
58
|
-
|
59
|
-
const clientID = dbutils.keyDigest(
|
60
|
-
dbutils.keyFromParts(tenant, product, idpMetadata.entityID)
|
61
|
-
);
|
62
|
-
|
63
|
-
let clientSecret;
|
64
|
-
|
65
|
-
const exists = await this.configStore.get(clientID);
|
66
|
-
|
67
|
-
if (exists) {
|
68
|
-
clientSecret = exists.clientSecret;
|
69
|
-
} else {
|
70
|
-
clientSecret = crypto.randomBytes(24).toString('hex');
|
71
|
-
}
|
72
|
-
|
73
|
-
const certs = await x509.generate();
|
74
|
-
|
75
|
-
if (!certs) {
|
76
|
-
throw new Error('Error generating x59 certs');
|
77
|
-
}
|
78
|
-
|
79
|
-
await this.configStore.put(
|
80
|
-
clientID,
|
81
|
-
{
|
82
|
-
idpMetadata,
|
83
|
-
defaultRedirectUrl,
|
84
|
-
redirectUrl: JSON.parse(redirectUrl), // redirectUrl is a stringified array
|
85
|
-
tenant,
|
86
|
-
product,
|
87
|
-
clientID,
|
88
|
-
clientSecret,
|
89
|
-
certs,
|
90
|
-
},
|
91
|
-
{
|
92
|
-
// secondary index on entityID
|
93
|
-
name: IndexNames.EntityID,
|
94
|
-
value: idpMetadata.entityID,
|
95
|
-
},
|
96
|
-
{
|
97
|
-
// secondary index on tenant + product
|
98
|
-
name: IndexNames.TenantProduct,
|
99
|
-
value: dbutils.keyFromParts(tenant, product),
|
100
|
-
}
|
101
|
-
);
|
102
|
-
|
103
|
-
return {
|
104
|
-
client_id: clientID,
|
105
|
-
client_secret: clientSecret,
|
106
|
-
provider: idpMetadata.provider,
|
107
|
-
};
|
108
|
-
}
|
109
|
-
|
110
|
-
public async get(body: {
|
111
|
-
clientID: string;
|
112
|
-
tenant: string;
|
113
|
-
product: string;
|
114
|
-
}): Promise<Partial<OAuth>> {
|
115
|
-
const { clientID, tenant, product } = body;
|
116
|
-
|
117
|
-
if (clientID) {
|
118
|
-
const samlConfig = await this.configStore.get(clientID);
|
119
|
-
|
120
|
-
return samlConfig ? { provider: samlConfig.idpMetadata.provider } : {};
|
121
|
-
}
|
122
|
-
|
123
|
-
if (tenant && product) {
|
124
|
-
const samlConfigs = await this.configStore.getByIndex({
|
125
|
-
name: IndexNames.TenantProduct,
|
126
|
-
value: dbutils.keyFromParts(tenant, product),
|
127
|
-
});
|
128
|
-
|
129
|
-
if (!samlConfigs || !samlConfigs.length) {
|
130
|
-
return {};
|
131
|
-
}
|
132
|
-
|
133
|
-
return { provider: samlConfigs[0].idpMetadata.provider };
|
134
|
-
}
|
135
|
-
|
136
|
-
throw new JacksonError(
|
137
|
-
'Please provide `clientID` or `tenant` and `product`.',
|
138
|
-
400
|
139
|
-
);
|
140
|
-
}
|
141
|
-
|
142
|
-
public async delete(body: {
|
143
|
-
clientID: string;
|
144
|
-
clientSecret: string;
|
145
|
-
tenant: string;
|
146
|
-
product: string;
|
147
|
-
}): Promise<void> {
|
148
|
-
const { clientID, clientSecret, tenant, product } = body;
|
149
|
-
|
150
|
-
if (clientID && clientSecret) {
|
151
|
-
const samlConfig = await this.configStore.get(clientID);
|
152
|
-
|
153
|
-
if (!samlConfig) {
|
154
|
-
return;
|
155
|
-
}
|
156
|
-
|
157
|
-
if (samlConfig.clientSecret === clientSecret) {
|
158
|
-
await this.configStore.delete(clientID);
|
159
|
-
} else {
|
160
|
-
throw new JacksonError('clientSecret mismatch.', 400);
|
161
|
-
}
|
162
|
-
|
163
|
-
return;
|
164
|
-
}
|
165
|
-
|
166
|
-
if (tenant && product) {
|
167
|
-
const samlConfigs = await this.configStore.getByIndex({
|
168
|
-
name: IndexNames.TenantProduct,
|
169
|
-
value: dbutils.keyFromParts(tenant, product),
|
170
|
-
});
|
171
|
-
|
172
|
-
if (!samlConfigs || !samlConfigs.length) {
|
173
|
-
return;
|
174
|
-
}
|
175
|
-
|
176
|
-
for (const conf of samlConfigs) {
|
177
|
-
await this.configStore.delete(conf.clientID);
|
178
|
-
}
|
179
|
-
|
180
|
-
return;
|
181
|
-
}
|
182
|
-
|
183
|
-
throw new JacksonError(
|
184
|
-
'Please provide `clientID` and `clientSecret` or `tenant` and `product`.',
|
185
|
-
400
|
186
|
-
);
|
187
|
-
}
|
188
|
-
|
189
|
-
// Ensure backward compatibility
|
190
|
-
|
191
|
-
async config(body: IdPConfig): Promise<OAuth> {
|
192
|
-
return this.create(body);
|
193
|
-
}
|
194
|
-
|
195
|
-
async getConfig(body: {
|
196
|
-
clientID: string;
|
197
|
-
tenant: string;
|
198
|
-
product: string;
|
199
|
-
}): Promise<Partial<OAuth>> {
|
200
|
-
return this.get(body);
|
201
|
-
}
|
202
|
-
|
203
|
-
async deleteConfig(body: {
|
204
|
-
clientID: string;
|
205
|
-
clientSecret: string;
|
206
|
-
tenant: string;
|
207
|
-
product: string;
|
208
|
-
}): Promise<void> {
|
209
|
-
return this.delete(body);
|
210
|
-
}
|
211
|
-
}
|
212
|
-
|
213
|
-
const extractHostName = (url: string): string | null => {
|
214
|
-
try {
|
215
|
-
const pUrl = new URL(url);
|
216
|
-
|
217
|
-
if (pUrl.hostname.startsWith('www.')) {
|
218
|
-
return pUrl.hostname.substring(4);
|
219
|
-
}
|
220
|
-
|
221
|
-
return pUrl.hostname;
|
222
|
-
} catch (err) {
|
223
|
-
return null;
|
224
|
-
}
|
225
|
-
};
|