├── .dockerignore
├── .env-gdc
├── .gitattributes
├── .gitignore
├── Dockerfile
├── LICENSE.txt
├── SECURITY.md
├── auth0_mock
├── .dockerignore
├── .gitignore
├── Dockerfile
├── README.md
├── ext_pk
│ ├── auth0_jwk.json
│ ├── auth0_jwks.json
│ └── auth0_rsa
├── index.ts
├── jest.config.ts
├── modules
│ ├── authentication.ts
│ ├── helpers.ts
│ ├── jwk-wrapper.ts
│ ├── middleware.ts
│ └── user.ts
├── package.json
├── public
│ └── images
│ │ ├── img.svg
│ │ └── ufo-2.svg
├── routes
│ ├── api.ts
│ ├── authentication.ts
│ └── index.ts
├── templates
│ └── login_page.ejs
├── tests
│ ├── integration
│ │ ├── api_route.test.ts
│ │ ├── authentication_route.test.ts
│ │ └── index_route.test.ts
│ ├── unit
│ │ ├── access_token_claims.test.ts
│ │ ├── authentication.test.ts
│ │ ├── default_token_claims.test.ts
│ │ ├── helpers.test.ts
│ │ ├── id_token_claims.test.ts
│ │ ├── jwk_wrapper.test.ts
│ │ ├── middleware.test.ts
│ │ └── user.test.ts
│ └── utils.ts
├── token-claims
│ ├── access.ts
│ ├── id.ts
│ └── token_defaults.ts
├── tsconfig.json
├── tslint.json
├── types.ts
└── users.json
├── dc-auth0-host.yml
├── dc-auth0-local-users.yml
├── dc-auth0.yml
├── dc-dns.yml
├── dc-host-custom-mount.yml
├── dc-host-home-dir-rw.yml
├── dc-host-home-dir.yml
├── dc-host-workspace-dir.yml
├── dc-ls-host-dns.yml
├── dc-ls-host.yml
├── dc-ls-persist.yml
├── dc-ls-pro.yml
├── dc-ls-shared.yml
├── dc-ls-static-ip.yml
├── dc-ls.yml
├── dc-proxy-dump.yml
├── dc-proxy-host.yml
├── dc-proxy-web-host.yml
├── dc-proxy-web.yml
├── dc-proxy.yml
├── dc-ssh-agent.yml
├── dc-ssh.yml
├── docker-compose.yml
├── docker-config.json
├── docs
├── auth0
│ └── readme.md
├── aws_ident
│ ├── images
│ │ ├── access_keys.png
│ │ ├── add_mfa.png
│ │ ├── change_pw.png
│ │ ├── close_button.png
│ │ ├── login.png
│ │ ├── manage_mfa.png
│ │ ├── mfa_account_name.png
│ │ ├── mfa_app_screen.png
│ │ ├── mfa_codes.png
│ │ ├── my_sec_creds.png
│ │ ├── new_access_key.png
│ │ ├── select_iam.png
│ │ └── show_qr.png
│ └── readme.md
├── aws_sso
│ ├── images
│ │ ├── aws_login.png
│ │ ├── aws_mfa_done.png
│ │ ├── aws_mfa_name.png
│ │ ├── aws_mfa_qr.png
│ │ ├── aws_new_mfa.png
│ │ ├── aws_new_user.png
│ │ ├── invite-email-body.png
│ │ └── invite-email-subject.png
│ └── readme.md
├── bitwarden
│ ├── images
│ │ └── pop-out.png
│ └── readme.md
├── container_dev
│ └── images
│ │ ├── GenericDevContainer.png
│ │ ├── compose_v2.png
│ │ ├── ddesktop-container.png
│ │ ├── ddesktop-memory.png
│ │ └── ddesktop-wsl2.png
├── contributing.md
├── cypress
│ ├── images
│ │ ├── cypress-error-1.png
│ │ └── xquartz-settings.png
│ └── readme.md
└── debugging
│ └── readme.md
├── etc
├── bash_completion.d
│ └── gdcex.sh
├── dpkg
│ └── dpkg.conf.d
│ │ └── 01_nodoc
├── locale.gen
├── profile.d
│ └── 02-locale-set.sh
├── skel
│ ├── .bashrc
│ └── .terraformrc
├── ssh
│ ├── ssh_config
│ └── sshd_config
└── term_colors.sh
├── init.sh
├── k8s
├── .dockerignore
├── .env-gdc
├── Dockerfile
├── awsls
│ ├── config.template
│ └── credentials
├── build-pod-image.sh
├── dev-deployment.yaml
├── docker-compose.yml
├── docker-config.json
├── etc
│ ├── bash_completion.d
│ │ └── gdcex.sh
│ ├── dpkg
│ │ └── dpkg.conf.d
│ │ │ └── 01_nodoc
│ ├── locale.gen
│ ├── profile.d
│ │ └── 02-locale-set.sh
│ ├── skel
│ │ └── .bashrc
│ ├── ssh
│ │ ├── ssh_config
│ │ └── sshd_config
│ └── term_colors.sh
├── init.sh
├── postStartCommand.sh
└── root
│ └── bin
│ ├── aws
│ ├── assume-role.sh
│ ├── aws-remote.py
│ ├── aws_assume_remaining.sh
│ ├── check-ecs-exec.sh
│ ├── export-aws-session.sh
│ ├── setup-aws.sh
│ ├── ssm-jump-tunnel-old.sh
│ ├── ssm-jump-tunnel.sh
│ ├── ssm-scp.sh
│ ├── ssm-send-command.sh
│ └── ssm-ssh.sh
│ ├── remote-client.sh
│ └── requirements.txt
├── noop
├── postStartCommand.sh
├── readme.md
├── root
└── bin
│ ├── auth0
│ ├── get-auth-token.sh
│ ├── start-auth0.sh
│ └── stop-auth0.sh
│ ├── aws
│ ├── assume-role.sh
│ ├── aws-remote.py
│ ├── aws_assume_remaining.sh
│ ├── check-ecs-exec.sh
│ ├── export-aws-session.sh
│ ├── setup-aws.sh
│ ├── ssm-jump-tunnel-old.sh
│ ├── ssm-jump-tunnel.sh
│ ├── ssm-scp.sh
│ ├── ssm-send-command.sh
│ └── ssm-ssh.sh
│ ├── check-gdc-update.sh
│ ├── docker
│ ├── docker-logs.sh
│ ├── docker-shell.sh
│ ├── docker-stats.sh
│ └── docker-stop.sh
│ ├── gdc-pipeline-exec.sh
│ ├── gdcex.sh
│ ├── ls
│ ├── start-ls.sh
│ └── stop-ls.sh
│ ├── remote-client.sh
│ ├── requirements.txt
│ └── run-gdc.sh
└── run-dev-container.sh
/.dockerignore:
--------------------------------------------------------------------------------
1 | docker-compose.yml
2 | **/temp
3 | test
4 | **/*.ps1
5 | **/.idea
6 | **/.vscode
7 | data
8 | attachments
9 | **/venv*
10 | **/vendor
11 | **/node_modules
12 | **/__pycache__
13 | **/*.zip
14 | **/test_data
15 | **/.cache
16 | **/.pulumi
17 | docs
18 | .run
19 | DEADJOE
20 |
--------------------------------------------------------------------------------
/.env-gdc:
--------------------------------------------------------------------------------
1 | export ROOT_PW=${ROOT_PW:=ContainersRule} # sets root password in container
2 |
3 | export USE_WORKSPACE=${USE_WORKSPACE:=yes}
4 |
5 | export USE_AWS_HOME=${USE_AWS_HOME:=yes} # copy .aws folder from host home if exists and enables USE_HOST_HOME=yes
6 | export USE_HOME_BIN=${USE_HOME_BIN:=no} # copy bin folder from host home directory if it exists and enables USE_HOST_HOME=yes
7 |
8 | if [ -z ${SHOW_VERSIONS_ON_LOGIN+x} ]; then
9 | export SHOW_VERSIONS_ON_LOGIN=yes # show installed versions on each login
10 | fi
11 |
12 | if [ -z ${TERRAFORM_VERSION+x} ]; then
13 | # export TERRAFORM_VERSION=latest # install this version of terraform by default
14 | export TERRAFORM_VERSION=''
15 | fi
16 | if [ -z ${PULUMI_VERSION+x} ]; then
17 | # export PULUMI_VERSION=latest # install this version of pulumi by default
18 | export PULUMI_VERSION='' # dont install pulumi by default
19 | fi
20 | if [ -z ${PHP_VERSION+x} ]; then
21 | export PHP_VERSION='' # available PHP versions 5.6, 7.0, 7.1, 7.2, 7.3, 7.4, 8.0, 8.1, 8.2
22 | fi
23 |
24 | export USE_BITWARDEN=${USE_BITWARDEN:=yes} # enable bitwarden workflow helpers. requires node install
25 | export PERSIST_BITWARDEN_SESSION=${PERSIST_BITWARDEN_SESSION:=no} # persist unlocked vault creds between container sessions
26 |
27 |
28 | export RUST_VERSION
29 | export CARGO_EXTRA
30 | #if [ -z ${CARGO_EXTRA+x} ]; then
31 | # export CARGO_EXTRA="cargo-edit cargo-outdated cargo-audit cargo-info bacon" # extra cargo packages to install
32 | #fi
33 | export LS_VERSION # starts requested localstack container version
34 | export USE_LOCALSTACK=${USE_LOCALSTACK:=yes} # does not install or start localstack. Only sets up some helpers
35 | export USE_LOCALSTACK_PRO=${USE_LOCALSTACK_PRO:=yes} # does not install or start localstack. Only sets up pro version api key / tokens
36 | export USE_LOCALSTACK_PERSISTENCE=${USE_LOCALSTACK_PERSISTENCE:=no} # toggle persistent storage for LS defaults to persistence disabled.
37 | export USE_LOCALSTACK_HOST=${USE_LOCALSTACK_HOST:=yes} # does not install or start localstack. Only sets up some helpers and port forwards
38 | if [ -z ${LOCALSTACK_HOST_DNS_PORT+x} ]; then
39 | LOCALSTACK_HOST_DNS_PORT=53 # forward this port from host to localstack for DNS
40 | fi
41 | export USE_LOCALSTACK_SHARED=${USE_LOCALSTACK_SHARED:=no} # mount shared volume in LS container under /shared
42 | export LOCALSTACK_HOST_DNS_PORT
43 | export LOCALSTACK_GATEWAY_LISTEN
44 | export USE_LOCALSTACK_DNS=${USE_LOCALSTACK_DNS:=no} # set to yes to assign static ip to LS container and use it as primary DNS
45 | export LS_DNS_NAME_PATTERNS_TO_RESOLVE_UPSTREAM=${LS_DNS_NAME_PATTERNS_TO_RESOLVE_UPSTREAM:=""} # comma separated list of patterns to resolve upstream
46 | export LS_LOG
47 | export USE_AUTH0 # starts up auth0 mock container in container only mode
48 | export USE_AUTH0_HOST # starts up auth0 mock container and forwards port from host. Use AUTH0_HOST_PORT to change default of 3001
49 | export AUTH0_HOST_PORT=${AUTH0_HOST_PORT:=3001} # default port for AUTH0 mock if enabled
50 | export AUTH0_LOCAL_USERS_FILE # used to specify location in container for auth0 to mount user override file
51 | export AUTH0_DEFAULT_USER=${AUTH0_DEFAULT_USER:="user1"} # used to auto-populate auth0 mock login page
52 | export AUTH0_DEFAULT_PASSWORD=${AUTH0_DEFAULT_USER:="user1"} # used to auto-populate auth0 mock login page
53 |
54 | export USE_JAVA # install ubuntu:latest openjdk packages
55 | export USE_DOT_NET # install ubuntu:latest dotnet core packages
56 | export USE_AZURE # install latest Azure cli
57 | export USE_POWERSHELL # install powershell 7.5.0
58 |
59 | export EDITOR=${EDITOR:=vi} # sets default editor in container. usually set to same as VISUAL
60 | export VISUAL=${VISUAL:=vi} # sets default editor in container. usually set to same as EDITOR
61 | if [ -z ${SSH_KEYSCAN_HOSTS+x} ]; then
62 | export SSH_KEYSCAN_HOSTS="gitlab.com github.com bitbucket.org" # copy ssh keys from these hosts to prevent unknown key prompts
63 | fi
64 |
65 | # default secondary dns to google secondary dns if not specified
66 | if [ -z "$GDC_DNS_SEC_IP" ]; then
67 | GDC_DNS_SEC_IP=8.8.4.4
68 | fi
69 |
70 | # these will only be used by the container if GDC_DNS_PRI_IP is defined
71 | export GDC_DNS_PRI_IP
72 | export GDC_DNS_SEC_IP
73 |
74 | export DEVNET_GATEWAY
75 |
76 | export USE_COLOR_PROMPT=${USE_COLOR_PROMPT:=yes} # enable colored bash prompt
77 |
78 | export CHECK_UPDATES=${CHECK_UPDATES:=yes} # check for updates on each login
79 | export SHARED_VOLUMES # specify volume names to create and share across all GDC's
80 | export GDC_RUN_MODE=${GDC_RUN_MODE:="start"} # options are start, stop, daemon
81 |
82 | export DEV_CONTAINER_NAME=${DEV_CONTAINER_NAME:="dev-1"} # dev container name
83 |
84 | export COPY_CMD_TO_CLIPBOARD=${COPY_CMD_TO_CLIPBOARD:=yes} # COPY GDC shell launch command to clipboard
85 |
86 | export USE_PROXY=${USE_PROXY:=no} # no, proxy, dump, web
87 | export USE_PROXY_CA=${USE_PROXY_CA:=yes} # if yes and USE_PROXY!=no then install proxy CA cert into GDC
88 | export PROXY_VERSION=${PROXY_VERSION:=latest} # container image version tag
89 | export PROXY_CONTAINER_NAME=${PROXY_CONTAINER_NAME:=proxy} # name of the container
90 | export PROXY_AUTO_EXPORT_ENV=${PROXY_AUTO_EXPORT_ENV:=no} # auto export HTTP_PROXY and HTTPS_PROXY
91 | export USE_PROXY_HOST=${USE_PROXY_HOST:=no} # no, yes
92 | export PROXY_HOST_PORT=${PROXY_HOST_PORT:=8080} # port to expose to host
93 | export PROXY_WEB_HOST_PORT=${PROXY_WEB_HOST_PORT:=8081} # if running in web mode expose this port
94 |
95 | # if not set default $HOME/.aws symlink to false
96 | if [ -z ${USE_AWS_SYMLINK+x} ]; then
97 | export USE_AWS_SYMLINK=no
98 | fi
99 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Autodetect text files
2 | * text=auto
3 |
4 | # ...Unless the name matches the following
5 | # overriding patterns
6 |
7 | # Definitively text files
8 | *.txt text
9 | *.json text
10 | *.js text
11 | *.ts text
12 | .env text
13 | *.sh text
14 | *.sql text
15 | *.yml text
16 | *.py text
17 | *.js text
18 | *.ts text
19 | *.ini text
20 | Dockerfile text
21 |
22 | # Ensure those won't be messed up with
23 | *.jpg binary
24 | *.gif binary
25 | *.png binary
26 |
27 | # force line endings to be lf so db container does not blow up
28 | **/*.sh text eol=lf
29 | **/*.sql text eol=lf
30 | **/.env text eol=lf
31 | **/.env* text eol=lf
32 | **/Dockerfile text eol=lf
33 | **/*.py text eol=lf
34 | **/*.js text eol=lf
35 | **/*.ts text eol=lf
36 | **/*.json text eol=lf
37 | **/*.yml text eol=lf
38 | **/Makefile text eol=lf
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | **/dist/
2 | **/node_modules/
3 | **/.idea/
4 | **/.vscode
5 | **/venv/
6 | **/.parcel-cache/
7 | **/__pycache__/
8 | **/*.js.map
9 | **/tmp
10 | **/temp
11 | *.env
12 | **/DEADJOE
13 |
14 | .DS_Store
15 | /.env-gdc-local
16 | k8s/.env-gdc-local
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) [2022] [Paul Robello]
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | ## Supported Versions
4 |
5 | | Version | Supported |
6 | | ------- | ------------------ |
7 | | 1.x.x | :white_check_mark: |
8 | | < 1.0 | :x: |
9 |
10 | ## Reporting a Vulnerability
11 |
12 | Please report any issue security or otherwise in the Issues
13 |
--------------------------------------------------------------------------------
/auth0_mock/.dockerignore:
--------------------------------------------------------------------------------
1 | docker-compose.yml
2 | **/temp
3 | **/tmp
4 | test
5 | **/*.ps1
6 | **/.idea
7 | **/.vscode
8 | data
9 | attachments
10 | **/venv*
11 | **/vendor
12 | **/node_modules
13 | **/__pycache__
14 | **/*.zip
15 | **/test_data
16 | **/.cache
17 | **/.pulumi
18 | docs
19 | .run
20 | DEADJOE
21 |
--------------------------------------------------------------------------------
/auth0_mock/.gitignore:
--------------------------------------------------------------------------------
1 | coverage/*
2 | keys.json
3 | *.log
4 | *.lock
5 | /package-lock.json
6 |
--------------------------------------------------------------------------------
/auth0_mock/Dockerfile:
--------------------------------------------------------------------------------
1 | #FROM node:current-alpine
2 | FROM node:18-alpine
3 |
4 | RUN mkdir /usr/local/app
5 | WORKDIR /usr/local/app
6 |
7 | COPY . ./
8 |
--------------------------------------------------------------------------------
/auth0_mock/README.md:
--------------------------------------------------------------------------------
1 | # auth0-mock
2 |
3 | > running auth0 locally in docker form. Build contained within docker compose yml
4 |
5 | ## Getting Started
6 |
7 | ### Prerequisites
8 |
9 | * Docker / Docker Compose
10 | * Node
11 | * yarn
12 | * mkcert -> discussed further in [Self Signed SSL Cert section](./certs/README.md)
13 |
14 | ## ENV Config opts (set in docker compose)
15 | * **APP_PORT** - port that auth0 mock is running on | defaults to 3001
16 | * **AUTH0_HOST** - host that auth0 mock is running on | defaults to localhost:APP_PORT
17 | * **FRONTEND_PORT** - port that frontend is running on | defaults to 3030
18 | * **FRONTEND_PROTOCOL** - protocol that frontend uses | defaults to http
19 | * **FRONTEND_DOMAIN** - domain that frontend is running on | defaults to localhost:FRONTEND_PORT
20 |
21 | ## Running the app
22 |
23 | * cd into directory with docker compose yml (`fos-data-portal/auto_tests`)
24 | * run `docker compose up`
25 | * startup script is contained within `auth0_mock/package.json -> 'start' script`
26 | * [Setup self signed cert](./certs/README.md)
27 |
28 | ## API Documentation
29 |
30 | ### ROUTES
31 |
32 | #### `GET` /
33 |
34 | returns list of routes and what they do
35 |
36 | #### `GET` /authorize
37 | *official auth0 service uses this route (most frontend frameworks will use it too)*
38 |
39 | renders a login page which makes a POST request to login route
40 |
41 | #### `GET` /login
42 | *required params - username & pw*
43 |
44 | logs a user in. [Users information can be found here](./users.json)
45 |
46 | #### `POST` /login
47 | *official auth0 service uses this route (most frontend frameworks will use it too)*
48 | *required params - username & pw & redirect & state*
49 |
50 | logs a user in. [Users information can be found here](./users.json)
51 |
52 | #### `GET` /logout
53 |
54 | logout user
55 |
56 | #### `GET` /v2/logout
57 | *official auth0 service uses this route (most frontend frameworks will use it too)*
58 |
59 | logout user
60 |
61 | #### `GET` /.well-known/jwks.json
62 | *official auth0 service uses this route (most frontend frameworks will use it too)*
63 | *user must be logged in to access*
64 |
65 | Returns JWKeySet
66 |
67 | #### `GET` /access_token
68 | *user must be logged in to access*
69 |
70 | Returns access_token for user. [access_token props can be found here](./token-claims/access.ts)
71 |
72 | #### `GET` /id_token
73 | *user must be logged in to access*
74 |
75 | returns id_token for user. [id_token props can be found here](./token-claims/id.ts)
76 |
77 | #### `POST` /oauth/token
78 | *user must be logged in to access*
79 | *official auth0 service uses this route (most frontend frameworks will use it too)*
80 | *required body params - client_id*
81 |
82 | returns JSON containing access token, id token, expires_in value, scope, and token type
83 |
84 | #### `GET` /verify_token_test
85 | *user must be logged in to access*
86 |
87 | verifies token for debug purposes - outputs to container logs
88 |
89 | #### `GET` /userinfo
90 | *user must be logged in to access*
91 | *official auth0 service uses this route (most frontend frameworks will use it too)*
92 |
93 | returns [id claims](./token-claims/id.ts)
94 |
95 | ### Modify user and/or properties
96 |
97 | To modify a user go into [user.json](./users.json). From here you can add/remove users and properties.
98 |
99 | *User json key must be same as username*
100 |
101 | *Every user must have a username and a pw*
102 |
103 | *If you are adding users & wish to use refresh tokens make sure to add offline_access to scope property*
104 |
105 | ### Modify token claims
106 |
107 | Claims may be modified from within the *Token_Claims* directory. Claim values can be static or pulled from user file (
108 | user.json) or [token defaults file](./token-claims/token_defaults.ts)
109 |
110 | ### Self Signed SSL Cert
111 | [instructions contained here!](./certs/README.md)
112 |
--------------------------------------------------------------------------------
/auth0_mock/ext_pk/auth0_jwk.json:
--------------------------------------------------------------------------------
1 | {
2 | "alg": "RS256",
3 | "kty": "RSA",
4 | "n": "wHkz_b53rjnY9n9-LGN8czUt2L0mOYTWu_799I8nYg9_TfRBNYv6-u4kt15AhgBn10vnlpMuuzrB7vt_NGFjOdpY4BvBBhrfvJZkLguEmaBGNqruQPy6vIiLXeSzEBezVRc5NrxIiV9KWfhASILKzfSxC-r6DUqbqfj-GMkKT2egSQaRoGiqDBG2JOelVCKubncwec7se3AOnaRnKrrdve1PLwQmEzkGpPorcKCCQVlsJX016u4XDXkqCaSpKv5pyBi-H4x0RZa-SoydBzDjXrrqkh9Kv8w0vyejPnykS31GI9h7vUS-akYCYRUwVFa2N387Pi1zrocyjGuVE138Zw",
5 | "e": "AQAB",
6 | "d": "NAgQh9yHWBUnxpd5huX1_51G9h5kccT6gDdyXpIIjfzcFSbd2r9ptqRx58Rb5WDYYLTK6h0uJ86-OiFSNbgxqOZ1QBQXAv7zq3SuGGFEbGWt7urXAMHV27JFFG7yU99o2x1sFYI45Q7McGnPgphw3Hru8QQGo7OAQX3ZjcACgsZayoRCgRA-cRGP6xiBIvUyT-75qT6g36BEu5bP4pRqAItUOoS8CL6IA5k39oNTsL-yR5Pn37IR42WxYUE7mtPblMypETSB1uiF7wL3-rmzT3KHb_kaz9gbZEyBc12W0T32ri5rNFNIQv2todcpIJGdlhObtp-IuyMYWdGGqZAB",
7 | "p": "231MkG5VF2Hi24wF2ZpBPnfhzRsiWZpz4OswAqcygG6Z5rdPdAethEvUz-Rk6VqbLrYxvSXkVS8by0iOxd628zwY3BosEgc7_ym1KIkstirWx4SnuAMvSD33QF7hyZVJury18zkud1xVQUNXn21HzK1OUSQ9Dv4UYrtDQuNSb7E",
8 | "q": "4H11liCmk1zVEdlZ3DZG5T9b8_wFIY6FjAQLGlpHL-ac2w9ijH8Q4vD7-9MsK8t9UoP2Sl-lQfTm_YIBLcgpc4MyYx2yaxZkjjVk94RH38vSgD1qPYhA2imrhs8XCyHjRnNpuVZBQY49VJ3SWZssjdDaFryWXOItlDBlxIPpi5c",
9 | "dp": "Lsv_SAgOImcfbDnlgWivIneC8C0p3LrenATo_pfRX6q1K4jH6vA8IandXNnQXiSQU5xK7I4oqbTakzQMJMoAbcnRbxQxc0KRmyy0UEk2_DwUAQQaklQzf46eqd3Q_B7VUngrvwjhDFfmYXzPMNGm7k_BE_HLBuhLRmWwyJEZIXE",
10 | "dq": "qMJHyiMjdjZcSr29SslWxHG7-4-if9Z3WImVmyrwxvazRg6rw_ilxiTpGSdn1kh0HrrrRH_gaNPlbf_0SOlnF9ox38bsYIqF703-Z__-VCQSS6tfmYA7WIXo10AJD6pbA5Qxj01jYxe9zUWTYx8_ACFYQa1lz8-L-hHj_zY3NGM",
11 | "qi": "lX0zzdQc-tYxLzsyE88GmMwe12lEEeTOhtZjvac4GDWBoEwq1B0j1TZE48IGbehI5XnCAMtgw_-5vlwO3H2PcqsEcR8sCywFWDAR0bYFzapTK5uqAVROeaeZTQCTz7VV8gh0uv2daqa2VoAzIlR4OSiRi45wIdRYFrRKOfNJw1k",
12 | "kid": "oauth-key"
13 | }
--------------------------------------------------------------------------------
/auth0_mock/ext_pk/auth0_jwks.json:
--------------------------------------------------------------------------------
1 | {"keys": [{"alg": "RS256", "kty": "RSA", "n": "wHkz_b53rjnY9n9-LGN8czUt2L0mOYTWu_799I8nYg9_TfRBNYv6-u4kt15AhgBn10vnlpMuuzrB7vt_NGFjOdpY4BvBBhrfvJZkLguEmaBGNqruQPy6vIiLXeSzEBezVRc5NrxIiV9KWfhASILKzfSxC-r6DUqbqfj-GMkKT2egSQaRoGiqDBG2JOelVCKubncwec7se3AOnaRnKrrdve1PLwQmEzkGpPorcKCCQVlsJX016u4XDXkqCaSpKv5pyBi-H4x0RZa-SoydBzDjXrrqkh9Kv8w0vyejPnykS31GI9h7vUS-akYCYRUwVFa2N387Pi1zrocyjGuVE138Zw", "e": "AQAB", "kid": "oauth-key"}]}
--------------------------------------------------------------------------------
/auth0_mock/ext_pk/auth0_rsa:
--------------------------------------------------------------------------------
1 | -----BEGIN PRIVATE KEY-----
2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDAeTP9vneuOdj2
3 | f34sY3xzNS3YvSY5hNa7/v30jydiD39N9EE1i/r67iS3XkCGAGfXS+eWky67OsHu
4 | +380YWM52ljgG8EGGt+8lmQuC4SZoEY2qu5A/Lq8iItd5LMQF7NVFzk2vEiJX0pZ
5 | +EBIgsrN9LEL6voNSpup+P4YyQpPZ6BJBpGgaKoMEbYk56VUIq5udzB5zux7cA6d
6 | pGcqut297U8vBCYTOQak+itwoIJBWWwlfTXq7hcNeSoJpKkq/mnIGL4fjHRFlr5K
7 | jJ0HMONeuuqSH0q/zDS/J6M+fKRLfUYj2Hu9RL5qRgJhFTBUVrY3fzs+LXOuhzKM
8 | a5UTXfxnAgMBAAECgf80CBCH3IdYFSfGl3mG5fX/nUb2HmRxxPqAN3JekgiN/NwV
9 | Jt3av2m2pHHnxFvlYNhgtMrqHS4nzr46IVI1uDGo5nVAFBcC/vOrdK4YYURsZa3u
10 | 6tcAwdXbskUUbvJT32jbHWwVgjjlDsxwac+CmHDceu7xBAajs4BBfdmNwAKCxlrK
11 | hEKBED5xEY/rGIEi9TJP7vmpPqDfoES7ls/ilGoAi1Q6hLwIvogDmTf2g1Owv7JH
12 | k+ffshHjZbFhQTua09uUzKkRNIHW6IXvAvf6ubNPcodv+RrP2BtkTIFzXZbRPfau
13 | Lms0U0hC/a2h1ykgkZ2WE5u2n4i7IxhZ0YapkAECgYEA231MkG5VF2Hi24wF2ZpB
14 | PnfhzRsiWZpz4OswAqcygG6Z5rdPdAethEvUz+Rk6VqbLrYxvSXkVS8by0iOxd62
15 | 8zwY3BosEgc7/ym1KIkstirWx4SnuAMvSD33QF7hyZVJury18zkud1xVQUNXn21H
16 | zK1OUSQ9Dv4UYrtDQuNSb7ECgYEA4H11liCmk1zVEdlZ3DZG5T9b8/wFIY6FjAQL
17 | GlpHL+ac2w9ijH8Q4vD7+9MsK8t9UoP2Sl+lQfTm/YIBLcgpc4MyYx2yaxZkjjVk
18 | 94RH38vSgD1qPYhA2imrhs8XCyHjRnNpuVZBQY49VJ3SWZssjdDaFryWXOItlDBl
19 | xIPpi5cCgYAuy/9ICA4iZx9sOeWBaK8id4LwLSncut6cBOj+l9FfqrUriMfq8Dwh
20 | qd1c2dBeJJBTnErsjiiptNqTNAwkygBtydFvFDFzQpGbLLRQSTb8PBQBBBqSVDN/
21 | jp6p3dD8HtVSeCu/COEMV+ZhfM8w0abuT8ET8csG6EtGZbDIkRkhcQKBgQCowkfK
22 | IyN2NlxKvb1KyVbEcbv7j6J/1ndYiZWbKvDG9rNGDqvD+KXGJOkZJ2fWSHQeuutE
23 | f+Bo0+Vt//RI6WcX2jHfxuxgioXvTf5n//5UJBJLq1+ZgDtYhejXQAkPqlsDlDGP
24 | TWNjF73NRZNjHz8AIVhBrWXPz4v6EeP/Njc0YwKBgQCVfTPN1Bz61jEvOzITzwaY
25 | zB7XaUQR5M6G1mO9pzgYNYGgTCrUHSPVNkTjwgZt6EjlecIAy2DD/7m+XA7cfY9y
26 | qwRxHywLLAVYMBHRtgXNqlMrm6oBVE55p5lNAJPPtVXyCHS6/Z1qprZWgDMiVHg5
27 | KJGLjnAh1FgWtEo580nDWQ==
28 | -----END PRIVATE KEY-----
29 |
--------------------------------------------------------------------------------
/auth0_mock/index.ts:
--------------------------------------------------------------------------------
1 | import cors from "cors"
2 | import express, {Application} from "express";
3 | import {json, urlencoded} from "body-parser";
4 | import {port} from "./modules/helpers";
5 | import {rawReqLogger} from "./modules/middleware";
6 | import {routerApi} from "./routes/api";
7 | import {routerIndex} from "./routes";
8 | import {routerAuth} from "./routes/authentication";
9 |
10 | const app: Application = express();
11 |
12 | app
13 | .set('view engine', 'ejs')
14 | .use(json())
15 | .use(urlencoded({extended: true}))
16 | .use(cors())
17 | .options('*', cors())
18 | .use(express.static('public'))
19 | .use(rawReqLogger)
20 | .use([routerIndex, routerAuth, routerApi]);
21 |
22 | // Jest automatically defines as test
23 | if (process.env.NODE_ENV !== 'test') {
24 | app.listen(port, '0.0.0.0', () =>
25 | console.log('http connected to localhost port ', port)
26 | );
27 | }
28 |
29 | export default app
--------------------------------------------------------------------------------
/auth0_mock/jest.config.ts:
--------------------------------------------------------------------------------
1 | import type {Config} from 'jest';
2 |
3 | const config: Config = {
4 | preset: 'ts-jest',
5 | testEnvironment: 'node',
6 | // testMatch: ["tests/"],
7 | verbose: true,
8 | };
9 |
10 | export default config;
11 |
--------------------------------------------------------------------------------
/auth0_mock/modules/authentication.ts:
--------------------------------------------------------------------------------
1 | import {IUsers, UsersDefaults} from "../types";
2 |
3 | class Authentication {
4 | public loggedIn: boolean;
5 | public currentUser: IUsers;
6 |
7 | constructor() {
8 | this.loggedIn = false;
9 | this.currentUser = UsersDefaults;
10 | }
11 |
12 | // log a user in
13 | // if userObj is passed in & not empty then username was correct & only pw needs to be checked
14 | login(userObj: IUsers, pw: string): boolean {
15 | if (
16 | userObj &&
17 | "pw" in userObj &&
18 | userObj.pw.toLowerCase() === pw.toLowerCase()
19 | ) {
20 | this.loggedIn = true;
21 | this.currentUser = userObj;
22 | return true;
23 | }
24 | return false;
25 | }
26 |
27 | // log a user out
28 | logout(): void {
29 | this.loggedIn = false;
30 | this.currentUser = UsersDefaults;
31 | console.log('logged out');
32 | }
33 |
34 | }
35 |
36 | export const Auth = new Authentication();
--------------------------------------------------------------------------------
/auth0_mock/modules/helpers.ts:
--------------------------------------------------------------------------------
1 | import {IIdTokenClaims} from "../types";
2 |
3 | export const removeNonceIfEmpty = (obj: IIdTokenClaims): IIdTokenClaims => {
4 | if ('nonce' in obj && obj.nonce === '') {
5 | delete obj.nonce;
6 | }
7 | return obj;
8 | };
9 |
10 | export const removeTrailingSlash = (str: string): string => str.endsWith('/') ? str.slice(0, -1) : str;
11 |
12 | export const buildUriParams = (vars: Record): string => Object.keys(vars)
13 | .reduce((a, k) => {
14 | a.push(`${k}=${encodeURIComponent(vars[k])}`);
15 | return a;
16 | }, [])
17 | .join('&');
18 |
19 |
20 | export const port: number = parseInt(process.env.APP_PORT, 10) || 3001;
21 | export const auth0Url: string = process.env.AUTH0_DOMAIN || 'http://localhost:' + port;
22 |
--------------------------------------------------------------------------------
/auth0_mock/modules/jwk-wrapper.ts:
--------------------------------------------------------------------------------
1 | import jwt from "jsonwebtoken";
2 | import {JWK, JWS} from "node-jose";
3 | import jwkToBuffer from "jwk-to-pem";
4 | import {existsSync, readFileSync, writeFileSync} from "fs";
5 | import {IIdTokenClaims, IAccessTokenClaims, IKeyList} from "../types";
6 |
7 | class JWKWrapper {
8 | private readonly kty: string;
9 | private readonly size: number;
10 | private readonly jwkFileName: string;
11 | public readonly expirationDurationInMinutesAccessToken: number;
12 | public readonly expirationDurationInMinutesIdToken: number;
13 | private nonce: string;
14 | private readonly props: any;
15 | private keyStore: JWK.KeyStore;
16 |
17 | constructor(
18 | kty: string = 'RSA',
19 | size: number = 2048,
20 | props: object = {alg: 'RS256', use: 'sig'},
21 | jwkFileName: string = 'keys.json'
22 | ) {
23 | this.kty = kty;
24 | this.size = size;
25 | this.props = props;
26 | this.jwkFileName = jwkFileName;
27 | this.keyStore = JWK.createKeyStore();
28 | // 1440 minutes === 24 hours
29 | this.expirationDurationInMinutesAccessToken = parseInt(process.env.AUTH0_ACCESS_TOKEN_EXP, 10) || 1440;
30 | this.expirationDurationInMinutesIdToken = parseInt(process.env.AUTH0_ID_TOKEN_EXP, 10) || 1440;
31 | this.nonce = '';
32 | this.createJwks();
33 | }
34 |
35 | // return nonce
36 | getNonce(): string {
37 | return this.nonce;
38 | }
39 |
40 | setNonce(nonce: string): void {
41 | this.nonce = nonce;
42 | }
43 |
44 | // generate & return iat value
45 | getIat(): number {
46 | return Math.floor(Date.now() / 1000);
47 | }
48 |
49 | // generate & return exp value
50 | getExp(durationInMinutes: number): number {
51 | const res= Math.floor(
52 | (Date.now() + durationInMinutes * 60 * 1000) / 1000
53 | );
54 | console.log(`RES EXP ${res}`);
55 | console.log(`expirationDurationInMinutes ${durationInMinutes}`);
56 | return res
57 | }
58 |
59 | // Create key set and store on local file system
60 | createJwks(): void {
61 | console.log('Creating JWKS store');
62 | let keyStorePromise: Promise = null;
63 | if (existsSync('./ext_pk/auth0_jwk.json')) {
64 | console.log('Found external JWK file, loading it in store');
65 | const keyData = readFileSync('./ext_pk/auth0_jwk.json', {
66 | encoding: 'utf8',
67 | flag: 'r'
68 | });
69 | const keyJson = JSON.parse(keyData);
70 | keyStorePromise = JWK.asKeyStore([keyJson]).then((result: any) => {
71 | // {result} is a jose.JWK.KeyStore
72 | this.keyStore = result;
73 | });
74 | } else {
75 | console.log('Generate new JWKS store');
76 | keyStorePromise = this.keyStore.generate(this.kty, this.size, this.props);
77 | }
78 |
79 | keyStorePromise.then(() =>
80 | writeFileSync(
81 | this.jwkFileName,
82 | JSON.stringify(this.keyStore.toJSON(true), null, ' ')
83 | )
84 | );
85 | }
86 |
87 | // return key set
88 | getKeys(includePrivateKey: boolean = false): IKeyList {
89 | return this.keyStore.toJSON(includePrivateKey) as IKeyList;
90 | }
91 |
92 | // create token with given payload & options
93 | async createToken(payload: IIdTokenClaims | IAccessTokenClaims, opt: object = {}): Promise {
94 | const key: JWK.Key = this.keyStore.all({use: 'sig'})[0];
95 |
96 | // default options if none passed in
97 | if (Object.keys(opt).length === 0) {
98 | opt = {compact: true, jwk: key, fields: {typ: 'jwt'}};
99 | }
100 |
101 | return await JWS.createSign(opt, key)
102 | .update(JSON.stringify(payload))
103 | .final();
104 | }
105 |
106 | async verify(token: JWS.CreateSignResult): Promise {
107 | try {
108 | console.log('verify token \n');
109 | console.log(`token \n ${token} \n`);
110 | // Use first sig key
111 | const key: JWK.Key = this.keyStore.all({use: 'sig'})[0];
112 | // Verify Token with jsonwebtoken
113 | const publicKey: string = jwkToBuffer(key.toJSON() as jwkToBuffer.JWK);
114 | const privateKey: string = jwkToBuffer(key.toJSON(true) as jwkToBuffer.JWK, {private: true});
115 | console.log(`public key \n ${publicKey} \n`);
116 | console.log(`private key \n ${privateKey} \n`);
117 | const decoded = jwt.verify(token.toString(), publicKey);
118 | console.log('decoded', decoded);
119 | return true;
120 | } catch (e) {
121 | return false
122 | }
123 | }
124 | }
125 |
126 | export const JwkWrapper = new JWKWrapper()
--------------------------------------------------------------------------------
/auth0_mock/modules/middleware.ts:
--------------------------------------------------------------------------------
1 | import {Auth} from './authentication'
2 | import {Request, Response, NextFunction} from "express";
3 |
4 | // checks if user is logged in
5 | export function checkLogin(req: Request, res: Response, next: NextFunction): Response | void {
6 | if (Auth.loggedIn) {
7 | return next();
8 | }
9 | console.log('Error user not logged in');
10 | return res.status(401).send('Unauthorized. User not logged in');
11 | }
12 |
13 | // logs raw request props
14 | export function rawReqLogger(req: Request, res: Response, next: NextFunction): void {
15 | // Debug helper | logs props for all requests
16 | console.log('==========================================');
17 | console.log(new Date().toISOString(), 'raw request logging');
18 | console.log('==========================================');
19 | console.log('route ' + req.path + ' hit \n');
20 | console.log('req headers ' + JSON.stringify(req.headers) + '\n');
21 | console.log('req body ' + JSON.stringify(req.body) + '\n');
22 | console.log('req params ' + JSON.stringify(req.params) + '\n');
23 | console.log('==========================================');
24 |
25 | return next();
26 | }
27 |
--------------------------------------------------------------------------------
/auth0_mock/modules/user.ts:
--------------------------------------------------------------------------------
1 | import {join} from "path";
2 | import {readFileSync, existsSync} from "fs";
3 | import {IUsers, UsersDefaults} from "../types";
4 |
5 | class Users {
6 | private readonly userList: Record;
7 |
8 | constructor(userFileName: string = "", userFileDir: string = './') {
9 | if (!userFileName) {
10 | if (existsSync('./users-local.json')) {
11 | console.log('using: users-local.json');
12 | userFileName = 'users-local.json';
13 | } else {
14 | console.log('using: users.json');
15 | userFileName = 'users.json';
16 | }
17 | }
18 | // parse user config file
19 | this.userList = JSON.parse(readFileSync(join(userFileDir, userFileName), 'utf8'));
20 | }
21 |
22 | // get user object for specific username
23 | public getUser(username: string): IUsers {
24 | return this.userList[username] || UsersDefaults;
25 | }
26 | }
27 |
28 | export const User = new Users()
29 |
--------------------------------------------------------------------------------
/auth0_mock/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "auth0-docker-mocker",
3 | "version": "1.0.0",
4 | "main": "dist/index.js",
5 | "scripts": {
6 | "prebuild": "tslint -c tslint.json -p tsconfig.json --fix",
7 | "build": "tsc",
8 | "prestart": "npm install && npm run build",
9 | "start": "node .",
10 | "cleanup": "rm -rf node_modules keys.json",
11 | "test": "jest",
12 | "test-dev": "jest --watch",
13 | "test-leaks": "jest --detectOpenHandles",
14 | "test-coverage": "jest --coverage"
15 | },
16 | "dependencies": {
17 | "body-parser": "^1.20.2",
18 | "cors": "^2.8.5",
19 | "debug": "^4.3.4",
20 | "ejs": "^3.1.9",
21 | "express": "^4.18.2",
22 | "jsonwebtoken": "^9.0.1",
23 | "jwk-to-pem": "^2.0.5",
24 | "node-jose": "^2.2.0"
25 | },
26 | "devDependencies": {
27 | "@jest/types": "^29.6.3",
28 | "@types/body-parser": "^1.19.2",
29 | "@types/cors": "^2.8.13",
30 | "@types/express": "^4.17.17",
31 | "@types/jest": "^29.5.4",
32 | "@types/jsonwebtoken": "^9.0.2",
33 | "@types/jwk-to-pem": "^2.0.1",
34 | "@types/node": "^20.5.7",
35 | "@types/node-jose": "^1.1.10",
36 | "@types/supertest": "^2.0.12",
37 | "jest": "^29.6.4",
38 | "node-mocks-http": "^1.13.0",
39 | "supertest": "^6.3.3",
40 | "ts-jest": "^29.1.1",
41 | "ts-node": "^10.9.1",
42 | "tslint": "^6.1.3",
43 | "typescript": "^4.9.5"
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/auth0_mock/public/images/ufo-2.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/auth0_mock/routes/api.ts:
--------------------------------------------------------------------------------
1 | import jwktopem from "jwk-to-pem";
2 | import {Router, Request, Response} from "express";
3 | import {auth0Url, removeNonceIfEmpty} from "../modules/helpers";
4 | import {checkLogin} from "../modules/middleware";
5 | import {JwkWrapper} from "../modules/jwk-wrapper";
6 | import {accessTokenClaims} from "../token-claims/access";
7 | import {idTokenClaims} from "../token-claims/id";
8 | import {IAccessTokenClaims} from "../types";
9 |
10 | export const routerApi: Router = Router();
11 |
12 | // Returns JWKS (This is public and does not require login)
13 | routerApi.get('/.well-known/jwks.json', (req: Request, res: Response) => {
14 | res.status(200).send(JwkWrapper.getKeys());
15 | });
16 |
17 | // Get the private key used to sign
18 | routerApi.get('/jwks', async (req: Request, res: Response) => {
19 | res.status(200).send(jwktopem(JwkWrapper.getKeys(true).keys[0], {private: true}));
20 | });
21 |
22 | // Returns access token for user
23 | routerApi.get('/access_token', checkLogin, async (req: Request, res: Response) => {
24 | res.status(200).send(
25 | await JwkWrapper.createToken(
26 | accessTokenClaims('', [`${auth0Url}/userinfo`])
27 | )
28 | );
29 | });
30 |
31 | // Returns id token for user
32 | routerApi.get('/id_token', checkLogin, async (req: Request, res: Response) => {
33 | res.status(200).send(
34 | await JwkWrapper.createToken(removeNonceIfEmpty(idTokenClaims()))
35 | );
36 | });
37 |
38 | // Auth0 token route | returns access && id token
39 | routerApi.post('/oauth/token', checkLogin, async (req: Request, res: Response) => {
40 | console.log(JwkWrapper.getKeys(true));
41 | const {client_id}: { client_id: string } = req.body;
42 | const accessTokenClaim: IAccessTokenClaims = accessTokenClaims(client_id, [
43 | `${auth0Url}/userinfo`
44 | ]);
45 | console.log({accessTokenClaim});
46 | res.status(200).send({
47 | access_token: await JwkWrapper.createToken(accessTokenClaim),
48 | expires_in: (JwkWrapper.expirationDurationInMinutesAccessToken * 60),
49 | id_token: await JwkWrapper.createToken(
50 | removeNonceIfEmpty(idTokenClaims(client_id))
51 | ),
52 | scope: accessTokenClaim.scope,
53 | token_type: 'Bearer',
54 | refresh_token: "refresh_token"
55 | });
56 | });
57 |
58 | // Used to verify token
59 | routerApi.get('/verify_token_test', checkLogin, async (req: Request, res: Response) => {
60 | const resp: boolean = await JwkWrapper.verify(
61 | await JwkWrapper.createToken(removeNonceIfEmpty(idTokenClaims()))
62 | );
63 | const msg: string = resp ? "token verified - ": "token verification failed";
64 | res.status(200).send(`${msg} - see logs for details`);
65 | });
66 |
67 | // Used to get userinfo
68 | routerApi.get('/userinfo', checkLogin, (req: Request, res: Response) => {
69 | res.status(200).json(removeNonceIfEmpty(idTokenClaims()));
70 | });
71 |
--------------------------------------------------------------------------------
/auth0_mock/routes/authentication.ts:
--------------------------------------------------------------------------------
1 | import {Router, Request, Response} from "express";
2 | import {User} from "../modules/user";
3 | import {Auth} from "../modules/authentication";
4 | import {idTokenClaims} from "../token-claims/id";
5 | import {JwkWrapper} from "../modules/jwk-wrapper";
6 | import {accessTokenClaims} from "../token-claims/access";
7 | import {buildUriParams, auth0Url, removeNonceIfEmpty} from "../modules/helpers"
8 | import {IAuthorize, AuthorizedDefaults, IAccessTokenClaims, ILogin, LoginDefaults} from "../types";
9 |
10 | export const routerAuth: Router = Router();
11 |
12 | // path renders login page | used in conjunction with auth0 frontend libs | makes POST to login route
13 | routerAuth.get('/authorize', async (req: Request, res: Response) => {
14 | const {redirect_uri, prompt, state, client_id, nonce, audience}: IAuthorize = {...AuthorizedDefaults, ...req.query};
15 |
16 | JwkWrapper.setNonce(nonce);
17 | if (!redirect_uri) {
18 | return res.status(400).send('missing redirect url');
19 | }
20 | if (prompt === 'none') {
21 | console.log('got silent refresh request');
22 | if (!Auth.loggedIn) {
23 | console.log('silent refresh user not logged in');
24 | const varsNoPrompt: Record = {
25 | state,
26 | error: 'login_required',
27 | error_description: 'login_required'
28 | };
29 | const paramsNoPrompt: string = buildUriParams(varsNoPrompt);
30 | const locationNoPrompt: string = `${redirect_uri}?${paramsNoPrompt}`;
31 | console.log('Redirect to Location', locationNoPrompt);
32 | return res.writeHead(302, {Location: locationNoPrompt}).end();
33 | }
34 | console.log('silent refresh user logged in, doing refresh');
35 | const accessTokenC: IAccessTokenClaims = accessTokenClaims(audience, [
36 | audience,
37 | `${auth0Url}/userinfo`
38 | ]);
39 | const vars:Record = {
40 | state,
41 | code: '1234',
42 | access_token: await JwkWrapper.createToken(accessTokenC),
43 | expires_in: 86400,
44 | id_token: await JwkWrapper.createToken(
45 | removeNonceIfEmpty(idTokenClaims(audience))
46 | ),
47 | scope: accessTokenC.scope,
48 | token_type: 'Bearer'
49 | };
50 | console.log('silent refresh vars', vars);
51 | const params: string = buildUriParams(vars);
52 | const location: string = `${redirect_uri}?${params}`;
53 | console.log('Redirect to Location', location);
54 | return res.writeHead(302, {Location: location}).end();
55 | }
56 | return res.render('../templates/login_page', {
57 | username: process.env.AUTH0_DEFAULT_USER || 'user1',
58 | password: process.env.AUTH0_DEFAULT_PASSWORD || 'user1',
59 | redirect: redirect_uri,
60 | state: encodeURIComponent(state)
61 | });
62 | });
63 |
64 | // ======================
65 | // login routes
66 | // ======================
67 |
68 | // login route | associated with user in user.json file | post made by authorizer route template
69 | routerAuth.post('/login', (req: Request, res: Response) => {
70 | const {redirect, state, username, pw}: ILogin = {...LoginDefaults, ...req.query, ...req.body}
71 | const logMsg: string = 'username = ' + username + ' && pw = ' + pw;
72 | // if logged-in user tries to hit login route twice then just log them out and start over
73 | if (Auth.loggedIn) {
74 | Auth.logout();
75 | }
76 | // if missing username || password params then error
77 | if (!username || !pw) {
78 | return res.status(400).send('missing username or password');
79 | }
80 | // if login fails
81 | if (!Auth.login(User.getUser(username), pw)) {
82 | console.error('invalid login - ' + logMsg);
83 | return res.status(401).send('invalid username or password');
84 | }
85 | // all good in the hood
86 | console.log('Logged in ' + logMsg);
87 |
88 | return res
89 | .writeHead(302, {
90 | Location: `${redirect}?code=1234&state=${encodeURIComponent(state)}`
91 | })
92 | .end();
93 | });
94 |
95 | // login route | alternative to using /authorizer->POST->/login flow
96 | routerAuth.get('/login', (req: Request, res: Response) => {
97 | const {username, pw}: ILogin = {...LoginDefaults, ...req.query}
98 | const logMsg = 'username = ' + username + ' && pw = ' + pw;
99 |
100 | if (Auth.loggedIn) {
101 | Auth.logout();
102 | }
103 | // if missing username || password params then error
104 | if (!username || !pw) {
105 | return res.status(400).send('missing username or password');
106 | }
107 | // if login fails
108 | if (!Auth.login(User.getUser(username), pw)) {
109 | console.error('invalid login - ' + logMsg);
110 | return res.status(401).send('invalid username or password');
111 | }
112 | // all good in the hood
113 | console.log('Logged in ' + logMsg);
114 |
115 | return res
116 | .status(200)
117 | .send(
118 | JSON.stringify(Auth.currentUser) +
119 | '
you may continue with your auth0 needs'
120 | );
121 | });
122 |
123 | // ======================
124 | // logout routes
125 | // ======================
126 |
127 | routerAuth.get('/logout', (req: Request, res: Response) => {
128 | const currentUser: string = JSON.stringify(Auth.currentUser);
129 | Auth.logout();
130 | console.log(`logged out ${currentUser}`);
131 | res.status(200).send('logged out');
132 | });
133 |
134 | routerAuth.get('/v2/logout', (req: Request, res: Response) => {
135 | const redirect: string = (req.query.returnTo || "").toString();
136 | const currentUser: string = JSON.stringify(Auth.currentUser);
137 | Auth.logout();
138 | console.log(`logged out ${currentUser}`);
139 | return res
140 | .writeHead(302, {
141 | Location: `${redirect}`
142 | })
143 | .end();
144 | });
145 |
--------------------------------------------------------------------------------
/auth0_mock/routes/index.ts:
--------------------------------------------------------------------------------
1 | import {Router, Request, Response} from "express";
2 |
3 | export const routerIndex: Router = Router();
4 |
5 | // lists all the available routes
6 | routerIndex.get('/', (req: Request, res: Response) => {
7 | const routes: Record = {
8 | '/authorize':
9 | 'GET - renders a login page which makes a POST request to login route - official auth0 service uses this route (most frontend frameworks will use it too)',
10 | '/login':
11 | 'POST|GET - login a user | POST used in conjunction with authorize route',
12 | '/logout': 'GET - logs a user out - empties active user obj',
13 | '/v2/logout':
14 | 'GET - official auth0 service uses this route (most frontend frameworks will use it too) -> same function as logout',
15 | '/.well-known/jwks.json':
16 | 'GET - Returns JWKS | official auth0 service uses this route (most frontend frameworks will use it too)',
17 | '/jwks':
18 | 'GET - get private keys used to sign tokens | used for debug purposes',
19 | '/access_token': 'GET - must be logged in - Returns access token for user',
20 | '/id_token': 'GET - must be logged in - Returns id token for user',
21 | '/oauth/token':
22 | 'POST - must be logged in - official auth0 service uses this route (most frontend frameworks will use it too) "token route" - returns object with tokens, expires, scope, and token type',
23 | '/verify_token_test':
24 | 'GET - must be logged in - verifies token for debug purposes - outputs to container logs',
25 | '/userinfo':
26 | 'GET - must be logged in - official auth0 service uses this route (most frontend frameworks will use it too) - returns userinfo aka id claims'
27 | };
28 | return res
29 | .status(200)
30 | .header('Content-Type', 'application/json')
31 | .send(JSON.stringify(routes, null, 4));
32 | });
33 |
--------------------------------------------------------------------------------
/auth0_mock/tests/integration/api_route.test.ts:
--------------------------------------------------------------------------------
1 | import {join} from "path";
2 | import {JWS} from "node-jose";
3 | import app from "../../index";
4 | import request from "supertest";
5 | import {readFileSync} from "fs";
6 | import {IUsers} from "../../types";
7 | import {Auth} from "../../modules/authentication";
8 | import {idTokenClaims} from "../../token-claims/id";
9 | import {JwkWrapper} from "../../modules/jwk-wrapper";
10 |
11 | describe("testing api routes", () => {
12 | beforeEach(async () => {
13 | Auth.logout();
14 | const username: string = "admin1";
15 | const password: string = "admin1";
16 | const userObject: IUsers = JSON.parse(readFileSync(join("./", "users.json"), 'utf8'))[username];
17 | Auth.login(userObject, password);
18 | });
19 | it("should return keys when /.well-known/jwks.json is hit", async () => {
20 | const res = await request(app).get("/.well-known/jwks.json");
21 | expect(res.status).toEqual(200);
22 | expect(res.headers["content-type"].includes("application/json"));
23 | expect("keys" in res.body);
24 | });
25 | it("should return return private key used to sign when /jwks is hit", async () => {
26 | const res = await request(app).get("/jwks");
27 | expect(res.status).toEqual(200);
28 | expect(res.headers["content-type"].includes("text/html"));
29 | expect(res.text.toLowerCase().includes("private key"));
30 | });
31 | it("should return access token when /access_token is hit", async () => {
32 | const res = await request(app).get("/access_token");
33 | expect(res.status).toEqual(200);
34 | expect(res.headers["content-type"].includes("text/html"));
35 | expect(JwkWrapper.verify(res.text as unknown as JWS.CreateSignResult)).toBeTruthy();
36 | });
37 | it("should return ID token when /id_token is hit", async () => {
38 | const res = await request(app).get("/id_token");
39 | expect(res.status).toEqual(200);
40 | expect(res.headers["content-type"].includes("text/html"));
41 | expect(JwkWrapper.verify(res.text as unknown as JWS.CreateSignResult)).toBeTruthy();
42 | });
43 | it("should create oauth token object when /oauth/token is hit", async () => {
44 | const res = await request(app).post("/oauth/token").send({client_id: "1234"});
45 | expect(res.status).toEqual(200);
46 | expect(res.headers["content-type"].includes("application/json"));
47 | const body = res.body;
48 | expect("access_token" in body).toBeTruthy();
49 | expect("expires_in" in body).toBeTruthy();
50 | expect("id_token" in body).toBeTruthy();
51 | expect("scope" in body).toBeTruthy();
52 | expect("token_type" in body).toBeTruthy();
53 | expect(JwkWrapper.verify(body.access_token as unknown as JWS.CreateSignResult)).toBeTruthy();
54 | expect(JwkWrapper.verify(body.id_token as unknown as JWS.CreateSignResult)).toBeTruthy();
55 | });
56 | it("should verify token via logs & send msg including done when /verify_token_test is hit", async () => {
57 | const res = await request(app).get("/verify_token_test");
58 | expect(res.headers["content-type"].includes("text/html"));
59 | expect(res.text.toLowerCase().includes("done"));
60 | });
61 | it("should return userinfo in json format when /userinfo is hit", async ()=>{
62 | const res = await request(app).get("/userinfo");
63 | expect(res.headers["content-type"].includes("application/json"));
64 | // userinfo is ID token claim | make sure props returned are contained in idTokenClaims
65 | expect(Object.keys(res.body).every(key => Object.keys(idTokenClaims()).includes(key))).toBeTruthy();
66 | });
67 | });
68 |
--------------------------------------------------------------------------------
/auth0_mock/tests/integration/authentication_route.test.ts:
--------------------------------------------------------------------------------
1 | import {join} from "path";
2 | import app from "../../index";
3 | import {readFileSync} from "fs";
4 | import request from "supertest";
5 | import {IUsers} from "../../types";
6 | import {UsersDefaults} from "../../types";
7 | import {Auth} from "../../modules/authentication";
8 | import {JwkWrapper} from "../../modules/jwk-wrapper";
9 |
10 | describe("Authentication route tests", () => {
11 | describe("/authorize route tests", () => {
12 | it("should set none to param provided", async () => {
13 | const nonce = "1234-4321";
14 | await request(app).get(`/authorize?nonce=${nonce}`);
15 | expect(JwkWrapper.getNonce()).toEqual(nonce);
16 | });
17 | it("should yield 400 with msg if redirect url is not in query string", async () => {
18 | const res = await request(app).get(`/authorize`);
19 | expect(res.headers["content-type"].includes("text/html"));
20 | expect(res.status).toEqual(400);
21 | expect(res.text.toLowerCase().includes("missing redirect url")).toBeTruthy();
22 | });
23 | it("should yield html login prompt if prompt is not set to none", async () => {
24 | const res = await request(app).get(`/authorize?redirect_uri=1234`);
25 | expect(res.headers["content-type"].includes("text/html"));
26 | expect(res.text.includes(" {
29 | const redirectUri = "testing_is_cool"
30 | const state = "234";
31 | const res = await request(app).get(`/authorize?redirect_uri=${redirectUri}&prompt=none&state=${state}`);
32 | expect(res.status).toEqual(302);
33 | const expectedParams = [redirectUri, `state=${state}`, "error=login_required", "error_description=login_required"]
34 | expectedParams.forEach((v) => {
35 | expect(res.headers.location.includes(v)).toBeTruthy();
36 | });
37 | });
38 | it("should yield 302 & redirect to redirect URI with specific params when prompt is set to none & user logged in", async () => {
39 | const username: string = "admin1";
40 | const password: string = "admin1";
41 | const userObject: IUsers = JSON.parse(readFileSync(join("./", "users.json"), 'utf8'))[username];
42 | Auth.login(userObject, password);
43 | const redirectUri = "testing_is_cool"
44 | const state = "234";
45 | const res = await request(app).get(`/authorize?redirect_uri=${redirectUri}&prompt=none&state=${state}`);
46 | expect(res.status).toEqual(302);
47 | const expectedParams = [redirectUri, `state=${state}`, "code=1234", "access_token", "expires_in=86400", "id_token", "scope", "token_type=Bearer"]
48 | expectedParams.forEach((v) => {
49 | expect(res.headers.location.includes(v)).toBeTruthy();
50 | });
51 | });
52 | });
53 | describe("/login route tests", () => {
54 | describe("post alternative", () => {
55 | it("should yield 400 status code & error message is username or password is not provided or empty", async () => {
56 | const res = await request(app).post(`/login`);
57 | expect(res.text.toLowerCase().includes("missing username or password"));
58 | expect(res.headers["content-type"].includes("text/html"));
59 | expect(res.status).toEqual(400);
60 | });
61 | it("should yield 401 status code & error message user or username is invalid", async () => {
62 | const validUser = "admin1";
63 | const invalidPassword = "invalid";
64 | const res = await request(app).post(`/login`).send({username: validUser, pw: invalidPassword});
65 | expect(res.text.toLowerCase().includes("invalid username or password"));
66 | expect(res.headers["content-type"].includes("text/html"));
67 | expect(res.status).toEqual(401);
68 | });
69 | it('should yield status code 302 and pass on specified query params when login successful', async () => {
70 | const validUser = "admin1";
71 | const validPw = "admin1";
72 | const redirectUri = "testing";
73 | const state = "9078";
74 | const res = await request(app).post(`/login`)
75 | .send({
76 | username: validUser,
77 | pw: validPw,
78 | state,
79 | redirect: redirectUri
80 | });
81 | expect(res.status).toEqual(302);
82 | const expectedParams = [redirectUri, `state=${state}`, "code=1234"]
83 | expectedParams.forEach((v) => {
84 | expect(res.headers.location.includes(v)).toBeTruthy();
85 | });
86 | });
87 | });
88 | describe("get alternative", () => {
89 | it("should yield 400 status code & error message is username or password is not provided or empty", async () => {
90 | const res = await request(app).get(`/login`);
91 | expect(res.text.toLowerCase().includes("missing username or password"));
92 | expect(res.headers["content-type"].includes("text/html"));
93 | expect(res.status).toEqual(400);
94 | });
95 | it("should yield 401 status code & error message user or username is invalid", async () => {
96 | const validUser = "admin1";
97 | const invalidPassword = "invalid";
98 | const res = await request(app).get(`/login?username=${validUser}&pw=${invalidPassword}`);
99 | expect(res.text.toLowerCase().includes("invalid username or password"));
100 | expect(res.headers["content-type"].includes("text/html"));
101 | expect(res.status).toEqual(401);
102 | });
103 | it('should yield status code 302 and pass on specified query params when login successful', async () => {
104 | const validUser = "admin1";
105 | const validPw = "admin1";
106 | const res = await request(app).get(`/login?username=${validUser}&pw=${validPw}`)
107 | expect(res.status).toEqual(200);
108 | expect(res.headers["content-type"].includes("text/html"));
109 | expect(res.text.includes("username")).toBeTruthy();
110 | expect(res.text.includes("pw")).toBeTruthy();
111 | expect(res.text.includes(validPw));
112 | });
113 | });
114 | });
115 | describe("logout route tests", () => {
116 | beforeEach(async () => {
117 | const username: string = "admin1";
118 | const password: string = "admin1";
119 | const userObject: IUsers = JSON.parse(readFileSync(join("./", "users.json"), 'utf8'))[username];
120 | Auth.login(userObject, password);
121 | });
122 | describe("/logout", () => {
123 | it("should log a user out & return 200 statusCode", async () => {
124 | // user is logged in
125 | expect(Auth.currentUser.username).toEqual("admin1");
126 | const res = await request(app).get(`/logout`);
127 | // user is logged out & props are reset to default
128 | expect(Auth.currentUser).toEqual(UsersDefaults);
129 | expect(res.status).toEqual(200);
130 | expect(res.headers["content-type"].includes("text/html"));
131 | expect(res.text.toLowerCase().includes("logged out"))
132 | });
133 | });
134 | describe("/v2/logout", ()=>{
135 | it("should log a user out & redirect to specified URL", async ()=>{
136 | // user is logged in
137 | expect(Auth.currentUser.username).toEqual("admin1");
138 | const redirectUri = "test";
139 | const res = await request(app).get(`/v2/logout?returnTo=${redirectUri}`);
140 | // user is logged out & props are reset to default
141 | expect(Auth.currentUser).toEqual(UsersDefaults);
142 | expect(res.status).toEqual(302);
143 | expect(res.headers.location).toEqual(redirectUri)
144 | });
145 | });
146 | });
147 | });
--------------------------------------------------------------------------------
/auth0_mock/tests/integration/index_route.test.ts:
--------------------------------------------------------------------------------
1 | import app from "../../index";
2 | import request from "supertest";
3 |
4 | describe("testing index router", () => {
5 | it("should return list of all routes", async () => {
6 | const res = await request(app).get("/");
7 | // if routes are added to index they need to be added here
8 | const routes = [
9 | "/authorize",
10 | "/login",
11 | "/logout",
12 | "/v2/logout",
13 | "/.well-known/jwks.json",
14 | "/jwks",
15 | "/access_token",
16 | "/id_token",
17 | "/oauth/token",
18 | "/verify_token_test",
19 | "/userinfo"
20 | ]
21 | expect(res.headers["content-type"].includes("application/json"));
22 | expect(Object.keys(res.body).every(key => routes.includes(key))).toBeTruthy();
23 | });
24 | });
--------------------------------------------------------------------------------
/auth0_mock/tests/unit/access_token_claims.test.ts:
--------------------------------------------------------------------------------
1 | import {accessTokenClaims} from "../../token-claims/access";
2 | import {tokenDefaults} from "../../token-claims/token_defaults";
3 |
4 | describe("access token claims tests", () => {
5 | it("should return IAccessTokenClaims property", () => {
6 | const defaultProps: string[] = [
7 | "iss",
8 | "sub",
9 | "aud",
10 | "iat",
11 | "exp",
12 | "azp",
13 | "scope",
14 | "permissions"
15 | ];
16 | const accessClaims = accessTokenClaims();
17 | expect(defaultProps.every(key => Object.keys(accessClaims).includes(key))).toBeTruthy();
18 | });
19 | it("should set azp to what the user sets", () => {
20 | const azpVal = "yes";
21 | const accessClaims = accessTokenClaims(azpVal);
22 | expect(accessClaims.azp).toEqual(azpVal)
23 | });
24 | it("should set aud to what was passed in", () => {
25 | const audVal = ["peter", "bug", "king"];
26 | const accessClaims = accessTokenClaims("yes", audVal);
27 | expect(accessClaims.aud).toEqual(tokenDefaults.aud.concat(audVal));
28 | });
29 | });
--------------------------------------------------------------------------------
/auth0_mock/tests/unit/authentication.test.ts:
--------------------------------------------------------------------------------
1 | import {Auth} from "../../modules/authentication";
2 | import {IUsers, UsersDefaults} from "../../types";
3 | import {readFileSync} from "fs";
4 | import {join} from "path";
5 |
6 | describe("testing Authentication class instance", () => {
7 | beforeEach(() => {
8 | Auth.logout();
9 | });
10 | it("should log a user in when user is valid", () => {
11 | const username: string = "admin1";
12 | const password: string = "admin1";
13 | const userObject: IUsers = JSON.parse(readFileSync(join("./", "users.json"), 'utf8'))[username];
14 |
15 | // pre-login
16 | expect(Auth.loggedIn).toBeFalsy();
17 | expect(Auth.currentUser).toEqual(UsersDefaults);
18 | // login should be successful & return true
19 | expect(Auth.login(userObject, password)).toBeTruthy();
20 | // post login props
21 | expect(Auth.loggedIn).toBeTruthy();
22 | expect(Auth.currentUser).toEqual(userObject);
23 | });
24 |
25 | it("should not log a user in when a user is invalid", () => {
26 | const username: string = "not_valid_username";
27 | const password: string = "not_valid_password";
28 | const userObject: IUsers = JSON.parse(readFileSync(join("./", "users.json"), 'utf8'))[username];
29 |
30 | // pre-login
31 | expect(Auth.loggedIn).toBeFalsy();
32 | expect(Auth.currentUser).toEqual(UsersDefaults);
33 | // login should be successful & return true
34 | expect(Auth.login(userObject, password)).toBeFalsy();
35 | // post login props
36 | expect(Auth.loggedIn).toBeFalsy();
37 | expect(Auth.currentUser).toEqual(UsersDefaults);
38 | });
39 |
40 | it('should set user properties back to default when logged out', () => {
41 | // pre-login
42 | const defaultLoggedIn: boolean = Auth.loggedIn;
43 | const defaultCurrentUser: IUsers = Auth.currentUser;
44 | const username: string = "admin1";
45 | const password: string = "admin1";
46 | const userObject: IUsers = JSON.parse(readFileSync(join("./", "users.json"), 'utf8'))[username];
47 |
48 | // successful login
49 | expect(Auth.login(userObject, password)).toBeTruthy();
50 |
51 | // post login props
52 | expect(Auth.loggedIn).toBeTruthy();
53 | expect(Auth.currentUser).toEqual(userObject);
54 |
55 | // logout
56 | Auth.logout();
57 |
58 | // post logout prop comparison
59 | expect(Auth.loggedIn).toEqual(defaultLoggedIn);
60 | expect(Auth.currentUser).toEqual(defaultCurrentUser);
61 |
62 | });
63 | });
--------------------------------------------------------------------------------
/auth0_mock/tests/unit/default_token_claims.test.ts:
--------------------------------------------------------------------------------
1 | import {tokenDefaults} from "../../token-claims/token_defaults";
2 |
3 | describe("testing token Defaults", () => {
4 | it("should return defaults specified properties", () => {
5 | const defaultProps: string[] = [
6 | "domain",
7 | "sub",
8 | "defaultPermissions",
9 | "defaultScope",
10 | "aud",
11 | "given_name",
12 | "family_name",
13 | "nickname",
14 | "name",
15 | "email",
16 | "picture",
17 | "amr"
18 | ];
19 | expect(Object.keys(tokenDefaults).every(key => defaultProps.includes(key))).toBeTruthy();
20 | });
21 | });
--------------------------------------------------------------------------------
/auth0_mock/tests/unit/helpers.test.ts:
--------------------------------------------------------------------------------
1 | import * as types from "../../types";
2 | import * as helpers from "../../modules/helpers";
3 | import {idTokenClaims} from "../../token-claims/id";
4 |
5 | describe("testing helper functions", () => {
6 | describe("testing removeNonceIfEmpty", () => {
7 | it("should remove nonce if it is empty", () => {
8 | let idTokenC = idTokenClaims()
9 | expect('nonce' in idTokenC).toBeTruthy();
10 | expect(idTokenC.nonce === "").toBeTruthy();
11 | idTokenC = helpers.removeNonceIfEmpty(idTokenC)
12 | expect('nonce' in idTokenC).toBeFalsy();
13 | expect(idTokenC.nonce === "").toBeFalsy();
14 | });
15 |
16 | it("should not remove nonce if it is not empty", () => {
17 | let idTokenC: types.IIdTokenClaims = idTokenClaims();
18 | const nonceVal: string = "123";
19 | idTokenC.nonce = nonceVal;
20 | expect('nonce' in idTokenC).toBeTruthy();
21 | expect(idTokenC.nonce === nonceVal).toBeTruthy();
22 | idTokenC = helpers.removeNonceIfEmpty(idTokenC);
23 | expect('nonce' in idTokenC).toBeTruthy();
24 | expect(idTokenC.nonce === nonceVal).toBeTruthy();
25 | });
26 | });
27 |
28 | describe("testing removeTrailingSlash", () => {
29 | it("should remove trailing slash when trailing slash exists", () => {
30 | let str: string = "this has a trailing slash /";
31 | expect(str.endsWith("/")).toBeTruthy();
32 | str = helpers.removeTrailingSlash(str);
33 | expect(str.endsWith("/")).toBeFalsy();
34 | });
35 | it("should not remove trailing slash when trailing slash is not present", () => {
36 | const str: string = "this doesn't have a trailing slash";
37 | expect(str.endsWith("/")).toBeFalsy();
38 | const strTwo: string = helpers.removeTrailingSlash(str);
39 | expect(str.endsWith("/")).toBeFalsy();
40 | expect(str === strTwo).toBeTruthy();
41 | });
42 |
43 | });
44 |
45 | describe("testing buildUriParams", () => {
46 | it("should take in object & return uri formatted string", () => {
47 | let v: any = {
48 | state: "1234",
49 | error: 'login_required',
50 | error_description: 'login_required'
51 | }
52 | expect(typeof v === "string").toBeFalsy();
53 | v = helpers.buildUriParams(v);
54 | expect(typeof v === "string").toBeTruthy();
55 | });
56 | });
57 |
58 | describe("testing port const", () => {
59 | it("should return a number in base 10", () => {
60 | expect(helpers.port === parseInt(helpers.port.toString(), 10)).toBeTruthy();
61 | });
62 | });
63 |
64 | describe("testing auth0Url const", () => {
65 | it("should return url string", () => {
66 | expect(typeof helpers.auth0Url === "string").toBeTruthy();
67 | expect((helpers.auth0Url).includes("http://")).toBeTruthy();
68 | expect((helpers.auth0Url).includes(`:${helpers.port}`)).toBeTruthy();
69 | });
70 | });
71 | });
72 |
73 |
--------------------------------------------------------------------------------
/auth0_mock/tests/unit/id_token_claims.test.ts:
--------------------------------------------------------------------------------
1 | import {idTokenClaims} from "../../token-claims/id";
2 |
3 | describe("id token claims tests", () => {
4 | it("should return IIdTokenClaims property", () => {
5 | const accessClaims = idTokenClaims();
6 | expect("given_name" in accessClaims)
7 | });
8 | it("should set aud to what the user sets via param", () => {
9 | const aud = "pking";
10 | const accessClaims = idTokenClaims(aud);
11 | expect(accessClaims.aud).toEqual([aud])
12 | });
13 | });
--------------------------------------------------------------------------------
/auth0_mock/tests/unit/jwk_wrapper.test.ts:
--------------------------------------------------------------------------------
1 | import fs from "fs";
2 | import {JwkWrapper} from "../../modules/jwk-wrapper";
3 | import {sleep} from "../utils";
4 | import {idTokenClaims} from "../../token-claims/id";
5 |
6 | describe("JWKWrapper tests", () => {
7 | it("should return Nonce when getNonce is called", () => {
8 | // set nonce
9 | const nonce = "1234"
10 | JwkWrapper.setNonce(nonce);
11 | expect(JwkWrapper.getNonce()).toEqual(nonce)
12 | });
13 | it("should set Nonce when setNonce is called", () => {
14 | ["1234", "4321", "9876", "6789"].forEach((value) => {
15 | JwkWrapper.setNonce(value);
16 | expect(JwkWrapper.getNonce()).toEqual(value);
17 | });
18 | });
19 | it("should get IAT (a number) when getIat is called", () => {
20 | expect(typeof JwkWrapper.getIat() === "number").toBeTruthy();
21 | });
22 | it("should get exp date (a number) when getExp is called", () => {
23 | expect(typeof JwkWrapper.getExp() === "number").toBeTruthy();
24 | });
25 | it("should create JWKS file when createJwks is called", async () => {
26 | const filePath = "./keys.json";
27 | // make sure keys.json is deleted
28 | fs.unlinkSync(filePath);
29 | // run method
30 | JwkWrapper.createJwks();
31 | // fails without sleep even though usage is synchronous
32 | await sleep(.00000000000000000000000000000001);
33 | console.log(fs.existsSync(filePath));
34 | // should create file
35 | expect(fs.existsSync(filePath)).toBeTruthy();
36 | });
37 | it("should create a token when createToken is called with given claims", async () => {
38 | const token = await JwkWrapper.createToken(idTokenClaims());
39 | expect(token.toString().split(".").length === 3).toBeTruthy();
40 | expect(JwkWrapper.verify(token)).toBeTruthy()
41 | });
42 | it("should return true if no issues with verifying token when verify is called", async () => {
43 | const token = await JwkWrapper.createToken(idTokenClaims());
44 | const logSpy = jest.spyOn(console, 'log');
45 | expect(JwkWrapper.verify(token)).toBeTruthy()
46 | expect(logSpy).toHaveBeenCalled();
47 |
48 | });
49 | });
--------------------------------------------------------------------------------
/auth0_mock/tests/unit/middleware.test.ts:
--------------------------------------------------------------------------------
1 | import * as middleware from "../../modules/middleware";
2 | import {Request, Response, NextFunction} from "express";
3 | import httpMocks from "node-mocks-http";
4 | import {IUsers} from "../../types";
5 | import {readFileSync} from "fs";
6 | import {join} from "path";
7 | import {Auth} from "../../modules/authentication";
8 |
9 |
10 | describe("middleware tests", () => {
11 | function nextFunc(): NextFunction {
12 | return true as unknown as NextFunction;
13 | }
14 |
15 | describe("checkLogin tests", () => {
16 | beforeEach(() => {
17 | Auth.logout();
18 | });
19 | it('should return next if logged in', () => {
20 | const request: Request = httpMocks.createRequest();
21 | const response: Response = httpMocks.createResponse();
22 | const username: string = "admin1";
23 | const password: string = "admin1";
24 | const userObject: IUsers = JSON.parse(readFileSync(join("./", "users.json"), 'utf8'))[username];
25 |
26 | // login successfully
27 | expect(Auth.login(userObject, password)).toBeTruthy();
28 |
29 | // nextFunc returns true so we check against a truthy return
30 | expect(middleware.checkLogin(request, response, nextFunc)).toBeTruthy();
31 | });
32 | it("should return a status code of 401 & body containing Unauthorized if not logged in", () => {
33 | const request: Request = httpMocks.createRequest();
34 | // cant type this with express typing since we're using mock special funcitonality
35 | const response: httpMocks.MockResponse>> = httpMocks.createResponse();
36 |
37 | // run middleware function
38 | middleware.checkLogin(request, response, nextFunc)
39 |
40 | // check response object
41 | expect(response.statusCode).toEqual(401);
42 | expect(response._getData().toLowerCase().includes("unauthorized")).toBeTruthy();
43 |
44 | });
45 | });
46 | describe("rawReqLogger tests", () => {
47 | it("should console.log things & return nextFunc", async () => {
48 | const request: Request = httpMocks.createRequest();
49 | const response: Response = httpMocks.createResponse();
50 | const logSpy = jest.spyOn(console, 'log');
51 | middleware.rawReqLogger(request, response, nextFunc)
52 | expect(logSpy).toHaveBeenCalledTimes(8);
53 | });
54 | });
55 | });
56 |
--------------------------------------------------------------------------------
/auth0_mock/tests/unit/user.test.ts:
--------------------------------------------------------------------------------
1 | import {User} from "../../modules/user";
2 | import {IUsers, UsersDefaults} from "../../types";
3 | import {readFileSync} from "fs";
4 | import {join} from "path";
5 |
6 | describe("testing user class instance", () => {
7 | it("should return user if user exists in users.json", () => {
8 | const username: string = "admin1";
9 | const userList: Record = JSON.parse(readFileSync(join("./", "users.json"), 'utf8'));
10 | expect(userList[username].username === "").toBeFalsy();
11 | expect(User.getUser(username).username === "").toBeFalsy();
12 | });
13 |
14 | it("should return user defaults if user doesn't exist", () => {
15 | const username: string = "user_dont_exist";
16 | expect(User.getUser(username) === UsersDefaults).toBeTruthy();
17 | });
18 | });
--------------------------------------------------------------------------------
/auth0_mock/tests/utils.ts:
--------------------------------------------------------------------------------
1 | // import request from "supertest";
2 |
3 | export const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms));
4 | // export function mkRequest(url)
--------------------------------------------------------------------------------
/auth0_mock/token-claims/access.ts:
--------------------------------------------------------------------------------
1 | import {Auth} from "../modules/authentication";
2 | import {JwkWrapper} from "../modules/jwk-wrapper";
3 | import {tokenDefaults} from "./token_defaults";
4 | import {IAccessTokenClaims} from "../types";
5 |
6 | // https://auth0.com/docs/secure/tokens/json-web-tokens/json-web-token-claims
7 | //
8 | // auth token claims -- claim props should be defined within scope of user aka user.json
9 | // if claim not defined in user.json then uses token default values
10 | export const accessTokenClaims = (azp: string = '', aud: string[] = []): IAccessTokenClaims => {
11 | const email = Auth.currentUser.email || tokenDefaults.email;
12 | return {
13 | iss: tokenDefaults.domain,
14 | sub: tokenDefaults.sub + email,
15 | aud: tokenDefaults.aud.concat(aud),
16 | iat: JwkWrapper.getIat(),
17 | exp: JwkWrapper.getExp(JwkWrapper.expirationDurationInMinutesAccessToken),
18 | azp,
19 | scope: Auth.currentUser.scope || tokenDefaults.defaultScope,
20 | permissions: Auth.currentUser.permissions || tokenDefaults.defaultPermissions
21 | };
22 | };
23 |
--------------------------------------------------------------------------------
/auth0_mock/token-claims/id.ts:
--------------------------------------------------------------------------------
1 | import {Auth} from "../modules/authentication";
2 | import {JwkWrapper} from "../modules/jwk-wrapper";
3 | import {tokenDefaults} from "./token_defaults";
4 | import {IIdTokenClaims} from "../types";
5 |
6 | // id token claims -- claim props should be defined within scope of user aka user.json
7 | // if claim not defined in user.json then uses token default values
8 | export const idTokenClaims = (aud: string = ''): IIdTokenClaims => {
9 | const email = Auth.currentUser.email || tokenDefaults.email;
10 | return {
11 | given_name: Auth.currentUser.given_name || tokenDefaults.given_name,
12 | family_name: Auth.currentUser.family_name || tokenDefaults.family_name,
13 | nickname: Auth.currentUser.nickname || tokenDefaults.nickname,
14 | name: Auth.currentUser.name || tokenDefaults.name,
15 | email,
16 | picture: Auth.currentUser.picture || tokenDefaults.picture,
17 | iss: tokenDefaults.domain,
18 | sub: tokenDefaults.sub + email,
19 | aud: [aud] || tokenDefaults.aud,
20 | iat: JwkWrapper.getIat(),
21 | exp: JwkWrapper.getExp(JwkWrapper.expirationDurationInMinutesIdToken),
22 | amr: tokenDefaults.amr,
23 | nonce: JwkWrapper.getNonce()
24 | };
25 | };
26 |
--------------------------------------------------------------------------------
/auth0_mock/token-claims/token_defaults.ts:
--------------------------------------------------------------------------------
1 | import {auth0Url} from "../modules/helpers"
2 | import {ITokenDefault} from "../types"
3 |
4 | export const tokenDefaults: ITokenDefault = {
5 | domain: auth0Url + '/',
6 | sub: 'samlp|MyAzure|',
7 | defaultPermissions: ['chat.admin', 'chat.user'],
8 | defaultScope: 'openid profile',
9 | aud: [process.env.AUTH0_AUDIENCE || 'app'],
10 | given_name: 'test_user_first_name',
11 | family_name: 'test_user_last_name',
12 | nickname: 'test_user_nickname',
13 | name: 'test_user',
14 | email: 'test_user@myorg.com',
15 | picture: 'https://en.gravatar.com/avatar.png',
16 | amr: ['mfa']
17 | };
18 |
--------------------------------------------------------------------------------
/auth0_mock/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "esModuleInterop": true,
5 | "target": "esnext",
6 | "noImplicitAny": true,
7 | "moduleResolution": "node",
8 | "sourceMap": true,
9 | "outDir": "dist",
10 | "baseUrl": ".",
11 | "paths": {
12 | "*": [
13 | "node_modules/*"
14 | ]
15 | }
16 | },
17 | "files": ["index.ts"]
18 | }
--------------------------------------------------------------------------------
/auth0_mock/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "defaultSeverity": "error",
3 | "extends": [
4 | "tslint:recommended"
5 | ],
6 | "jsRules": {},
7 | "rules": {
8 | "no-console": false,
9 | "trailing-comma": [
10 | false
11 | ]
12 | },
13 | "rulesDirectory": []
14 | }
--------------------------------------------------------------------------------
/auth0_mock/types.ts:
--------------------------------------------------------------------------------
1 | import jwkToBuffer from "jwk-to-pem";
2 |
3 | export interface IAuthorize {
4 | redirect_uri: string
5 | prompt: string
6 | state: string
7 | client_id?: string
8 | nonce: string
9 | audience: string
10 | }
11 |
12 | export interface ILogin {
13 | redirect?: string
14 | state?: string
15 | username: string
16 | pw: string
17 | }
18 |
19 | export interface IUsers {
20 | username: string
21 | pw: string
22 | permissions: string[]
23 | scope: string
24 | given_name: string
25 | family_name: string
26 | nickname: string
27 | name: string
28 | email: string
29 | picture: string
30 | }
31 |
32 | export interface IIdTokenClaims {
33 | given_name: string
34 | family_name: string
35 | nickname: string
36 | name: string
37 | email: string
38 | picture: string
39 | iss: string
40 | sub: string
41 | aud: string[]
42 | iat: number
43 | exp: number
44 | amr: string[]
45 | nonce?: string
46 | }
47 |
48 | export interface IAccessTokenClaims {
49 | iss: string
50 | sub: string
51 | aud: string[]
52 | iat: number
53 | exp: number
54 | azp: string
55 | scope: string
56 | permissions: string[]
57 | }
58 |
59 | export interface ITokenDefault {
60 | domain: string
61 | sub: string
62 | defaultPermissions: string[]
63 | defaultScope: string
64 | aud: string[]
65 | given_name: string
66 | family_name: string
67 | nickname: string
68 | name: string
69 | email: string
70 | picture: string
71 | amr: string[]
72 | }
73 |
74 | export const AuthorizedDefaults: IAuthorize = {
75 | redirect_uri: "",
76 | prompt: "",
77 | state: "",
78 | client_id: "",
79 | nonce: "",
80 | audience: "",
81 | };
82 |
83 | export const UsersDefaults: IUsers = {
84 | username: "",
85 | pw: "",
86 | permissions: [""],
87 | scope: "",
88 | given_name: "",
89 | family_name: "",
90 | nickname: "",
91 | name: "",
92 | email: "",
93 | picture: "",
94 | };
95 |
96 | export const LoginDefaults: ILogin = {
97 | redirect: "",
98 | state: "",
99 | username: "",
100 | pw: "",
101 | };
102 |
103 | export interface IKeyList {
104 | keys: jwkToBuffer.JWK[]
105 | }
106 |
--------------------------------------------------------------------------------
/auth0_mock/users.json:
--------------------------------------------------------------------------------
1 | {
2 | "user1": {
3 | "username": "user1",
4 | "pw": "user1",
5 | "permissions": ["user"],
6 | "scope": "openid profile email offline_access",
7 | "given_name": "John",
8 | "family_name": "Doe",
9 | "nickname":"JD",
10 | "name":"John Doe",
11 | "email":"john.doe@unknown.com",
12 | "picture":"https://s.gravatar.com/avatar/4cf8395b3f38515aa3144ccef5a49800?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fjd.png"
13 | },
14 | "admin1":{
15 | "username":"admin1",
16 | "pw":"admin1",
17 | "permissions":["admin"],
18 | "scope":"openid profile email offline_access",
19 | "given_name":"Bob",
20 | "family_name":"Builder",
21 | "nickname":"Bob",
22 | "name":"Bob Builder",
23 | "email":"bob.builder@build.com",
24 | "picture":"https://s.gravatar.com/avatar/50a7070e1892b9227579b318cd8b677b?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fpr.png"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/dc-auth0-host.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | auth0_mock:
4 | container_name: "${AUTH0_CONTAINER_NAME-auth0_mock}"
5 | stdin_open: true
6 | tty: true
7 | build:
8 | context: ./auth0_mock
9 | dockerfile: Dockerfile
10 | networks:
11 | devnet:
12 | ports:
13 | - "${AUTH0_HOST_PORT-3001}:3001"
14 | command: yarn run start
15 | environment:
16 | NODE_ENV: dev
17 | DEBUG: nodejs-docker-express:*
18 | AUTH0_DOMAIN:
19 | AUTH0_AUDIENCE:
20 | AUTH0_DEFAULT_USER:
21 | AUTH0_DEFAULT_PASSWORD:
22 | AUTH0_ACCESS_TOKEN_EXP:
23 | AUTH0_ID_TOKEN_EXP:
24 |
25 | networks:
26 | devnet:
27 | name: ${DEVNET_NAME-devnet}
28 | external: true
29 |
--------------------------------------------------------------------------------
/dc-auth0-local-users.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | auth0_mock:
4 | volumes:
5 | - ${HOST_PROJECT_PATH-.}/${AUTH0_LOCAL_USERS_FILE}:/usr/local/app/users-local.json
6 |
--------------------------------------------------------------------------------
/dc-auth0.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | auth0_mock:
4 | container_name: "${AUTH0_CONTAINER_NAME-auth0_mock}"
5 | stdin_open: true
6 | tty: true
7 | build:
8 | context: ./auth0_mock
9 | dockerfile: Dockerfile
10 | networks:
11 | devnet:
12 | command: yarn run start
13 | environment:
14 | NODE_ENV: dev
15 | DEBUG: nodejs-docker-express:*
16 | AUTH0_DOMAIN:
17 | AUTH0_AUDIENCE:
18 | AUTH0_DEFAULT_USER:
19 | AUTH0_DEFAULT_PASSWORD:
20 | AUTH0_ACCESS_TOKEN_EXP:
21 | AUTH0_ID_TOKEN_EXP:
22 |
23 | networks:
24 | devnet:
25 | name: ${DEVNET_NAME-devnet}
26 | external: true
27 |
--------------------------------------------------------------------------------
/dc-dns.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | dev:
4 | dns:
5 | - ${GDC_DNS_PRI_IP}
6 | - ${GDC_DNS_SEC_IP}
--------------------------------------------------------------------------------
/dc-host-custom-mount.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | dev:
4 | volumes:
5 | - ${HOST_CUSTOM_MOUNT}:/host_custom_mount
6 |
--------------------------------------------------------------------------------
/dc-host-home-dir-rw.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | dev:
4 | volumes:
5 | - ~:/root/home-host # read write home dir mounted inside container
6 |
--------------------------------------------------------------------------------
/dc-host-home-dir.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | dev:
4 | volumes:
5 | - ~:/root/home-host:ro # needed to copy .aws and bin folder from your home if enabled and they exists
6 |
--------------------------------------------------------------------------------
/dc-host-workspace-dir.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | dev:
4 | volumes:
5 | - ${HOST_PROJECT_PATH-.}:/workspace
6 |
--------------------------------------------------------------------------------
/dc-ls-host-dns.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | localstack:
4 | ports:
5 | - "${LOCALSTACK_HOST_DNS_PORT}:53" # only required for Pro dns proxy
6 | - "${LOCALSTACK_HOST_DNS_PORT}:53/udp" # only required for Pro dns proxy
7 |
--------------------------------------------------------------------------------
/dc-ls-host.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | localstack:
4 | ports:
5 | - "4566:4566" # LocalStack Gateway
6 | - "4510-4560:4510-4560" # external services port range
7 | - "8001:8080" # only required for Pro
8 | - "443:443" # LocalStack HTTPS Gateway (required for Pro)
9 | - "4571:4571" # elasticsearch service
10 | environment:
11 | - LOCALSTACK_HOST=${LOCALSTACK_HOST-localhost.localstack.cloud:4566}
12 | - GATEWAY_LISTEN=${LOCALSTACK_GATEWAY_LISTEN-0.0.0.0:4566,0.0.0.0:443}
13 |
--------------------------------------------------------------------------------
/dc-ls-persist.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | localstack:
4 | environment:
5 | - PERSISTENCE=1
6 |
7 |
--------------------------------------------------------------------------------
/dc-ls-pro.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | localstack:
4 | environment:
5 | - LOCALSTACK_API_KEY=${LOCALSTACK_API_KEY-}
6 | - LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN-}
7 |
--------------------------------------------------------------------------------
/dc-ls-shared.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | localstack:
4 | volumes:
5 | - shared:/shared # persisted and shared between stacks / containers
6 |
7 | volumes:
8 | shared: # this volume is persisted and shared between all stacks
9 | name: shared
10 | external: true
11 |
--------------------------------------------------------------------------------
/dc-ls-static-ip.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | localstack:
4 | networks:
5 | devnet:
6 | ipv4_address: ${LOCALSTACK_STATIC_IP}
7 |
--------------------------------------------------------------------------------
/dc-ls.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | localstack:
4 | image: "${LS_IMAGE-localstack/localstack}:${LS_VERSION-latest}"
5 | container_name: "${LS_MAIN_CONTAINER_NAME-localstack}"
6 | stdin_open: true
7 | tty: true
8 | networks:
9 | devnet:
10 | environment:
11 | - DOCKER_HOST=unix:///var/run/docker.sock
12 | - MAIN_CONTAINER_NAME=${LS_MAIN_CONTAINER_NAME-localstack}
13 | - EXTRA_CORS_ALLOWED_ORIGINS=*
14 | - DISABLE_CORS_CHECKS=1
15 | - DEBUG=${DEBUG-}
16 | - LS_LOG=${LS_LOG-}
17 | # how long to keep idle lambdas around
18 | - LAMBDA_RUNTIME_ENVIRONMENT_TIMEOUT=15
19 | # remove idle lambdas
20 | - LAMBDA_REMOVE_CONTAINERS=1
21 | # Tell Localstack to put Lambda containers on the same shared network
22 | - LAMBDA_DOCKER_NETWORK=${DEVNET_NAME-devnet}
23 | - KINESIS_ERROR_PROBABILITY=${KINESIS_ERROR_PROBABILITY-}
24 | # enable IAM checks. Only takes action if IAM_SOFT_MODE=0
25 | - ENFORCE_IAM=${LS_ENFORCE_IAM-1}
26 | # only check IAM do not enforce it
27 | - IAM_SOFT_MODE=${LS_IAM_SOFT_MODE-1}
28 | - OPENSEARCH_ENDPOINT_STRATEGY=port
29 | - PROVIDER_OVERRIDE_CLOUDWATCH=v2
30 | - DYNAMODB_REMOVE_EXPIRED_ITEMS=1
31 | - DNS_NAME_PATTERNS_TO_RESOLVE_UPSTREAM=${LS_DNS_NAME_PATTERNS_TO_RESOLVE_UPSTREAM}
32 | volumes:
33 | - "/var/run/docker.sock:/var/run/docker.sock"
34 | - "${LOCALSTACK_VOLUME_DIR:-/tmp/ls_volume}:/var/lib/localstack"
35 |
36 | networks:
37 | devnet:
38 | name: ${DEVNET_NAME-devnet}
39 | external: true
40 |
--------------------------------------------------------------------------------
/dc-proxy-dump.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | proxy:
4 | command: mitmdump --set block_global=false --set flow_detail=3
5 |
--------------------------------------------------------------------------------
/dc-proxy-host.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | proxy:
4 | ports:
5 | - "${PROXY_HOST_PORT-8080}:8080"
6 |
--------------------------------------------------------------------------------
/dc-proxy-web-host.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | proxy:
4 | ports:
5 | - "${PROXY_WEB_HOST_PORT-8081}:8081"
6 | command: mitmweb --web-iface 0.0.0.0 --web-host 0.0.0.0
7 |
--------------------------------------------------------------------------------
/dc-proxy-web.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | proxy:
4 | command: mitmweb --web-iface 0.0.0.0 --web-host 0.0.0.0
5 |
--------------------------------------------------------------------------------
/dc-proxy.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | proxy:
4 | image: "mitmproxy/mitmproxy:${PROXY_VERSION-latest}"
5 | container_name: "${PROXY_CONTAINER_NAME-proxy}"
6 | stdin_open: true
7 | tty: true
8 | dns:
9 | - ${GDC_DNS_PRI_IP}
10 | - ${GDC_DNS_SEC_IP}
11 | networks:
12 | devnet:
13 | volumes:
14 | - "${PROXY_VOLUME_DIR:-/tmp/mitmproxy}:/home/mitmproxy/.mitmproxy"
15 |
16 |
17 | networks:
18 | devnet:
19 | name: ${DEVNET_NAME-devnet}
20 | external: true
21 |
--------------------------------------------------------------------------------
/dc-ssh-agent.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | dev:
4 | environment:
5 | - SSH_AUTH_SOCK=/var/run/ssh-agent.sock
6 | volumes:
7 | - ${SSH_AUTH_SOCK}:/var/run/ssh-agent.sock # attach ssh agent socket inside container
8 |
--------------------------------------------------------------------------------
/dc-ssh.yml:
--------------------------------------------------------------------------------
1 |
2 | services:
3 | dev:
4 | ports:
5 | - "${SSH_SERVER_PORT}:22"
6 |
--------------------------------------------------------------------------------
/docker-config.json:
--------------------------------------------------------------------------------
1 | { "credsStore": "ecr-login" }
2 |
--------------------------------------------------------------------------------
/docs/auth0/readme.md:
--------------------------------------------------------------------------------
1 | # Auth0 Mock
2 |
3 | The Auth0 Mock is a container that emulates an auth0 login prompt and backend.
4 | Users login via its login page and are authenticated against info in one of 2 json files.
5 | if `users-local.json` is present it will be used, otherwise `users.json` will be used.
6 |
7 | `users.json` / `users-local.json` file format:
8 |
9 | ```json
10 | {
11 | "user1": {
12 | "username": "user1",
13 | "pw": "user1",
14 | "permissions": ["user"],
15 | "scope": "openid profile email",
16 | "given_name": "John",
17 | "family_name": "Doe",
18 | "nickname":"JD",
19 | "name":"John Doe",
20 | "email":"john.doe@unknown.com",
21 | "picture":"https://s.gravatar.com/avatar/4cf8395b3f38515aa3144ccef5a49800?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fjd.png"
22 | },
23 | "admin1":{
24 | "username":"admin1",
25 | "pw":"admin1",
26 | "permissions":["admin"],
27 | "scope":"openid profile email",
28 | "given_name":"Bob",
29 | "family_name":"Builder",
30 | "nickname":"Bob",
31 | "name":"Bob Builder",
32 | "email":"bob.builder@build.com",
33 | "picture":"https://s.gravatar.com/avatar/50a7070e1892b9227579b318cd8b677b?s=480&r=pg&d=https%3A%2F%2Fcdn.auth0.com%2Favatars%2Fpr.png"
34 | }
35 | }
36 | ```
37 |
38 | You can go to http://host.docker.internal:3001/ to see a list of all supported routes.
39 |
40 | The login page is located at http://host.docker.internal:3001/authorize?redirect_uri=YOUR_CALLBACK_URL
41 | YOUR_CALLBACK_URL should be the url of your application that is expecting the auth0 response.
42 |
43 |
--------------------------------------------------------------------------------
/docs/aws_ident/images/access_keys.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/access_keys.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/add_mfa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/add_mfa.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/change_pw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/change_pw.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/close_button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/close_button.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/login.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/manage_mfa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/manage_mfa.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/mfa_account_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/mfa_account_name.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/mfa_app_screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/mfa_app_screen.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/mfa_codes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/mfa_codes.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/my_sec_creds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/my_sec_creds.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/new_access_key.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/new_access_key.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/select_iam.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/select_iam.png
--------------------------------------------------------------------------------
/docs/aws_ident/images/show_qr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_ident/images/show_qr.png
--------------------------------------------------------------------------------
/docs/aws_ident/readme.md:
--------------------------------------------------------------------------------
1 | # Setting up MFA for the Identity Account.
2 |
3 | Open a browser to the following URL: [https://YOURSITE.signin.aws.amazon.com/console](https://YOURSITE.signin.aws.amazon.com/console)
4 | Replacing YOURSITE with your site info.
5 |
6 | Enter the username and password that were provided to you.
7 |
8 | 
9 |
10 | On first login you may be prompted to change your password. (Note this login is separate from your SSO login. You may use same password if you want, just know that your SSO login and identity login are managed separately as well as MFA)
11 |
12 | 
13 |
14 | Your console will look like the picture below. Please click on the IAM service.
15 |
16 | 
17 |
18 | Click the "Add MFA" button. This will take you to the "My Security Credential" page where you will be able to change
19 | your IAM password, create and delete your AWS access key, and set up your MFA device.
20 |
21 | 
22 |
23 | Click on the "Assign MFA device" button. This is very important as well as creating the Access key, otherwise, you won't
24 | be able to establish an AWS session via ssm-ssh.
25 |
26 | 
27 |
28 | After you click the MFA device make your you select Virtual MFA device and click the continue button as shown below:
29 |
30 | 
31 |
32 | Click on the Show QR code, so you can scan it with your MFA Authenticator such as Microsoft Authenticator, DUO Mobile or Google Authenticator.
33 |
34 | 
35 |
36 | In this example I am using an iPhone to scan the QR code with DUO Mobile. The mfa.usr is an example.
37 |
38 | Your username will appear here.
39 |
40 | 
41 |
42 | Once you set IAM MFA account on your mobile type two consecutive MFA codes to finalize the MFA setup as shown below:
43 |
44 | 
45 |
46 | Your aws-identity MFA account would look similar to the following picture once you type the two consecutive codes.
47 |
48 | 
49 |
50 | Click on the close button
51 |
52 | 
53 |
54 | # Creating AWS access keys
55 |
56 | Click on the "Create access key" button
57 |
58 | 
59 |
60 | A new set of AWS access keys will be generated. Click the "Download .csv file" button. *You must download before closing the screen. There is no way to retrieve the keys after the page is closed.***
61 |
62 | 
63 |
64 | # Setting up local AWS credentials
65 |
66 | Opening the csv file you downloaded from previous step should show something like the following: (note your values will be different)
67 |
68 | 
69 |
70 | In your home directory create a folder named ".aws" if you don't already have one.
71 | Then create or edit a file named credentials in that folder with the following structure:
72 | Replacing
73 | * mfa.user with your aws username.
74 | * aws_access_key_id with value from csv in the "Access key ID" column.
75 | * aws_secret_access_key with the value from csv in the "Secret access key" column.
76 |
77 | The localstack section should be kept as is.
78 |
79 | ```ini
80 | [mfa.user-identity]
81 | aws_access_key_id=AKIATHSY35ZK3P3YEGHZ
82 | aws_secret_access_key=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
83 |
84 | [localstack]
85 | aws_access_key_id=test
86 | aws_secret_access_key=test
87 | ```
88 | Next create or edit a file named config in that folder with the following structure:
89 | Replacing
90 | * mfa.user with your aws username.
91 |
92 | The localstack section should be kept as is.
93 | ```ini
94 | [profile mfa.user-identity]
95 | region=us-west-2
96 | output=json
97 |
98 | [profile localstack]
99 | region=us-east-1
100 | output=text
101 | ```
102 |
103 | # Managing password, MFA, and access keys
104 |
105 | Use the following link to update your password, MFA, and access keys:
106 | [My security credentials](https://us-east-1.console.aws.amazon.com/iam/home#/security_credentials)
107 |
108 |
--------------------------------------------------------------------------------
/docs/aws_sso/images/aws_login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_sso/images/aws_login.png
--------------------------------------------------------------------------------
/docs/aws_sso/images/aws_mfa_done.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_sso/images/aws_mfa_done.png
--------------------------------------------------------------------------------
/docs/aws_sso/images/aws_mfa_name.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_sso/images/aws_mfa_name.png
--------------------------------------------------------------------------------
/docs/aws_sso/images/aws_mfa_qr.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_sso/images/aws_mfa_qr.png
--------------------------------------------------------------------------------
/docs/aws_sso/images/aws_new_mfa.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_sso/images/aws_new_mfa.png
--------------------------------------------------------------------------------
/docs/aws_sso/images/aws_new_user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_sso/images/aws_new_user.png
--------------------------------------------------------------------------------
/docs/aws_sso/images/invite-email-body.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_sso/images/invite-email-body.png
--------------------------------------------------------------------------------
/docs/aws_sso/images/invite-email-subject.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/aws_sso/images/invite-email-subject.png
--------------------------------------------------------------------------------
/docs/aws_sso/readme.md:
--------------------------------------------------------------------------------
1 | # AWS SSO LOG IN Process
2 |
3 | You should receive an AWS invite email in your inbox once your SSO account is created that will look as follows:
4 |
5 | 
6 |
7 | 
8 |
9 | Once you click on the accept invitation you will be directed to create a new password as shown below:
10 |
11 | 
12 |
13 | To log into AWS SSO please go to this website: [https://YOURSITE.awsapps.com/start](https://YOURSITE.awsapps.com/start)
14 | Replace YOURSITE with your correct url.
15 |
16 | You will be directed to the logon page where you will be entering your username in the recommended format: firstname.lastname.
17 |
18 | Example:
19 |
20 | 
21 |
22 | In the next page, you will be asked to register your MFA (Multi Factor Authenticator) device to access your AWS account.
23 |
24 | 
25 |
26 | You can use any MFA authenticator such as DUO Mobile, Microsoft Authenticator, Google Authenticator to add the AWS MFA account with QR Code as shown below:
27 |
28 | 
29 |
30 | 
31 |
32 |
33 | This is how it looks in DUO after you type the name of the account:
34 |
35 | 
36 |
37 | Once you type the MFA code it may ask you to reset the password if this is your first logging into AWS SSO.
38 |
--------------------------------------------------------------------------------
/docs/bitwarden/images/pop-out.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/bitwarden/images/pop-out.png
--------------------------------------------------------------------------------
/docs/container_dev/images/GenericDevContainer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/container_dev/images/GenericDevContainer.png
--------------------------------------------------------------------------------
/docs/container_dev/images/compose_v2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/container_dev/images/compose_v2.png
--------------------------------------------------------------------------------
/docs/container_dev/images/ddesktop-container.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/container_dev/images/ddesktop-container.png
--------------------------------------------------------------------------------
/docs/container_dev/images/ddesktop-memory.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/container_dev/images/ddesktop-memory.png
--------------------------------------------------------------------------------
/docs/container_dev/images/ddesktop-wsl2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/container_dev/images/ddesktop-wsl2.png
--------------------------------------------------------------------------------
/docs/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | ## Bare Minimum
4 | 1. Create new branch
5 | 2. Change files
6 | 3. Update the version for the `DEV_CONTAINER` variable in the [docker-compose.yml](../docker-compose.yml) file to the next version
7 | 4. Do a PR
8 | 5. Merge the PR
9 | 6. Checkout and pull latest main
10 | 7. Create a new tag with the latest version.
11 | The tag version starts with a "v", and the `DEV_CONTAINER` version variable does not.
12 | ```shell
13 | git checkout main
14 | git pull
15 | git tag -a v -m
16 | ```
17 | 8. Push the tag
18 | ```shell
19 | git push --tags
20 | ```
21 |
22 | NOTE - We only bump the `DEV_CONTAINER` version and cut a tag
23 | version when the code for the GDC changes. For example, we don't cut new tags for README-only changes.
24 |
--------------------------------------------------------------------------------
/docs/cypress/images/cypress-error-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/cypress/images/cypress-error-1.png
--------------------------------------------------------------------------------
/docs/cypress/images/xquartz-settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devxpod/GDC/b6234bab2507ae2aa29605e0bf59b50818dd083c/docs/cypress/images/xquartz-settings.png
--------------------------------------------------------------------------------
/docs/cypress/readme.md:
--------------------------------------------------------------------------------
1 | # Cypress End-to-End Testing
2 |
3 | ## Table of Contents
4 |
5 | - [Overview](#overview)
6 | - [Getting Started](#getting_started)
7 | - [Interactive Mode](#interactive_mode)
8 | - [Troubleshooting](#troubleshooting)
9 |
10 | ## Overview
11 | Cypress End-to-End Testing is a powerful testing framework that allows you to automate and validate the behavior of your web applications. It provides an intuitive and developer-friendly interface for creating tests, making it easier to catch bugs and ensure the quality of your application.
12 |
13 | With Cypress, you can simulate real user interactions, such as clicking buttons, filling out forms, and navigating between pages. It runs directly in the browser, allowing you to observe and debug your tests in real-time, which significantly speeds up the development and debugging process.
14 |
15 | ## Getting Started
16 | To start using Cypress in your project with the GDC, follow the steps below:
17 | 1. Create a `.env-gdc` file in the root directory of your project repository and add the following environment variables:
18 | ```
19 | export EXTRA_PACKAGES="libgtk2.0-0 libgtk-3-0 libgbm-dev libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb"
20 |
21 | # only needed for interactive mode
22 | export GDC_ENV_DISPLAY="host.docker.internal:0"
23 | ```
24 | **Note:** The `EXTRA_PACKAGES` environment variable must be set as shown to run headless tests. Additionally, setting the `GDC_ENV_DISPLAY` environment variable configures the GDC for Cypress Interactive Mode.
25 |
26 |
27 | 2. For new projects, the GDC is configured and ready to be used with Cypress. Follow the [Cypress documentation](https://docs.cypress.io/guides/getting-started/installing-cypress) for installing and using Cypress. For existing projects, stop the GDC (if running) and restart it using the command below. Doing so will clear the GDC build cache and allow the Cypress dependencies (`EXTRA_PACKAGES`) to be downloaded and installed during the next build process.
28 | ```
29 | CLEAN=yes run-dev-container.sh
30 | ```
31 |
32 | ## Interactive Mode
33 | With Cypress installed in the GDC, you may use Interactive Mode with the GDC by following the steps below:
34 |
35 | ### macOS
36 | 1. Install XQuartz on your host machine:
37 | ```
38 | brew install --cask xquartz
39 | ```
40 | 2. Run XQuartz on your host machine:
41 | ```
42 | open -a XQuartz
43 | ```
44 | 3. From your host machine's Apple menu, select **XQuartz > Settings...**
45 |
46 |
47 | 4. Select the `Security` tab and ensure that **Allow connections from network clients** is enabled.
48 | 
49 |
50 |
51 | 5. From within the terminal of your host machine, add the GDC address to X11 server access control list by running the following command:
52 | ```
53 | /usr/X11/bin/xhost + host.docker.internal
54 | ```
55 | 6. From the GDC terminal, change into your UI project directory containing the `package.json` file and Cypress installation.
56 |
57 |
58 | 7. Start your development server.
59 |
60 |
61 | 8. Run `npx cypress open`, `yarn run cypress open`, or any command for a custom script listed within your `package.json` file.
62 | ### Windows
63 |
64 | 1. Download and install VcXsrv Windows X Server onto your host machine from [SourceForge.net](https://sourceforge.net/projects/vcxsrv/).
65 |
66 |
67 | 2. Run VcXsrv Windows X Server on your host machine.
68 |
69 |
70 | 3. Add `host.docker.internal` to the server's access control list.
71 |
72 |
73 | 4. From the GDC terminal, change into your UI project directory containing the `package.json` file and Cypress installation.
74 |
75 |
76 | 5. Start your development server.
77 |
78 |
79 | 6. Run `npx cypress open`, `yarn run cypress open`, or any command for a custom script listed within your `package.json` file.
80 |
81 | ## Troubleshooting
82 |
83 | ### Cypress Failed to Start
84 | 
85 |
86 | 1. If you encounter a missing library or dependency error like the one depicted above, try running the following command from the terminal on your host machine, followed by re-attempting to run Interactive Mode from within the GDC terminal:
87 | ```
88 | xhost + host.docker.internal
89 | ```
90 | **Note:** If the xhost command is not found, it may not be listed in your path. Try `/usr/X11/bin/xhost`.
91 |
92 |
93 | 2. Ensure that `host.docker.internal` in your hosts file on your local machine is pointing to `127.0.0.1`. For macOS, the hosts file is located at `/etc/hosts`. For Windows, the hosts file is located at `c:\windows\system32\drivers\etc\hosts`.
94 |
95 | **NOTE**: Admin permissions are required to edit the hosts file. Use `sudo` for macOS. For Windows, edit the file as an administrator.
96 |
--------------------------------------------------------------------------------
/docs/debugging/readme.md:
--------------------------------------------------------------------------------
1 | # Debugging
2 |
3 | ## Python
4 | ### Pycharm
5 | In **PyCharm** IDE go to `Run->Edit Configurations`
6 | Click the + in top left and select `Python Debug Server`
7 | Give it a name of `gdc-python-debug`
8 | `IDE host name` = `host.docker.internal`
9 | `Port = 12345`
10 | Put check in `Redirect output to console`
11 | Uncheck `Suspend after connect`
12 | Click the folder icon to the right of `Path mappings` and click the + to add a new one
13 | `Local Path` =