diff --git a/.codeclimate.yml b/.codeclimate.yml
index 1891493f0d..af9d856f0d 100644
--- a/.codeclimate.yml
+++ b/.codeclimate.yml
@@ -22,15 +22,14 @@ exclude_patterns:
- "src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/submission/mappers/SubmissionMapper.java"
- "src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/submission/service/SubmissionService.java"
- "src/backend/efiling-backend-demo/src/main/java/ca/bc/gov/open/jag/efilingbackenddemo/EfilingBackendDemoApplication.java"
- - "src/backend/efiling-worker/src/main/java/ca/bc/gov/open/jag/efilingworker/EfilingWorkerApplication.java"
- - "src/backend/efiling-worker/src/main/java/ca/bc/gov/open/jag/efilingworker/service/DocumentStoreService.java"
- "src/backend/libs/efiling-lookup-client/src/main/java/ca/bc/gov/open/jag/efilinglookupclient/EfilingLookupService.java"
- "src/backend/libs/efiling-status-client/src/main/java/ca/bc/gov/open/jag/efilingstatusclient/EfilingStatusService.java"
- "src/backend/libs/efiling-submission-client/src/main/java/ca/bc/gov/open/jag/efilingsubmissionclient/EfilingSubmissionService.java"
+ - "src/backend/**/test/**"
# Frontend Pattern Excludes
- "src/frontend/*/src/*.js"
+ - "src/frontend/*/src/components/hoc/*.js"
- "src/frontend/efiling-frontend/src/modules/confirmationPopupTestData.js"
- - "src/frontend/shared-components/src/modules/termsOfUseTestData.js"
- "src/frontend/*/public/"
- "src/frontend/*/.storybook/"
diff --git a/.env.template b/.env.template
index d36f8fa712..2fdda5001d 100644
--- a/.env.template
+++ b/.env.template
@@ -1,4 +1,15 @@
-MVN_PROFILE=demo
+DEMO_MODE=
+MVN_PROFILE=
+SERVER_PORT=8080
+
+# KEYCLOAK CONFIG
+KEYCLOAK_SSL_REQUIRED=none
+KEYCLOAK_RESOURCE=efiling-api
+KEYCLOAK_URL=http://localhost:8081/auth
+KEYCLOAK_REALM=Efiling-Hub
+KEYCLOAK_CREDENTIALS_SECRET=
+KEYCLOAK_AUTH_SERVER_URL=
+
CSO_ACCOUNTFACADE_URI=
CSO_ACCOUNTFACADE_USERNAME=
CSO_ACCOUNTFACADE_PASSWORD=
@@ -8,6 +19,43 @@ CSO_ROLEREGISTRY_URI=
CSO_LOOKUPFACADE_USERNAME=
CSO_LOOKUPFACADE_PASSWORD=
CSO_LOOKUPFACADE_URI=
-BCEID_LOOKUP_USERNAME=
-BCEID_LOOKUP_PASSWORD=
-BCEID_LOOKUP_URI=
+CSO_BCEIDSERVICE_URI=
+CSO_BCEIDSERVICE_USERNAME=
+CSO_BCEIDSERVICE_PASSWORD=
+CSO_FILINGSTATSFACADE_URI=
+CSO_FILINGSTATSFACADE_USERNAME=
+CSO_FILINGSTATSFACADE_PASSWORD=
+CSOWS_USERNAME=
+CSOWS_PASSWORD=
+CSOWS_URI=
+CSO_FILINGFACADE_URI=
+CSO_FILINGFACADE_PASSWORD=
+CSO_FILINGFACADE_USERNAME=
+CSO_SERVICEFACADE_URI=
+CSO_SERVICEFACADE_USERNAME=
+CSO_SERVICEFACADE_PASSWORD=
+CSO_FILE_SERVER_HOST=
+CSO_DEBUG_ENABLED=true
+
+CEIS_BASE_PATH=
+CEIS_USERNAME=BLANK?
+CEIS_PASSWORD=BLANK?
+
+BAMBORA_APIPASSCODE=
+BAMBORA_APIBASEPATH=
+BAMBORA_MERCHANTID=
+BAMBORA_PROFILE_URL=
+BAMBORA_HASHKEY=
+BAMBORA_PROFILE_SERVICE_VERSION=
+BAMBORA_URL_EXPIRY=
+
+MAIL_SEND_BASE_URL=
+
+SFTP_KNOWNHOSTS=
+SFTP_REMOTELOCATION=
+SFTP_PRIVATE_KEY=
+
+BCEID_SERVICE_URI=
+BCEID_SERVICE_USERNAME=
+BCEID_SERVICE_PASSWORD=
+BCEID_SERVICE_ONLINE_SERVICE_ID=
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000000..8cd5aff5be
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+*.sh text eol=lf
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000000..dd84ea7824
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,38 @@
+---
+name: Bug report
+about: Create a report to help us improve
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**To Reproduce**
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
+
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000000..bbcbbe7d61
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,20 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Describe alternatives you've considered**
+A clear and concise description of any alternative solutions or features you've considered.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/ISSUE_TEMPLATE/onboarding-request.md b/.github/ISSUE_TEMPLATE/onboarding-request.md
new file mode 100644
index 0000000000..cdbd8d031b
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/onboarding-request.md
@@ -0,0 +1,15 @@
+---
+name: Onboarding Request
+about: Request for access to Efiling Hub API and Frontend
+title: "[ONBOARDING]"
+labels: Onboarding
+assignees: akroon3r, alexjoybc
+
+---
+
+After this issue has been opened, please provide the following information:
+
+- contact email that admins can reach you at
+- a brief description of what you're looking to accomplish by integrating with the efiling-hub
+- a link to github repository of the application that is requesting access to the efiling-hub
+- a list of the types of documents you're looking to upload to the efiling-hub
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index c6abd64c51..bf3d702442 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -5,10 +5,16 @@ updates:
directory: "/src/backend"
schedule:
interval: "daily"
- time: "18:00"
- # npm dependencies
+ time: "05:00"
+ # npm dependencies - frontend
- package-ecosystem: "npm"
- directory: "/src/frontend"
+ directory: "/src/frontend/efiling-frontend"
schedule:
interval: "daily"
- time: "18:00"
+ time: "05:00"
+ # npm dependencies - demo
+ - package-ecosystem: "npm"
+ directory: "/src/frontend/efiling-demo"
+ schedule:
+ interval: "daily"
+ time: "05:00"
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 7573b2a19d..e3477f936c 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -9,6 +9,7 @@ This PR includes the following proposed change(s):
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Refactoring / Documentation
+- [ ] Version change
if your change is a breaking change, please add `breaking change` label to this PR
@@ -16,6 +17,16 @@ if your change is a breaking change, please add `breaking change` label to this
Please describe the tests that you ran to verify your changes.
+## Does the change impact or break the Docker build?
+
+- [ ] Yes
+- [ ] No
+
+If Yes: Has Docker been updated accordingly?
+
+- [ ] Yes
+- [ ] No
+
## Checklist:
- [ ] My code follows the style guidelines of this project
diff --git a/.github/workflows/code-climate-coverage-aggregation.yml b/.github/workflows/code-climate-coverage-aggregation.yml
index 9fed1b0124..2e7ce1b7c7 100644
--- a/.github/workflows/code-climate-coverage-aggregation.yml
+++ b/.github/workflows/code-climate-coverage-aggregation.yml
@@ -10,90 +10,30 @@ jobs:
yarn:
env:
FILE_COUNTER: 0
- CC_TEST_REPORTER_ID: 9ada3133fe9babf91a222009998b3545b7eae897a05900930bfa8a27fd82f385
ACTION_DEBUG: true
- name: Create, format and upload Javascript coverage artifact
+ name: Build and Test React Apps
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v2
-
- # Get Code Climate binary
- - name: Download Code Climate Binary
- run: curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
-
- # Permissions applied to the Code Climate Executable
- - name: Apply executable perms to Code Climate Binary
- run: chmod +x ./cc-test-reporter
-
- # Before build
- - name: Before build
- run: ./cc-test-reporter before-build
-
- # Set required Git env vars for either pull request
- - name: Set ENV for codeclimate (pull_request)
- run: |
- echo "::set-env name=GIT_BRANCH::${{ github.event.pull_request.head.ref }}"
- echo "::set-env name=GIT_COMMIT_SHA::${{ github.event.pull_request.head.sha }}"
- if: github.event_name == 'pull_request'
-
- # Set required Git env vars for a push to master
- - name: Set ENV for codeclimate (push)
- run: |
- echo "::set-env name=GIT_BRANCH::$GITHUB_REF"
- echo "::set-env name=GIT_COMMIT_SHA::$GITHUB_SHA"
- if: github.event_name == 'push'
-
- # Trimming the ref to master in order to publish correct report (paambaati)
- - name: Set ref/head/master to master
- run: |
- echo "::set-env name=GIT_BRANCH::master"
- if: env.GIT_BRANCH == 'refs/heads/master'
+ - uses: actions/checkout@v4
+ - name: Printing node and yarn versions
+ run: node --version && yarn --version
# Figure out where yarn is caching things
- name: Yarn Cache
run: yarn cache dir
- # Implement Caching Action for Yarn Project
- - name: Cache node modules
- uses: actions/cache@v2
- env:
- cache-name: cache-node-modules
- with:
- # YARN cache files are stored in `/home/runner/.cache/yarn/v6` on git actions
- path: /home/runner/.cache/yarn/v6
- key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
- restore-keys: |
- ${{ runner.os }}-build-${{ env.cache-name }}-
- ${{ runner.os }}-build-
- ${{ runner.os }}-
-
- # Run Yarn Install - Shared Components
- - name: Run Yarn Install - Shared components
- run: yarn --cwd src/frontend/shared-components install
-
- # Yarn Coverage - Shared Components
- - name: Run Yarn Coverage - Shared components
- run: yarn --cwd /home/runner/work/jag-file-submission/jag-file-submission/src/frontend/shared-components coverage
-
# Run Yarn Install - eFiling Frontend
- name: Run Yarn Install - eFiling Frontend
run: yarn --cwd src/frontend/efiling-frontend install
- # Install link local globally
- - name: Install linklocal
- run: sudo npm install -g --unsafe-perm linklocal
+ # Check lint version
+ - name: Check lint - eFiling Frontend
+ run: yarn --cwd src/frontend/efiling-frontend run lint -v
- # Link react versions between apps
- - name: Run npm link
- run: |
- npm --prefix ${{ github.workspace }}/src/frontend/shared-components link ${{ github.workspace }}/src/frontend/efiling-frontend/node_modules/react
-
- # Run linklocal
- - name: Run linklocal
- run: |
- cd ${{ github.workspace }}/src/frontend/efiling-frontend
- linklocal
+ # Run lint - eFiling Frontend
+ - name: Run lint - eFiling Frontend
+ run: yarn --cwd src/frontend/efiling-frontend run lint
# Yarn Coverage - eFiling Frontend
- name: Run Yarn Coverage - eFiling Frontend
@@ -103,248 +43,87 @@ jobs:
- name: Run Yarn Install - eFiling Demo
run: yarn --cwd src/frontend/efiling-demo install
+ # Run lint - eFiling Demo
+ - name: Run lint - eFiling Demo
+ run: yarn --cwd src/frontend/efiling-demo run lint
+
# Yarn Coverage - eFiling Demo
- name: Run Yarn Coverage - eFiling Demo
run: yarn --cwd /home/runner/work/jag-file-submission/jag-file-submission/src/frontend/efiling-demo coverage
- # Formatting the FRONTEND coverage report
- - name: Format the FRONTEND coverage report
- run: |
- ./cc-test-reporter format-coverage -t lcov -o coverage/frontend-codeclimate.json ${{github.workspace}}/src/frontend/efiling-frontend/coverage/lcov.info
-
# Formatting the FRONTEND DEMO coverage report
- - name: Format the FRONTEND DEMO coverage report
- run: |
- ./cc-test-reporter format-coverage -t lcov -o coverage/frontend-demo-codeclimate.json ${{github.workspace}}/src/frontend/efiling-demo/coverage/lcov.info
-
- # Formatting the SHARED COMPONENTS coverage report
- - name: Format the SHARED COMPONENTS coverage report
- run: |
- ./cc-test-reporter format-coverage -t lcov -o coverage/shared-components-codeclimate.json ${{github.workspace}}/src/frontend/shared-components/coverage/lcov.info
-
- # List all formatted files in coverage directory
- - name: WHERE AM I - FORMATTED?
- run: |
- ls ${{ github.workspace }}/coverage
- if: ${{ env.ACTION_DEBUG }}
+ #- name: Format the FRONTEND DEMO coverage report
+ # run: |
+ # pushd .
+ # cd ${{github.workspace}}/src/frontend/efiling-demo/
+ # ${{github.workspace}}/cc-test-reporter format-coverage -t lcov -o ${{github.workspace}}/coverage/frontend-demo-codeclimate.json coverage/lcov.info
+ # popd
+ # Implement Caching Action for Yarn Project
+ - name: Cache node modules
+ uses: actions/cache@v4
+ env:
+ cache-name: cache-node-modules
+ with:
+ # YARN cache files are stored in `/home/runner/.cache/yarn/v6` on git actions
+ path: /home/runner/.cache/yarn/v6
+ key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-build-${{ env.cache-name }}-
+ ${{ runner.os }}-build-
+ ${{ runner.os }}-
- # Count of all total coverage files available
- - name: Count files present
- run: |
- echo "::set-env name=FILE_COUNTER::$(ls -1q ./coverage | wc -l )"
- # Sum the coverage reports
- - name: Summing the coverage reports generated
- run: ./cc-test-reporter sum-coverage coverage/*-codeclimate.json -p ${{ env.FILE_COUNTER }} -o coverage/total-codeclimate.json
- # Upload JSON for debugging purposes
- - name: Upload JSON for debugging purposes
- uses: actions/upload-artifact@v2
- with:
- name: summed-yarn-coverage-report
- path: coverage/total-codeclimate.json
spring-boot:
- name: Create, format and upload Java coverage artifact
+ name: Build and Test Java
runs-on: ubuntu-latest
env:
FILE_COUNTER: 0
- CC_TEST_REPORTER_ID: 9ada3133fe9babf91a222009998b3545b7eae897a05900930bfa8a27fd82f385
ACTION_DEBUG: true
steps:
- - uses: actions/checkout@v2
-
- # Get Code Climate binary
- - name: Download Code Climate Binary
- run: curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
-
- # Permissions applied to the Code Climate Executable
- - name: Apply executable perms to Code Climate Binary
- run: chmod +x ./cc-test-reporter
-
- # Before build
- - name: Before build
- run: ./cc-test-reporter before-build
-
- # Set required Git env vars for either pull request
- - name: Set ENV for codeclimate (pull_request)
- run: |
- echo "::set-env name=GIT_BRANCH::${{ github.event.pull_request.head.ref }}"
- echo "::set-env name=GIT_COMMIT_SHA::${{ github.event.pull_request.head.sha }}"
- if: github.event_name == 'pull_request'
-
- # Set required Git env vars for a push to master
- - name: Set ENV for codeclimate (push)
- run: |
- echo "::set-env name=GIT_BRANCH::$GITHUB_REF"
- echo "::set-env name=GIT_COMMIT_SHA::$GITHUB_SHA"
- if: github.event_name == 'push'
-
- # Trimming the ref to master in order to publish correct report (paambaati)
- - name: Set ref/head/master to master
- run: |
- echo "::set-env name=GIT_BRANCH::master"
- if: env.GIT_BRANCH == 'refs/heads/master'
-
+ - name: Checkout Spring Starters Repository
+ uses: actions/checkout@v4
+ with:
+ repository: bcgov/spring-boot-starters
+ path: spring-boot-starters
+ ref: v1.0.5
+
# Setup Java Environment
- - name: Set up JDK 1.8
+ - name: Set up JDK 17
uses: actions/setup-java@v1
with:
- java-version: 1.8
- - uses: actions/cache@v1
- with:
- path: ~/.m2/repository
- key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- restore-keys: |
- ${{ runner.os }}-maven-
+ java-version: 17
- # Run Maven Verify to generate all jacoco reports
- - name: Build with Maven
- run: mvn -B verify -P all --file src/backend/pom.xml
+ # TODO REMOVE AFTER SFTP IS IN MAVEN CENTRAL
+ - name: Build Spring Starters
+ run: mvn install -P all --file ./spring-boot-starters/src/pom.xml
- # Loop through all BACKEND services to show that jacoco reports have been generated
- - name: WHERE AM I - BACKEND?
- run: |
- for s in efiling-backend-demo efiling-api
- do
- ls ${{ github.workspace }}/src/backend/$s/target/site/jacoco;
- done
- if: ${{ env.ACTION_DEBUG }}
+ - name: Checkout File Submission Repository
+ uses: actions/checkout@v2
- # Formatting the BACKEND coverage reports generated (dynamically)
- - name: Format BACKEND coverage reports
- run: |
- projectRelRegex="^\.\/src\/backend\/(.*)\/target\/site\/jacoco\/jacoco\.xml$"
- for file in $(find . -name "jacoco.xml")
- do
- echo $file
- echo $projectRelRegex
- if [[ $file =~ $projectRelRegex ]]
- then
- projectRel="${BASH_REMATCH[1]}"
- echo "analyzing project: " $projectRel
- projectName="${projectRel//\//-}"
- JACOCO_SOURCE_PATH=${{ github.workspace }}/src/backend/$projectRel/src/main/java ./cc-test-reporter format-coverage ${{github.workspace}}/src/backend/$projectRel/target/site/jacoco/jacoco.xml --input-type jacoco --output coverage/$projectName-codeclimate.json;
- echo "coverage generated: coverage/$projectName-codeclimate.json;"
- else
- echo $file does not match
- fi
- done
-
- # List all formatted files in coverage directory
- - name: WHERE AM I - FORMATTED?
- run: |
- ls ${{ github.workspace }}/coverage
- if: ${{ env.ACTION_DEBUG }}
-
- # Count of all total coverage files available
- - name: Count files present
- run: |
- echo "::set-env name=FILE_COUNTER::$(ls -1q ./coverage | wc -l )"
-
- # Sum the coverage reports
- - name: Summing the coverage reports generated
- run: ./cc-test-reporter sum-coverage coverage/*-codeclimate.json -p ${{ env.FILE_COUNTER }} -o coverage/total-codeclimate.json
-
- # Upload JSON for debugging purposes
- - name: Upload JSON for debugging purposes
- uses: actions/upload-artifact@v2
- with:
- name: summed-java-coverage-report
- path: coverage/total-codeclimate.json
-
- aggregation:
- name: Aggregate Spring Boot and Javascript reports
- needs: [yarn, spring-boot]
- env:
- CC_TEST_REPORTER_ID: 9ada3133fe9babf91a222009998b3545b7eae897a05900930bfa8a27fd82f385
- runs-on: ubuntu-latest
- steps:
- # Get Code Climate binary
- - name: Download Code Climate Binary
- run: curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
-
- # Permissions applied to the Code Climate Executable
- - name: Apply executable perms to Code Climate Binary
- run: chmod +x ./cc-test-reporter
-
- # Before build
- - name: Before build
- run: ./cc-test-reporter before-build
-
- # Set required Git env vars for either pull request
- - name: Set ENV for codeclimate (pull_request)
- run: |
- echo "::set-env name=GIT_BRANCH::${{ github.event.pull_request.head.ref }}"
- echo "::set-env name=GIT_COMMIT_SHA::${{ github.event.pull_request.head.sha }}"
- if: github.event_name == 'pull_request'
-
- # Set required Git env vars for a push to master
- - name: Set ENV for codeclimate (push)
- run: |
- echo "::set-env name=GIT_BRANCH::$GITHUB_REF"
- echo "::set-env name=GIT_COMMIT_SHA::$GITHUB_SHA"
- if: github.event_name == 'push'
# Trimming the ref to master in order to publish correct report (paambaati)
- name: Set ref/head/master to master
run: |
- echo "::set-env name=GIT_BRANCH::master"
+ echo "GIT_BRANCH=master" >> $GITHUB_ENV
+ #echo "::set-env name=GIT_BRANCH::master"
if: env.GIT_BRANCH == 'refs/heads/master'
- # Make Directory for downloaded files
- - name: Make directory
- run: mkdir coverage-reports
-
- # Download Spring-boot coverage report
- - name: Download spring-boot coverage report
- uses: actions/download-artifact@v1
- with:
- name: summed-java-coverage-report
-
- # See what is inside
- - name: List items inside java coverage report object
- run: |
- ls summed-java-coverage-report
-
- # Copy total java to outside directory
- - name: Copy Java Coverage to directory
- run: |
- cp summed-java-coverage-report/total-codeclimate.json coverage-reports/total-java-codeclimate.json
-
- # Download Yarn coverage report
- - name: Download javascript coverage report
- uses: actions/download-artifact@v1
- with:
- name: summed-yarn-coverage-report
-
- # See what is inside
- - name: List items inside java coverage report object
- run: |
- ls summed-yarn-coverage-report
-
- # Copy total Yarn to outside directory
- - name: Copy Yarn Coverage to directory
- run: |
- cp summed-yarn-coverage-report/total-codeclimate.json coverage-reports/total-yarn-codeclimate.json
+ #- uses: actions/cache@v1
+ # with:
+ # path: ~/.m2/repository
+ # key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ # restore-keys: |
+ # ${{ runner.os }}-maven-
- # See what is inside coverage
- - name: List items inside java coverage report object
- run: |
- ls coverage-reports
-
- # Sum the coverage reports
- - name: Summing the coverage reports generated
- run: ./cc-test-reporter sum-coverage coverage-reports/*-codeclimate.json -p 2 -o coverage-reports/total-codeclimate.json
-
- # Upload JSON for debugging purposes
- - name: Upload JSON for debugging purposes
- uses: actions/upload-artifact@v2
+ #Set env again??
+ - name: Set up JDK 17
+ uses: actions/setup-java@v1
with:
- name: summed-total-coverage-report
- path: coverage-reports/total-codeclimate.json
+ java-version: 17
- # Upload total coverage report to Code Climate
- - name: Upload coverage report to Code Climate
- run: ./cc-test-reporter upload-coverage -i coverage-reports/total-codeclimate.json
+ # Run Maven Verify to generate all jacoco reports
+ - name: Build with Maven
+ run: mvn -B verify -P all --file src/backend/pom.xml
diff --git a/.github/workflows/cucumber-tests.yml b/.github/workflows/cucumber-tests.yml
new file mode 100644
index 0000000000..14b21ccd87
--- /dev/null
+++ b/.github/workflows/cucumber-tests.yml
@@ -0,0 +1,215 @@
+name: Cucumber Tests
+
+on:
+ pull_request:
+ branches: [ master ]
+ push:
+ branches: [ master ]
+ workflow_dispatch:
+
+jobs:
+
+ efiling-api-gcr:
+ name: Efiling Api GCR
+ runs-on: ubuntu-latest
+ steps:
+ - name: Pull Git repo.
+ uses: actions/checkout@v2
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v1
+ with:
+ registry: docker.pkg.github.com
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Pull efiling-api-builder
+ run: docker pull docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-api:builder || true
+
+ - name: build efiling-api-builder
+ run: docker build ./src/backend
+ -f ./src/backend/Dockerfile.efiling-api
+ --target build
+ -t efiling-api:builder
+ --build-arg SERVICE_NAME=efiling-api
+ --build-arg MVN_PROFILE=efiling-api-demo
+ --build-arg STARTERS_V=v1.0.5
+ --cache-from=docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-api:builder
+
+ - name: tag & push efiling-api to git container registry
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ run: docker tag efiling-api:builder docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-api:builder && docker push docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-api:builder
+
+ - name: Pull efiling-api-demo
+ run: docker pull docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-api:demo || true
+
+ - name: build efiling-api-demo
+ run: docker build ./src/backend
+ -f ./src/backend/Dockerfile.efiling-api
+ -t efiling-api:demo
+ --build-arg SERVICE_NAME=efiling-api
+ --build-arg MVN_PROFILE=efiling-api-demo
+ --build-arg STARTERS_V=v1.0.5
+ --cache-from=docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-api:builder
+ --cache-from=docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-api:demo
+
+ # Optional only for branch on repo
+ - name: tag & push efiling-api to git container registry
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ run: docker tag efiling-api:demo docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-api:demo && docker push docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-api:demo
+
+ efiling-frontend-gcr:
+ name: Efiling Frontend GCR
+ runs-on: ubuntu-latest
+ steps:
+ - name: Pull Git repo.
+ uses: actions/checkout@v2
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v1
+ with:
+ registry: docker.pkg.github.com
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Pull efiling-frontend-builder
+ run: docker pull docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-frontend:builder || true
+
+ - name: build efiling-frontend-builder
+ run: docker build ./src/frontend/efiling-frontend
+ --target build
+ -t efiling-frontend:builder
+ --cache-from=docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-frontend:builder
+
+ - name: tag & push efiling-frontend to git container registry
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ run: docker tag efiling-frontend:builder docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-frontend:builder && docker push docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-frontend:builder
+
+ - name: Pull efiling-frontend-demo
+ run: docker pull docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-frontend:demo || true
+
+ - name: build efiling-frontend-demo
+ run: docker build ./src/frontend/efiling-frontend
+ -t efiling-frontend:demo
+ --cache-from=docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-frontend:builder
+ --cache-from=docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-frontend:demo
+
+ - name: tag & push efiling-frontend to git container registry
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ run: docker tag efiling-frontend:demo docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-frontend:demo && docker push docker.pkg.github.com/$GITHUB_REPOSITORY/efiling-frontend:demo
+
+ keycloak-config-gcr:
+ name: Keycloack Config GCR
+ runs-on: ubuntu-latest
+ steps:
+ - name: Pull Git repo.
+ uses: actions/checkout@v2
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v1
+ with:
+ registry: docker.pkg.github.com
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Pull efiling-frontend-builder
+ run: docker pull docker.pkg.github.com/$GITHUB_REPOSITORY/keycloak-config:demo || true
+
+ - name: build efiling-frontend-builder
+ run: docker build ./infrastructure/keycloak
+ -t keycloak-config:demo
+ --build-arg KEYCLOAK_URL=http://keycloak:8080
+ --cache-from=docker.pkg.github.com/$GITHUB_REPOSITORY/keycloak-config:demo
+
+ - name: tag & push keycloak-config to git container registry
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ run: docker tag keycloak-config:demo docker.pkg.github.com/$GITHUB_REPOSITORY/keycloak-config:demo && docker push docker.pkg.github.com/$GITHUB_REPOSITORY/keycloak-config:demo
+
+ cucumber-tests:
+ name: Runs cucumber-tests
+ runs-on: ubuntu-latest
+ needs: [ efiling-api-gcr, efiling-frontend-gcr, keycloak-config-gcr ]
+ steps:
+ - name: Pull Git repo.
+ uses: actions/checkout@v2
+
+ # pulling images is faster than caching in most of the case
+ - name: pull available docker images first
+ run: docker compose pull -q --parallel redis clamav keycloak
+
+ - name: Standup Infra
+ run: docker compose up -d redis clamav keycloak
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v1
+ with:
+ registry: docker.pkg.github.com
+ username: ${{ github.repository_owner }}
+ password: ${{ secrets.GITHUB_TOKEN }}
+
+ - name: Cache local Maven repository
+ uses: actions/cache@v4
+ with:
+ path: ~/.m2/repository
+ key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
+ restore-keys: |
+ ${{ runner.os }}-maven-
+
+ - name: Pull images (Local REPO only)
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ run: docker compose -f docker-compose.yml -f tests/docker-compose-integration.yml pull --parallel -q efiling-api efiling-frontend keycloak-config
+
+ - name: Standup Docker Pods (Local REPO only)
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ run: docker compose -f docker-compose.yml -f tests/docker-compose-integration.yml up -d efiling-api efiling-frontend
+
+
+ - name: Standup Docker Pods (FORK only)
+ if: github.event.pull_request.head.repo.full_name != github.repository
+ run: docker compose up -d efiling-api efiling-frontend
+
+ - name: Configure keycloak (Local REPO only)
+ if: github.event.pull_request.head.repo.full_name == github.repository
+ run: |
+ docker compose -f docker-compose.yml -f tests/docker-compose-integration.yml up keycloak-config
+
+ - name: Configure keycloak (FORK only)
+ if: github.event.pull_request.head.repo.full_name != github.repository
+ run: |
+ docker compose up keycloak-config
+
+ - name: Running Integration Tests
+ env:
+ DOCKERIZE_VERSION: v0.6.1
+ continue-on-error: true
+ id: cucumber-test
+ run: |
+
+ # Maven requires chrome driver.
+ wget -q https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb
+ sudo apt-get -qq -y install ./google-chrome-stable_current_amd64.deb
+
+ # We need to test if efiling-api pod and service is running before we can proceed. Using dockerize to proceed only after efiling-demo:8080 can be reached.
+ wget -q https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
+ tar -xzvf dockerize-linux-amd64-$DOCKERIZE_VERSION.tar.gz
+
+ ./dockerize -wait http://127.0.0.1:8080/actuator/health -timeout 120s
+ mvn verify -ntp -f tests/pom.xml
+
+ # Upload Spark report for debugging purposes
+ - name: Upload Spark report for debugging purposes
+ uses: actions/upload-artifact@v4
+ with:
+ name: cucumber-spark-report
+ path: ./tests/test-output/extent/Spark/Index.html
+
+ # Upload Cucumber JSON for debugging purposes
+ - name: Upload Cucumber JSON for debugging purposes
+ uses: actions/upload-artifact@v4
+ with:
+ name: cucumber-json-report
+ path: ./tests/target/cucumber-reports/CucumberTestReport.json
+
+ - name: Set action status
+ if: steps.cucumber-test.outcome != 'success'
+ run: exit 1
diff --git a/.github/workflows/dev-efiling-admin-build.yaml b/.github/workflows/dev-efiling-admin-build.yaml
new file mode 100644
index 0000000000..793a760053
--- /dev/null
+++ b/.github/workflows/dev-efiling-admin-build.yaml
@@ -0,0 +1,104 @@
+name: Build Efiling Admin Docker Image and Push to Openshift Image Registry
+
+on:
+ schedule:
+ - cron: "0 0 * */3 *"
+ push:
+ branches: [master]
+ paths:
+ - "src/frontend/efiling-demo/**"
+ - ".github/workflows/dev-efiling-admin-build.yaml"
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Login to Artifactory
+ uses: docker/login-action@v1
+ with:
+ registry: artifacts.developer.gov.bc.ca
+ username: ${{ secrets.EFILING_ARTIFACTORY_USERNAME }}
+ password: ${{ secrets.EFILING_ARTIFACTORY_PASSWORD }}
+
+ - name: Build Image
+ run: |
+ docker compose build efiling-demo
+ docker tag jag-file-submission-efiling-demo artifacts.developer.gov.bc.ca/efc7-efiling-admin/efiling-admin:dev
+
+ #Run Vulnerability Scan usinig Trivy scanner
+ - name: Run Trivy vulnerability scanner
+ uses: aquasecurity/trivy-action@master
+ with:
+ scan-type: image
+ image-ref: jag-file-submission-efiling-demo
+ format: sarif
+ output: trivy-results.sarif
+ exit-code: 1
+ ignore-unfixed: true
+ limit-severities-for-sarif: true
+ severity: HIGH,CRITICAL
+
+ #Upload results to the Github security tab.
+ - name: Upload Trivy scan results to GitHub Security tab
+ uses: github/codeql-action/upload-sarif@v3
+ if: always()
+ with:
+ sarif_file: trivy-results.sarif
+
+ - name: Docker Push to Artifactory
+ run: |
+ docker push artifacts.developer.gov.bc.ca/efc7-efiling-admin/efiling-admin:dev
+
+ # Get SHORT_SHA for the version
+ - name: Get short SHA
+ id: short_sha
+ run: |
+ echo "::set-output name=SHORT_SHA::$(git rev-parse --short HEAD)"
+ echo "Short SHA: $SHORT_SHA"
+
+ - name: Checkout ArgoCD Repo
+ id: gitops
+ uses: actions/checkout@v4
+ with:
+ repository: bcgov-c/tenant-gitops-fc726a
+ ref: develop
+ token: ${{ secrets.ARGO_PAT }} # `ARGO_PAT` is a secret that contains your PAT
+ path: gitops
+
+ - name: Update Helm Values and Commit
+ id: helm
+ if: steps.gitops.outcome == 'success' # Only run if the previous step (publish) was successful
+ run: |
+ # Clone the GitOps deployment configuration repository
+ # Navigate to the directory containing your Helm values file for the environment develop -> DEV, test -> test and
+ cd gitops/charts
+
+ # Update the Helm values file with the new image tag and version
+ DATETIME=$(date +'%Y-%m-%d %H:%M:%S') # Get current date and time
+
+ sed -i "s/admintag: .*/admintag: dev # Image Updated on $DATETIME/" ../deploy/dev_values.yaml
+ sed -i "s/adminVersion: .*/adminVersion: ${{ steps.short_sha.outputs.SHORT_SHA }} # Version Updated on $DATETIME/" ../deploy/dev_values.yaml
+
+ # Commit and push the changes
+ git config --global user.email "actions@github.com"
+ git config --global user.name "GitHub Actions"
+
+ git add .
+
+ git add ../deploy/dev_values.yaml
+
+ # Repackage Helm Chart
+
+ cd efiling-gitops
+
+ helm dependency build
+
+ cd charts
+
+ git add .
+
+ git commit -m "Update Dev Admin image tag"
+ git push origin develop # Update the branch name as needed
\ No newline at end of file
diff --git a/.github/workflows/dev-efiling-api-build.yaml b/.github/workflows/dev-efiling-api-build.yaml
new file mode 100644
index 0000000000..c13434ffdd
--- /dev/null
+++ b/.github/workflows/dev-efiling-api-build.yaml
@@ -0,0 +1,108 @@
+name: Build Efiling API Image and Push to Openshift 4 Registry
+
+on:
+ schedule:
+ - cron: "0 0 * */3 *"
+ push:
+ branches: [master]
+ paths:
+ - "src/backend/**"
+ - ".github/workflows/dev-efiling-api-build.yaml"
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Login to Artifactory
+ uses: docker/login-action@v1
+ with:
+ registry: artifacts.developer.gov.bc.ca
+ username: ${{ secrets.EFILING_ARTIFACTORY_USERNAME }}
+ password: ${{ secrets.EFILING_ARTIFACTORY_PASSWORD }}
+
+ - name: Build Image
+ env:
+ MVN_PROFILE: efiling-api,splunk
+ STARTERS_V: v1.0.5
+ run: |
+ docker compose build efiling-api
+ docker tag jag-file-submission-efiling-api artifacts.developer.gov.bc.ca/efc7-efiling-api/efiling-api:dev
+
+ #Run Vulnerability Scan usinig Trivy scanner
+ - name: Run Trivy vulnerability scanner
+ uses: aquasecurity/trivy-action@master
+ with:
+ scan-type: image
+ image-ref: jag-file-submission-efiling-api
+ format: sarif
+ output: trivy-results.sarif
+ exit-code: 1
+ ignore-unfixed: true
+ limit-severities-for-sarif: true
+ severity: HIGH,CRITICAL
+
+ #Upload results to the Github security tab.
+ - name: Upload Trivy scan results to GitHub Security tab
+ uses: github/codeql-action/upload-sarif@v3
+ if: always()
+ with:
+ sarif_file: trivy-results.sarif
+
+ - name: Docker Push to Artifactory
+ run: |
+ docker push artifacts.developer.gov.bc.ca/efc7-efiling-api/efiling-api:dev
+
+ # Get SHORT_SHA for the version
+ - name: Get short SHA
+ id: short_sha
+ run: |
+ echo "::set-output name=SHORT_SHA::$(git rev-parse --short HEAD)"
+ echo "Short SHA: $SHORT_SHA"
+
+ - name: Checkout ArgoCD Repo
+ id: gitops
+ uses: actions/checkout@v4
+ with:
+ repository: bcgov-c/tenant-gitops-fc726a
+ ref: develop
+ token: ${{ secrets.ARGO_PAT }} # `ARGO_PAT` is a secret that contains your PAT
+ path: gitops
+
+ - name: Update Helm Values and Commit
+ id: helm
+ if: steps.gitops.outcome == 'success' # Only run if the previous step (publish) was successful
+ run: |
+ # Clone the GitOps deployment configuration repository
+ # Navigate to the directory containing your Helm values file for the environment develop -> DEV, test -> test and
+ cd gitops/charts
+
+ # Update the Helm values file with the new image tag and version
+ DATETIME=$(date +'%Y-%m-%d %H:%M:%S') # Get current date and time
+
+ sed -i "s/apitag: .*/apitag: dev # Image Updated on $DATETIME/" ../deploy/dev_values.yaml
+ sed -i "s/apiVersion: .*/apiVersion: ${{ steps.short_sha.outputs.SHORT_SHA }} # Version Updated on $DATETIME/" ../deploy/dev_values.yaml
+
+ # Commit and push the changes
+ git config --global user.email "actions@github.com"
+ git config --global user.name "GitHub Actions"
+
+ git add .
+
+ git add ../deploy/dev_values.yaml
+
+ # Repackage Helm Chart
+
+ cd efiling-gitops
+
+ helm dependency build
+
+ cd charts
+
+ git add .
+
+ git commit -m "Update Dev API image tag"
+ git push origin develop # Update the branch name as needed
diff --git a/.github/workflows/dev-efiling-frontend-build.yaml b/.github/workflows/dev-efiling-frontend-build.yaml
new file mode 100644
index 0000000000..961b929d5b
--- /dev/null
+++ b/.github/workflows/dev-efiling-frontend-build.yaml
@@ -0,0 +1,103 @@
+name: Build Efiling Frontend Image and Push to Openshift Registry
+
+on:
+ push:
+ branches: [master]
+ paths:
+ - "src/frontend/efiling-frontend/**"
+ - ".github/workflows/dev-efiling-frontend-build.yaml"
+ workflow_dispatch:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+
+ - name: Login to Artifactory
+ uses: docker/login-action@v1
+ with:
+ registry: artifacts.developer.gov.bc.ca
+ username: ${{ secrets.EFILING_ARTIFACTORY_USERNAME }}
+ password: ${{ secrets.EFILING_ARTIFACTORY_PASSWORD }}
+
+ - name: Build Image
+ run: |
+ docker compose build efiling-frontend
+ docker tag jag-file-submission-efiling-frontend artifacts.developer.gov.bc.ca/efc7-efiling-frontend/efiling-frontend:dev
+
+ #Run Vulnerability Scan usinig Trivy scanner
+ - name: Run Trivy vulnerability scanner
+ uses: aquasecurity/trivy-action@master
+ with:
+ scan-type: image
+ image-ref: jag-file-submission-efiling-frontend
+ format: sarif
+ output: trivy-results.sarif
+ exit-code: 1
+ ignore-unfixed: true
+ limit-severities-for-sarif: true
+ severity: HIGH,CRITICAL
+
+ #Upload results to the Github security tab.
+ - name: Upload Trivy scan results to GitHub Security tab
+ uses: github/codeql-action/upload-sarif@v3
+ if: always()
+ with:
+ sarif_file: trivy-results.sarif
+
+ - name: Docker Push to Artifactory
+ run: |
+ docker push artifacts.developer.gov.bc.ca/efc7-efiling-frontend/efiling-frontend:dev
+
+ # Get SHORT_SHA for the version
+ - name: Get short SHA
+ id: short_sha
+ run: |
+ echo "::set-output name=SHORT_SHA::$(git rev-parse --short HEAD)"
+ echo "Short SHA: $SHORT_SHA"
+
+ - name: Checkout ArgoCD Repo
+ id: gitops
+ uses: actions/checkout@v4
+ with:
+ repository: bcgov-c/tenant-gitops-fc726a
+ ref: develop
+ token: ${{ secrets.ARGO_PAT }} # `ARGO_PAT` is a secret that contains your PAT
+ path: gitops
+
+ - name: Update Helm Values and Commit
+ id: helm
+ if: steps.gitops.outcome == 'success' # Only run if the previous step (publish) was successful
+ run: |
+ # Clone the GitOps deployment configuration repository
+ # Navigate to the directory containing your Helm values file for the environment develop -> DEV, test -> test and
+ cd gitops/charts
+
+ # Update the Helm values file with the new image tag and version
+ DATETIME=$(date +'%Y-%m-%d %H:%M:%S') # Get current date and time
+
+ sed -i "s/frontendtag: .*/frontendtag: dev # Image Updated on $DATETIME/" ../deploy/dev_values.yaml
+ sed -i "s/frontendVersion: .*/frontendVersion: ${{ steps.short_sha.outputs.SHORT_SHA }} # Version Updated on $DATETIME/" ../deploy/dev_values.yaml
+
+ # Commit and push the changes
+ git config --global user.email "actions@github.com"
+ git config --global user.name "GitHub Actions"
+
+ git add .
+
+ git add ../deploy/dev_values.yaml
+
+ # Repackage Helm Chart
+
+ cd efiling-gitops
+
+ helm dependency build
+
+ cd charts
+
+ git add .
+
+ git commit -m "Update Dev Frontend image tag"
+ git push origin develop # Update the branch name as needed
\ No newline at end of file
diff --git a/.github/workflows/prod-promote.yaml b/.github/workflows/prod-promote.yaml
new file mode 100644
index 0000000000..439307f4c5
--- /dev/null
+++ b/.github/workflows/prod-promote.yaml
@@ -0,0 +1,170 @@
+# Deploy an artifact onto Prod
+name: Promote to Prod
+
+on:
+ workflow_dispatch:
+ inputs:
+ application:
+ required: true
+ description: What application you want to promote?
+ type: choice
+ options:
+ - efiling-api
+ - efiling-frontend
+ - efiling-admin
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Login to Artifactory
+ uses: docker/login-action@v1
+ with:
+ registry: artifacts.developer.gov.bc.ca
+ username: ${{ secrets.EFILING_ARTIFACTORY_USERNAME }}
+ password: ${{ secrets.EFILING_ARTIFACTORY_PASSWORD }}
+
+ - name: Backup Prod Image from Artifactory
+ working-directory: ${{env.WORKING_DIRECTORY}}
+ run: |
+ docker pull artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:prod
+ docker tag artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:prod artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:prod-backup
+ docker push artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:prod-backup
+
+ - name: Docker Pull Test Image from Artifactory
+ working-directory: ${{env.WORKING_DIRECTORY}}
+ run: |
+ docker pull artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:test
+ docker tag artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:test artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:prod
+
+
+ - name: Docker Push Prod Image To Artifactory
+ working-directory: ${{env.WORKING_DIRECTORY}}
+ run: |
+ docker push artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:prod
+
+ # Get SHORT_SHA for the version
+ - name: Get short SHA
+ id: short_sha
+ run: |
+ echo "::set-output name=SHORT_SHA::$(git rev-parse --short HEAD)"
+ echo "Short SHA: $SHORT_SHA"
+
+ - name: Checkout ArgoCD Repo
+ id: gitops
+ uses: actions/checkout@v4
+ with:
+ repository: bcgov-c/tenant-gitops-fc726a
+ ref: main
+ token: ${{ secrets.ARGO_PAT }}
+ path: gitops
+
+ - name: Update ADMIN Helm Values and Commit
+ id: helm-admin
+ if: ${{ github.event.inputs.application == 'efiling-admin' }}
+ run: |
+ # Clone the GitOps deployment configuration repository
+ # Navigate to the directory containing your Helm values file for the environment develop -> DEV, test -> test and
+ cd gitops/charts
+
+ # Update the Helm values file with the new image tag and version
+ DATETIME=$(date +'%Y-%m-%d %H:%M:%S') # Get current date and time
+
+ sed -i "s/admintag: .*/admintag: prod # Image Updated on $DATETIME/" ../deploy/prod_values.yaml
+ sed -i "s/adminVersion: .*/adminVersion: ${{ steps.short_sha.outputs.SHORT_SHA }} # Version Updated on $DATETIME/" ../deploy/prod_values.yaml
+
+ # Commit and push the changes
+ git config --global user.email "actions@github.com"
+ git config --global user.name "GitHub Actions"
+
+ git add .
+
+ git add ../deploy/prod_values.yaml
+
+ # Repackage Helm Chart
+
+ cd efiling-gitops
+
+ helm dependency build
+
+ cd charts
+
+ git add .
+
+ git commit -m "Update Prod Admin image tag"
+ git push origin main # Update the branch name as needed
+
+ - name: Update API Helm Values and Commit
+ id: helm-api
+ if: ${{ github.event.inputs.application == 'efiling-api' }}
+ run: |
+ # Clone the GitOps deployment configuration repository
+ # Navigate to the directory containing your Helm values file for the environment develop -> DEV, test -> test and
+ cd gitops/charts
+
+ # Update the Helm values file with the new image tag and version
+ DATETIME=$(date +'%Y-%m-%d %H:%M:%S') # Get current date and time
+
+ sed -i "s/apitag: .*/apitag: prod # Image Updated on $DATETIME/" ../deploy/prod_values.yaml
+ sed -i "s/apiVersion: .*/apiVersion: ${{ steps.short_sha.outputs.SHORT_SHA }} # Version Updated on $DATETIME/" ../deploy/prod_values.yaml
+
+ # Commit and push the changes
+ git config --global user.email "actions@github.com"
+ git config --global user.name "GitHub Actions"
+
+ git add .
+
+ git add ../deploy/prod_values.yaml
+
+ # Repackage Helm Chart
+
+ cd efiling-gitops
+
+ helm dependency build
+
+ cd charts
+
+ git add .
+
+ git commit -m "Update Prod API image tag"
+ git push origin main # Update the branch name as needed
+
+ - name: Update FRONTEND Helm Values and Commit
+ id: helm-frontend
+ if: ${{ github.event.inputs.application == 'efiling-frontend' }}
+ run: |
+ # Clone the GitOps deployment configuration repository
+ # Navigate to the directory containing your Helm values file for the environment develop -> DEV, test -> test and
+ cd gitops/charts
+
+ # Update the Helm values file with the new image tag and version
+ DATETIME=$(date +'%Y-%m-%d %H:%M:%S') # Get current date and time
+
+ sed -i "s/frontendtag: .*/frontendtag: prod # Image Updated on $DATETIME/" ../deploy/prod_values.yaml
+ sed -i "s/frontendVersion: .*/frontendVersion: ${{ steps.short_sha.outputs.SHORT_SHA }} # Version Updated on $DATETIME/" ../deploy/prod_values.yaml
+
+ # Commit and push the changes
+ git config --global user.email "actions@github.com"
+ git config --global user.name "GitHub Actions"
+
+ git add .
+
+ git add ../deploy/prod_values.yaml
+
+ # Repackage Helm Chart
+
+ cd efiling-gitops
+
+ helm dependency build
+
+ cd charts
+
+ git add .
+
+ git commit -m "Update Prod FRONTEND image tag"
+ git push origin main # Update the branch name as needed
+
+
+
diff --git a/.github/workflows/test-promote.yaml b/.github/workflows/test-promote.yaml
new file mode 100644
index 0000000000..b5c923dc46
--- /dev/null
+++ b/.github/workflows/test-promote.yaml
@@ -0,0 +1,158 @@
+# Deploy an artifact onto Test
+name: Promote to Test
+on:
+ workflow_dispatch:
+ inputs:
+ application:
+ required: true
+ description: What application you want to promote?
+ type: choice
+ options:
+ - efiling-api
+ - efiling-frontend
+ - efiling-admin
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Login to Artifactory
+ uses: docker/login-action@v1
+ with:
+ registry: artifacts.developer.gov.bc.ca
+ username: ${{ secrets.EFILING_ARTIFACTORY_USERNAME }}
+ password: ${{ secrets.EFILING_ARTIFACTORY_PASSWORD }}
+
+ - name: Docker Pull Dev Image from Artifactory
+ working-directory: ${{env.WORKING_DIRECTORY}}
+ run: |
+ docker pull artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:dev
+ docker tag artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:dev artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:test
+
+ - name: Docker Push Test Image To Artifactory
+ working-directory: ${{env.WORKING_DIRECTORY}}
+ run: |
+ docker push artifacts.developer.gov.bc.ca/efc7-${{ github.event.inputs.application }}/${{ github.event.inputs.application }}:test
+
+ # Get SHORT_SHA for the version
+ - name: Get short SHA
+ id: short_sha
+ run: |
+ echo "::set-output name=SHORT_SHA::$(git rev-parse --short HEAD)"
+ echo "Short SHA: $SHORT_SHA"
+
+ - name: Checkout ArgoCD Repo
+ id: gitops
+ uses: actions/checkout@v4
+ with:
+ repository: bcgov-c/tenant-gitops-fc726a
+ ref: test
+ token: ${{ secrets.ARGO_PAT }}
+ path: gitops
+
+ - name: Update ADMIN Helm Values and Commit
+ id: helm-admin
+ if: ${{ github.event.inputs.application == 'efiling-admin' }}
+ run: |
+ # Clone the GitOps deployment configuration repository
+ # Navigate to the directory containing your Helm values file for the environment develop -> DEV, test -> test and
+ cd gitops/charts
+
+ # Update the Helm values file with the new image tag and version
+ DATETIME=$(date +'%Y-%m-%d %H:%M:%S') # Get current date and time
+
+ sed -i "s/admintag: .*/admintag: test # Image Updated on $DATETIME/" ../deploy/test_values.yaml
+ sed -i "s/adminVersion: .*/adminVersion: ${{ steps.short_sha.outputs.SHORT_SHA }} # Version Updated on $DATETIME/" ../deploy/test_values.yaml
+
+ # Commit and push the changes
+ git config --global user.email "actions@github.com"
+ git config --global user.name "GitHub Actions"
+
+ git add .
+
+ git add ../deploy/test_values.yaml
+
+ # Repackage Helm Chart
+
+ cd efiling-gitops
+
+ helm dependency build
+
+ cd charts
+
+ git add .
+
+ git commit -m "Update Test Admin image tag"
+ git push origin test # Update the branch name as needed
+
+ - name: Update API Helm Values and Commit
+ id: helm-api
+ if: ${{ github.event.inputs.application == 'efiling-api' }}
+ run: |
+ # Clone the GitOps deployment configuration repository
+ # Navigate to the directory containing your Helm values file for the environment develop -> DEV, test -> test and
+ cd gitops/charts
+
+ # Update the Helm values file with the new image tag and version
+ DATETIME=$(date +'%Y-%m-%d %H:%M:%S') # Get current date and time
+
+ sed -i "s/apitag: .*/apitag: test # Image Updated on $DATETIME/" ../deploy/test_values.yaml
+ sed -i "s/apiVersion: .*/apiVersion: ${{ steps.short_sha.outputs.SHORT_SHA }} # Version Updated on $DATETIME/" ../deploy/test_values.yaml
+
+ # Commit and push the changes
+ git config --global user.email "actions@github.com"
+ git config --global user.name "GitHub Actions"
+
+ git add .
+
+ git add ../deploy/test_values.yaml
+
+ # Repackage Helm Chart
+
+ cd efiling-gitops
+
+ helm dependency build
+
+ cd charts
+
+ git add .
+
+ git commit -m "Update Test API image tag"
+ git push origin test # Update the branch name as needed
+
+ - name: Update FRONTEND Helm Values and Commit
+ id: helm-frontend
+ if: ${{ github.event.inputs.application == 'efiling-frontend' }}
+ run: |
+ # Clone the GitOps deployment configuration repository
+ # Navigate to the directory containing your Helm values file for the environment develop -> DEV, test -> test and
+ cd gitops/charts
+
+ # Update the Helm values file with the new image tag and version
+ DATETIME=$(date +'%Y-%m-%d %H:%M:%S') # Get current date and time
+
+ sed -i "s/frontendtag: .*/frontendtag: test # Image Updated on $DATETIME/" ../deploy/test_values.yaml
+ sed -i "s/frontendVersion: .*/frontendVersion: ${{ steps.short_sha.outputs.SHORT_SHA }} # Version Updated on $DATETIME/" ../deploy/test_values.yaml
+
+ # Commit and push the changes
+ git config --global user.email "actions@github.com"
+ git config --global user.name "GitHub Actions"
+
+ git add .
+
+ git add ../deploy/test_values.yaml
+
+ # Repackage Helm Chart
+
+ cd efiling-gitops
+
+ helm dependency build
+
+ cd charts
+
+ git add .
+
+ git commit -m "Update Test FRONTEND image tag"
+ git push origin test # Update the branch name as needed
\ No newline at end of file
diff --git a/.github/workflows/zap-baseline.yaml b/.github/workflows/zap-baseline.yaml
new file mode 100644
index 0000000000..e16f63d74e
--- /dev/null
+++ b/.github/workflows/zap-baseline.yaml
@@ -0,0 +1,21 @@
+name: Zap Baseline Scan
+
+on: [workflow_dispatch]
+
+jobs:
+ zap_scan:
+ runs-on: ubuntu-latest
+ name: Scan the eFiling Frontend Web Application
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v2
+ with:
+ ref: master
+ - name: ZAP Scan
+ uses: zaproxy/action-baseline@v0.4.0
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }}
+ docker_name: 'owasp/zap2docker-stable'
+ target: 'https://test.justice.gov.bc.ca/efilinghub'
+ rules_file_name: '.zap/rules.tsv'
+ cmd_options: '-a'
diff --git a/.gitignore b/.gitignore
index a9500bfdc4..d9f78b7768 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,4 +6,12 @@ tests/logs
*.log
.idea
tests/test-output
+tests/src/test/resources/application.properties
.env
+src/frontend/.vscode/
+src/frontend/efiling-frontend/.vscode/
+src/frontend/efiling-frontend/node_modules
+*.lock
+node_modules
+.metadata
+/TestAutomation/target
diff --git a/.mdlrc b/.mdlrc
new file mode 100644
index 0000000000..1fa2ca3703
--- /dev/null
+++ b/.mdlrc
@@ -0,0 +1 @@
+style ".settings/mdl/ruleset.rb"
diff --git a/.settings/mdl/ruleset.rb b/.settings/mdl/ruleset.rb
new file mode 100644
index 0000000000..18f0d8408e
--- /dev/null
+++ b/.settings/mdl/ruleset.rb
@@ -0,0 +1,2 @@
+all
+rule 'MD013', :code_blocks => false, :tables => false
diff --git a/.settings/nginx.conf b/.settings/nginx.conf
new file mode 100644
index 0000000000..d2120549a9
--- /dev/null
+++ b/.settings/nginx.conf
@@ -0,0 +1,18 @@
+worker_processes 1;
+worker_rlimit_nofile 8192;
+
+events {
+ worker_connections 4096; ## Default: 1024
+}
+
+http {
+
+ server { # simple reverse-proxy
+ listen 80;
+
+ # pass requests for dynamic content to rails/turbogears/zope, et al
+ location / {
+ proxy_pass http://keycloak:8080;
+ }
+ }
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000000..af9a6adae9
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "java.configuration.updateBuildConfiguration": "disabled"
+}
diff --git a/Jenkinsfile b/Jenkinsfile
deleted file mode 100644
index 8b13789179..0000000000
--- a/Jenkinsfile
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/README.md b/README.md
index 2ad9325295..8329668fd9 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,12 @@
-[](https://codeclimate.com/github/bcgov/jag-file-submission/maintainability) [](https://codeclimate.com/github/bcgov/jag-file-submission/test_coverage)
+# EFiling Hub
-# jag-file-submission
+[](https://github.com/bcgov/repomountie/blob/master/doc/lifecycle-badges.md) [](https://codeclimate.com/github/bcgov/jag-file-submission/maintainability) [](https://codeclimate.com/github/bcgov/jag-file-submission/test_coverage)  [](https://chat.developer.gov.bc.ca/group/efiling-hub-integration)
-Generic File Submission API (to be used by the Family Law Act Application at first)
+## Summary
+
+As a component of the Court Digital Transformation Strategy (CDTS), the eFiling hub uses modern, secure, scalable, microservice architecture and API first design to facilitate easy integration of other applications (i.e. Family Law Act application, Online Divorce Assistant, Representation Agreement app) with the current electronic filing services that are provisioned by the Court Services Online application.
+
+The eFiling hub is a foundational component to enhance citizen experiences for the submission of court documents electronically, while streamlining backend court registry processes.
## Project Structure
@@ -12,16 +16,15 @@ Generic File Submission API (to be used by the Family Law Act Application at fir
├── src/ # application source files
│ ├── backend # backend applications
│ │ ├── efiling-api # efiling api
- │ │ ├── efiling-worker # file submission worker
│ │ ├── libs # backend libraries
- │ │ | ├── efiling-account-client # efiling soap client that checks CSO account, FILE role, BCeID account info
- │ │ | ├── efiling-submission-client # efiling soap client that submits packages to CSO
- │ │ | ├── efiling-lookup-client # efiling soap client that looksup required info for submission
- │ │ | └── efiling-status-client # efiling soap client for checking status of a submitted package
+ │ │ | ├── efiling-bambora-api-client # bamabora swagger for client generation
+ │ │ | ├── efiling-bom # pom Bill Of Materials
+ │ │ | ├── efiling-commons # efiling soap client that submits packages to CSO
+ │ │ | ├── efiling-cso-starter # efiling soap client that contains all soap implementations
+ │ │ | └── efiling-demo-starter # efiling demo app that mocks all soap implementations
│ └── frontend # frontend applications
│ ├── efiling-frontend # efiling frontend
│ └── efiling-demo # efiling demo app frontend
- │ └── shared-components # shared bcgov themed component library
├── COMPLIANCE.yaml #
├── CONTRIBUTING.md #
├── LICENSE # Apache License
@@ -29,52 +32,33 @@ Generic File Submission API (to be used by the Family Law Act Application at fir
## Apps
-| Name | description | doc |
-| -------------------- | -------------------------------------------- | ---------------------------------------------------- |
-| backend | all server side services | [README](src/backend/README.md) |
-| efiling-api | the main api for interating with the service | [README](src/backend/efiling-api/README.md) |
-| efiling-demo-backend | a demo backend that emulates a client | [README](src/backend/efiling-backend-demo/README.md) |
-| efiling-worker | process submitted documents | [README](src/backend/efiling-worker/README.md) |
-| frontend | all client side applications | [README](src/frontend/README.md) |
-| efiling-frontend | the frontend for uploading documents | [README](src/frontend/efiling-frontend/README.md) |
-| efiling-demo | the frontend for demo application | [README](src/frontend/efiling-demo/README.md) |
-| shared-components | shared bcgov themed component library | [README](src/frontend/shared-components/README.md) |
-| cucumber-tests | automated tests for frontend and backend | [README](tests/README.md) |
+| Name | Description | Doc |
+| ------------------- | -------------------------------------------- | -------------------------------------------------------- |
+| backend | all server side services | [README](src/backend/README.md) |
+| efiling-api | the main api for interating with the service | [README](src/backend/efiling-api/README.md) |
+| efiling-cso-starter | soap client implementations | [README](src/backend/libs/efiling-cso-starter/README.md) |
+| frontend | all client side applications | [README](src/frontend/README.md) |
+| efiling-frontend | the frontend for uploading documents | [README](src/frontend/efiling-frontend/README.md) |
+| efiling-demo | the frontend for demo application | [README](src/frontend/efiling-demo/README.md) |
+| cucumber-tests | automated tests for frontend and backend | [README](tests/README.md) |
## Running the App
By default a demo mode is enabled.
-if you want to integrate with the CSO application, first create a local `.env` at the root of the repository based off `.env.template`.
-
-Change the `MVN_PROFILE` to `default`
-Set the following environement variables:
+First create a local `.env` at the root of the repository based off [.env.template](.env.template). Below are the variables that need to be configured to get the application running in demo mode.
-```
-MVN_PROFILE=default
-CSO_ACCOUNTFACADE_URI=
-CSO_ACCOUNTFACADE_USERNAME=
-CSO_ACCOUNTFACADE_PASSWORD=
-CSO_ROLEREGISTRY_USERNAME=
-CSO_ROLEREGISTRY_PASSWORD=
-CSO_ROLEREGISTRY_URI=
-CSO_LOOKUPFACADE_USERNAME=
-CSO_LOOKUPFACADE_PASSWORD=
-CSO_LOOKUPFACADE_URI=
-BCEID_LOOKUP_USERNAME=
-BCEID_LOOKUP_PASSWORD=
-BCEID_LOOKUP_URI=
-```
+Configure Keycloak
run
```bash
-docker-compose up -d --build
+docker-compose up -d
```
-to get started, access the front end application [here](http://localhost:3001) and enter a user account and you will get redirected to the file upload.
+login at [http://localhost:3001](http://localhost:3001) with `bobross` and `changeme`
-You can get test accounts [here](https://bcgov.github.io/jag-file-submission/#/gettingStarted?id=test-accounts) when the app is running in demo mode.
+To get started, access the front end application [here](http://localhost:3001) use the following username `bobross` and password `changeme`

@@ -96,14 +80,21 @@ Efiling Api check health at [http://localhost:8080/actuator/health](http://local
A [redis](https://redis.io/) instance exposed on port 6379
-#### rabbitmq
+#### redis commander
-A [rabbitmq](https://www.rabbitmq.com/) access the management console at [http://localhost:15672](http://localhost:15672)
+A [redis-commander](http://joeferner.github.io/redis-commander/) instance to query redis accessible at [http://localhost:8082](http://localhost:8082)
-#### postgres:
+#### keycloak
-A [postgresql](https://www.postgresql.org/) to support keycloak
+A [keycloak](https://www.keycloak.org/) instance accessible at [http://localhost:8081/auth](http://localhost:8081/auth)
-#### keycloak:
+#### Spring starter update
+
+When updating the spring starter ensure all hardcoded references are updated.
+[Code Climate] (https://github.com/bcgov/jag-file-submission/blob/master/.github/workflows/code-climate-coverage-aggregation.yml)
+[Docker File] (https://github.com/bcgov/jag-file-submission/blob/master/docker-compose.override.yml)
+[Cucumber] (https://github.com/bcgov/jag-file-submission/blob/master/.github/workflows/cucumber-tests.yml)
+
+
+## Github action
-A [keycloak](https://www.keycloak.org/) instance accessible at [http://localhost:8081/auth](http://localhost:8081/auth)
diff --git a/TestAutomation/.gitignore b/TestAutomation/.gitignore
new file mode 100644
index 0000000000..f089b48b8b
--- /dev/null
+++ b/TestAutomation/.gitignore
@@ -0,0 +1,16 @@
+### IntelliJ IDEA ###
+tests/target
+tests/.idea
+tests/logs
+*.iml
+*.log
+.idea
+tests/test-output
+tests/src/test/resources/application.properties
+.env
+src/frontend/.vscode/
+src/frontend/efiling-frontend/.vscode/
+src/frontend/efiling-frontend/node_modules
+*.lock
+node_modules
+
diff --git a/TestAutomation/bin/.gitignore b/TestAutomation/bin/.gitignore
new file mode 100644
index 0000000000..6013929ddf
--- /dev/null
+++ b/TestAutomation/bin/.gitignore
@@ -0,0 +1,14 @@
+/target/
+.classpath
+.idea/
+.metadata/
+.project
+.settings/
+/bin/chromedriver.exe
+/bin/sqljdbc4-4.0.jar
+/src/main/resources/jdbc.properties
+/src/test/resources/jdbc.properties
+debug.log
+src/main/java/ca/epbc/ui/Config.java
+src/test/java/ca/epbc/ui/LoginAccountRecoveryEnv.java
+/src/
diff --git a/TestAutomation/bin/README.md b/TestAutomation/bin/README.md
new file mode 100644
index 0000000000..b9cf4fbb3a
Binary files /dev/null and b/TestAutomation/bin/README.md differ
diff --git a/TestAutomation/bin/chr.ab b/TestAutomation/bin/chr.ab
new file mode 100644
index 0000000000..c0efae8059
Binary files /dev/null and b/TestAutomation/bin/chr.ab differ
diff --git a/TestAutomation/bin/chromedriver.exe b/TestAutomation/bin/chromedriver.exe
new file mode 100644
index 0000000000..454b1809fa
Binary files /dev/null and b/TestAutomation/bin/chromedriver.exe differ
diff --git a/TestAutomation/bin/geckodriver.exe b/TestAutomation/bin/geckodriver.exe
new file mode 100644
index 0000000000..dd2daa9001
Binary files /dev/null and b/TestAutomation/bin/geckodriver.exe differ
diff --git a/TestAutomation/bin/sqljdbc4-4.0.jar b/TestAutomation/bin/sqljdbc4-4.0.jar
new file mode 100644
index 0000000000..d6b7f6daf4
Binary files /dev/null and b/TestAutomation/bin/sqljdbc4-4.0.jar differ
diff --git a/TestAutomation/pom.xml b/TestAutomation/pom.xml
new file mode 100644
index 0000000000..ef3fbf8d6d
--- /dev/null
+++ b/TestAutomation/pom.xml
@@ -0,0 +1,157 @@
+
+
+ 4.0.0
+
+ ca.bc.gov.open.jagFileSubmission
+ TestAutomation
+ 1.0-SNAPSHOT
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.0.0
+
+
+
+ eFilling-TesAutomation
+
+
+ UTF-8
+ 1.8
+ 4.7.2
+ 2.0.26
+ 1.18.20
+ 4.13.1
+ 3.7.0
+ 3.1.0
+
+
+
+
+
+ org.seleniumhq.selenium
+ selenium-java
+ ${org.seleniumhq.selenium.version}
+
+
+
+ junit
+ junit
+ ${junit.version}
+ jar
+
+
+
+ org.apache.pdfbox
+ pdfbox
+ ${org.apache.pdfbox.version}
+
+
+ org.projectlombok
+ lombok
+ ${org.projectlombok.version}
+ test
+
+
+
+ org.projectlombok
+ lombok
+ ${org.projectlombok.version}
+ provided
+
+
+ org.springframework.boot
+ spring-boot-starter
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+ **/*.properties
+ **/*.bat
+ **/*.sh
+ **/.keystore
+
+
+
+
+
+ maven-assembly-plugin
+
+
+ package
+
+ single
+
+
+
+
+
+
+ ca.epbc.ui.Atest
+
+
+
+ jar-with-dependencies
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ ${maven-compiler-plugin.version}
+
+ ${java.version}
+ ${java.version}
+ ${java.version}
+ ${java.version}
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ copy-dependencies
+ prepare-package
+
+ copy-dependencies
+
+
+
+ ${project.build.directory}/libs
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ ${maven-jar-plugin.version}
+
+
+
+ test-jar
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Atest.java b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Atest.java
new file mode 100644
index 0000000000..21707b9ca7
--- /dev/null
+++ b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Atest.java
@@ -0,0 +1,42 @@
+package ca.bc.gov.open.jagFileSubmission;
+
+import org.junit.Test;
+import org.junit.runner.JUnitCore;
+import org.junit.runner.RunWith;
+
+import java.util.Random;
+
+public class Atest {
+
+ @RunWith(ConcurrentJunitRunner.class)
+ @Concurent.Concurrent(threads = 6)
+ public final class ATest {
+
+ @Test
+ public void test0() throws Throwable { printAndWait(); }
+ @Test public void test1() throws Throwable { printAndWait(); }
+ @Test public void test2() throws Throwable { printAndWait(); }
+ @Test public void test3() throws Throwable { printAndWait(); }
+ @Test public void test4() throws Throwable { printAndWait(); }
+ @Test public void test5() throws Throwable { printAndWait(); }
+ @Test public void test6() throws Throwable { printAndWait(); }
+ @Test public void test7() throws Throwable { printAndWait(); }
+ @Test public void test8() throws Throwable { printAndWait(); }
+ @Test public void test9() throws Throwable { printAndWait(); }
+
+ void printAndWait() throws Throwable {
+ int w = new Random().nextInt(1000);
+ System.out.println(String.format("[%s] %s %s %s",
+ Thread.currentThread().getName(),
+ getClass().getName(),
+ new Throwable().getStackTrace()[1].getMethodName(),
+ w));
+ Thread.sleep(w);
+ }
+
+ public void main(String[] args) {
+ JUnitCore.main("ca.epbc.ATest");
+ }
+ }
+
+}
diff --git a/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/CommonUtils.java b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/CommonUtils.java
new file mode 100644
index 0000000000..63b77360fe
--- /dev/null
+++ b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/CommonUtils.java
@@ -0,0 +1,30 @@
+package ca.bc.gov.open.jagFileSubmission;
+
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+
+import java.util.logging.Logger;
+
+public class CommonUtils {
+
+ private static Logger log = Logger.getLogger("CommonUtils.class");
+
+ public static void login() throws Exception {
+
+ WebDriver driver = WebDriverManager.getDriver();
+ WebElement element = WebDriverManager.getElement();
+
+ if (Config.ENVIROMENT.equals(Constants.DEV)) {
+ driver.get("https://court-of-appeal-dev.apps.silver.devops.gov.bc.ca/court-of-appeal/");
+ driver.navigate().to("https://court-of-appeal-dev.apps.silver.devops.gov.bc.ca/court-of-appeal/");
+ driver.navigate().refresh();
+
+ } else if (Config.ENVIROMENT.equals(Constants.TST)) {
+ driver.get("");
+ driver.navigate().to("");
+ driver.navigate().refresh();
+
+ }
+ }
+
+}
diff --git a/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Concurent.java b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Concurent.java
new file mode 100644
index 0000000000..3ea6a92e3a
--- /dev/null
+++ b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Concurent.java
@@ -0,0 +1,16 @@
+package ca.bc.gov.open.jagFileSubmission;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+public class Concurent {
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.TYPE})
+ public @interface Concurrent {
+ int threads() default 5;
+ }
+
+}
diff --git a/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/ConcurrentJunitRunner.java b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/ConcurrentJunitRunner.java
new file mode 100644
index 0000000000..d386624794
--- /dev/null
+++ b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/ConcurrentJunitRunner.java
@@ -0,0 +1,58 @@
+package ca.bc.gov.open.jagFileSubmission;
+
+import io.netty.util.concurrent.Future;
+import org.junit.runners.BlockJUnit4ClassRunner;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerScheduler;
+
+import java.lang.annotation.Annotation;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ConcurrentJunitRunner extends BlockJUnit4ClassRunner {
+ public ConcurrentJunitRunner(final Class> klass) throws InitializationError {
+ super(klass);
+ setScheduler(new RunnerScheduler() {
+ ExecutorService executorService = Executors.newFixedThreadPool(
+ klass.isAnnotationPresent((Class extends Annotation>) Concurent.Concurrent.class) ?
+ klass.getAnnotation(Concurent.Concurrent.class).threads() :
+ (int) (Runtime.getRuntime().availableProcessors() * 1.5),
+ new NamedThreadFactory(klass.getSimpleName()));
+ CompletionService completionService = new ExecutorCompletionService(executorService);
+ Queue> tasks = new LinkedList>();
+
+ public void schedule(Runnable childStatement) {
+ tasks.offer((Future) completionService.submit(childStatement, null));
+ }
+
+ public void finished() {
+ try {
+ while (!tasks.isEmpty())
+ tasks.remove(completionService.take());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } finally {
+ while (!tasks.isEmpty())
+ tasks.poll().cancel(true);
+ executorService.shutdownNow();
+ }
+ }
+ });
+ }
+
+ static final class NamedThreadFactory implements ThreadFactory {
+ static final AtomicInteger poolNumber = new AtomicInteger(1);
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ final ThreadGroup group;
+
+ NamedThreadFactory(String poolName) {
+ group = new ThreadGroup(poolName + "-" + poolNumber.getAndIncrement());
+ }
+
+ public Thread newThread(Runnable r) {
+ return new Thread(group, r, group.getName() + "-thread-" + threadNumber.getAndIncrement(), 0);
+ }
+ }}
+
diff --git a/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/ConcurrentSuite.java b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/ConcurrentSuite.java
new file mode 100644
index 0000000000..44a91e672e
--- /dev/null
+++ b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/ConcurrentSuite.java
@@ -0,0 +1,88 @@
+package ca.bc.gov.open.jagFileSubmission;
+
+import org.junit.internal.builders.AllDefaultPossibilitiesBuilder;
+import org.junit.runner.Runner;
+import org.junit.runners.Suite;
+import org.junit.runners.model.InitializationError;
+import org.junit.runners.model.RunnerBuilder;
+import org.junit.runners.model.RunnerScheduler;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ConcurrentSuite extends Suite {
+ public ConcurrentSuite(final Class> klass) throws InitializationError {
+ super(klass, new AllDefaultPossibilitiesBuilder(true) {
+ @Override
+ public Runner runnerForClass(Class> testClass) throws Throwable {
+ List builders = Arrays.asList(
+ new RunnerBuilder() {
+ @Override
+ public Runner runnerForClass(Class> testClass) throws Throwable {
+ Concurent.Concurrent annotation = testClass.getAnnotation(Concurent.Concurrent.class);
+ if (annotation != null)
+ return new ConcurrentJunitRunner(testClass);
+ return null;
+ }
+ },
+ ignoredBuilder(),
+ annotatedBuilder(),
+ suiteMethodBuilder(),
+ junit3Builder(),
+ junit4Builder());
+ for (RunnerBuilder each : builders) {
+ Runner runner = each.safeRunnerForClass(testClass);
+ if (runner != null)
+ return runner;
+ }
+ return null;
+ }
+ });
+ setScheduler(new RunnerScheduler() {
+ ExecutorService executorService = Executors.newFixedThreadPool(
+ klass.isAnnotationPresent(Concurent.Concurrent.class) ?
+ klass.getAnnotation(Concurent.Concurrent.class).threads() :
+ (int) (Runtime.getRuntime().availableProcessors() * 1.5),
+ new NamedThreadFactory(klass.getSimpleName()));
+ CompletionService completionService = new ExecutorCompletionService(executorService);
+ Queue> tasks = new LinkedList>();
+
+ public void schedule(Runnable childStatement) {
+ tasks.offer(completionService.submit(childStatement, null));
+ }
+
+ public void finished() {
+ try {
+ while (!tasks.isEmpty())
+ tasks.remove(completionService.take());
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ } finally {
+ while (!tasks.isEmpty())
+ tasks.poll().cancel(true);
+ executorService.shutdownNow();
+ }
+ }
+ });
+ }
+
+ static final class NamedThreadFactory implements ThreadFactory {
+ static final AtomicInteger poolNumber = new AtomicInteger(1);
+ final AtomicInteger threadNumber = new AtomicInteger(1);
+ final ThreadGroup group;
+
+ NamedThreadFactory(String poolName) {
+ group = new ThreadGroup(poolName + "-" + poolNumber.getAndIncrement());
+ }
+
+ public Thread newThread(Runnable r) {
+ return new Thread(group, r, group.getName() + "-thread-" + threadNumber.getAndIncrement(), 0);
+ }
+ }
+
+}
+
diff --git a/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Config.java b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Config.java
new file mode 100644
index 0000000000..7116dedfa5
--- /dev/null
+++ b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Config.java
@@ -0,0 +1,25 @@
+package ca.bc.gov.open.jagFileSubmission;
+
+import java.math.BigDecimal;
+
+public class Config {
+
+ public static final String SELECTED_DRIVER = Constants.CHROME_DRIVER;
+ //public static final String SELECTED_DRIVER = Constants.FIREFOX_DRIVER;
+ //public static final String SELECTED_DRIVER = Constants.EDGE_DRIVER;
+ //public static final String ENVIROMENT = Constants.DEV;
+ public static final String ENVIROMENT = Constants.DEV;
+
+
+ public static String TEST_SCENARIO = Constants.NOT_SET;
+ public static boolean SKIP_SCREENSHOTS_OF_SHOPPING_CART = false; //not implemented yet
+
+ public static final int TIMEOUT = 30; //the time webdriver waits before giving up (in seconds)
+ public static final int SLEEP_TIME_FULL_REFRESH = 3500; //time used in Thread.sleep() in milliseconds
+ public static final int SLEEP_TIME_PART_REFRESH = SLEEP_TIME_FULL_REFRESH/2; //time used in Thread.sleep() in milliseconds
+
+ //app constants
+ public static BigDecimal CLAIM_CREDITS_PER_AREA = new BigDecimal("25");
+ public static String CLIENT_ID = Constants.NOT_SET;
+
+}
diff --git a/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Constants.java b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Constants.java
new file mode 100644
index 0000000000..91a943bf16
--- /dev/null
+++ b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/Constants.java
@@ -0,0 +1,20 @@
+package ca.bc.gov.open.jagFileSubmission;
+
+public class Constants {
+
+ //drivers
+ public static final String CHROME_DRIVER = "CHROME_DRIVER";
+ public static final String FIREFOX_DRIVER = "FIREFOX_DRIVER";
+ public static final String IE_DRIVER = "IE_DRIVER";
+ public static final String EDGE_DRIVER = "EDGE_DRIVER";
+
+ //enviroments
+ public static final String DEV = "DEV";
+ public static final String TST = "TST";
+
+
+ //others
+ public static final String NOT_SET = "NOT_SET";
+ public static final String JDBCURL = "JDBCURL";
+
+}
diff --git a/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/WaitTool.java b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/WaitTool.java
new file mode 100644
index 0000000000..50f46f04bc
--- /dev/null
+++ b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/WaitTool.java
@@ -0,0 +1,54 @@
+package ca.bc.gov.open.jagFileSubmission;
+
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+
+public class WaitTool {
+
+ /** Default wait time for an element. 7 seconds. */
+ public static final int DEFAULT_WAIT_4_ELEMENT = 7;
+ /** Default wait time for a page to be displayed. 12 seconds.
+ * The average webpage load time is 6 seconds in 2012.
+ * Based on your tests, please set this value.
+ * "0" will nullify implicitlyWait and speed up a test. */
+ public static final int DEFAULT_WAIT_4_PAGE = 12;
+
+
+
+
+ /**
+ * Wait for the element to be present in the DOM, and displayed on the page.
+ * And returns the first WebElement using the given method.
+ *
+ * @param driver The driver object to be used
+ * @param by selector to find the element
+ * @param timeOutInSeconds The time in seconds to wait until returning a failure
+ *
+ * @return WebElement the first WebElement using the given method, or null (if the timeout is reached)
+ */
+ public static WebElement waitForElement(WebDriver driver, final By by, Duration timeOutInSeconds) {
+ WebElement element;
+ try {
+ //To use WebDriverWait(), we would have to nullify implicitlyWait().
+ //Because implicitlyWait time also set "driver.findElement()" wait time.
+ //info from: https://groups.google.com/forum/?fromgroups=#!topic/selenium-users/6VO_7IXylgY
+ driver.manage().timeouts().implicitlyWait(0, TimeUnit.SECONDS); //nullify implicitlyWait()
+
+ WebDriverWait wait = new WebDriverWait(driver, timeOutInSeconds);
+ element = wait.until(ExpectedConditions.visibilityOfElementLocated(by));
+
+ driver.manage().timeouts().implicitlyWait(DEFAULT_WAIT_4_PAGE, TimeUnit.SECONDS); //reset implicitlyWait
+ return element; //return the element
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+
+ }
+ }
diff --git a/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/WebDriverManager.java b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/WebDriverManager.java
new file mode 100644
index 0000000000..b7b30fbc08
--- /dev/null
+++ b/TestAutomation/src/main/java/ca/bc/gov/open/jagFileSubmission/WebDriverManager.java
@@ -0,0 +1,150 @@
+package ca.bc.gov.open.jagFileSubmission;
+
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.chrome.ChromeDriver;
+import org.openqa.selenium.chrome.ChromeOptions;
+import org.openqa.selenium.edge.EdgeDriver;
+import org.openqa.selenium.edge.EdgeOptions;
+import org.openqa.selenium.firefox.FirefoxBinary;
+import org.openqa.selenium.firefox.FirefoxDriver;
+import org.openqa.selenium.firefox.FirefoxOptions;
+import org.openqa.selenium.ie.InternetExplorerDriver;
+import org.openqa.selenium.remote.DesiredCapabilities;
+import org.openqa.selenium.support.ui.Select;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.io.File;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class WebDriverManager {
+
+ public static WebDriverManager instance = null;
+
+ // web driver objects
+ private static WebDriver driver = null;
+ private static WebDriverWait driverWait = null;
+ private static WebElement element = null;
+ private static List elements = null;
+ private static Select select = null;
+
+ /**
+ * private ctor - initialize everything
+ */
+ private WebDriverManager() {
+ driver = initDriver();
+ Duration duration4 = Duration.ofSeconds(10);
+ driverWait = (new WebDriverWait(driver,duration4));
+ element = null;
+ elements = null;
+ select = null;
+ }
+
+ public static WebDriverManager getInstance() {
+ if (instance == null) {
+ instance = new WebDriverManager();
+ }
+ return instance;
+ }
+
+ @SuppressWarnings("deprecation")
+ private static WebDriver initDriver() {
+
+ if (Config.SELECTED_DRIVER.equals(Constants.CHROME_DRIVER)) {
+
+ File file = new File("bin/chromedriver.exe");
+
+ System.setProperty("webdriver.chrome.driver", file.getAbsolutePath());
+
+ DesiredCapabilities capabilities = new DesiredCapabilities();
+
+ Map prefs = new HashMap<>();
+ prefs.put("safebrowsing.enabled", "false"); // Bypass warning message, keep file anyway (for .exe, .jar, etc.)
+
+ ChromeOptions options = new ChromeOptions();
+
+ options.addArguments("test-type");
+ options.setExperimentalOption("prefs", prefs);
+ options.addArguments("start-maximized");
+ options.addArguments("--remote-allow-origins=*");
+ options.addArguments("--headless", "--disable-gpu", "--window-size=1920,1080","--ignore-certificate-errors","--no-sandbox", "--disable-dev-shm-usage");
+
+ capabilities.setCapability("chrome.binary", file.getAbsolutePath());
+
+ capabilities.setCapability(ChromeOptions.CAPABILITY, options);
+
+ driver = new ChromeDriver(options);
+
+ } else if (Config.SELECTED_DRIVER.equals(Constants.FIREFOX_DRIVER)) {
+
+ FirefoxBinary firefoxBinary = new FirefoxBinary();
+ firefoxBinary.addCommandLineOptions("--headless");
+ File file = new File("bin/geckodriver.exe");
+ System.setProperty("webdriver.gecko.driver", file.getAbsolutePath());
+ FirefoxOptions firefoxOptions = new FirefoxOptions();
+ firefoxOptions.setBinary(firefoxBinary);
+ driver = new FirefoxDriver(firefoxOptions);
+ driver.manage().window().maximize();
+
+ } else if (Config.SELECTED_DRIVER.equals(Constants.IE_DRIVER)) {
+
+ // driver = new InternetExplorerDriver();
+
+ String service = "C:\\repo\\epbc-ui-test\\TestProject\\lib\\IEDriverServer.exe";
+ System.setProperty("webdriver.ie.driver", service);
+
+ // Create the DesiredCapability object of InternetExplorer
+ //DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer();
+
+ // Settings to Accept the SSL Certificate in the Capability object
+ //capabilities.setCapability(CapabilityType.ACCEPT_INSECURE_CERTS, true);
+
+ InternetExplorerDriver driver = new InternetExplorerDriver();
+ // driver.get("URL for which certificate error is coming");
+ driver.get("https://tst-apply.educationplannerbc.ca/account/create" + "/account/login");
+
+ } else if (Config.SELECTED_DRIVER.equals(Constants.EDGE_DRIVER)) {
+
+ // Defining System Property for Edge
+ File file = new File("bin/msedgedriver.exe");
+ System.setProperty("webdriver.edge.driver", file.getAbsolutePath());
+
+ driver = new EdgeDriver();
+ driver.manage().window().maximize();
+
+ // Initialize the EdgeOptions class
+ EdgeOptions edgeOptions = new EdgeOptions();
+
+ // Use the addArguments method for configuring headless
+ // edgeOptions.addArguments("headless");
+
+ }
+
+ return driver;
+
+ }
+
+ public static WebDriver getDriver() {
+ return getInstance().driver;
+ }
+
+ public static WebDriverWait getDriverWait() {
+ return getInstance().driverWait;
+ }
+
+ public static WebElement getElement() {
+ return getInstance().element;
+ }
+
+ public static List getElements() {
+ return getInstance().elements;
+ }
+
+ public static Select getSelect() {
+ return getInstance().select;
+ }
+
+}
diff --git a/TestAutomation/src/test/java/ca/bc/gov/open/ui/LoginBCID.java b/TestAutomation/src/test/java/ca/bc/gov/open/ui/LoginBCID.java
new file mode 100644
index 0000000000..691e500cdc
--- /dev/null
+++ b/TestAutomation/src/test/java/ca/bc/gov/open/ui/LoginBCID.java
@@ -0,0 +1,60 @@
+package ca.bc.gov.open.ui;
+
+import ca.bc.gov.open.jagFileSubmission.CommonUtils;
+import ca.bc.gov.open.jagFileSubmission.WebDriverManager;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+import org.springframework.stereotype.Component;
+
+
+import java.time.Duration;
+@Component
+public class LoginBCID {
+
+ private WebDriver driver;
+
+ @After
+ public void tearDown() {
+ driver.close();
+ driver.quit();
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ WebDriverManager.instance = null;
+ }
+
+ @Test
+ public void test() throws Exception {
+ driver = WebDriverManager.getDriver();
+ WebDriverWait driverWait = WebDriverManager.getDriverWait();
+ WebElement element = WebDriverManager.getElement();
+ WebDriverManager.getElements();
+ String bceidUSERNAME = System.getenv("USERNAME_BCEID");
+ String bceidPASSWORD = System.getenv("PASSWORD_BCEID");
+ CommonUtils.login();
+
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), ' Login with my ')]"))).click();
+ System.out.println("Login with BCID page loaded successfully");
+
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.id("user")));
+ element.sendKeys(bceidUSERNAME);
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.id("password")));
+ element.sendKeys(bceidPASSWORD);
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.name("btnSubmit")));
+ element.click();
+ //Login successfully
+ new WebDriverWait(driver, Duration.ofSeconds(50)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), ' New Form ')]")));
+ System.out.println("Login successfully");
+
+
+ }
+}
diff --git a/TestAutomation/src/test/java/ca/bc/gov/open/ui/NoticeOfAppearance.java b/TestAutomation/src/test/java/ca/bc/gov/open/ui/NoticeOfAppearance.java
new file mode 100644
index 0000000000..8533c86df9
--- /dev/null
+++ b/TestAutomation/src/test/java/ca/bc/gov/open/ui/NoticeOfAppearance.java
@@ -0,0 +1,107 @@
+package ca.bc.gov.open.ui;
+
+import ca.bc.gov.open.jagFileSubmission.WebDriverManager;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.JavascriptExecutor;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.interactions.Actions;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.time.Duration;
+
+public class NoticeOfAppearance {
+
+ private WebDriver driver;
+
+ @After
+ public void tearDown() {
+ driver.close();
+ driver.quit();
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ WebDriverManager.instance = null;
+ }
+
+ @Test
+ public void test() throws Exception {
+ driver = WebDriverManager.getDriver();
+ WebDriverWait driverWait = WebDriverManager.getDriverWait();
+ WebElement element = WebDriverManager.getElement();
+ WebDriverManager.getElements();
+
+ LoginBCID notice = new LoginBCID();
+ notice.test();
+
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), ' Notice of Appearance (Form 2) ')]"))).click();
+
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.id("court-of-appeal-file-no")));
+ element.sendKeys("CA46532");
+
+ driverWait.until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[@id=\"respondent\"]/div[1]/label/span"))).click();
+
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.id("first-name")));
+ element.sendKeys("Blair");
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.id("last-name")));
+ element.sendKeys("Greenwood");
+ Thread.sleep(1000);
+ // Scroll down till the bottom of the page
+ JavascriptExecutor js = (JavascriptExecutor) driver;
+ js.executeScript("window.scrollBy(0,document.body.scrollHeight)");
+ driver.findElement(By.xpath("//html")).click();
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(
+ ExpectedConditions.presenceOfElementLocated(By.className("btn-success"))).click();
+ Thread.sleep(1000);
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("/html/body/div/main/div/div/div[4]/div/div/div/div[1]/div[2]/div[1]/select")));
+ element.sendKeys("4 Pillars Consulting Group Inc.");
+ Thread.sleep(1000);
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("/html/body/div/main/div/div/div[4]/div/div/div/div[1]/div[2]/div[2]/select")));
+ element.sendKeys("Blair Greenwood");
+ driver.findElement(By.cssSelector(".custom-control:nth-child(7) > .custom-control-label")).click();
+ //text with address
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("/html/body/div/main/div/div/div[4]/div/div/div/div[2]/div[2]/div[2]/div/textarea")));
+ element.sendKeys("Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a, venenatis vi");
+ //phone no
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("/html/body/div/main/div/div/div[4]/div/div/div/div[2]/div[3]/div[2]/div[1]/input")));
+ element.sendKeys("999-999-9999");
+ //email
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("/html/body/div/main/div/div/div[4]/div/div/div/div[2]/div[4]/div[2]/div/input")));
+ element.sendKeys("test@test.ca");
+ //name
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.xpath("/html/body/div/main/div/div/div[4]/div/div/div/div[2]/div[5]/div[2]/input")));
+ element.sendKeys("Blair Greenwood");
+ //Click Continue
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), 'Continue ')]"))).click();
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), 'OK')]"))).click();
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), 'Blair Greenwood')]")));
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), 'Lorem ipsum dolor sit amet, consectetuer adipiscing')]")));
+ Thread.sleep(1500);
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), 'Proceed ')]"))).click();
+ Thread.sleep(1500);
+ new WebDriverWait(driver, Duration.ofSeconds(50)).until(
+ ExpectedConditions.presenceOfElementLocated(By.className("btn-success"))).click();
+ Thread.sleep(1000);
+ new WebDriverWait(driver, Duration.ofSeconds(50)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), 'Continue')]"))).click();
+ element = driverWait.until(ExpectedConditions.presenceOfElementLocated(By.id("agreeCallout")));
+ element.click();
+ new WebDriverWait(driver, Duration.ofSeconds(50)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), 'Submit')]"))).click();
+ new WebDriverWait(driver, Duration.ofSeconds(50)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), ' Done ')]")));
+
+ }
+}
diff --git a/TestAutomation/src/test/java/ca/bc/gov/open/ui/VerifyNoticeSubmitted.java b/TestAutomation/src/test/java/ca/bc/gov/open/ui/VerifyNoticeSubmitted.java
new file mode 100644
index 0000000000..25c1518a67
--- /dev/null
+++ b/TestAutomation/src/test/java/ca/bc/gov/open/ui/VerifyNoticeSubmitted.java
@@ -0,0 +1,56 @@
+package ca.bc.gov.open.ui;
+
+import ca.bc.gov.open.jagFileSubmission.WebDriverManager;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Test;
+import org.openqa.selenium.By;
+import org.openqa.selenium.WebDriver;
+import org.openqa.selenium.WebElement;
+import org.openqa.selenium.support.ui.ExpectedConditions;
+import org.openqa.selenium.support.ui.WebDriverWait;
+
+import java.time.Duration;
+
+public class VerifyNoticeSubmitted {
+
+ private WebDriver driver;
+
+ @After
+ public void tearDown() {
+ driver.close();
+ driver.quit();
+ }
+
+ @AfterClass
+ public static void afterClass() {
+ WebDriverManager.instance = null;
+ }
+
+ @Test
+ public void test() throws Exception {
+ driver = WebDriverManager.getDriver();
+ WebDriverWait driverWait = WebDriverManager.getDriverWait();
+ WebElement element = WebDriverManager.getElement();
+ WebDriverManager.getElements();
+
+ NoticeOfAppearance packageNo = new NoticeOfAppearance();
+ packageNo.test();
+
+
+ WebElement e = driver.findElement(
+ By.xpath("/html/body/div/main/div/div/div/div[2]/div[2]/div[3]/div[2]/span"));
+ String actualpackageID = e.getText();
+
+ System.out.println("packageID: " + actualpackageID);
+
+ //Click Done
+ new WebDriverWait(driver, Duration.ofSeconds(10)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), ' Done ')]"))).click();
+ new WebDriverWait(driver, Duration.ofSeconds(50)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), ' New Form ')]")));
+ new WebDriverWait(driver, Duration.ofSeconds(50)).until(
+ ExpectedConditions.presenceOfElementLocated(By.xpath("//*[contains(text(), '" + actualpackageID + "')]")));
+
+ }
+}
diff --git a/TestAutomation/src/test/resources/application.properties b/TestAutomation/src/test/resources/application.properties
new file mode 100644
index 0000000000..20bf908e68
--- /dev/null
+++ b/TestAutomation/src/test/resources/application.properties
@@ -0,0 +1,4 @@
+
+#BCEIDCREDS
+USERNAME_BCEID=${USERNAME_BCEID}
+PASSWORD_BCEID=${PASSWORD_BCEID}
diff --git a/docker-compose.override.yml b/docker-compose.override.yml
new file mode 100644
index 0000000000..244e7acb46
--- /dev/null
+++ b/docker-compose.override.yml
@@ -0,0 +1,30 @@
+version: "3.7"
+services:
+
+ #############################################################################################
+ ### EFILING FRONTEND ###
+ #############################################################################################
+ efiling-frontend:
+ build:
+ context: ./src/frontend/efiling-frontend
+
+ #############################################################################################
+ ### Efiling api backend app ###
+ #############################################################################################
+ efiling-api:
+ build:
+ context: ./src/backend
+ dockerfile: Dockerfile.efiling-api
+ args:
+ - MVN_PROFILE=${MVN_PROFILE:-efiling-api-demo}
+ - SKIP_TESTS=true
+ - STARTERS_V=v1.0.5
+
+ # #############################################################################################
+ # ### KEYCLOAK Config ###
+ # #############################################################################################
+ keycloak-config:
+ build:
+ context: ./infrastructure/keycloak
+ args:
+ - KEYCLOAK_URL=http://keycloak:8080
diff --git a/docker-compose.yml b/docker-compose.yml
index 77819b6780..aa21b77d25 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -4,60 +4,101 @@ services:
### EFILING FRONTEND ###
#############################################################################################
efiling-frontend:
- # need stdin_open:true because there is an issue with container being auto exited after startup with react-scripts 3.4.1
- stdin_open: true
container_name: efiling-frontend
- build:
- context: ./src/frontend
- args:
- - SERVICE_NAME=efiling-frontend
ports:
- - 3000:3000
+ - 3000:8080
+ environment:
+ - REACT_APP_KEYCLOAK_REALM=${KEYCLOAK_REALM:-Efiling-Hub}
+ - REACT_APP_KEYCLOAK_CLIENT_ID=efiling-frontend
+ - REACT_APP_KEYCLOAK_URL=${KEYCLOAK_URL:-http://localhost:8081/auth}
+ - REACT_APP_API_BASE_URL=http://localhost:8080
+ - REACT_APP_BAMBORA_REDIRECT_URL=http://localhost:3000/efilinghub
+ - REACT_APP_CSO_BASE_URL=http://localhost/cso
+ - REACT_APP_RUSH_TAB_FEATURE_FLAG=true
#############################################################################################
### EFILING DEMO ###
#############################################################################################
efiling-demo:
- # need stdin_open:true because there is an issue with container being auto exited after startup with react-scripts 3.4.1
- stdin_open: true
container_name: efiling-demo
build:
- context: ./src/frontend
- args:
- - SERVICE_NAME=efiling-demo
+ context: ./src/frontend/efiling-demo
+ environment:
+ - REACT_APP_KEYCLOAK_REALM=Efiling-Hub
+ - REACT_APP_KEYCLOAK_CLIENT_ID=efiling-admin
+ - REACT_APP_KEYCLOAK_URL=http://localhost:8081/auth
+ - REACT_APP_API_BASE_URL=http://localhost:8080
+ - REACT_APP_BAMBORA_REDIRECT_URL=http://localhost:3000/efilinghub
ports:
- - 3001:3000
+ - 3001:8080
#############################################################################################
### Efiling api backend app ###
#############################################################################################
efiling-api:
- build:
- context: ./src/backend
- args:
- - SERVICE_NAME=efiling-api
- - MVN_PROFILE=${MVN_PROFILE}
+ container_name: efiling-api
+ hostname: efiling-api
ports:
- "8080:8080"
environment:
- - REDIS_HOST=redis
- - REDIS_PORT=6379
- - REDIS_PASSWORD=admin
- - NAVIGATION_BASE_URL=http://localhost:3000/efiling
- - NAVIGATION_EXPIRYTIME=10
- - DEMO_MODE=${DEMO_MODE:-true}
+ - BAMBORA_APIPASSCODE=${BAMBORA_APIPASSCODE:-passcode}
+ - BAMBORA_MERCHANTID=${BAMBORA_MERCHANTID-merchantid}
+ - BAMBORA_PROFILE_URL=${BAMBORA_PROFILE_URL:-http://localhost:3001/updatecard}
+ - BAMBORA_HASHKEY=${BAMBORA_HASHKEY:-key}
+ - BAMBORA_PROFILE_SERVICE_VERSION=${BAMBORA_PROFILE_SERVICE_VERSION}
+ - BAMBORA_URL_EXPIRY=10
+
+ - KEYCLOAK_AUTH_SERVER_URL=${KEYCLOAK_AUTH_SERVER_URL:-http://localhost:8081/auth/realms/Efiling-Hub}
+ - KEYCLOAK_JWK_SERVER_URL=${KEYCLOAK_JWK_SERVER_URL:-http://keycloak:8080/auth/realms/Efiling-Hub}
+ - KEYCLOAK_REALM=${KEYCLOAK_RESOURCE:-efiling-api}
+
+ - CSO_ACCOUNTFACADE_URI=${CSO_ACCOUNTFACADE_URI}
- CSO_ACCOUNTFACADE_USERNAME=${CSO_ACCOUNTFACADE_USERNAME}
- CSO_ACCOUNTFACADE_PASSWORD=${CSO_ACCOUNTFACADE_PASSWORD}
- - CSO_ACCOUNTFACADE_URI=${CSO_ACCOUNTFACADE_URI}
- CSO_ROLEREGISTRY_USERNAME=${CSO_ROLEREGISTRY_USERNAME}
- CSO_ROLEREGISTRY_PASSWORD=${CSO_ROLEREGISTRY_PASSWORD}
- CSO_ROLEREGISTRY_URI=${CSO_ROLEREGISTRY_URI}
- CSO_LOOKUPFACADE_USERNAME=${CSO_LOOKUPFACADE_USERNAME}
- CSO_LOOKUPFACADE_PASSWORD=${CSO_LOOKUPFACADE_PASSWORD}
- CSO_LOOKUPFACADE_URI=${CSO_LOOKUPFACADE_URI}
- - BCEID_LOOKUP_USERNAME=${BCEID_LOOKUP_USERNAME}
- - BCEID_LOOKUP_PASSWORD=${BCEID_LOOKUP_PASSWORD}
- - BCEID_LOOKUP_URI=${BCEID_LOOKUP_URI}
+ - CSO_BCEIDSERVICE_URI=${CSO_BCEIDSERVICE_URI}
+ - CSO_FILINGSTATSFACADE_URI=${CSO_FILINGSTATSFACADE_URI}
+ - CSO_FILINGSTATSFACADE_USERNAME=${CSO_FILINGSTATSFACADE_USERNAME}
+ - CSO_FILINGSTATSFACADE_PASSWORD=${CSO_FILINGSTATSFACADE_PASSWORD}
+ - CSO_BCEIDSERVICE_USERNAME=${CSO_BCEIDSERVICE_USERNAME}
+ - CSO_BCEIDSERVICE_PASSWORD=${CSO_BCEIDSERVICE_PASSWORD}
+ - CSOWS_USERNAME=${CSOWS_USERNAME}
+ - CSOWS_PASSWORD=${CSOWS_PASSWORD}
+ - CSOWS_URI=${CSOWS_URI}
+ - CSO_FILINGFACADE_URI=${CSO_FILINGFACADE_URI}
+ - CSO_FILINGFACADE_PASSWORD=${CSO_FILINGFACADE_PASSWORD}
+ - CSO_FILINGFACADE_USERNAME=${CSO_FILINGFACADE_USERNAME}
+ - CSO_SERVICEFACADE_URI=${CSO_SERVICEFACADE_URI}
+ - CSO_SERVICEFACADE_USERNAME=${CSO_SERVICEFACADE_USERNAME}
+ - CSO_SERVICEFACADE_PASSWORD=${CSO_SERVICEFACADE_PASSWORD}
+
+ - SFTP_KNOWNHOSTS=${SFTP_KNOWNHOSTS}
+ - SFTP_REMOTELOCATION=${SFTP_REMOTELOCATION}
+ - SFTP_PRIVATE_KEY=${SFTP_PRIVATE_KEY}
+
+ - BCEID_SERVICE_URI=${BCEID_SERVICE_URI}
+ - BCEID_SERVICE_USERNAME=${BCEID_SERVICE_USERNAME}
+ - BCEID_SERVICE_PASSWORD=${BCEID_SERVICE_PASSWORD}
+ - BCEID_SERVICE_ONLINE_SERVICE_ID=${BCEID_SERVICE_ONLINE_SERVICE_ID}
+
+ - REDIS_HOST=redis
+ - REDIS_PORT=6379
+ - REDIS_PASSWORD=admin
+
+ - NAVIGATION_BASE_URL=http://localhost:3000/efilinghub
+ - NAVIGATION_EXPIRYTIME=10
+
+ - CLAMAV_HOST=clamav
+ - CLAMAV_TIMEOUT=150000
+
+ - MVN_PROFILE=${MVN_PROFILE}
+ - STARTERS_V=${STARTERS_V}
+
networks:
- fisu-net
@@ -65,7 +106,7 @@ services:
### REDIS SERVER ###
#############################################################################################
redis:
- container_name: redis
+ container_name: efiling_redis
image: redis
command: redis-server --requirepass admin
ports:
@@ -77,61 +118,75 @@ services:
- fisu-net
#############################################################################################
- ### RABBIT MQ SERVER ###
+ ### REDIS COMMANDER ###
#############################################################################################
- rabbitmq:
- image: rabbitmq:3.7.15-management
- container_name: rabbitmq
- hostname: rabbitmq
+ redis-commander:
+ container_name: efiling_redis-commander
+ hostname: redis-commander
+ image: rediscommander/redis-commander:latest
+ restart: always
+ environment:
+ - REDIS_PORT=6379
+ - REDIS_HOST=redis
+ - REDIS_PASSWORD=admin
ports:
- - 5672:5672
- - 15672:15672
+ - "8082:8081"
+ networks:
+ - fisu-net
+
+ # #############################################################################################
+ # ### KEYCLOAK ###
+ # #############################################################################################
+ keycloak:
+ image: quay.io/keycloak/keycloak:26.1.3
+ environment:
+ - KC_HEALTH_ENABLED=true
+ - KC_METRICS_ENABLED=true
+ - KC_HTTP_ENABLED=true
+ - KC_HOSTNAME_STRICT_HTTPS=false
+ - KEYCLOAK_SSL_REQUIRED=none
+ - KC_HOSTNAME_STRICT_BACKCHANNEL=false
+ - KC_PROXY_HEADERS=xforwarded
+ - KC_HOSTNAME=localhost
+ - KC_HTTP_RELATIVE_PATH=/auth
+ - KC_HOSTNAME_PORT=8080
+ - DB_VENDOR=H2
+ - KC_BOOTSTRAP_ADMIN_USERNAME=admin
+ - KC_BOOTSTRAP_ADMIN_PASSWORD=admin
+ - KC_DIR=/opt/keycloak/data/import
volumes:
- - data-rabbit:/var/lib/rabbitmq/mnesia/rabbit@app-rabbitmq:cached
+ - ./infrastructure/keycloak/realm-export.json:/opt/keycloak/data/import/realm-export.json
+ ports:
+ - 8081:8080
restart: always
+ command: start --import-realm
networks:
- fisu-net
- #############################################################################################
- ### KEYCLOAK POSTGRES ###
- #############################################################################################
-
- postgres:
- image: postgres
- volumes:
- - postgres_data:/var/lib/postgresql/data
- environment:
- POSTGRES_DB: keycloak
- POSTGRES_USER: keycloak
- POSTGRES_PASSWORD: password
+ # #############################################################################################
+ # ### KEYCLOAK Config ###
+ # #############################################################################################
+ keycloak-config:
+ command: sh -c "dockerize -timeout 300s /tmp/createuser.sh"
+ networks:
+ - fisu-net
#############################################################################################
- ### KEYCLOAK ###
+ ### CLAMAV ###
#############################################################################################
-
- keycloak:
- image: quay.io/keycloak/keycloak:latest
- environment:
- DB_VENDOR: POSTGRES
- DB_ADDR: postgres
- DB_DATABASE: keycloak
- DB_USER: keycloak
- DB_SCHEMA: public
- DB_PASSWORD: password
- KEYCLOAK_USER: admin
- KEYCLOAK_PASSWORD: Pa55w0rd
- # Uncomment the line below if you want to specify JDBC parameters. The parameter below is just an example, and it shouldn't be used in production without knowledge. It is highly recommended that you read the PostgreSQL JDBC driver documentation in order to use it.
- #JDBC_PARAMS: "ssl=true"
+ clamav:
+ image: mk0x/docker-clamav
ports:
- - 8081:8080
- depends_on:
- - postgres
+ - "3310:3310"
+ networks:
+ - fisu-net
volumes:
data-redis:
- data-rabbit:
- postgres_data:
driver: local
+ data01:
+ driver: local
+ mongo-volume:
networks:
fisu-net:
diff --git a/docs/README.md b/docs/README.md
index e1c788064f..cabac54691 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,2 +1,239 @@
# jag-file-submission
+
Generic File Submission API (to be used by the Family Law Act Application at first)
+
+## Introduction
+
+Are you ready to integrate your application with the BC Gov E-filing Hub in order to allow your users to e-file documents?
+
+This guide will provide you with all the required information you need to get started.
+
+### Request a profile
+
+> Follow the following instructions in [Getting started - Onboarding](onboarding.md)
+
+### Start Integrating
+
+Get an oauth token from our Keycloak Server using the following curl command:
+
+```bash
+curl --location --request POST 'keycloak_url' \
+--header 'Content-Type: application/x-www-form-urlencoded' \
+--data-urlencode 'client_id=[your client id]' \
+--data-urlencode 'grant_type=client_credentials' \
+--data-urlencode 'client_secret=[your client secret]'
+```
+
+> the secret should be kept safe and not exposed to the public
+
+Start by uploading document(s) to the **eFiling Hub** API:
+
+```bash
+curl --location --request POST '[filing-hub-url]/submission/documents' \
+--header 'X-Transaction-Id: ca09e538-d34e-11ea-87d0-0242ac130003' \
+--header 'X-User-Id: [X-User-Id]' \
+--header 'Content-Type: multipart/form-data' \
+--header 'Authorization: Bearer [bearer_token]' \
+--form 'files=test.pdf'
+```
+
+the response includes a submission id that you will use to generate a redirect url
+
+```json
+{
+ "submissionId": "5e9492cf-e87e-48b5-ba55-0c198d8edde5",
+ "received": 1
+}
+```
+
+Then generate a unique url to redirect the users to the **eFiling Hub**
+
+```bash
+curl --location --request POST '[filing-hub-url]/submission/5e9492cf-e87e-48b5-ba55-0c198d8edde5/generateUrl' \
+--header 'X-Transaction-Id: ca09e538-d34e-11ea-87d0-0242ac130003' \
+--header 'X-User-Id: [X-User-Id]' \
+--header 'Content-Type: application/json' \
+--header 'Authorization: Bearer [bearer_token]' \
+--data-raw 'the json payload bellow'
+```
+
+payload:
+
+```json
+{
+ "clientAppName": "string",
+ "filingPackage": {
+ "court": {
+ "location": "string",
+ "level": "P",
+ "courtClass": "F",
+ "division": "I",
+ "fileNumber": "string"
+ },
+ "documents": [
+ {
+ "name": "string",
+ "type": "ABP",
+ "isAmendment": true,
+ "isSupremeCourtScheduling": true,
+ "data": {},
+ "md5": "string"
+ }
+ ],
+ "parties": [
+ {
+ "roleType": "ABC",
+ "firstName": "string",
+ "middleName": "string",
+ "lastName": "string"
+ }
+ ],
+ "organizationParties": [
+ {
+ "roleType": "ABC",
+ "name": "string"
+ }
+ ]
+ },
+ "navigationUrls": {
+ "success": "string",
+ "error": "string",
+ "cancel": "string"
+ }
+}
+```
+
+### Generate URL Payload Details
+
+#### navigation
+
+The `navigation` object represents a list of possible returns to your application based on the status of the document e-filing.
+
+#### clientApplication
+
+The `clientApplication` object represents how your application is labelled in **efiling hub**.
+
+#### filingPackage
+
+The `filingPackage` object represents the court information about the submitted package along with the document(s) info.
+
+##### court
+
+The `court` object represents the court details.
+
+##### Properties
+
+| name | type | required | description |
+| ---------- | ------ | -------- | ----------------------------------------------------------------------------- |
+| location | string | true | Court House where the package is submitted to |
+| level | string | true | Court level, can be `Supreme` of `Provincial` |
+| courtClass | string | true | Court Classification see [Court Classification](data.md#Court-Classification) |
+| division | string | true | R for Criminal, I for Civil see [Court Division](data.md#Court-Division) |
+| fileNumber | string | false | The court file number, leave blank for new Package Submission |
+
+##### Documents
+
+The `documents` array represents the previously uploaded documents.
+
+###### Properties
+
+| name | type | required | description |
+| ------------------------ | ------- | -------- | ------------------------------------------------------------------------------------------ |
+| name | string | true | the document name, must be the same name as uploaded previously |
+| type | string | true | the type of document see [Document Type Codes](data.md#Document-Type-Codes) |
+| isAmendment | boolean | true | if the document is an amendment |
+| isSupremeCourtScheduling | boolean | true | if the document is directed to Supreme Court Scheduling |
+| data | object | false | A non defined json object representing the form data of the document |
+| md5 | string | false | The md5 hash value of the document content, used to validate the integrity of the document |
+
+##### parties
+
+The `parties` array represents a list of individual parties for the submission
+
+##### Properties
+
+
+| name | type | required | description |
+| ---------- | ------ | -------- | ----------------------------------------------------------------------------------------------- |
+| roleType | string | true | the party role, see [Party Role](data.md#Party-Role) |
+| firstName | string | true | the party first name |
+| middleName | string | false | the party middle name |
+| lastName | string | true | the party last name |
+
+##### organizationParties
+
+The `organizationParties` array represents a list of organization parties for the submission
+
+##### Properties
+
+
+| name | type | required | description |
+| ---------- | ------ | -------- | ----------------------------------------------------------------------------------------------- |
+| roleType | string | true | the party role, see [Party Role](data.md#Party-Role) |
+| name | string | true | the organization name |
+
+### Package Review
+
+The efiling Package Review screen shows the details of a submitted package.
+
+https://dev.justice.gov.bc.ca/efilinghub/packagereview/:packageId?returnUrl=&returnAppName=&defaultTab=
+
+The returnUrl parameter is optional, but if an encoded URL is supplied, the
+page will render with a button that will return the user to the given URL
+(i.e., parent application).
+
+The returnAppName parameter is optional, but if an encoded name of the Parent Application
+is specified, the "Return to Parent App" button will be named accordingly.
+
+The defaultTab parameter is optional, but if an encoded defaultTab
+is specified, the Package Review will display that tab by default.
+
+### Api Documentation
+
+eFiling API is documented using [openapi](http://editor.swagger.io/?url=https://raw.githubusercontent.com/bcgov/jag-file-submission/master/src/backend/efiling-api/jag-efiling-api.yaml) and we have a [postman collection](https://raw.githubusercontent.com/bcgov/jag-file-submission/master/src/backend/jag-efiling-api/src/test/jag-efiling-api.postman_collection.json) that you can use to test the eFiling API
+
+#### Answers to FAQ:
+
+##### What should be used for `roleType` and `partyType` in parties?
+
+The default values to be used for `roleType` is CLA and for `partyType` it is IND. Can refer to the roles in the code tables for more details.
+
+#### Are the various types of documents the ones present in this list? - https://bcgov.github.io/jag-file-submission/#/data?
+
+Yes. This is our list of various document types that can be submitted.
+For FLA, the document types are as follows: Application to Obtain an Order (APO) , Notice of Motion (NM), Affidavit (AFF), and Electronic Filing Statement (EFS- Provincial).
+
+##### For the parties info, would this be the applicant and respondent?
+
+Yes. Applicant and respondent is correct for the parties.
+
+##### For documents, what kind of information should/can be included in the following fields?
+
+`Data`: A copy of the data collected on parent app side. JSON object containing the party info, potential issue, acts, things associated with divorce, etc.
+
+`MD5`: Computed hash value of the document content, it is used as a checksum to validate the document integrity.
+
+`isAmendment`: This marks if the document is an amendment.
+
+`isSupremeCourtScheduling`: This marks if the document is for supreme court scheduling. The Supreme Court Scheduling will not apply initially as we are dealing with Provincial Court, but in the future Supreme Court will be applicable.
+
+##### What should the value of `clientAppName` be?
+
+This field signifies the name of the parent application integrating with the eFiling hub and will show up on the eFiling hub, so please use a full form name such as `Family Law Act Application`.
+
+##### For the court information, how should the fields be determined for this section?
+
+Parent app should know level and class. Court location can be provided through the code tables.
+
+#### Response
+
+on submission you will receive the following response:
+
+```json
+{
+ "expiryDate": 1597944879789,
+ "efilingUrl": "a link where the user should be redirected"
+}
+```
+
+Redirect the user to `efilingUrl` and we will handle the rest for you.
diff --git a/docs/_sidebar.md b/docs/_sidebar.md
index 8ea4d22da6..c2bb1f305a 100644
--- a/docs/_sidebar.md
+++ b/docs/_sidebar.md
@@ -1,5 +1,7 @@
-* [Home](/)
-* [Getting started](gettingStarted.md)
-* [Integration](integration.md)
-* [Dictionary](dictionary.md)
-* [Timeline](timeline.md)
+- [Home](/)
+- [Onboarding](onboarding.md)
+- [Error Handling](errorHandling.md)
+- [Data](data.md)
+- [Integration](integration.md)
+- [Dictionary](dictionary.md)
+- [Timeline](timeline.md)
diff --git a/docs/data.md b/docs/data.md
new file mode 100644
index 0000000000..d00976309b
--- /dev/null
+++ b/docs/data.md
@@ -0,0 +1,240 @@
+# Data
+
+In this section you can find values to use for efling packages to Court Services Online
+
+## Document Type Codes
+
+| documentTypeCd | documentTypeDesc |
+| -------------- | --------------------------------------------------------------------------------------- |
+| AFF | Affidavit |
+| AFJ | Affidavit Section 51 |
+| AAS | Affidavit of Attempted Service |
+| APS | Affidavit of Personal Service |
+| AMM | Agreement Made In a Facilitated Planning Meeting or Mediation |
+| AEO | Application Respecting Existing Orders or Agreements |
+| AFO | Application for an Order - CFCSA |
+| APC | Application to Change/Cancel Order |
+| AEC | Application to Enforce a Custody Order |
+| APO | Application to Obtain an Order |
+| ARC | Application to Recognize a Custody or Access Order made by an Extra-Provincial Tribunal |
+| AEA | Application to Recognize an Extraprovincial Order |
+| ARE | Application to Renew, Change or Cancel an Order (Adult Guardianship) |
+| ARD | Application to re-set Court date |
+| CCB | Case Conference Brief |
+| CCR | Case Conference Record |
+| CRDF | Certificate - Notice of Default Fee |
+| CRA | Certificate of Attempted Service |
+| COEA | Certificate of Enforceability and Arrears |
+| CRF | Certificate of Fitness |
+| COI | Certificate of Incapability (Form 2 AGA) |
+| COJ | Certificate of Judgment |
+| CSV | Certificate of Service |
+| COT | Consent (Form 19) |
+| COR | Consent Order |
+| CPR | Consent for Child Protection Record Check |
+| CCA | Consent to Court Date |
+| CRP | Correspondence |
+| CUR | Currency Certificate |
+| CAR | Custody and Access Report |
+| DPO | Default Payment Order |
+| DOR | Desk Order |
+| DET | Determination |
+| EFSP | Electronic Filing Statement - Provincial |
+| FRCC | FMEP Request for Certified Copies |
+| FCR | Family Case Conference Record (FLA) |
+| FLC | Family Law Matter Claim (Victoria only) |
+| FSUM | File Summary (Victoria only - ERP Project) |
+| FS | Financial Statement/Statement of Finances |
+| FAC | Form A - Circumstances that caused removal |
+| FBW | Form B - Withdrawal by Director |
+| FFS | Form F - Section 29.1 Application for Supervision Order Report |
+| ORNA | Form J Order without Notice/Appearance |
+| FULL | Full Report - FLA s.211 |
+| GOA | Garnishing Order After Judgment |
+| GOB | Garnishing Order Before Judgment |
+| HCL | Hague Convention Article 16 Letter |
+| IPR | Internal Pre-Trial Conference Record |
+| LOD | List of Documents |
+| NID | NOI to Dispute Monies Pd into Court |
+| NOA | Notice of Appeal |
+| NA | Notice of Attachment |
+| NCD | Notice of Change of Address For Delivery |
+| NCS | Notice of Change of Solicitor |
+| NFC | Notice of Family Claim |
+| NFMC | Notice of Family Management Case Conference |
+| NOF | Notice of Filing |
+| NOH | Notice of Hearing or Conference |
+| NIAP | Notice of Intention to Act in Person |
+| NPR | Notice of Intention to Proceed |
+| NM | Notice of Motion |
+| NME | Notice of Motion in Maintenance Enforcement Proceedings |
+| NPO | Notice of Payment Out |
+| NRP | Notice of Protection or Restraining Order |
+| NRG | Notice of Registration |
+| NRO | Notice of Restraining Order (PFA 806) |
+| NWD | Notice of Withdrawal |
+| NWS | Notice of Withdrawal of Solicitor |
+| NTR | Notice to Appear (Adult Guardianship Act) |
+| NTD | Notice to Debtor - FMEP |
+| ORD | Order |
+| ODT | Order (Form 7) |
+| ORO | Order (opens file) |
+| ORP | Order for Attendance of a Prisoner in a Civil or Family Matter |
+| OA | Order for Attendence of a Prisoner |
+| OTH | Other Document |
+| PAS | Parenting After Separation Certificate |
+| PASE | Parenting After Separation Exemption |
+| PAR | Parenting Arrangement Report |
+| POC | Plan of Care |
+| REP | Presentation Report |
+| PPL | Proposal |
+| PTS | Proposed terms of supervision (CFCSA) |
+| POR | Protection Order |
+| PIO | Protective Intervention Order |
+| PVO | Provisional Order |
+| RFJ | Reasons For Judgment |
+| RCF | Record Check Results - s.51 Child Protection (MCFD) |
+| RCR | Record Check Results - s.51 Protection Order Registry |
+| REF | Referal Request |
+| RO | Release (FRA) |
+| RPL | Reply |
+| RTC | Reply to a Counterclaim |
+| RPC | Reply with Counterclaim |
+| RQT | Request (Form 18) |
+| RCE | Request for Court Enforcement |
+| RPS | Request for Protection Order Registry Search |
+| RFS | Request for Service of Documents |
+| RFT | Request for Teleconference |
+| RFR | Request for s.211 Report - FLA |
+| RGW | Request to Adjourn Generally or Withdraw Application |
+| REQ | Requisition |
+| RSA | Respondent's Answer to Application - ISO Form N |
+| RSO | Restraining Order |
+| ROR | Restraining Order under Family Maintenance Enforcement Act |
+| SNR | Scheduling Instructions - No Reply |
+| SWR | Scheduling Instructions - With Reply |
+| SR | Search Request |
+| SRR | Search Request Response from Locate Services |
+| SA | Separation Agreement |
+| SOA | Statement of Arrears |
+| SRO | Statement of Recalculation |
+| SUB | Submissions |
+| STW | Subpoena to a Witness |
+| SUM | Summons |
+| SCH | Summons to a Committal Hearing |
+| SDH | Summons to a Default Hearing |
+| SAP | Support Application |
+| SVA | Support Variation Application |
+| TRN | Transcript |
+| TC | Transfer Consent |
+| VOC | Views of the Child Report - FLA s.211 |
+| WAV | Waiver (Notification period CFCSA) |
+| WCL | Warrant Cancellation |
+| WFA | Warrant for Arrest |
+| WAW | Warrant for Witness |
+| WOC | Warrant of Committal |
+| WAE | Warrant of Execution |
+| WEX | Warrant of Execution |
+| WAA | Warrant to Arrest |
+| HCLW | Withdrawal of Hague Convention Letter - Article 16 |
+| WNC | Without Notice Application Checklist |
+| WRT | Writ of Summons |
+| WAG | Written Agreement |
+| WCT | Written Consent |
+
+## Court Classification
+
+| Level | Level Description | Classification | Classification Description |
+| ----- | ----------------- | -------------- | ------------------------------ |
+| A | Appeal | O | Appeal Civil |
+| P | Provincial | C | Small Claims |
+| P | Provincial | F | Family |
+| P | Provincial | L | Enforcement/Legislated Statute |
+| P | Provincial | M | Motor Vehicle Accidents |
+| S | Supreme | B | Bankruptcy |
+| S | Supreme | D | Divorce |
+| S | Supreme | E | Family Law Proceedings |
+| S | Supreme | H | Foreclosure |
+| S | Supreme | L | Enforcement/Legislated Statute |
+| S | Supreme | M | Motor Vehicle Accidents |
+| S | Supreme | N | Adoption |
+| S | Supreme | P | Probate |
+| S | Supreme | S | Supreme Civil (General) |
+| S | Supreme | V | Caveat |
+
+## Court Division
+
+| Code | Description |
+| R | Criminal Court |
+| C | Civil Court |
+
+## Party Role
+
+| Code | Description |
+| ---- | --------------------------------- |
+| ABC | Aboriginal Community |
+| ADJ | Adjudicator |
+| ADP | Adoptee |
+| APL | Appellant |
+| APP | Applicant |
+| ANT | Aunt |
+| AUT | Authority |
+| BKP | Bankrupt |
+| BKS | Bankrupts (Spouse) |
+| CAV | Caveator |
+| CHD | Child |
+| COF | Child on File |
+| CIT | Citator |
+| CLA | Claimant |
+| CLA1 | Claimant 1 |
+| CLA2 | Claimant 2 |
+| CLI | Client |
+| CI | Court Issued |
+| CRD | Creditor |
+| DBT | Debtor |
+| DEC | Deceased |
+| DEF | Defendant |
+| DEO | Defendant by Counterclaim |
+| DIS | Disputant |
+| FTH | Father |
+| FNA | First Nation |
+| GRF | Grandfather |
+| GRM | Grandmother |
+| GUA | Guardian |
+| HSB | Husband - Divorce |
+| INB | Indian Band |
+| INC | Indigenous Community |
+| ITV | Intervener |
+| MOT | Mother |
+| NIS | Nisga'a Lisims Government |
+| PAR1 | Party 1 |
+| PA1 | Party 1 Joint Divorce Form127A |
+| PAR2 | Party 2 |
+| PA2 | Party 2 Joint Divorce Form127A |
+| PAR3 | Party 3 |
+| PAR4 | Party 4 |
+| PAR5 | Party 5 |
+| PET | Petitioner |
+| PLA | Plaintiff |
+| RES | Respondent |
+| REO | Respondent by way of Counterclaim |
+| SOL | Solicitor |
+| SP1 | Spouse 1- Divorce |
+| SP2 | Spouse 2 - Divorce |
+| SFH | Step-Father |
+| SMH | Step-Mother |
+| TST | Testator |
+| TSX | Testatrix |
+| THR | Third Party |
+| TFN | Treaty First Nation |
+| TRU | Trustee |
+| UNC | Uncle |
+| WIF | Wife - Divorce |
+| WIT | Witness |
+
+## Party type
+
+| Code | Description |
+| ---- | ------------ |
+| IND | Individual |
+| ORG | Organization |
diff --git a/docs/errorHandling.md b/docs/errorHandling.md
new file mode 100644
index 0000000000..84a3161e0e
--- /dev/null
+++ b/docs/errorHandling.md
@@ -0,0 +1,87 @@
+# Error Handling
+
+This documentation defines how errors may be handled by the eFiling Hub; it is based on the User Flow diagram.
+
+## Incorrect Navigation
+
+1. Navigating to the site without a submission ID or with an invalid submission ID will result in rendering an error message.
+
+## Initial Package Verification
+
+1. Package information from Parent App is not sufficient - does not include document descriptions, valid Parent App return link etc.
+ - System returns error to Parent App
+ - Parent App action TDB
+
+## User Account Verification/Setup
+
+1. User does not have an eFiling role
+
+ - Parent app may hide button/option to use eFiling (Check for eFiling role on authentication?)
+ - Parent app may display error message. E.g. "You do not have a valid CSO account and are unable to use the eFiling Hub to file documents at this time"
+
+2. User does not authorize creation of CSO account (Does not tick the "I Accept" checkbox)
+
+ - "Create CSO Account" button is in disabled state with roll-over/tap text "Please accept the Service Agreement to continue"
+
+3. CSO Account cannot be created (may be multiple reasons)
+ - User is returned to Parent App with error message. E.g. "CSO Account required for eFiling could not be created at this time. Please try again later"
+
+## Package Confirmation
+
+- No known error potential at this step. Initial Package Verification error handling should catch error states.
+
+## Document Upload
+
+1. Document fails upload because size is over 10mb
+
+ - eFiling Hub displays error message. E.g. “Document size is limited to 10mb. Please reduce the size of your documents (_tips on how to reduce size?_) or visit (_information on process?_) to learn how to file larger documents”
+
+2. Document fails to upload because extention type is not supported
+
+ - eFiling Hub displays error message. E.g. "Documents with the following extension type are not supported: exe"
+
+3. Document fails to upload to staging area
+
+ - eFiling Hub displays error message. E.g. "Document upload failed. Please try again"
+
+4. Document fails to upload to staging area more than 3 times
+ - TBD
+
+## Payment Review
+
+1. Registering a new card with Bambora fails
+
+ - Bambora app handles validation failure. User stays on Bambora until they cancel.
+
+2. If user cancels on Bambora
+
+ - eFiling Hub displays the alert "You do not have a valid Credit Card registered with your CSO Account. Register a card now to continue.
+
+3. If a user tries to "Register a card now" more than 5 times
+ - (_do we want to treat this an card validation attempt security event?_) TBD
+
+## Package Submission
+
+1. User does not accept the "I have reviewed the information" prompt (Does not tick the "I Agree" checkbox)
+
+ - "Submit" button is in disabled state with roll-over/tap text "Please review your submission and Agree to continue"
+
+2. Submit documents to CSO failed because CSO is down
+
+ - System tried again with loading indicator displayed in eFiling Hub
+
+3. Submit documents to CSO failed more than 3 times
+
+ - User is returned to Parent App with error message. E.g. "Package filing failed. Please try again later"
+
+4. CSO fee processing failed
+ - TBD
+
+## Rush/Urgent Submission
+
+- TBD
+
+## Cancel
+
+1. User clicks "Cancel" button
+ - User is prompted to confirm, and if yes, is returned to Parent App with message. E.g. "Your eFiling submission has been cancelled"
diff --git a/docs/gettingStarted.md b/docs/gettingStarted.md
deleted file mode 100644
index bf010c427e..0000000000
--- a/docs/gettingStarted.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# Getting started
-
-## Introduction
-
-Ready for integrating your application with bcgov efiling service and allow your users to efile document ?
-
-This guide will provide you with all information you need to get started.
-
-## Test accounts
-
-Use the following accounts to test the application
-
-| Account Guid | Description |
-| --- | --- |
-| 77da92db-0791-491e-8c58-1a969e67d2fa | An account with a linked CSO account and an efiling role |
-| 77da92db-0791-491e-8c58-1a969e67d2fb | An account with a linked CSO account and no efiling role |
-| 88da92db-0791-491e-8c58-1a969e67d2fb | An account without CSO account but a fake bceid profile |
-
-## Quick start
-
-Generate a secure url by calling the generateUrl endpoint
-
-```bash
-
-curl --location --request POST 'http://localhost:8080/document/generateUrl' \
---header 'Content-Type: application/json' \
---data-raw '{
- "documentMetadata": {
- "type": "string",
- "subType": "string",
- "documentAccess": {
- "url": "string",
- "verb": "GET",
- "headers": {
- "additionalProp1": "string",
- "additionalProp2": "string",
- "additionalProp3": "string"
- }
- }
- },
- "navigation": {
- "success": {
- "url": "string"
- },
- "error": {
- "url": "string"
- },
- "cancel": {
- "url": "string"
- }
- }
-}'
-
-```
-
-## Api Documentation
-
-E-filing-api is documented using [openapi](http://editor.swagger.io/?url=https://raw.githubusercontent.com/bcgov/jag-file-submission/master/src/backend/efiling-api/jag-efiling-api.yaml) and we have a [postman collection](https://raw.githubusercontent.com/bcgov/jag-file-submission/master/src/backend/jag-efiling-api/src/test/jag-efiling-api.postman_collection.json) that you can use to test the e-filing-api
-
-## Diagram flow
-
-
diff --git a/docs/integration.md b/docs/integration.md
index c8988a7aef..41ceb03177 100644
--- a/docs/integration.md
+++ b/docs/integration.md
@@ -1,8 +1,8 @@
# JAG File Submission Continuous Integration
-## Git Action Workflow
+## CI/CD Workflow
-
+
## Code Climate
diff --git a/docs/media/demoApp.png b/docs/media/demoApp.png
index ce372958ea..068e83b22e 100644
Binary files a/docs/media/demoApp.png and b/docs/media/demoApp.png differ
diff --git a/docs/onboarding.md b/docs/onboarding.md
new file mode 100644
index 0000000000..061bb4e0ce
--- /dev/null
+++ b/docs/onboarding.md
@@ -0,0 +1,34 @@
+# Getting Started - Onboarding
+
+## Request Keycloak Client
+
+Create a Github [issue](https://github.com/bcgov/jag-file-submission/issues/new?assignees=akroon3r%2C+alexjoybc&labels=Onboarding&template=onboarding-request.md&title=%5BONBOARDING%5D) to begin the onboarding process to our application.
+
+On completion of the Github issue, the user will be provided [OpenId Connect](https://openid.net/connect/) information such as *client_id*, *realm*, *client_secret*. All of which are required to be kept secured at all times.
+
+## Request Keycloak Token
+
+First, users will want to POST against the following URL: ${keycloakBaseUrl}/realms/${keycloakRealm}/protocol/openid-connect/token
+
+- ${keycloakBaseUrl} will be the value https://sso-${ENVIRONMENT}.pathfinder.gov.bc.ca/auth, where ${ENVIRONMENT} is either dev, test or prod
+- ${keycloakRealm} will be provided to you by the admin after the keycloak client request has been fufilled
+
+In the request body, the following information will be required
+
+Example body: client_id=${keycloakClientId}&grant_type=client_credentials&client_secret=${keycloakClientSecret}
+
+- client_id : Provided to the user by the admin after the keycloak client request has been fufilled
+- grant_type : value will always be `client_credentials`
+- client_secret : Provided to the user by the admin after the keycloak client request has been fufilled
+
+Once the request for the keycloak token has been completed successfully, the user can begin to interface with the Efiling Hub [API](https://editor.swagger.io/?url=https://raw.githubusercontent.com/bcgov/jag-file-submission/master/src/backend/efiling-api/jag-efiling-api.yaml) and Frontend Applications. The two API endpoints that a parent application will interface with are the `/submission/documents` and `/submission/${submissionId}/generateUrl`.
+
+The following is a sample curl command for generating a token from any keycloak environment:
+
+``` bash
+curl --location --request POST 'https://[keycloak auth endpoint]/auth/realms/[keycloak-realm]/protocol/openid-connect/token' \
+--header 'Content-Type: application/x-www-form-urlencoded' \
+--data-urlencode 'client_id=[your client id]' \
+--data-urlencode 'grant_type=client_credentials' \
+--data-urlencode 'client_secret=[your client secret]'
+```
diff --git a/infrastructure/keycloak/Dockerfile b/infrastructure/keycloak/Dockerfile
new file mode 100644
index 0000000000..4442b201d2
--- /dev/null
+++ b/infrastructure/keycloak/Dockerfile
@@ -0,0 +1,23 @@
+FROM ubuntu:18.04
+
+ARG KEYCLOAK_URL
+ARG DOCKERIZE_VERSION=v0.6.1
+
+ENV KEYCLOAK_URL=$KEYCLOAK_URL
+
+# Temp fix for maching have clock issue. see https://stackoverflow.com/questions/63526272/release-file-is-not-valid-yet-docker
+RUN echo "Acquire::Check-Valid-Until \"false\";\nAcquire::Check-Date \"false\";" | cat > /etc/apt/apt.conf.d/10no--check-valid-until
+
+RUN apt-get update && \
+ apt-get install -y curl jq wget && \
+ apt-get clean && \
+ rm -rf /var/lib/apt/lists
+
+RUN wget https://github.com/jwilder/dockerize/releases/download/$DOCKERIZE_VERSION/dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz && \
+ tar -C /usr/local/bin -xzvf dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz && \
+ rm dockerize-alpine-linux-amd64-$DOCKERIZE_VERSION.tar.gz
+
+COPY createuser.sh /tmp/createuser.sh
+RUN chmod +x /tmp/createuser.sh
+
+CMD ["/tmp/createuser.sh"]
diff --git a/infrastructure/keycloak/createuser.sh b/infrastructure/keycloak/createuser.sh
new file mode 100755
index 0000000000..b83780632d
--- /dev/null
+++ b/infrastructure/keycloak/createuser.sh
@@ -0,0 +1,112 @@
+#!/bin/bash
+
+sleep 1m
+
+KEYCLOAK_REALM_URL="$KEYCLOAK_URL/auth/admin/realms/Efiling-Hub"
+USERNAME="bobross"
+ADMIN_GROUP="efiling-admin"
+EARLY_GROUP="efiling-early-adopters"
+
+# Get admin user token
+ADMIN_TOKEN=$(curl -s --location --request POST "$KEYCLOAK_URL/auth/realms/master/protocol/openid-connect/token" \
+ --header 'Content-Type: application/x-www-form-urlencoded' \
+ --header 'Cookie: 8a49b93d4f41531bc1d1ef85f2b65254=2fb8f4c2fe6843d186204f21cc45dd4b' \
+ --data-urlencode 'client_id=admin-cli' \
+ --data-urlencode 'grant_type=password' \
+ --data-urlencode 'username=admin' \
+ --data-urlencode 'password=admin' | jq -r '.access_token')
+
+if [ -z "$ADMIN_TOKEN" ]
+then
+ echo "Error connecting to keycloak"
+ exit 1
+fi
+
+echo "Successfully connected to keycloak"
+
+# Create efiling-hub user
+CREATE_USER_STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
+ --request POST "$KEYCLOAK_REALM_URL/users" \
+ --header "Authorization: Bearer $ADMIN_TOKEN" \
+ --header 'Content-Type: application/json' \
+ --data-raw '{
+ "firstName": "bob",
+ "lastName": "ross",
+ "email": "bobross@paintit.com",
+ "enabled": "true",
+ "username": "bobross",
+ "attributes": {
+ "universal-id": ["77da92db-0791-491e-8c58-1a969e67d2fa"]
+ },
+ "credentials": [
+ {
+ "type": "password",
+ "temporary": false,
+ "value": "changeme"
+ }
+ ]}')
+
+if [ $CREATE_USER_STATUS -eq 201 ]; then
+ echo "user created"
+elif [ $CREATE_USER_STATUS -eq 409 ]; then
+ echo "user already exists"
+else
+ echo "Error connecting to keycloak"
+ exit 2
+fi
+
+
+# Get user id
+USER_ID=$(curl -s --location --request GET "$KEYCLOAK_REALM_URL/users?username=$USERNAME" \
+--header "Authorization: Bearer $ADMIN_TOKEN" | jq -r '.[0].id')
+
+if [ -z "$USER_ID" ]; then
+ echo "user bob ross does not exists"
+ exit 3
+fi
+
+# Get group id
+ADMIN_GROUP_ID=$(curl -s --location --request GET "$KEYCLOAK_REALM_URL/groups?search=$ADMIN_GROUP" \
+--header "Authorization: Bearer $ADMIN_TOKEN" | jq -r '.[0].id')
+
+if [ -z "$ADMIN_GROUP_ID" ]; then
+ echo "admin group id does not exist"
+ exit 4
+fi
+
+# Add user to efiling-admin group
+ADD_TO_ADMIN_STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
+ --request PUT "$KEYCLOAK_REALM_URL/users/$USER_ID/groups/$ADMIN_GROUP_ID" \
+ --header "Authorization: Bearer $ADMIN_TOKEN" \
+ --header 'Content-Type: application/json')
+
+if [ $ADD_TO_ADMIN_STATUS -eq 204 ]; then
+ echo "user added to admin group"
+else
+ echo "Error adding user to admin group"
+ exit 5
+fi
+
+# Get early-adopters id
+EARLY_GROUP_ID=$(curl -s --location --request GET "$KEYCLOAK_REALM_URL/groups?search=$EARLY_GROUP" \
+--header "Authorization: Bearer $ADMIN_TOKEN" | jq -r '.[0].id')
+
+if [ -z "$EARLY_GROUP_ID" ]; then
+ echo "early adopters group id does not exist"
+ exit 4
+fi
+
+# Add user to efiling-early-adopters group
+ADD_TO_EARLY_STATUS=$(curl -s -o /dev/null -w '%{http_code}' \
+ --request PUT "$KEYCLOAK_REALM_URL/users/$USER_ID/groups/$EARLY_GROUP_ID" \
+ --header "Authorization: Bearer $ADMIN_TOKEN" \
+ --header 'Content-Type: application/json')
+
+if [ $ADD_TO_EARLY_STATUS -eq 204 ]; then
+ echo "user added to efiling-early-adopters group"
+else
+ echo "Error adding user to efiling-early-adopters group"
+ exit 5
+fi
+
+exit 0
diff --git a/infrastructure/keycloak/realm-export.json b/infrastructure/keycloak/realm-export.json
new file mode 100644
index 0000000000..1eb889d10b
--- /dev/null
+++ b/infrastructure/keycloak/realm-export.json
@@ -0,0 +1,2263 @@
+{
+ "id": "test",
+ "realm": "Efiling-Hub",
+ "displayName": "Efiling Hub",
+ "notBefore": 0,
+ "revokeRefreshToken": false,
+ "refreshTokenMaxReuse": 0,
+ "accessTokenLifespan": 300,
+ "accessTokenLifespanForImplicitFlow": 900,
+ "ssoSessionIdleTimeout": 1800,
+ "ssoSessionMaxLifespan": 36000,
+ "ssoSessionIdleTimeoutRememberMe": 0,
+ "ssoSessionMaxLifespanRememberMe": 0,
+ "offlineSessionIdleTimeout": 2592000,
+ "offlineSessionMaxLifespanEnabled": false,
+ "offlineSessionMaxLifespan": 5184000,
+ "clientSessionIdleTimeout": 0,
+ "clientSessionMaxLifespan": 0,
+ "clientOfflineSessionIdleTimeout": 0,
+ "clientOfflineSessionMaxLifespan": 0,
+ "accessCodeLifespan": 60,
+ "accessCodeLifespanUserAction": 300,
+ "accessCodeLifespanLogin": 1800,
+ "actionTokenGeneratedByAdminLifespan": 43200,
+ "actionTokenGeneratedByUserLifespan": 300,
+ "enabled": true,
+ "sslRequired": "external",
+ "registrationAllowed": false,
+ "registrationEmailAsUsername": false,
+ "rememberMe": false,
+ "verifyEmail": false,
+ "loginWithEmailAllowed": true,
+ "duplicateEmailsAllowed": false,
+ "resetPasswordAllowed": false,
+ "editUsernameAllowed": false,
+ "bruteForceProtected": false,
+ "permanentLockout": false,
+ "maxFailureWaitSeconds": 900,
+ "minimumQuickLoginWaitSeconds": 60,
+ "waitIncrementSeconds": 60,
+ "quickLoginCheckMilliSeconds": 1000,
+ "maxDeltaTimeSeconds": 43200,
+ "failureFactor": 30,
+ "roles": {
+ "realm": [
+ {
+ "id": "88016b52-2916-41a2-9d15-33723dc31551",
+ "name": "offline_access",
+ "description": "${role_offline-access}",
+ "composite": false,
+ "clientRole": false,
+ "containerId": "test",
+ "attributes": {}
+ },
+ {
+ "id": "29b5ee13-d47f-4eb6-b6f7-448bdf6c458c",
+ "name": "uma_authorization",
+ "description": "${role_uma_authorization}",
+ "composite": false,
+ "clientRole": false,
+ "containerId": "test",
+ "attributes": {}
+ }
+ ],
+ "client": {
+ "realm-management": [
+ {
+ "id": "109a1138-953d-4b75-8873-388ec21dc1f1",
+ "name": "view-events",
+ "description": "${role_view-events}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "26e3489a-6993-4f76-a341-bc223b5c092e",
+ "name": "impersonation",
+ "description": "${role_impersonation}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "2751d2fb-3368-46ce-bf95-f9e257aeb2de",
+ "name": "manage-authorization",
+ "description": "${role_manage-authorization}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "bbf3ca94-a057-44ba-a160-7df37bc54c21",
+ "name": "query-groups",
+ "description": "${role_query-groups}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "b8adf8df-b633-4cb3-a606-ad0d094e1577",
+ "name": "realm-admin",
+ "description": "${role_realm-admin}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "realm-management": [
+ "view-events",
+ "impersonation",
+ "manage-authorization",
+ "query-groups",
+ "view-realm",
+ "query-clients",
+ "view-clients",
+ "view-users",
+ "manage-events",
+ "query-users",
+ "manage-realm",
+ "view-identity-providers",
+ "query-realms",
+ "manage-identity-providers",
+ "manage-users",
+ "create-client",
+ "view-authorization",
+ "manage-clients"
+ ]
+ }
+ },
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "fb02f4e9-a444-4579-9be7-c3e813f547f8",
+ "name": "query-clients",
+ "description": "${role_query-clients}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "a104b612-c1cb-46b6-ad46-29565c6b5e0f",
+ "name": "view-realm",
+ "description": "${role_view-realm}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "6e02b81b-466c-4d98-98ea-a4576c8f8abb",
+ "name": "view-clients",
+ "description": "${role_view-clients}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "realm-management": ["query-clients"]
+ }
+ },
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "bc2ad235-53e1-49c3-871a-6e34922897fc",
+ "name": "manage-events",
+ "description": "${role_manage-events}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "e6039dcc-669c-4435-8344-ae4a2c41fb00",
+ "name": "query-users",
+ "description": "${role_query-users}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "46cbbf73-c504-490c-b647-e979aee6a032",
+ "name": "view-users",
+ "description": "${role_view-users}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "realm-management": ["query-groups", "query-users"]
+ }
+ },
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "19a3779d-0694-4201-a8f5-27c086cb05e5",
+ "name": "manage-realm",
+ "description": "${role_manage-realm}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "6ff82c7e-0713-4c4e-8a6a-e285cb1cd3d0",
+ "name": "query-realms",
+ "description": "${role_query-realms}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "055db674-6963-41c7-9a55-9df1f09094bc",
+ "name": "view-identity-providers",
+ "description": "${role_view-identity-providers}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "9610a238-c19b-4041-a949-73848d4527b1",
+ "name": "manage-identity-providers",
+ "description": "${role_manage-identity-providers}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "d5b7c513-bce5-4b77-a224-0819febaba68",
+ "name": "create-client",
+ "description": "${role_create-client}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "7a4bb1d2-c8ba-43b4-ba83-5b7348e5634f",
+ "name": "manage-users",
+ "description": "${role_manage-users}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "bc8d5c3e-7738-4d81-896a-8ba66433383f",
+ "name": "view-authorization",
+ "description": "${role_view-authorization}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ },
+ {
+ "id": "079deeb5-b344-47e2-ada5-b5cb2af3ad56",
+ "name": "manage-clients",
+ "description": "${role_manage-clients}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "attributes": {}
+ }
+ ],
+ "security-admin-console": [],
+ "efiling-admin": [],
+ "efiling-frontend": [],
+ "admin-cli": [],
+ "efiling-api": [
+ {
+ "id": "102cf99b-8b2c-4568-b447-a5c0d6d21c27",
+ "name": "efiling-admin",
+ "description": "controls - access to admin features",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "972b79de-44ab-4b64-8bf3-9c1794bfbbbe",
+ "attributes": {}
+ },
+ {
+ "id": "4689e81c-0c72-4a4d-bb5c-660eee970540",
+ "name": "early-adopters",
+ "description": "group for early adopters",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "972b79de-44ab-4b64-8bf3-9c1794bfbbbe",
+ "attributes": {}
+ },
+ {
+ "id": "0f0d19fb-3ee1-4881-a1f6-3bff60386d4c",
+ "name": "efiling-rush",
+ "description": "This role allow user to submit rushed submissions",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "972b79de-44ab-4b64-8bf3-9c1794bfbbbe",
+ "attributes": {}
+ },
+ {
+ "id": "baeb0a13-43ee-4f43-a6b6-e3125009b875",
+ "name": "efiling-user",
+ "description": "default efiling user role",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "972b79de-44ab-4b64-8bf3-9c1794bfbbbe",
+ "attributes": {}
+ },
+ {
+ "id": "f47cddc6-9f88-4aea-82f5-a7a0244b372b",
+ "name": "efiling-client",
+ "description": "Role for client application, allows client to interact with dedicated endpoints",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "972b79de-44ab-4b64-8bf3-9c1794bfbbbe",
+ "attributes": {}
+ }
+ ],
+ "account-console": [],
+ "broker": [
+ {
+ "id": "acf420c6-8aeb-46a3-9fd7-eaa6e8df4a9d",
+ "name": "read-token",
+ "description": "${role_read-token}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "a0f4b6ca-76b6-4a43-919d-8e7decb308d1",
+ "attributes": {}
+ }
+ ],
+ "account": [
+ {
+ "id": "e9033b04-7d86-448f-b45a-7aaa3200075c",
+ "name": "view-consent",
+ "description": "${role_view-consent}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "924c2240-577c-4737-9279-9febbb800a1b",
+ "attributes": {}
+ },
+ {
+ "id": "84586445-80c7-4c43-8e33-7e286ab999dd",
+ "name": "manage-account-links",
+ "description": "${role_manage-account-links}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "924c2240-577c-4737-9279-9febbb800a1b",
+ "attributes": {}
+ },
+ {
+ "id": "08de3662-56e8-48ff-a6b7-e12299943a22",
+ "name": "delete-account",
+ "description": "${role_delete-account}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "924c2240-577c-4737-9279-9febbb800a1b",
+ "attributes": {}
+ },
+ {
+ "id": "2e48fd0e-5036-451d-af6e-34cc114c5b1f",
+ "name": "view-profile",
+ "description": "${role_view-profile}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "924c2240-577c-4737-9279-9febbb800a1b",
+ "attributes": {}
+ },
+ {
+ "id": "bc8f543c-6d1d-462c-b731-9a695fc8467a",
+ "name": "view-applications",
+ "description": "${role_view-applications}",
+ "composite": false,
+ "clientRole": true,
+ "containerId": "924c2240-577c-4737-9279-9febbb800a1b",
+ "attributes": {}
+ },
+ {
+ "id": "e650447d-63e0-4ced-bf44-cecf9ecc15d4",
+ "name": "manage-consent",
+ "description": "${role_manage-consent}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "account": ["view-consent"]
+ }
+ },
+ "clientRole": true,
+ "containerId": "924c2240-577c-4737-9279-9febbb800a1b",
+ "attributes": {}
+ },
+ {
+ "id": "a77f02a4-4de5-465b-b64c-617644d8b19e",
+ "name": "manage-account",
+ "description": "${role_manage-account}",
+ "composite": true,
+ "composites": {
+ "client": {
+ "account": ["manage-account-links"]
+ }
+ },
+ "clientRole": true,
+ "containerId": "924c2240-577c-4737-9279-9febbb800a1b",
+ "attributes": {}
+ }
+ ]
+ }
+ },
+ "groups": [
+ {
+ "id": "53514a5a-cbac-41c3-9942-881f1a2c0798",
+ "name": "efiling-admin",
+ "path": "/efiling-admin",
+ "attributes": {},
+ "realmRoles": [],
+ "clientRoles": {
+ "efiling-api": ["efiling-admin"]
+ },
+ "subGroups": []
+ },
+ {
+ "id": "92a7b5e7-c246-4eff-856d-80b7500df3f0",
+ "name": "efiling-early-adopters",
+ "path": "/efiling-early-adopters",
+ "attributes": {},
+ "realmRoles": [],
+ "clientRoles": {
+ "efiling-api": ["early-adopters"]
+ },
+ "subGroups": []
+ },
+ {
+ "id": "4dbc7648-1055-4838-ba10-6a5d91cc1c00",
+ "name": "efiling-user",
+ "path": "/efiling-user",
+ "attributes": {},
+ "realmRoles": [],
+ "clientRoles": {
+ "efiling-api": ["efiling-user"]
+ },
+ "subGroups": []
+ }
+ ],
+ "defaultRoles": ["offline_access", "uma_authorization"],
+ "defaultGroups": ["/efiling-user"],
+ "requiredCredentials": ["password"],
+ "otpPolicyType": "totp",
+ "otpPolicyAlgorithm": "HmacSHA1",
+ "otpPolicyInitialCounter": 0,
+ "otpPolicyDigits": 6,
+ "otpPolicyLookAheadWindow": 1,
+ "otpPolicyPeriod": 30,
+ "otpSupportedApplications": ["FreeOTP", "Google Authenticator"],
+ "webAuthnPolicyRpEntityName": "keycloak",
+ "webAuthnPolicySignatureAlgorithms": ["ES256"],
+ "webAuthnPolicyRpId": "",
+ "webAuthnPolicyAttestationConveyancePreference": "not specified",
+ "webAuthnPolicyAuthenticatorAttachment": "not specified",
+ "webAuthnPolicyRequireResidentKey": "not specified",
+ "webAuthnPolicyUserVerificationRequirement": "not specified",
+ "webAuthnPolicyCreateTimeout": 0,
+ "webAuthnPolicyAvoidSameAuthenticatorRegister": false,
+ "webAuthnPolicyAcceptableAaguids": [],
+ "webAuthnPolicyPasswordlessRpEntityName": "keycloak",
+ "webAuthnPolicyPasswordlessSignatureAlgorithms": ["ES256"],
+ "webAuthnPolicyPasswordlessRpId": "",
+ "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified",
+ "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified",
+ "webAuthnPolicyPasswordlessRequireResidentKey": "not specified",
+ "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified",
+ "webAuthnPolicyPasswordlessCreateTimeout": 0,
+ "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false,
+ "webAuthnPolicyPasswordlessAcceptableAaguids": [],
+ "scopeMappings": [
+ {
+ "clientScope": "offline_access",
+ "roles": ["offline_access"]
+ }
+ ],
+ "clientScopeMappings": {
+ "account": [
+ {
+ "client": "account-console",
+ "roles": ["manage-account"]
+ }
+ ]
+ },
+ "clients": [
+ {
+ "id": "924c2240-577c-4737-9279-9febbb800a1b",
+ "clientId": "account",
+ "name": "${client_account}",
+ "rootUrl": "${authBaseUrl}",
+ "baseUrl": "/realms/Efiling-Hub/account/",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "**********",
+ "defaultRoles": ["view-profile", "manage-account"],
+ "redirectUris": ["/realms/Efiling-Hub/account/*"],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": false,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {},
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "d5d11c5e-72db-4436-9701-b3c17f10de3d",
+ "clientId": "account-console",
+ "name": "${client_account-console}",
+ "rootUrl": "${authBaseUrl}",
+ "baseUrl": "/realms/test/account/",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "**********",
+ "redirectUris": ["/realms/test/account/*"],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "pkce.code.challenge.method": "S256"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "protocolMappers": [
+ {
+ "id": "388ef7e2-9edf-4e4e-8591-d182df18484c",
+ "name": "audience resolve",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-audience-resolve-mapper",
+ "consentRequired": false,
+ "config": {}
+ }
+ ],
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "25785dc8-7a99-4019-9f37-b75f1b0f0c94",
+ "clientId": "admin-cli",
+ "name": "${client_admin-cli}",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "**********",
+ "redirectUris": [],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": false,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": true,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {},
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "a0f4b6ca-76b6-4a43-919d-8e7decb308d1",
+ "clientId": "broker",
+ "name": "${client_broker}",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "**********",
+ "redirectUris": [],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": false,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {},
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "68deda16-9566-4b12-ac89-84b11e09780c",
+ "clientId": "efiling-admin",
+ "rootUrl": "http://localhost:3001",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "**********",
+ "redirectUris": ["http://localhost:3001/*"],
+ "webOrigins": ["*"],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": true,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "saml.assertion.signature": "false",
+ "saml.force.post.binding": "false",
+ "saml.multivalued.roles": "false",
+ "saml.encrypt": "false",
+ "backchannel.logout.revoke.offline.tokens": "false",
+ "saml.server.signature": "false",
+ "saml.server.signature.keyinfo.ext": "false",
+ "exclude.session.state.from.auth.response": "false",
+ "backchannel.logout.session.required": "true",
+ "client_credentials.use_refresh_token": "false",
+ "saml_force_name_id_format": "false",
+ "saml.client.signature": "false",
+ "tls.client.certificate.bound.access.tokens": "false",
+ "saml.authnstatement": "false",
+ "display.on.consent.screen": "false",
+ "saml.onetimeuse.condition": "false"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": true,
+ "nodeReRegistrationTimeout": -1,
+ "protocolMappers": [
+ {
+ "id": "0db5d028-403a-4566-b415-1218fc135925",
+ "name": "universal-id",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "universal-id",
+ "id.token.claim": "false",
+ "access.token.claim": "true",
+ "claim.name": "universal-id",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "8a7e052f-99ea-4e02-a570-4f1391c01a2a",
+ "name": "Efiling App Code",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-hardcoded-claim-mapper",
+ "consentRequired": false,
+ "config": {
+ "claim.value": "DEMO",
+ "userinfo.token.claim": "true",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "cso-application-code",
+ "jsonType.label": "String",
+ "access.tokenResponse.claim": "false"
+ }
+ }
+ ],
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "972b79de-44ab-4b64-8bf3-9c1794bfbbbe",
+ "clientId": "efiling-api",
+ "rootUrl": "http://localhost:8080",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "**********",
+ "redirectUris": ["http://localhost:8080/*"],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": true,
+ "serviceAccountsEnabled": false,
+ "publicClient": false,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "saml.assertion.signature": "false",
+ "saml.force.post.binding": "false",
+ "saml.multivalued.roles": "false",
+ "saml.encrypt": "false",
+ "backchannel.logout.revoke.offline.tokens": "false",
+ "saml.server.signature": "false",
+ "saml.server.signature.keyinfo.ext": "false",
+ "exclude.session.state.from.auth.response": "false",
+ "backchannel.logout.session.required": "true",
+ "client_credentials.use_refresh_token": "false",
+ "saml_force_name_id_format": "false",
+ "saml.client.signature": "false",
+ "tls.client.certificate.bound.access.tokens": "false",
+ "saml.authnstatement": "false",
+ "display.on.consent.screen": "false",
+ "saml.onetimeuse.condition": "false"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": true,
+ "nodeReRegistrationTimeout": -1,
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "4afbfd92-0fe6-4801-a2eb-19b5852d5e13",
+ "clientId": "efiling-frontend",
+ "rootUrl": "http://localhost:3000",
+ "adminUrl": "http://localhost:3000",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "**********",
+ "redirectUris": ["http://localhost:3000/*"],
+ "webOrigins": ["http://localhost:3000"],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": true,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "backchannel.logout.session.required": "true",
+ "backchannel.logout.revoke.offline.tokens": "false"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": true,
+ "nodeReRegistrationTimeout": -1,
+ "protocolMappers": [
+ {
+ "id": "33c4c1a3-5701-41e2-b986-9249395aac44",
+ "name": "universal-id",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "universal-id",
+ "id.token.claim": "false",
+ "access.token.claim": "true",
+ "claim.name": "universal-id",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "4ca6d182-e816-469d-8933-ab81814625ac",
+ "name": "application-code",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-hardcoded-claim-mapper",
+ "consentRequired": false,
+ "config": {
+ "claim.value": "DEMO",
+ "userinfo.token.claim": "true",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "cso-application-code",
+ "jsonType.label": "String",
+ "access.tokenResponse.claim": "false"
+ }
+ }
+ ],
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "67b85937-008d-414c-9ee9-5f0fc5950254",
+ "clientId": "realm-management",
+ "name": "${client_realm-management}",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "**********",
+ "redirectUris": [],
+ "webOrigins": [],
+ "notBefore": 0,
+ "bearerOnly": true,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": false,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {},
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ },
+ {
+ "id": "ab0aae54-b778-4251-870d-aef6143369dc",
+ "clientId": "security-admin-console",
+ "name": "${client_security-admin-console}",
+ "rootUrl": "${authAdminUrl}",
+ "baseUrl": "/admin/Efiling-Hub/console/",
+ "surrogateAuthRequired": false,
+ "enabled": true,
+ "alwaysDisplayInConsole": false,
+ "clientAuthenticatorType": "client-secret",
+ "secret": "**********",
+ "redirectUris": ["/admin/Efiling-Hub/console/*"],
+ "webOrigins": ["+"],
+ "notBefore": 0,
+ "bearerOnly": false,
+ "consentRequired": false,
+ "standardFlowEnabled": true,
+ "implicitFlowEnabled": false,
+ "directAccessGrantsEnabled": false,
+ "serviceAccountsEnabled": false,
+ "publicClient": true,
+ "frontchannelLogout": false,
+ "protocol": "openid-connect",
+ "attributes": {
+ "pkce.code.challenge.method": "S256"
+ },
+ "authenticationFlowBindingOverrides": {},
+ "fullScopeAllowed": false,
+ "nodeReRegistrationTimeout": 0,
+ "protocolMappers": [
+ {
+ "id": "a5579394-34b8-48c1-81a3-66c4fc03bece",
+ "name": "locale",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "locale",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "locale",
+ "jsonType.label": "String"
+ }
+ }
+ ],
+ "defaultClientScopes": [
+ "web-origins",
+ "role_list",
+ "roles",
+ "profile",
+ "email"
+ ],
+ "optionalClientScopes": [
+ "address",
+ "phone",
+ "offline_access",
+ "microprofile-jwt"
+ ]
+ }
+ ],
+ "clientScopes": [
+ {
+ "id": "725470de-8981-4c81-98bd-3509261adf24",
+ "name": "address",
+ "description": "OpenID Connect built-in scope: address",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "display.on.consent.screen": "true",
+ "consent.screen.text": "${addressScopeConsentText}"
+ },
+ "protocolMappers": [
+ {
+ "id": "615ca1ef-f157-4dd1-b695-3c815aeb9aa2",
+ "name": "address",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-address-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.attribute.formatted": "formatted",
+ "user.attribute.country": "country",
+ "user.attribute.postal_code": "postal_code",
+ "userinfo.token.claim": "true",
+ "user.attribute.street": "street",
+ "id.token.claim": "true",
+ "user.attribute.region": "region",
+ "access.token.claim": "true",
+ "user.attribute.locality": "locality"
+ }
+ }
+ ]
+ },
+ {
+ "id": "52b9840a-9717-4f09-b80b-1f02a8ff74c9",
+ "name": "email",
+ "description": "OpenID Connect built-in scope: email",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "display.on.consent.screen": "true",
+ "consent.screen.text": "${emailScopeConsentText}"
+ },
+ "protocolMappers": [
+ {
+ "id": "de4aa464-c83e-4685-80e5-42651e25a062",
+ "name": "email",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-property-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "email",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "email",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "471922f2-ca12-4bf9-8a36-bf8e26e8a707",
+ "name": "email verified",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-property-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "emailVerified",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "email_verified",
+ "jsonType.label": "boolean"
+ }
+ }
+ ]
+ },
+ {
+ "id": "94fd8806-be94-430c-9eef-38d38be37139",
+ "name": "microprofile-jwt",
+ "description": "Microprofile - JWT built-in scope",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "display.on.consent.screen": "false"
+ },
+ "protocolMappers": [
+ {
+ "id": "84d81c56-2d5b-4853-9500-c14b02b00b8e",
+ "name": "upn",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-property-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "username",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "upn",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "01a28e74-339a-409f-8a56-5482a405ba74",
+ "name": "groups",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-realm-role-mapper",
+ "consentRequired": false,
+ "config": {
+ "multivalued": "true",
+ "userinfo.token.claim": "true",
+ "user.attribute": "foo",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "groups",
+ "jsonType.label": "String"
+ }
+ }
+ ]
+ },
+ {
+ "id": "005a0de9-1ca4-4e76-8567-724e3b0be5e3",
+ "name": "offline_access",
+ "description": "OpenID Connect built-in scope: offline_access",
+ "protocol": "openid-connect",
+ "attributes": {
+ "consent.screen.text": "${offlineAccessScopeConsentText}",
+ "display.on.consent.screen": "true"
+ }
+ },
+ {
+ "id": "0ff3d639-7bea-407a-ba30-38d9e33641ae",
+ "name": "phone",
+ "description": "OpenID Connect built-in scope: phone",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "display.on.consent.screen": "true",
+ "consent.screen.text": "${phoneScopeConsentText}"
+ },
+ "protocolMappers": [
+ {
+ "id": "ae6e7e67-1a52-47f8-a795-6472bfafb74e",
+ "name": "phone number",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "phoneNumber",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "phone_number",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "c75256c2-7fc5-41ac-9ef7-caab7b031591",
+ "name": "phone number verified",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "phoneNumberVerified",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "phone_number_verified",
+ "jsonType.label": "boolean"
+ }
+ }
+ ]
+ },
+ {
+ "id": "777bdfd5-8889-4d38-94fd-a95340cea829",
+ "name": "profile",
+ "description": "OpenID Connect built-in scope: profile",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "true",
+ "display.on.consent.screen": "true",
+ "consent.screen.text": "${profileScopeConsentText}"
+ },
+ "protocolMappers": [
+ {
+ "id": "476826c3-c240-4bfc-b366-0c295b1a20e3",
+ "name": "website",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "website",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "website",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "1626e94f-31a3-49ac-845d-252823e61ac2",
+ "name": "full name",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-full-name-mapper",
+ "consentRequired": false,
+ "config": {
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "userinfo.token.claim": "true"
+ }
+ },
+ {
+ "id": "968fe49b-3a14-4d71-b6dc-6cc584b34ed0",
+ "name": "zoneinfo",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "zoneinfo",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "zoneinfo",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "7700d3ed-f183-492f-bb4f-328f6ceb0490",
+ "name": "picture",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "picture",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "picture",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "8a330d1d-1049-4e55-94f1-fbc0444c8941",
+ "name": "updated at",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "updatedAt",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "updated_at",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "91a76d6e-13b5-4782-b0d8-6decfc60b431",
+ "name": "middle name",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "middleName",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "middle_name",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "25e87355-e714-41b3-a6bf-e8de18639ccb",
+ "name": "username",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-property-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "username",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "preferred_username",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "4647c894-f950-4b17-8892-ce46f3382e87",
+ "name": "gender",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "gender",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "gender",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "4f1af02c-c8a5-463b-8c20-a698078f9cc3",
+ "name": "family name",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-property-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "lastName",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "family_name",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "198612dd-56cf-4a76-bc2c-007c3302ac72",
+ "name": "nickname",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "nickname",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "nickname",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "c51cb373-42ad-4a2a-b845-1dbf3e369a3b",
+ "name": "profile",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "profile",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "profile",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "9f52ec0c-3e39-472f-a80b-6dc7a807d0ca",
+ "name": "locale",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "locale",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "locale",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "6740e9c8-0f93-4de3-aac8-84c9927621ba",
+ "name": "given name",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-property-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "firstName",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "given_name",
+ "jsonType.label": "String"
+ }
+ },
+ {
+ "id": "e3350022-e59d-40b2-8e99-a04f1b8b6bb9",
+ "name": "birthdate",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-attribute-mapper",
+ "consentRequired": false,
+ "config": {
+ "userinfo.token.claim": "true",
+ "user.attribute": "birthdate",
+ "id.token.claim": "true",
+ "access.token.claim": "true",
+ "claim.name": "birthdate",
+ "jsonType.label": "String"
+ }
+ }
+ ]
+ },
+ {
+ "id": "ce13a215-ee3f-4ea3-8ce9-3f0663ebaa83",
+ "name": "role_list",
+ "description": "SAML role list",
+ "protocol": "saml",
+ "attributes": {
+ "consent.screen.text": "${samlRoleListScopeConsentText}",
+ "display.on.consent.screen": "true"
+ },
+ "protocolMappers": [
+ {
+ "id": "a6a3a862-b822-4907-9211-f728fd73954f",
+ "name": "role list",
+ "protocol": "saml",
+ "protocolMapper": "saml-role-list-mapper",
+ "consentRequired": false,
+ "config": {
+ "single": "false",
+ "attribute.nameformat": "Basic",
+ "attribute.name": "Role"
+ }
+ }
+ ]
+ },
+ {
+ "id": "206f88ef-2770-43e3-a0a1-bf84d0daa573",
+ "name": "roles",
+ "description": "OpenID Connect scope for add user roles to the access token",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "false",
+ "display.on.consent.screen": "true",
+ "consent.screen.text": "${rolesScopeConsentText}"
+ },
+ "protocolMappers": [
+ {
+ "id": "85c71801-edf2-4a3b-987a-9823de69f351",
+ "name": "audience resolve",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-audience-resolve-mapper",
+ "consentRequired": false,
+ "config": {}
+ },
+ {
+ "id": "5d7b30e9-4db8-497b-be92-2cc564cd388b",
+ "name": "realm roles",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-realm-role-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.attribute": "foo",
+ "access.token.claim": "true",
+ "claim.name": "realm_access.roles",
+ "jsonType.label": "String",
+ "multivalued": "true"
+ }
+ },
+ {
+ "id": "fa5097f5-70b5-4e98-a3f5-040d4fb79d39",
+ "name": "client roles",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-usermodel-client-role-mapper",
+ "consentRequired": false,
+ "config": {
+ "user.attribute": "foo",
+ "access.token.claim": "true",
+ "claim.name": "resource_access.${client_id}.roles",
+ "jsonType.label": "String",
+ "multivalued": "true"
+ }
+ }
+ ]
+ },
+ {
+ "id": "2d289740-f863-4be0-9031-8ca6b00b3d4c",
+ "name": "web-origins",
+ "description": "OpenID Connect scope for add allowed web origins to the access token",
+ "protocol": "openid-connect",
+ "attributes": {
+ "include.in.token.scope": "false",
+ "display.on.consent.screen": "false",
+ "consent.screen.text": ""
+ },
+ "protocolMappers": [
+ {
+ "id": "e35dafca-1611-4f90-bb79-a0007e53a9d5",
+ "name": "allowed web origins",
+ "protocol": "openid-connect",
+ "protocolMapper": "oidc-allowed-origins-mapper",
+ "consentRequired": false,
+ "config": {}
+ }
+ ]
+ }
+ ],
+ "defaultDefaultClientScopes": [
+ "roles",
+ "web-origins",
+ "email",
+ "profile",
+ "role_list"
+ ],
+ "defaultOptionalClientScopes": [
+ "offline_access",
+ "phone",
+ "address",
+ "microprofile-jwt"
+ ],
+ "browserSecurityHeaders": {
+ "contentSecurityPolicyReportOnly": "",
+ "xContentTypeOptions": "nosniff",
+ "xRobotsTag": "none",
+ "xFrameOptions": "SAMEORIGIN",
+ "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';",
+ "xXSSProtection": "1; mode=block",
+ "strictTransportSecurity": "max-age=31536000; includeSubDomains"
+ },
+ "smtpServer": {},
+ "eventsEnabled": false,
+ "eventsListeners": ["jboss-logging"],
+ "enabledEventTypes": [],
+ "adminEventsEnabled": false,
+ "adminEventsDetailsEnabled": false,
+ "identityProviders": [],
+ "identityProviderMappers": [],
+ "components": {
+ "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [
+ {
+ "id": "87012b33-af56-4f4a-992e-913d219540e8",
+ "name": "Allowed Protocol Mapper Types",
+ "providerId": "allowed-protocol-mappers",
+ "subType": "authenticated",
+ "subComponents": {},
+ "config": {
+ "allowed-protocol-mapper-types": [
+ "oidc-full-name-mapper",
+ "oidc-address-mapper",
+ "oidc-usermodel-attribute-mapper",
+ "saml-role-list-mapper",
+ "oidc-usermodel-property-mapper",
+ "oidc-sha256-pairwise-sub-mapper",
+ "saml-user-attribute-mapper",
+ "saml-user-property-mapper"
+ ]
+ }
+ },
+ {
+ "id": "3ae64f88-567e-452b-8652-e738badf57c8",
+ "name": "Consent Required",
+ "providerId": "consent-required",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {}
+ },
+ {
+ "id": "d860bc28-c059-4e6e-810d-1dbe6d60c238",
+ "name": "Allowed Protocol Mapper Types",
+ "providerId": "allowed-protocol-mappers",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {
+ "allowed-protocol-mapper-types": [
+ "oidc-address-mapper",
+ "saml-role-list-mapper",
+ "oidc-sha256-pairwise-sub-mapper",
+ "oidc-usermodel-attribute-mapper",
+ "saml-user-property-mapper",
+ "oidc-full-name-mapper",
+ "saml-user-attribute-mapper",
+ "oidc-usermodel-property-mapper"
+ ]
+ }
+ },
+ {
+ "id": "03678af3-eeec-4f38-a986-cc2ccdcab37c",
+ "name": "Allowed Client Scopes",
+ "providerId": "allowed-client-templates",
+ "subType": "authenticated",
+ "subComponents": {},
+ "config": {
+ "allow-default-scopes": ["true"]
+ }
+ },
+ {
+ "id": "41063432-8717-47f9-bab8-b8a9e4c62322",
+ "name": "Allowed Client Scopes",
+ "providerId": "allowed-client-templates",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {
+ "allow-default-scopes": ["true"]
+ }
+ },
+ {
+ "id": "85e7c066-bcf4-4fdf-ac81-0e9626701884",
+ "name": "Trusted Hosts",
+ "providerId": "trusted-hosts",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {
+ "host-sending-registration-request-must-match": ["true"],
+ "client-uris-must-match": ["true"]
+ }
+ },
+ {
+ "id": "44d0b688-4f7f-4475-b62f-c5733454129d",
+ "name": "Full Scope Disabled",
+ "providerId": "scope",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {}
+ },
+ {
+ "id": "80f2b705-a7f0-4e56-94b6-f150992b9c78",
+ "name": "Max Clients Limit",
+ "providerId": "max-clients",
+ "subType": "anonymous",
+ "subComponents": {},
+ "config": {
+ "max-clients": ["200"]
+ }
+ }
+ ],
+ "org.keycloak.keys.KeyProvider": [
+ {
+ "id": "4f57a139-24eb-4b6f-9d9a-ace7c2565c92",
+ "name": "aes-generated",
+ "providerId": "aes-generated",
+ "subComponents": {},
+ "config": {
+ "priority": ["100"]
+ }
+ },
+ {
+ "id": "7b70a240-9ab5-4f88-bee2-52cb7cb44823",
+ "name": "hmac-generated",
+ "providerId": "hmac-generated",
+ "subComponents": {},
+ "config": {
+ "priority": ["100"],
+ "algorithm": ["HS256"]
+ }
+ },
+ {
+ "id": "2d911441-12b7-487e-9063-494de95028bc",
+ "name": "rsa-generated",
+ "providerId": "rsa-generated",
+ "subComponents": {},
+ "config": {
+ "priority": ["100"]
+ }
+ }
+ ]
+ },
+ "internationalizationEnabled": false,
+ "supportedLocales": [],
+ "authenticationFlows": [
+ {
+ "id": "0184ff58-7984-4821-86f7-598430d9084e",
+ "alias": "Account verification options",
+ "description": "Method with which to verity the existing account",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "idp-email-verification",
+ "requirement": "ALTERNATIVE",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "ALTERNATIVE",
+ "priority": 20,
+ "flowAlias": "Verify Existing Account by Re-authentication",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "20d5739d-5321-4a38-b94c-be975f8d98b9",
+ "alias": "Authentication Options",
+ "description": "Authentication options.",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "basic-auth",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "basic-auth-otp",
+ "requirement": "DISABLED",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "auth-spnego",
+ "requirement": "DISABLED",
+ "priority": 30,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ }
+ ]
+ },
+ {
+ "id": "03e731f1-2678-4ca8-9a65-26cfdc7199ed",
+ "alias": "Browser - Conditional OTP",
+ "description": "Flow to determine if the OTP is required for the authentication",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "auth-otp-form",
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ }
+ ]
+ },
+ {
+ "id": "e817fbc7-a8bd-4e6a-8833-a62e7e44ae00",
+ "alias": "Direct Grant - Conditional OTP",
+ "description": "Flow to determine if the OTP is required for the authentication",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "direct-grant-validate-otp",
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ }
+ ]
+ },
+ {
+ "id": "337a3d15-0441-4cf7-acf4-8c71232d0ccc",
+ "alias": "First broker login - Conditional OTP",
+ "description": "Flow to determine if the OTP is required for the authentication",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "auth-otp-form",
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ }
+ ]
+ },
+ {
+ "id": "3de8f1d8-f0bd-4f0f-89af-18835e8312a0",
+ "alias": "Handle Existing Account",
+ "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "idp-confirm-link",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "flowAlias": "Account verification options",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "92176992-8993-4f58-93ee-6e63749dfbfd",
+ "alias": "Reset - Conditional OTP",
+ "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "conditional-user-configured",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "reset-otp",
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ }
+ ]
+ },
+ {
+ "id": "87e82fdd-76ba-47e5-8102-af2c88d2f2fb",
+ "alias": "User creation or linking",
+ "description": "Flow for the existing/non-existing user alternatives",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticatorConfig": "create unique user config",
+ "authenticator": "idp-create-user-if-unique",
+ "requirement": "ALTERNATIVE",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "ALTERNATIVE",
+ "priority": 20,
+ "flowAlias": "Handle Existing Account",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "2798ef9e-55b6-40bf-8d3e-1e9bbef72359",
+ "alias": "Verify Existing Account by Re-authentication",
+ "description": "Reauthentication of existing account",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "idp-username-password-form",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "CONDITIONAL",
+ "priority": 20,
+ "flowAlias": "First broker login - Conditional OTP",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "d914e3f1-57ae-49a1-a80a-faa7c99ec389",
+ "alias": "browser",
+ "description": "browser based authentication",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "auth-cookie",
+ "requirement": "ALTERNATIVE",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "auth-spnego",
+ "requirement": "DISABLED",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "identity-provider-redirector",
+ "requirement": "ALTERNATIVE",
+ "priority": 25,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "ALTERNATIVE",
+ "priority": 30,
+ "flowAlias": "forms",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "a9cc0bc8-8277-45a1-8199-c313667637db",
+ "alias": "clients",
+ "description": "Base authentication for clients",
+ "providerId": "client-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "client-secret",
+ "requirement": "ALTERNATIVE",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "client-jwt",
+ "requirement": "ALTERNATIVE",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "client-secret-jwt",
+ "requirement": "ALTERNATIVE",
+ "priority": 30,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "client-x509",
+ "requirement": "ALTERNATIVE",
+ "priority": 40,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ }
+ ]
+ },
+ {
+ "id": "93632cc9-6a8c-4acb-afa2-a21df781aa49",
+ "alias": "direct grant",
+ "description": "OpenID Connect Resource Owner Grant",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "direct-grant-validate-username",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "direct-grant-validate-password",
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "CONDITIONAL",
+ "priority": 30,
+ "flowAlias": "Direct Grant - Conditional OTP",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "48bee5d3-397c-488b-94a7-d29ff24762c0",
+ "alias": "docker auth",
+ "description": "Used by Docker clients to authenticate against the IDP",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "docker-http-basic-authenticator",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ }
+ ]
+ },
+ {
+ "id": "d4596dec-91c4-4a65-8113-336ad6b47028",
+ "alias": "first broker login",
+ "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticatorConfig": "review profile config",
+ "authenticator": "idp-review-profile",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "flowAlias": "User creation or linking",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "97e3cb3b-310d-445f-8c9a-ceabf1063724",
+ "alias": "forms",
+ "description": "Username, password, otp and other auth forms.",
+ "providerId": "basic-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "auth-username-password-form",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "CONDITIONAL",
+ "priority": 20,
+ "flowAlias": "Browser - Conditional OTP",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "cbc568bb-79e4-4808-b486-f9eab24cc576",
+ "alias": "http challenge",
+ "description": "An authentication flow based on challenge-response HTTP Authentication Schemes",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "no-cookie-redirect",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "flowAlias": "Authentication Options",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "c1356b41-5b0e-4eff-946c-331473144b1b",
+ "alias": "registration",
+ "description": "registration flow",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "registration-page-form",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "flowAlias": "registration form",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "4fa24705-10dc-47e1-a163-0bfc9b317645",
+ "alias": "registration form",
+ "description": "registration form",
+ "providerId": "form-flow",
+ "topLevel": false,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "registration-user-creation",
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "registration-profile-action",
+ "requirement": "REQUIRED",
+ "priority": 40,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "registration-password-action",
+ "requirement": "REQUIRED",
+ "priority": 50,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "registration-recaptcha-action",
+ "requirement": "DISABLED",
+ "priority": 60,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ }
+ ]
+ },
+ {
+ "id": "8e462f4c-da9f-4aa1-b337-139a7591c504",
+ "alias": "reset credentials",
+ "description": "Reset credentials for a user if they forgot their password or something",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "reset-credentials-choose-user",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "reset-credential-email",
+ "requirement": "REQUIRED",
+ "priority": 20,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "authenticator": "reset-password",
+ "requirement": "REQUIRED",
+ "priority": 30,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ },
+ {
+ "requirement": "CONDITIONAL",
+ "priority": 40,
+ "flowAlias": "Reset - Conditional OTP",
+ "userSetupAllowed": false,
+ "autheticatorFlow": true
+ }
+ ]
+ },
+ {
+ "id": "c6a772cb-7a8c-45f6-9cc8-7f065a5dd0ff",
+ "alias": "saml ecp",
+ "description": "SAML ECP Profile Authentication Flow",
+ "providerId": "basic-flow",
+ "topLevel": true,
+ "builtIn": true,
+ "authenticationExecutions": [
+ {
+ "authenticator": "http-basic-authenticator",
+ "requirement": "REQUIRED",
+ "priority": 10,
+ "userSetupAllowed": false,
+ "autheticatorFlow": false
+ }
+ ]
+ }
+ ],
+ "authenticatorConfig": [
+ {
+ "id": "b6348bec-eeb1-468b-813e-de7461b41a0b",
+ "alias": "create unique user config",
+ "config": {
+ "require.password.update.after.registration": "false"
+ }
+ },
+ {
+ "id": "252fcbb0-d67e-4121-8445-bac8132989ca",
+ "alias": "review profile config",
+ "config": {
+ "update.profile.on.first.login": "missing"
+ }
+ }
+ ],
+ "requiredActions": [
+ {
+ "alias": "CONFIGURE_TOTP",
+ "name": "Configure OTP",
+ "providerId": "CONFIGURE_TOTP",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 10,
+ "config": {}
+ },
+ {
+ "alias": "terms_and_conditions",
+ "name": "Terms and Conditions",
+ "providerId": "terms_and_conditions",
+ "enabled": false,
+ "defaultAction": false,
+ "priority": 20,
+ "config": {}
+ },
+ {
+ "alias": "UPDATE_PASSWORD",
+ "name": "Update Password",
+ "providerId": "UPDATE_PASSWORD",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 30,
+ "config": {}
+ },
+ {
+ "alias": "UPDATE_PROFILE",
+ "name": "Update Profile",
+ "providerId": "UPDATE_PROFILE",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 40,
+ "config": {}
+ },
+ {
+ "alias": "VERIFY_EMAIL",
+ "name": "Verify Email",
+ "providerId": "VERIFY_EMAIL",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 50,
+ "config": {}
+ },
+ {
+ "alias": "delete_account",
+ "name": "Delete Account",
+ "providerId": "delete_account",
+ "enabled": false,
+ "defaultAction": false,
+ "priority": 60,
+ "config": {}
+ },
+ {
+ "alias": "update_user_locale",
+ "name": "Update User Locale",
+ "providerId": "update_user_locale",
+ "enabled": true,
+ "defaultAction": false,
+ "priority": 1000,
+ "config": {}
+ }
+ ],
+ "browserFlow": "browser",
+ "registrationFlow": "registration",
+ "directGrantFlow": "direct grant",
+ "resetCredentialsFlow": "reset credentials",
+ "clientAuthenticationFlow": "clients",
+ "dockerAuthenticationFlow": "docker auth",
+ "attributes": {
+ "clientOfflineSessionMaxLifespan": "0",
+ "clientSessionIdleTimeout": "0",
+ "clientSessionMaxLifespan": "0",
+ "clientOfflineSessionIdleTimeout": "0"
+ },
+ "keycloakVersion": "12.0.1",
+ "userManagedAccessAllowed": false
+}
diff --git a/node_modules/.yarn-integrity b/node_modules/.yarn-integrity
new file mode 100644
index 0000000000..74953049ef
--- /dev/null
+++ b/node_modules/.yarn-integrity
@@ -0,0 +1,12 @@
+{
+ "systemParams": "linux-x64-83",
+ "modulesFolders": [
+ "node_modules"
+ ],
+ "flags": [],
+ "linkedModules": [],
+ "topLevelPatterns": [],
+ "lockfileEntries": {},
+ "files": [],
+ "artifacts": {}
+}
\ No newline at end of file
diff --git a/openshift/zap/zap-scan.conf b/openshift/zap/zap-scan.conf
new file mode 100644
index 0000000000..6a7acbfdd1
--- /dev/null
+++ b/openshift/zap/zap-scan.conf
@@ -0,0 +1,57 @@
+# zap-baseline rule configuration file
+# Change WARN to IGNORE to ignore rule or FAIL to fail if rule matches
+# Only the rule identifiers are used - the names are just for info
+# You can add your own messages to each rule by appending them after a tab on each line.
+* OUTOFSCOPE .*\.svg
+* OUTOFSCOPE .*\.png
+10010 WARN (Cookie No HttpOnly Flag)
+10011 WARN (Cookie Without Secure Flag)
+10015 WARN (Incomplete or No Cache-control and Pragma HTTP Header Set)
+10016 IGNORE (Web Browser XSS Protection Not Enabled)
+10017 WARN (Cross-Domain JavaScript Source File Inclusion)
+10019 WARN (Content-Type Header Missing)
+10020 WARN (X-Frame-Options Header Scanner)
+10021 IGNORE (X-Content-Type-Options Header Missing)
+10023 WARN (Information Disclosure - Debug Error Messages)
+10024 WARN (Information Disclosure - Sensitive Information in URL)
+10025 WARN (Information Disclosure - Sensitive Information in HTTP Referrer Header)
+10026 WARN (HTTP Parameter Override)
+10027 WARN (Information Disclosure - Suspicious Comments)
+10028 WARN (Open Redirect)
+10029 WARN (Cookie Poisoning)
+10030 WARN (User Controllable Charset)
+10031 WARN (User Controllable HTML Element Attribute (Potential XSS))
+10032 WARN (Viewstate Scanner)
+10033 WARN (Directory Browsing)
+10034 WARN (Heartbleed OpenSSL Vulnerability (Indicative))
+10035 WARN (Strict-Transport-Security Header Scanner)
+10036 WARN (HTTP Server Response Header Scanner)
+10037 WARN (Server Leaks Information via "X-Powered-By" HTTP Response Header Field(s))
+10038 WARN (Content Security Policy (CSP) Header Not Set)
+10039 WARN (X-Backend-Server Header Information Leak)
+10040 WARN (Secure Pages Include Mixed Content)
+10041 WARN (HTTP to HTTPS Insecure Transition in Form Post)
+10042 WARN (HTTPS to HTTP Insecure Transition in Form Post)
+10043 WARN (User Controllable JavaScript Event (XSS))
+10044 WARN (Big Redirect Detected (Potential Sensitive Information Leak))
+10050 WARN (Retrieved from Cache)
+10052 WARN (X-ChromeLogger-Data (XCOLD) Header Information Leak)
+10054 WARN (Cookie Without SameSite Attribute)
+10055 WARN (CSP Scanner)
+10056 WARN (X-Debug-Token Information Leak)
+10057 WARN (Username Hash Found)
+10061 WARN (X-AspNet-Version Response Header Scanner)
+10062 WARN (PII Scanner)
+10096 WARN (Timestamp Disclosure)
+10097 WARN (Hash Disclosure)
+10098 WARN (Cross-Domain Misconfiguration)
+10105 WARN (Weak Authentication Method)
+10108 WARN (Reverse Tabnabbing)
+10202 WARN (Absence of Anti-CSRF Tokens)
+2 WARN (Private IP Disclosure)
+3 WARN (Session ID in URL Rewrite)
+50001 WARN (Script Passive Scan Rules)
+90001 WARN (Insecure JSF ViewState)
+90011 WARN (Charset Mismatch)
+90022 WARN (Application Error Disclosure)
+90033 WARN (Loosely Scoped Cookie)
diff --git a/src/backend/.dockerignore b/src/backend/.dockerignore
new file mode 100644
index 0000000000..f4ceea7856
--- /dev/null
+++ b/src/backend/.dockerignore
@@ -0,0 +1 @@
+**/target/
diff --git a/src/backend/.gitignore b/src/backend/.gitignore
index a2a3040aa8..501e312805 100644
--- a/src/backend/.gitignore
+++ b/src/backend/.gitignore
@@ -29,3 +29,6 @@ build/
### VS Code ###
.vscode/
+
+*.versionsBackup
+/libs/spring-boot-starters/
diff --git a/src/backend/Dockerfile b/src/backend/Dockerfile.efiling-api
similarity index 54%
rename from src/backend/Dockerfile
rename to src/backend/Dockerfile.efiling-api
index b9a697b0c8..d5f82319b9 100644
--- a/src/backend/Dockerfile
+++ b/src/backend/Dockerfile.efiling-api
@@ -1,32 +1,50 @@
#############################################################################################
### Stage where Docker is building spring boot app using maven ###
#############################################################################################
-FROM maven:3.6.3-jdk-8 as build
+FROM maven:3.8.3-openjdk-17 as build
ARG MVN_PROFILE
-ARG SERVICE_NAME
+ARG SERVICE_NAME=efiling-api
+ARG SKIP_TESTS=false
+ARG STARTERS_V
ENV SERVICE_NAME=${SERVICE_NAME}
+ENV STARTERS_V=${STARTERS_V}
-COPY . .
+#Temporary removal.
+#RUN mkdir /root/.ssh && \
+# chmod 0700 /root/.ssh && \
+# ssh-keyscan -t rsa localhost >> ~/.ssh/known_hosts && \
+# apt-get update && \
+# apt-get -y install git
-RUN mvn -B clean install \
- -P libs
+WORKDIR /libs
-WORKDIR ${SERVICE_NAME}
+RUN git clone https://github.com/bcgov/spring-boot-starters.git
-RUN mvn -B clean package \
- -P ${MVN_PROFILE}
+WORKDIR /libs/spring-boot-starters
+
+RUN git checkout $STARTERS_V && \
+ mvn install -P all -f src/pom.xml
+
+WORKDIR /
+
+COPY . .
+
+RUN mvn -B clean install \
+ -P ${MVN_PROFILE} \
+ -Dmaven.test.skip=${SKIP_TESTS}
-#############################################################################################
#############################################################################################
### Stage where Docker is running a java process to run a service built in previous stage ###
#############################################################################################
-FROM openjdk:8-jdk-slim
+FROM eclipse-temurin:17-jre-alpine
+
+RUN apk update && apk add --upgrade --no-cache libexpat # fix CVE-2024-8176
# ARG MVN_PROFILES
-ARG SERVICE_NAME
+ARG SERVICE_NAME=efiling-api
COPY --from=build ./${SERVICE_NAME}/target/${SERVICE_NAME}-*.jar /app/service.jar
diff --git a/src/backend/README.md b/src/backend/README.md
index 12a0866f55..e69fa3733b 100644
--- a/src/backend/README.md
+++ b/src/backend/README.md
@@ -25,3 +25,15 @@ mvn clean install -P libs
```
mvn clean verify -P all
```
+
+### Update Version
+
+Run
+
+```
+mvn -f src/backend/pom.xml versions:set -DartifactId=* -DgroupId=*
+```
+
+## caching
+
+Currently lookups are cached using redis. In the event of a code table change redis should be restarted. Check the api for activity beore doing so.
\ No newline at end of file
diff --git a/src/backend/efiling-api/README.md b/src/backend/efiling-api/README.md
index a8d427397e..f0615aafe1 100644
--- a/src/backend/efiling-api/README.md
+++ b/src/backend/efiling-api/README.md
@@ -13,34 +13,74 @@ mvn install -P openshift
### Demo
-This profile self isolate the application from any third party dependencies
+This profile self isolate the application from any third individual dependencies
```bash
mvn install -P demo
```
+### Dev
+
+This profile is required to pull the soap services
+
+```bash
+mvn install -P efiling-api
+```
+
## Configuration
You should use environment variables to configure the jag efiling api
-| Environment Variable | Type | Description | Notes |
-| --- | --- | --- | --- |
-| SERVER_PORT | Integer | web application server port | defaulted to `8080` |
-| DEMO_MODE | Boolean | A flag to turn on/off demo mode | defaulted to `false` |
-| REDIS_HOST | String | Redis storage host | defaulted to `localhost` |
-| REDIS_PORT | Integer | Redis storage port | defaulted to `6379` |
-| REDIS_PASSWORD | String | Redis storage password | Defaulted to `admin` |
-| NAVIGATION_BASE_URL | String | The base path of the secure file upload | not set by default |
-| CACHE_TTL | Integer | The default time to live for the cache in ms | Defaulted to `600000` (10 min) |
-| CSO_ACCOUNTFACADE_USERNAME | String | CSO account facade username | not set by default |
-| CSO_ACCOUNTFACADE_PASSWORD | String | CSO account facade password | not set by default |
-| CSO_ACCOUNTFACADE_URI | String | CSO account facade URI | not set by default |
-| CSO_ROLEREGISTRY_USERNAME | String | role registry username | not set by default |
-| CSO_ROLEREGISTRY_PASSWORD | String | role registry password | not set by default |
-| CSO_ROLEREGISTRY_URI | String | role registry URI | not set by default |
-| BCEID_LOOKUP_USERNAME | String | bceid lookup username | not set by default |
-| BCEID_LOOKUP_PASSWORD | String | bceid lookup password | not set by default |
-| BCEID_LOOKUP_URI | String | bceid lookup URI | not set by default |
+| Environment Variable | Type | Description | Notes |
+| ------------------------------- | ------- | -------------------------------------------- | ------------------------------ |
+| SERVER_PORT | Integer | web application server port | defaulted to `8080` |
+| DEMO_MODE | Boolean | A flag to turn on/off demo mode | defaulted to `false` |
+| REDIS_HOST | String | Redis storage host | defaulted to `localhost` |
+| REDIS_PORT | Integer | Redis storage port | defaulted to `6379` |
+| REDIS_PASSWORD | String | Redis storage password | Defaulted to `admin` |
+| NAVIGATION_BASE_URL | String | The base path of the secure file upload | not set by default |
+| CSO_BASE_URL | String | The cso application base URL | not set by default |
+| CACHE_TTL | Integer | The default time to live for the cache in ms | Defaulted to `600000` (10 min) |
+| CSO_ACCOUNTFACADE_USERNAME | String | CSO account facade username | not set by default |
+| CSO_ACCOUNTFACADE_PASSWORD | String | CSO account facade password | not set by default |
+| CSO_ACCOUNTFACADE_URI | String | CSO account facade URI | not set by default |
+| CSO_ROLEREGISTRY_USERNAME | String | role registry username | not set by default |
+| CSO_ROLEREGISTRY_PASSWORD | String | role registry password | not set by default |
+| CSO_ROLEREGISTRY_URI | String | role registry URI | not set by default |
+| CSO_FILINGSTATSFACADE_USERNAME | String | status facade username | not set by default |
+| CSO_FILINGSTATSFACADE_PASSWORD | String | status facade password | not set by default |
+| CSO_FILINGSTATSFACADE_URI | String | status facade URI | not set by default |
+| CSOWS_USERNAME | String | csows username | not set by default |
+| CSOWS_PASSWORD | String | csows password | not set by default |
+| CSOWS_URI | String | csows URI | not set by default |
+| CSO_FILINGFACADE_USERNAME | String | filing facade username | not set by default |
+| CSO_FILINGFACADE_PASSWORD | String | filing facade password | not set by default |
+| CSO_FILINGFACADE_URI | String | filing facade URI | not set by default |
+| CSO_SERVICEFACADE_USERNAME | String | service facade username | not set by default |
+| CSO_SERVICEFACADE_PASSWORD | String | service facade password | not set by default |
+| CSO_SERVICEFACADE_URI | String | service facade URI | not set by default |
+| KEYCLOAK_AUTH_SERVER_URL | String | The keycloak auth server URL | not set by default |
+| KEYCLOAK_REALM | String | The keycloak realm name | not set by default |
+| KEYCLOAK_RESOURCE | String | The keycloak resource name | not set by default |
+| KEYCLOAK_CREDENTIALS_SECRET | String | The keycloak Credentials Secrets | not set by default |
+| BAMBORA_APIBASEPATH | String | API base path | not set by default |
+| BAMBORA_APIPASSCODE | String | API passcode for bambora auth | not set by default |
+| BAMBORA_MERCHANTID | String | merchant id for bambora auth | not set by default |
+| MAIL_SEND_BASE_URL | String | API base path | not set by default |
+| SFTP_HOST | String | sftp host | defaulted to `localhost` |
+| SFTP_PORT | Integer | sftp port | defaulted to `22` |
+| SFTP_USERNAME | String | sftp username | Defaulted to `admin` |
+| SFTP_PASSWORD | String | sftp password | Defaulted to `admin` |
+| SFTP_REMOTELOCATION | String | remote directory | not set by default |
+| SFTP_KNOWNHOSTS | String | location of known hosts file | not set by default |
+| SFTP_ALLOWUNKNOWN | Boolean | allow unkown hosts | not set by default |
+| CEIS_BASE_PATH | String | Base path for ords | not set by default |
+| CEIS_USERNAME | String | Basic auth username | not set by default |
+| CEIS_PASSWORD | String | Basic auth password | not set by default |
+| BCEID_SERVICE_URI | String | BCEID uri | not set by default |
+| BCEID_SERVICE_USERNAME | String | BCEID username | not set by default |
+| BCEID_SERVICE_PASSWORD | String | BCEID password | not set by default |
+| BCEID_SERVICE_ONLINE_SERVICE_ID | String | BCEID online service id | not set by default |
## Backend Folder Structure
diff --git a/src/backend/efiling-api/jag-efiling-api.yaml b/src/backend/efiling-api/jag-efiling-api.yaml
index 41fcacdf2a..d5251bc33e 100644
--- a/src/backend/efiling-api/jag-efiling-api.yaml
+++ b/src/backend/efiling-api/jag-efiling-api.yaml
@@ -1,100 +1,854 @@
openapi: 3.0.0
info:
- version: 0.3.0
+ version: 0.7.0
title: jag-efiling-api
description: Efiling api
servers:
- - url: 'http://localhost:8080'
+ - url: "http://localhost:8080"
tags:
+ - name: clientEndpoints
+ description: Endpoints that are exposed to external client
- name: submission
description: Submission Api
+ - name: courts
+ description: Courts
+ - name: filingPackages
+ description: File Packages
+security:
+ - bearerAuth: []
paths:
- '/submission/generateUrl':
+ "/submission/documents":
+ post:
+ summary: Initial documents upload
+ operationId: UploadSubmissionDocuments
+ tags:
+ - submission
+ - clientEndpoints
+ parameters:
+ - $ref: "#/components/parameters/xTransactionId"
+ - $ref: "#/components/parameters/xUserId"
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ files:
+ type: array
+ items:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: File successfully received
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UploadSubmissionDocumentsResponse"
+ "/submission/{submissionId}":
+ parameters:
+ - $ref: "#/components/parameters/submissionId"
+ - $ref: "#/components/parameters/xTransactionId"
+ delete:
+ summary: Delete a submission by id
+ operationId: DeleteSubmission
+ tags:
+ - submission
+ responses:
+ "200":
+ description: submission deleted
+ "/submission/{submissionId}/documents":
+ post:
+ summary: Additional documents upload
+ operationId: UploadAdditionalSubmissionDocuments
+ tags:
+ - submission
+ parameters:
+ - $ref: "#/components/parameters/submissionId"
+ - $ref: "#/components/parameters/xTransactionId"
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ files:
+ type: array
+ items:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: File successfully received
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UploadSubmissionDocumentsResponse"
+ "404":
+ description: Submission not found
+ "/submission/{submissionId}/rushDocuments":
+ post:
+ summary: Rush documents upload
+ operationId: UploadRushDocuments
+ tags:
+ - submission
+ parameters:
+ - $ref: "#/components/parameters/submissionId"
+ - $ref: "#/components/parameters/xTransactionId"
+ requestBody:
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ files:
+ type: array
+ items:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: File successfully received
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UploadSubmissionDocumentsResponse"
+ "404":
+ description: Submission not found
+ "/submission/{submissionId}/update-documents":
+ post:
+ summary: Additional documents properties
+ operationId: UpdateDocumentProperties
+ tags:
+ - submission
+ parameters:
+ - $ref: "#/components/parameters/submissionId"
+ - $ref: "#/components/parameters/xTransactionId"
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UpdateDocumentRequest"
+ responses:
+ "200":
+ description: Document properties updated
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/UpdateDocumentResponse"
+ "404":
+ description: Submission not found
+ "/submission/{submissionId}/config":
+ parameters:
+ - $ref: "#/components/parameters/submissionId"
+ - $ref: "#/components/parameters/xTransactionId"
+ get:
+ summary: Get configuration for a given submission
+ operationId: GetSubmissionConfig
+ tags:
+ - submission
+ responses:
+ "200":
+ description: Config found
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/GetSubmissionConfigResponse"
+ "404":
+ description: Config not found
+ "/submission/{submissionId}/generateUrl":
post:
summary: Generates a secure URL for e-filing submission
operationId: GenerateUrl
tags:
- submission
+ - clientEndpoints
parameters:
- - in: header
- name: X-Auth-UserId
- schema:
- type: string
- format: uuid
- required: true
- description: Authenticated user id
+ - $ref: "#/components/parameters/xTransactionId"
+ - $ref: "#/components/parameters/xUserId"
+ - $ref: "#/components/parameters/submissionId"
requestBody:
description: requested parameters to generate a url
required: true
content:
application/json:
schema:
- $ref: '#/components/schemas/GenerateUrlRequest'
+ $ref: "#/components/schemas/GenerateUrlRequest"
responses:
- '200':
+ "200":
description: File successfully received
content:
application/json:
schema:
- $ref: '#/components/schemas/GenerateUrlResponse'
- '403':
+ $ref: "#/components/schemas/GenerateUrlResponse"
+ "403":
description: Request does not meet the required criteria
content:
application/json:
schema:
- $ref: '#/components/schemas/EfilingError'
- '/submission/{id}':
+ $ref: "#/components/schemas/EfilingError"
+ "/submission/{submissionId}/submit":
+ post:
+ summary: Create service for payment processing
+ operationId: submit
+ tags:
+ - submission
+ parameters:
+ - $ref: "#/components/parameters/xTransactionId"
+ - $ref: "#/components/parameters/submissionId"
+ requestBody:
+ description: filing submit parameters
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SubmitRequest"
+ responses:
+ "201":
+ description: Service created
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SubmitResponse"
+ "403":
+ description: Request does not meet the required criteria
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EfilingError"
+ "/submission/{submissionId}/filing-package":
get:
- summary: Get user detail for a given submission
- operationId: GetSubmission
+ summary: Get filing package information
+ operationId: GetSubmissionFilingPackage
tags:
- submission
parameters:
- - name: id
+ - $ref: "#/components/parameters/xTransactionId"
+ - $ref: "#/components/parameters/submissionId"
+ responses:
+ "200":
+ description: Filing Package Information found
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/SubmissionFilingPackage"
+ "404":
+ description: Filing Package Information not found
+ "/submission/{submissionId}/document/{filename}":
+ get:
+ summary: Get document by name
+ operationId: GetSubmissionDocument
+ tags:
+ - submission
+ parameters:
+ - $ref: "#/components/parameters/xTransactionId"
+ - $ref: "#/components/parameters/submissionId"
+ - name: filename
in: path
- description: A submission id
+ description: A document name
required: true
schema:
type: string
- format: uuid
responses:
- '200':
- description: Config found
+ "200":
+ description: Filing Package Information found
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ "404":
+ description: Document not found
+ "/submission/{submissionId}/rushProcessing":
+ post:
+ summary: add rush processing to package
+ operationId: PostRushProcessing
+ tags:
+ - submission
+ parameters:
+ - $ref: "#/components/parameters/xTransactionId"
+ - $ref: "#/components/parameters/submissionId"
+ requestBody:
+ description: filing submit parameters
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Rush"
+ responses:
+ "201":
+ description: Rush created
+ "404":
+ description: Submission not found
+ "/csoAccount":
+ post:
+ summary: Create a CSO account
+ operationId: CreateAccount
+ description: In order to create an account, an item with type BCeID is required in the accounts field.
+ tags:
+ - account
+ parameters:
+ - $ref: "#/components/parameters/xTransactionId"
+ requestBody:
+ description: cso account details
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CreateCsoAccountRequest"
+ responses:
+ "201":
+ description: Account Created
content:
application/json:
schema:
- $ref: '#/components/schemas/GetSubmissionResponse'
- '404':
- description: Config not found
+ $ref: "#/components/schemas/CsoAccount"
+ get:
+ summary: Get user CSO account
+ operationId: GetCsoAccount
+ description: Get a user cso account.
+ tags:
+ - account
+ parameters:
+ - $ref: "#/components/parameters/xTransactionId"
+ responses:
+ "200":
+ description: A CSO Account
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CsoAccount"
+ "404":
+ description: Cso Account not found
+ put:
+ summary: Update CSO account internal client number
+ operationId: updateCsoAccount
+ tags:
+ - account
+ parameters:
+ - $ref: "#/components/parameters/xTransactionId"
+ requestBody:
+ description: update client details parameters
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CsoAccountUpdateRequest"
+ responses:
+ "200":
+ description: Client updated
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CsoAccount"
+ "403":
+ description: Request does not meet the required criteria
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EfilingError"
+ "/bceidAccount":
+ get:
+ summary: Get a BCeID account
+ operationId: GetBceidAccount
+ description: Retrieve BCeID user account information
+ tags:
+ - account
+ parameters:
+ - $ref: "#/components/parameters/xTransactionId"
+ responses:
+ "200":
+ description: Account Created
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/BceidAccount"
+ "404":
+ description: Account not found
+ "/documents/types":
+ get:
+ summary: Get document types
+ operationId: GetDocumentTypes
+ description: A list of document types
+ tags:
+ - lookup
+ - clientEndpoints
+ parameters:
+ - name: courtLevel
+ in: query
+ description: court level
+ required: true
+ schema:
+ $ref: "#/components/schemas/CourtLevel"
+ - name: courtClassification
+ in: query
+ description: court classification
+ required: true
+ schema:
+ $ref: "#/components/schemas/CourtClassification"
+ responses:
+ "200":
+ description: List of document types
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/DocumentTypes"
+ "/countries":
+ get:
+ summary: Get countries
+ operationId: GetCountries
+ description: A list of countries
+ tags:
+ - lookup
+ responses:
+ "200":
+ description: List of countries
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: "#/components/schemas/CountryCode"
+ "/courts":
+ get:
+ summary: Get court locations
+ operationId: GetCourtLocations
+ description: get court information by court name
+ tags:
+ - courts
+ parameters:
+ - name: courtLevel
+ in: query
+ description: court type filter
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Information of a court
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/CourtLocations"
+ "/payment/generate-update-card":
+ post:
+ summary: Update card on bambora
+ operationId: UpdateCreditCard
+ description: For expired credit card get url to update
+ tags:
+ - payment
+ parameters:
+ - $ref: "#/components/parameters/xTransactionId"
+ requestBody:
+ description: card update params
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/GenerateCardUrlRequest"
+ responses:
+ "200":
+ description: Card url generated
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/GenerateCardUrlResponse"
+ "/filingpackages":
+ get:
+ summary: Get filing packages
+ operationId: GetFilingPackages
+ description: get filing packages from cso
+ tags:
+ - filingPackages
+ parameters:
+ - name: parentApplication
+ in: query
+ description: parent application
+ required: false
+ schema:
+ type: string
+ responses:
+ "200":
+ description: All filing package details
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ $ref: "#/components/schemas/FilingPackage"
+ "/filingpackages/{packageIdentifier}":
+ get:
+ summary: Get filing package
+ operationId: GetFilingPackage
+ description: get filing package details from cso
+ tags:
+ - filingPackages
+ - clientEndpoints
+ parameters:
+ - $ref: "#/components/parameters/packageIdentifier"
+ responses:
+ "200":
+ description: All filing package details
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/FilingPackage"
+ "/filingpackages/{packageIdentifier}/actionRequiredDetails":
+ get:
+ summary: Get details for documents that require action
+ operationId: GetActionRequiredDetails
+ description: get action required details from cso
+ tags:
+ - filingPackages
+ - clientEndpoints
+ parameters:
+ - $ref: "#/components/parameters/packageIdentifier"
+ responses:
+ "200":
+ description: All filing package details
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ActionRequiredDetails"
+ "404":
+ description: Package not found
+ "403":
+ description: Request does not meet the required criteria
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/EfilingError"
+ "/filingpackages/{packageIdentifier}/submissionSheet":
+ get:
+ summary: Get submission sheet for package
+ operationId: GetSubmissionSheet
+ description: get submission sheet file from cso
+ tags:
+ - filingPackages
+ parameters:
+ - $ref: "#/components/parameters/packageIdentifier"
+ responses:
+ "200":
+ description: File was returned
+ content:
+ application/pdf:
+ schema:
+ type: string
+ format: binary
+ "404":
+ description: file not found
+ "/filingpackages/{packageIdentifier}/paymentReceipt":
+ get:
+ summary: Get submission payment receipt
+ operationId: GetPaymentReceipt
+ description: get payment receipt file from cso
+ tags:
+ - filingPackages
+ parameters:
+ - $ref: "#/components/parameters/packageIdentifier"
+ responses:
+ "200":
+ description: File was returned
+ content:
+ application/pdf:
+ schema:
+ type: string
+ format: binary
+ "404":
+ description: file not found
+ "/filingpackages/{packageIdentifier}/registryNotice":
+ get:
+ summary: Get submission registry notice
+ operationId: GetRegistryNotice
+ description: get registry notice file from cso
+ tags:
+ - filingPackages
+ - clientEndpoints
+ parameters:
+ - $ref: "#/components/parameters/packageIdentifier"
+ responses:
+ "200":
+ description: File was returned
+ content:
+ application/pdf:
+ schema:
+ type: string
+ format: binary
+ "404":
+ description: file not found
+ "/filingpackages/{packageIdentifier}/document/{documentIdentifier}":
+ get:
+ summary: Get submitted document
+ operationId: GetSubmittedDocument
+ description: get submitted document
+ tags:
+ - filingPackages
+ parameters:
+ - $ref: "#/components/parameters/packageIdentifier"
+ - name: documentIdentifier
+ in: path
+ description: document identifier
+ required: true
+ schema:
+ type: number
+ format: int
+ responses:
+ "200":
+ description: File was returned
+ content:
+ application/pdf:
+ schema:
+ type: string
+ format: binary
+ "404":
+ description: file not found
+ delete:
+ summary: delete(withdraw) submitted document
+ operationId: DeleteSubmittedDocument
+ description: Delete submitted document
+ tags:
+ - filingPackages
+ parameters:
+ - $ref: "#/components/parameters/packageIdentifier"
+ - name: documentIdentifier
+ in: path
+ description: document identifier
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: Document was deleted
+ "/filingpackages/{packageIdentifier}/rushDocument/{fileName}":
+ get:
+ summary: Get rush document
+ operationId: GetRushDocument
+ description: get rush document
+ tags:
+ - filingPackages
+ parameters:
+ - $ref: "#/components/parameters/packageIdentifier"
+ - name: fileName
+ in: path
+ description: document file name
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: File was returned
+ content:
+ application/pdf:
+ schema:
+ type: string
+ format: binary
+ "404":
+ description: file not found
+ "/filingpackages/{packageIdentifier}/parentDetails":
+ get:
+ summary: Get rush document
+ operationId: GetParentDetails
+ description: get parent app details for package
+ tags:
+ - filingPackages
+ parameters:
+ - $ref: "#/components/parameters/packageIdentifier"
+ responses:
+ "200":
+ description: parent app details
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ParentAppDetails"
+ "404":
+ description: Package not found
components:
+ securitySchemes:
+ bearerAuth: # arbitrary name for the security scheme
+ type: http
+ scheme: bearer
+ bearerFormat: JWT
+ parameters:
+ xTransactionId:
+ name: X-Transaction-Id
+ in: header
+ schema:
+ type: string
+ format: uuid
+ required: true
+ description: A unique Transaction Id generated by FilingHub clients
+ xUserId:
+ name: X-User-Id
+ in: header
+ schema:
+ type: string
+ format: string
+ required: true
+ description: A unique BCeID universal id passed to initial calls
+ submissionId:
+ name: submissionId
+ in: path
+ description: A submission id
+ required: true
+ schema:
+ type: string
+ format: uuid
+ packageIdentifier:
+ name: packageIdentifier
+ in: path
+ description: package identifier
+ required: true
+ schema:
+ type: number
schemas:
- Account:
+ BceidAccount:
type: object
- description: represents a user account
+ description: BCeID account details
properties:
+ firstName:
+ type: string
+ lastName:
+ type: string
+ middleName:
+ type: string
+ CourtClassification:
+ type: string
+ enum: [B, C, D, E, F, H, L, M, N, O, P, S, V]
+ description: >
+ court classification:
+ * `B` - Bankruptcy
+ * `C` - Small Claims
+ * `D` - Divorce
+ * `E` - Family Law Proceedings
+ * `F` - Family
+ * `H` - Foreclosure
+ * `L` - Enforcement/Legislated Statute
+ * `M` - Motor Vehicle Accidents
+ * `N` - Adoption
+ * `O` - Appeal Civil
+ * `P` - Probate
+ * `S` - Supreme Civil (General)
+ * `V` - Caveat
+ CourtLevel:
+ type: string
+ enum: [A, P, S]
+ description: >
+ court level:
+ * `A` - Appeal
+ * `P` - Provincial
+ * `S` - Supreme
+ InitialDocument:
+ type: object
+ description: Submission Metadata used to describe the submission that will be e-filled
+ required:
+ - type
+ - name
+ - isAmendment
+ - isSupremeCourtScheduling
+ - data
+ - md5
+ properties:
+ name:
+ type: string
+ description: the name of the document
type:
type: string
- enum: [BCEID, CSO]
- description: the account type
+ description: cso document type
+ isAmendment:
+ type: boolean
+ description: is the document an amendment to another
+ isSupremeCourtScheduling:
+ type: boolean
+ description: supreme court scheduling required
+ data:
+ type: object
+ description: store additional details
+ documentId:
+ type: string
+ description: identifier of document from parent application
+ md5:
+ type: string
+ description: Computed hash value of the document content, it is used as a checksum to validate the document integrity.
+ actionDocument:
+ $ref: "#/components/schemas/ActionDocument"
+ Document:
+ required:
+ - identifier
+ - description
+ - status
+ - paymentProcessed
+ - filingDate
+ type: object
+ description: A Efiling Document
+ properties:
identifier:
type: string
- description: the account identifier
+ description: document identifier
+ filingDate:
+ type: string
+ description: date of document filing
+ description:
+ type: string
+ description: document description
+ paymentProcessed:
+ type: boolean
+ description: Has the payment been processed
+ rushRequired:
+ type: boolean
+ description: Does the document require rush
+ documentId:
+ type: string
+ description: identifier of document from parent application
+ documentProperties:
+ $ref: "#/components/schemas/DocumentProperties"
+ status:
+ $ref: "#/components/schemas/Status"
DocumentProperties:
- type: object
- description: Submission Metadata used to describe the submission that will be e-filled
required:
+ - name
- type
- - subType
- - documentAccess
+ description: common document properties.
properties:
+ name:
+ type: string
+ description: the name of the document
type:
type: string
- description: the submission type
- subType:
+ description: Court Service Online document type
+ isAmendment:
+ type: boolean
+ description: is the document an amendment to another
+ isSupremeCourtScheduling:
+ type: boolean
+ description: supreme court scheduling required
+ SubmissionDocument:
+ required:
+ - description
+ - statutoryFeeAmount
+ type: object
+ description: A Efiling Document
+ allOf:
+ - $ref: "#/components/schemas/InitialDocument"
+ properties:
+ documentProperties:
+ $ref: "#/components/schemas/DocumentProperties"
+ description:
+ type: string
+ description: the description of the document
+ statutoryFeeAmount:
+ type: number
+ description: statutory fee amount
+ mimeType:
type: string
- description: the submission sub type
- submissionAccess:
- $ref: '#/components/schemas/EndpointAccess'
+ description: File mime type
+ status:
+ $ref: "#/components/schemas/Status"
+ paymentProcessed:
+ type: boolean
+ description: Has the payment been processed
+ rushRequired:
+ type: boolean
+ description: Does the document require rush
EfilingError:
required:
- error
@@ -104,29 +858,24 @@ components:
type: string
message:
type: string
- EndpointAccess:
- type: object
- description: Represent an http endpoint
- properties:
- url:
- type: string
- verb:
- type: string
- enum: [GET, POST]
- headers:
- type: object
- additionalProperties:
+ details:
+ type: array
+ items:
type: string
GenerateUrlRequest:
description: details about the required transaction
required:
- - navigation
- - documentProperties
+ - clientApplication
+ - filingPackage
+ - navigationUrls
properties:
- documentProperties:
- $ref: '#/components/schemas/DocumentProperties'
- navigation:
- $ref: '#/components/schemas/Navigation'
+ clientAppName:
+ type: string
+ description: Name of the application to be displayed
+ filingPackage:
+ $ref: "#/components/schemas/InitialPackage"
+ navigationUrls:
+ $ref: "#/components/schemas/NavigationUrls"
GenerateUrlResponse:
description: A temporary url for uploading submission
properties:
@@ -135,37 +884,489 @@ components:
format: int64
efilingUrl:
type: string
- GetSubmissionResponse:
+ GetSubmissionConfigResponse:
type: object
required:
- - userDetails
- navigation
+ - clientAppName
+ - csoBaseUrl
properties:
- userDetails:
- $ref: '#/components/schemas/UserDetails'
- navigation:
- $ref: '#/components/schemas/Navigation'
- Navigation:
+ navigationUrls:
+ $ref: "#/components/schemas/NavigationUrls"
+ clientAppName:
+ type: string
+ description: the client app name
+ csoBaseUrl:
+ type: string
+ description: the CSO base Url
+ NavigationUrls:
required:
- success
- error
- cancel
properties:
success:
- $ref: '#/components/schemas/Redirect'
+ type: string
+ description: where user should be redirected on success
error:
- $ref: '#/components/schemas/Redirect'
+ type: string
+ description: where user should be redirected on error
cancel:
- $ref: '#/components/schemas/Redirect'
- Redirect:
+ type: string
+ description: where user should be redirected on cancel
+ InitialPackage:
+ type: object
+ description: A filing package can contain one or multiple documents that have or are being submitted electronically for new or existing court file.
+ required:
+ - documents
+ - court
+ properties:
+ packageNumber:
+ type: number
+ description: Identifer of package that is being modified
+ court:
+ $ref: "#/components/schemas/CourtBase"
+ documents:
+ type: array
+ items:
+ $ref: "#/components/schemas/InitialDocument"
+ parties:
+ type: array
+ items:
+ $ref: "#/components/schemas/Individual"
+ organizationParties:
+ type: array
+ items:
+ $ref: "#/components/schemas/Organization"
+ FilingPackage:
+ type: object
+ description: A filing package can contain one or multiple documents that have or are being submitted electronically for new or existing court file.
+ required:
+ - packageNumber
+ - documents
+ - submittedBy
+ - submittedDate
+ - links
+ - court
+ - hasRegistryNotice
+ properties:
+ packageNumber:
+ type: number
+ description: Submitted package number
+ status:
+ type: string
+ description: Calculated status of package
+ filingComments:
+ type: string
+ description: Filing comments
+ submittedBy:
+ $ref: "#/components/schemas/Account"
+ submittedDate:
+ type: string
+ description: Submitted date
+ court:
+ $ref: "#/components/schemas/Court"
+ documents:
+ type: array
+ items:
+ $ref: "#/components/schemas/Document"
+ parties:
+ type: array
+ items:
+ $ref: "#/components/schemas/Individual"
+ organizationParties:
+ type: array
+ items:
+ $ref: "#/components/schemas/Organization"
+ payments:
+ type: array
+ items:
+ $ref: "#/components/schemas/Payment"
+ links:
+ type: object
+ properties:
+ packageHistoryUrl:
+ type: string
+ description: a link to view all submitted package
+ hasRegistryNotice:
+ type: boolean
+ description: this filing package has a registry notice
+ rush:
+ $ref: "#/components/schemas/Rush"
+ SubmissionFilingPackage:
+ type: object
+ description: Submitted
+ required:
+ - submissionFeeAmount
+ - documents
+ properties:
+ submissionFeeAmount:
+ type: number
+ description: Package submission fee.
+ packageNumber:
+ type: number
+ description: Submitted package number
+ filingComments:
+ type: string
+ description: Filing comments
+ submittedBy:
+ $ref: "#/components/schemas/Account"
+ submittedDate:
+ type: string
+ description: Submitted date
+ court:
+ $ref: "#/components/schemas/Court"
+ documents:
+ type: array
+ items:
+ $ref: "#/components/schemas/SubmissionDocument"
+ parties:
+ type: array
+ items:
+ $ref: "#/components/schemas/Individual"
+ organizationParties:
+ type: array
+ items:
+ $ref: "#/components/schemas/Organization"
+ payments:
+ type: array
+ items:
+ $ref: "#/components/schemas/Payment"
+ rush:
+ $ref: "#/components/schemas/Rush"
+ CourtBase:
+ type: object
+ description: "Court related information"
+ required:
+ - location
+ - level
+ - courtClass
+ - division
+ properties:
+ location:
+ type: string
+ description: the court location
+ level:
+ type: string
+ description: the court level
+ courtClass:
+ type: string
+ description: the court class
+ division:
+ type: string
+ description: the court division
+ fileNumber:
+ type: string
+ description: the file number if case already exists
+ participatingClass:
+ type: string
+ Court:
+ type: object
+ description: "Court related information"
+ allOf:
+ - $ref: "#/components/schemas/CourtBase"
+ required:
+ - locationDescription
+ properties:
+ agencyId:
+ type: number
+ description: the agancy identifier
+ locationDescription:
+ type: string
+ description: the court location description
+ levelDescription:
+ type: string
+ description: the court location description
+ classDescription:
+ type: string
+ description: the court location description
+ Rush:
+ type: object
+ required:
+ - rushType
+ - firstName
+ - lastName
+ properties:
+ rushType:
+ type: string
+ description: >
+ rush type code
+ * `rule` - Application is made under rule 8-5 (1) SCR
+ * `court` - The court directed that the order be processeed on an urgent basis
+ * `pro` - This is based on a document type
+ * `other` - Other
+ enum:
+ [
+ rule,
+ court,
+ pro,
+ other
+ ]
+ firstName:
+ type: string
+ description: first name of rush party
+ lastName:
+ type: string
+ description: last name of rush party
+ organization:
+ type: string
+ description: organization
+ phoneNumber:
+ type: string
+ description: phone number
+ email:
+ type: string
+ description: email address
+ courtDate:
+ type: string
+ description: court directed date
+ country:
+ type: string
+ description: country
+ countryCode:
+ type: string
+ description: code value for country
+ reason:
+ type: string
+ description: clear and detailed reason
+ status:
+ type: string
+ description: current status of the rush request
+ statusReason:
+ type: string
+ description: current registry reason text
+ supportingDocuments:
+ type: array
+ items:
+ $ref: "#/components/schemas/RushDocument"
+ RushDocument:
+ type: object
+ properties:
+ fileName:
+ type: string
+ description: file name of document
+ identifier:
+ type: string
+ description: guid of file
+ CsoAccount:
+ type: object
+ description: a CsoAccount
required:
- - url
+ - clientId
+ - accountId
+ - internalClientNumber
+ - fileRolePresent
properties:
- url:
+ clientId:
type: string
- UserDetails:
- description: represents a user submitting a package
+ description: the user cso clientId
+ accountId:
+ type: string
+ description: the user cso accountId
+ internalClientNumber:
+ type: string
+ description: the user cso internal client number
+ fileRolePresent:
+ type: boolean
+ description: if the user as file role
+ DocumentType:
type: object
+ required:
+ - type
+ - description
+ properties:
+ type:
+ type: string
+ description: code value
+ description:
+ type: string
+ description: human readable value
+ DocumentTypes:
+ type: array
+ items:
+ $ref: "#/components/schemas/DocumentType"
+ UploadSubmissionDocumentsResponse:
+ description: represents upload document response
+ type: object
+ required:
+ - submissionId
+ properties:
+ submissionId:
+ type: string
+ format: uuid
+ description: a unique identifier for the submission
+ received:
+ type: number
+ description: the number of document received
+ Party:
+ description: party related to filing package
+ required:
+ - roleType
+ properties:
+ roleType:
+ type: string
+ description: >
+ role type code
+ * `ABC` - Aboriginal Community
+ * `ADJ` - Adjudicator
+ * `ADP` - Adoptee
+ * `APL` - Appellant
+ * `APP` - Applicant
+ * `ANT` - Aunt
+ * `AUT` - Authority
+ * `BKP` - Bankrupt
+ * `BKS` - Bankrupts (Spouse)
+ * `CAV` - Caveator
+ * `CHD` - Child
+ * `COF` - Child on File
+ * `CIT` - Citator
+ * `CLA` - Claimant
+ * `CLA1` - Claimant 1
+ * `CLA2` - Claimant 2
+ * `CLI` - Client
+ * `CI` - Court Issued
+ * `CRD` - Creditor
+ * `DBT` - Debtor
+ * `DEC` - Deceased
+ * `DEF` - Defendant
+ * `DEO` - Defendant by Counterclaim
+ * `DIS` - Disputant
+ * `FTH` - Father
+ * `FNA` - First Nation
+ * `GRF` - Grandfather
+ * `GRM` - Grandmother
+ * `GUA` - Guardian
+ * `HSB` - Husband - Divorce
+ * `INB` - Indian Band
+ * `INC` - Indigenous Community
+ * `ITV` - Intervener
+ * `MOT` - Mother
+ * `NIS` - Nisga'a Lisims Government
+ * `OPAR` - Other Party
+ * `PAR` - Party
+ * `PAR1` - Party 1
+ * `PA1` - Party 1 Joint Divorce Form127A
+ * `PAR2` - Party 2
+ * `PA2` - Party 2 Joint Divorce Form127A
+ * `PAR3` - Party 3
+ * `PAR4` - Party 4
+ * `PAR5` - Party 5
+ * `PET` - Petitioner
+ * `PLA` - Plaintiff
+ * `RES` - Respondent
+ * `REO` - Respondent by way of Counterclaim
+ * `SOL` - Solicitor
+ * `SP1` - Spouse 1- Divorce
+ * `SP2` - Spouse 2 - Divorce
+ * `SFH` - Step-Father
+ * `SMH` - Step-Mother
+ * `TST` - Testator
+ * `TSX` - Testatrix
+ * `THR` - Third Party
+ * `TFN` - Treaty First Nation
+ * `TRU` - Trustee
+ * `UNC` - Uncle
+ * `WIF` - Wife - Divorce
+ * `WIT` - Witness
+ enum:
+ [
+ ABC,
+ ADJ,
+ ADP,
+ APL,
+ APP,
+ ANT,
+ AUT,
+ BKP,
+ BKS,
+ CAV,
+ CHD,
+ COF,
+ CIT,
+ CLA,
+ CLA1,
+ CLA2,
+ CLI,
+ CI,
+ CRD,
+ DBT,
+ DEC,
+ DEF,
+ DEO,
+ DIS,
+ FTH,
+ FNA,
+ GRF,
+ GRM,
+ GUA,
+ HSB,
+ INB,
+ INC,
+ ITV,
+ MOT,
+ NIS,
+ OPAR,
+ PAR,
+ PAR1,
+ PA1,
+ PAR2,
+ PA2,
+ PAR3,
+ PAR4,
+ PAR5,
+ PET,
+ PLA,
+ RES,
+ REO,
+ SOL,
+ SP1,
+ SP2,
+ SFH,
+ SMH,
+ TST,
+ TSX,
+ THR,
+ TFN,
+ TRU,
+ UNC,
+ WIF,
+ WIT,
+ ]
+ roleDescription:
+ type: string
+ description: description of role
+ partyDescription:
+ type: string
+ description: description of party
+ Individual:
+ description: Individual party type
+ allOf:
+ - $ref: "#/components/schemas/Party"
+ required:
+ - firstName
+ - lastName
+ properties:
+ firstName:
+ type: string
+ description: first name
+ middleName:
+ type: string
+ description: middle name
+ lastName:
+ type: string
+ description: last name
+ Organization:
+ description: Organization party type
+ allOf:
+ - $ref: "#/components/schemas/Party"
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ description: organization name
+ CreateCsoAccountRequest:
+ description: represents a request to create a user
required:
- firstName
- lastName
@@ -184,7 +1385,238 @@ components:
email:
type: string
description: the user email address
- accounts:
+ UpdateDocumentRequest:
+ description: request body for update documents
+ type: object
+ properties:
+ documents:
+ type: array
+ items:
+ $ref: "#/components/schemas/DocumentProperties"
+ UpdateDocumentResponse:
+ description: response body for update documents
+ type: object
+ properties:
+ documents:
+ type: array
+ items:
+ $ref: "#/components/schemas/SubmissionDocument"
+ SubmitRequest:
+ description: create service request
+ type: object
+ SubmitResponse:
+ description: result of submit filing package
+ type: object
+ required:
+ - packageRef
+ properties:
+ packageRef:
+ type: string
+ description: base64 encoded package reference url
+ GenerateCardUrlRequest:
+ description: create service request
+ type: object
+ required:
+ - internalClientNumber
+ - redirectUrl
+ properties:
+ internalClientNumber:
+ type: string
+ description: client id for request to bambora
+ redirectUrl:
+ type: string
+ description: url bambora return from
+ GenerateCardUrlResponse:
+ description: result generate url
+ type: object
+ required:
+ - bamboraUrl
+ properties:
+ bamboraUrl:
+ type: string
+ description: redirect url
+ CsoAccountUpdateRequest:
+ description: update client details
+ type: object
+ required:
+ - internalClientNumber
+ properties:
+ internalClientNumber:
+ type: string
+ description: internal client number for request to bambora
+ CourtLocation:
+ type: object
+ description: "Court related information"
+ required:
+ - id
+ - name
+ - code
+ - identifierCode
+ - isSupremeCourt
+ - address
+ properties:
+ id:
+ type: number
+ description: the court id
+ identifierCode:
+ type: string
+ description: the court id code
+ name:
+ type: string
+ description: the court name
+ code:
+ type: string
+ description: the court code
+ isSupremeCourt:
+ type: boolean
+ description: the court supreme
+ address:
+ $ref: "#/components/schemas/Address"
+ CourtLocations:
+ description: resposne body for courtlocations
+ type: object
+ properties:
+ courts:
type: array
items:
- $ref: '#/components/schemas/Account'
+ $ref: "#/components/schemas/CourtLocation"
+ Address:
+ description: address object
+ type: object
+ required:
+ - addressLine1
+ - cityName
+ - provinceName
+ - countryName
+ properties:
+ addressLine1:
+ type: string
+ description: the court address line one
+ addressLine2:
+ type: string
+ description: the court address line two
+ addressLine3:
+ type: string
+ description: the court address line three
+ postalCode:
+ type: string
+ description: the court postal code
+ cityName:
+ description: the court city name
+ type: string
+ provinceName:
+ type: string
+ description: the court province name
+ countryName:
+ description: the address country name
+ type: string
+ Payment:
+ description: payment object
+ type: object
+ properties:
+ feeExempt:
+ type: boolean
+ description: Is the fee exempt
+ paymentCategory:
+ type: number
+ description: Category for fee
+ paymentDescription:
+ type: string
+ description: a description of the payment
+ processedAmount:
+ type: number
+ description: Amount
+ submittedAmount:
+ type: number
+ description: Amount
+ serviceIdentifier:
+ type: number
+ description: Id of payment
+ transactionDate:
+ type: string
+ description: date time of transaction
+ Status:
+ description: document status
+ type: object
+ properties:
+ description:
+ type: string
+ description: description of status
+ code:
+ type: string
+ description: status identifier
+ changeDate:
+ type: string
+ description: date changed
+ Account:
+ description: account object
+ type: object
+ properties:
+ firstName:
+ type: string
+ description: first name
+ lastName:
+ type: string
+ description: last name
+ CountryCode:
+ description: Country Code Table Entry
+ type: object
+ properties:
+ code:
+ type: string
+ description: code value
+ description:
+ type: string
+ description: country name
+ ActionRequiredDetails:
+ description: Action required details
+ type: object
+ properties:
+ clientId:
+ type: number
+ description: user identifier
+ packageIdentifier:
+ type: number
+ description: package identifier
+ documents:
+ type: array
+ description: any document that requires action
+ items:
+ $ref: "#/components/schemas/ActionDocument"
+ ActionDocument:
+ description: Document that requires action
+ type: object
+ properties:
+ id:
+ type: number
+ description: document identifier
+ status:
+ type: string
+ description: >
+ document status:
+ * `SUB` - Submitted
+ * `RSUB` - Resubmitted
+ * `REF` - Referred
+ * `REJ` - Reject
+ * `CCOR` - Courtesy Correction
+ enum:
+ [
+ SUB,
+ RSUB,
+ REF,
+ REJ,
+ CCOR
+ ]
+ type:
+ type: string
+ description: document type
+ ParentAppDetails:
+ description: Action required details
+ type: object
+ properties:
+ returnUrl:
+ type: string
+ description: the url that users will return to
+ rejectedDocumentFeature:
+ type: boolean
+ description: the feature is enabled or disabled for this parent
diff --git a/src/backend/efiling-api/pom.xml b/src/backend/efiling-api/pom.xml
index 940f0eab8c..56427427c1 100644
--- a/src/backend/efiling-api/pom.xml
+++ b/src/backend/efiling-api/pom.xml
@@ -1,317 +1,473 @@
-
-
- 4.0.0
-
- org.springframework.boot
- spring-boot-starter-parent
- 2.3.1.RELEASE
-
-
- ca.bc.gov.open.jag
- efiling-api
- 0.0.1-SNAPSHOT
- efiling-api
- Demo project for Spring Boot
-
-
- 1.8
- 1.3.1.Final
- ca.bc.gov.open.jag.efilingapi
-
-
-
-
- org.springframework.boot
- spring-boot-starter-web
-
-
-
- org.springframework.boot
- spring-boot-starter-test
- test
-
-
- org.junit.vintage
- junit-vintage-engine
-
-
-
-
-
- org.springframework.boot
- spring-boot-starter-actuator
-
-
-
- org.springframework.boot
- spring-boot-starter-cache
-
-
-
- ca.bc.gov.open.jag
- efiling-commons
- 0.0.1-SNAPSHOT
-
-
-
- ca.bc.gov.open.jag
- efiling-account-client
- 0.0.1-SNAPSHOT
-
-
-
- ca.bc.gov.open.jag
- efiling-lookup-client
- 0.0.1-SNAPSHOT
- compile
-
-
-
- commons-codec
- commons-codec
-
-
-
- org.apache.commons
- commons-lang3
-
-
-
- joda-time
- joda-time
-
-
-
- javax.validation
- validation-api
-
-
-
-
- io.opentracing.contrib
- opentracing-spring-jaeger-web-starter
-
-
- io.github.openfeign.opentracing
- feign-opentracing
-
-
-
-
- ch.qos.logback
- logback-classic
-
-
- ch.qos.logback
- logback-core
-
-
- ch.qos.logback
- logback-access
-
-
-
- net.rakugakibox.spring.boot
- logback-access-spring-boot-starter
-
-
-
-
- io.swagger
- swagger-annotations
-
-
- org.springdoc
- springdoc-openapi-ui
-
-
- io.springfox
- springfox-swagger2
-
-
- io.springfox
- springfox-swagger-ui
-
-
-
-
- org.springframework.boot
- spring-boot-starter-data-redis
-
-
- org.springframework.data
- spring-data-redis
-
-
- redis.clients
- jedis
-
-
-
-
- org.mapstruct
- mapstruct
-
-
-
- org.openapitools
- jackson-databind-nullable
-
-
-
-
-
-
-
- ca.bc.gov.open.jag
- efiling-bom
- 0.0.1-SNAPSHOT
- pom
- import
-
-
-
-
-
-
-
- default
-
-
-
-
- openshift
-
-
-
- splunk-artifactory
- Splunk Releases
- https://splunk.jfrog.io/artifactory/ext-releases-local/
-
-
-
-
-
- com.splunk.logging
- splunk-library-javalogging
-
-
-
-
-
-
- demo
-
-
- ca.bc.gov.open.jag
- efiling-demo-starter
- 0.0.1-SNAPSHOT
-
-
-
-
-
-
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
- ca.bc.gov.open.jag.efilingapi.EfilingApiApplication
-
-
-
-
- org.apache.maven.plugins
- maven-surefire-plugin
- 2.22.2
-
-
-
- org.apache.maven.plugins
- maven-failsafe-plugin
- 2.22.2
-
-
-
-
- org.openapitools
- openapi-generator-maven-plugin
- 4.3.1
-
-
- spring-boot-api
-
- generate
-
-
- ${project.basedir}/jag-efiling-api.yaml
- spring
-
- joda
- true
-
- spring-boot
- ${default-package}.api
- ${default-package}.api.model
- ${default-package}.api.handler
-
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
-
- ${java.version}
- ${java.version}
-
-
- org.mapstruct
- mapstruct-processor
- ${org.mapstruct.version}
-
-
-
-
-
-
-
- org.jacoco
- jacoco-maven-plugin
- 0.8.4
-
-
-
- **/*/mappers/*Impl.java
- **/*/efilingapi/api/**/*
- org/openapitools/configuration/**/*
-
-
-
-
-
-
- prepare-agent
-
-
-
-
-
- report
- test
-
- report
-
-
-
-
-
-
-
-
-
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.5.4
+
+
+
+ ca.bc.gov.open.jag
+ efiling-api
+ 2.0.12-SNAPSHOT
+ efiling-api
+ Demo project for Spring Boot
+
+
+ 17
+ 1.5.5.Final
+ ca.bc.gov.open.jag.efilingapi
+ 2.17.1
+ 2.0
+
+ jdt_apt
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+ org.junit.vintage
+ junit-vintage-engine
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+
+
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ org.springframework.boot
+ spring-boot-starter-oauth2-resource-server
+
+
+
+ ca.bc.gov.open.jag
+ efiling-commons
+ 2.0.12-SNAPSHOT
+
+
+
+ ca.bc.gov.open
+ spring-sftp-starter
+
+
+
+ ca.bc.gov.open
+ spring-bceid-starter
+
+
+ org.mapstruct
+ mapstruct-processor
+
+
+
+
+
+ ca.bc.gov.open
+ spring-clamav-starter
+
+
+
+ ca.bc.gov.open
+ bambora-payment-starter
+
+
+
+ commons-codec
+ commons-codec
+
+
+
+ org.apache.commons
+ commons-lang3
+
+
+
+ org.apache.tika
+ tika-core
+
+
+
+ joda-time
+ joda-time
+
+
+
+ javax.validation
+ validation-api
+
+
+
+
+ ch.qos.logback
+ logback-classic
+
+
+ ch.qos.logback
+ logback-core
+
+
+ ch.qos.logback.access
+ logback-access-common
+
+
+
+ net.rakugakibox.spring.boot
+ logback-access-spring-boot-starter
+
+
+
+
+ io.swagger.core.v3
+ swagger-annotations
+
+
+ org.springdoc
+ springdoc-openapi-ui
+
+
+
+ io.springfox
+ springfox-swagger-ui
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
+
+ org.springframework.data
+ spring-data-redis
+
+
+ redis.clients
+ jedis
+ 6.0.0
+
+
+
+ org.mapstruct
+ mapstruct
+
+
+ org.openapitools
+ jackson-databind-nullable
+
+
+ org.apache.commons
+ commons-collections4
+
+
+ org.springframework.boot
+ spring-boot-test
+
+
+ org.testng
+ testng
+ 7.8.0
+ compile
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ compile
+
+
+ org.springframework.security
+ spring-security-test
+ test
+
+
+ org.mockito
+ mockito-inline
+ 3.11.2
+ test
+
+
+ org.apache.tomcat.embed
+ tomcat-embed-core
+ 11.0.10
+
+
+ org.json
+ json
+
+
+ org.springframework.security
+ spring-security-core
+
+
+ org.springframework.security
+ spring-security-web
+
+
+ org.springframework
+ spring-web
+
+
+ org.springframework
+ spring-webmvc
+
+
+ io.netty
+ netty-common
+
+
+ io.netty
+ netty-handler
+ 4.1.118.Final
+
+
+ org.apache.cxf
+ cxf-core
+ 4.1.3
+
+
+ org.springframework.security
+ spring-security-crypto
+ 6.5.3
+
+
+
+
+
+
+
+ ca.bc.gov.open.jag
+ efiling-bom
+ 2.0.12-SNAPSHOT
+ pom
+ import
+
+
+
+
+
+
+
+
+ default
+
+
+
+
+ efiling-api
+
+
+
+
+ ca.bc.gov.open.jag
+ efiling-cso-starter
+ 2.0.12-SNAPSHOT
+
+
+
+ ca.bc.gov.open.jag
+ efiling-bambora-api-client
+ 2.0.12-SNAPSHOT
+
+
+
+ ca.bc.gov.open.jag
+ efiling-ceis-api-client
+ 2.0.12-SNAPSHOT
+
+
+
+
+ com.github.java-json-tools
+ jackson-coreutils
+ 2.0
+
+
+
+
+
+
+
+
+ splunk
+
+
+
+ splunk-artifactory
+ Splunk Releases
+ https://splunk.jfrog.io/splunk/ext-releases-local
+
+
+
+
+
+ com.splunk.logging
+ splunk-library-javalogging
+ 1.11.8
+
+
+
+
+
+
+
+ efiling-api-demo
+
+
+ ca.bc.gov.open.jag
+ efiling-demo-starter
+ 2.0.12-SNAPSHOT
+
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+ ca.bc.gov.open.jag.efilingapi.EfilingApiApplication
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+
+ org.apache.maven.plugins
+ maven-failsafe-plugin
+
+
+
+
+ org.openapitools
+ openapi-generator-maven-plugin
+ 6.2.1
+
+
+ spring-boot-api
+
+ generate
+
+
+ ${project.basedir}/jag-efiling-api.yaml
+ spring
+
+ joda
+ true
+
+
+ true
+ true
+
+
+ spring-boot
+ ${default-package}.api
+ ${default-package}.api.model
+ ${default-package}.api.handler
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ -parameters
+
+ true
+ ${java.version}
+ ${java.version}
+
+
+ org.mapstruct
+ mapstruct-processor
+ ${org.mapstruct.version}
+
+
+
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.8
+
+
+
+ **/*/mappers/*Impl.java
+ **/*/efilingapi/api/**/*
+ org/openapitools/configuration/**/*
+
+
+
+
+
+
+ prepare-agent
+
+
+
+
+
+ report
+ test
+
+ report
+
+
+
+
+
+
+ org.codehaus.mojo
+ build-helper-maven-plugin
+
+
+ add-source
+ generate-sources
+
+ add-source
+
+
+
+ ${project.build.directory}/generated-sources/annotations
+
+
+
+
+
+
+
+
+
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/Keys.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/Keys.java
index c10dc6e49a..3e9dcd2ecf 100644
--- a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/Keys.java
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/Keys.java
@@ -4,6 +4,32 @@ public class Keys {
protected Keys() {}
- public static final String SECURE_URL_CACHE_NAME = "SECURE_URL_CACHE";
+ public static final String EFILING_APP = "efiling";
+
+ public static final String EFILING_API_NAME = "efiling-api";
+
+ public static final String MDC_EFILING_REQUEST_HEADERS = EFILING_APP + ".headers";
+
+ public static final String MDC_EFILING_JWT = EFILING_APP + ".jwt";
+
+ public static final String MDC_EFILING_SUBMISSION_ID = EFILING_APP + ".submissionId";
+
+ public static final String UNIVERSAL_ID_CLAIM_KEY = "universal-id";
+
+ public static final String CSO_APPLICATION_CLAIM_KEY = "cso-application-code";
+
+ public static final String IDENTITY_PROVIDER_CLAIM_KEY = "identityProviderAlias";
+
+ public static final String EFILING_CLIENT_ROLE = "efiling-client";
+
+ public static final String EFILING_USER_ROLE = "efiling-user";
+
+ public static final String EFILING_PAYMENT_RECEIPT_FILENAME = "payment-receipt.pdf";
+
+ public static final String EFILING_SUBMISSION_SHEET_FILENAME = "submission-sheet.pdf";
+
+ public static final String EFILING_REGISTRY_NOTICE_FILENAME = "registry-notice.pdf";
+
+ public static final String REJECTED_DOCUMENT_CODE = "REJ";
}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/AccountConfig.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/AccountConfig.java
new file mode 100644
index 0000000000..7e79c369d3
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/AccountConfig.java
@@ -0,0 +1,31 @@
+package ca.bc.gov.open.jag.efilingapi.account;
+
+import ca.bc.gov.open.jag.efilingapi.account.mappers.*;
+import ca.bc.gov.open.jag.efilingapi.account.service.AccountService;
+import ca.bc.gov.open.jag.efilingapi.account.service.AccountServiceImpl;
+import ca.bc.gov.open.jag.efilingcommons.service.EfilingAccountService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class AccountConfig {
+
+ @Bean
+ public CreateAccountRequestMapper createAccountRequestMapper() {
+ return new CreateAccountRequestMapperImpl();
+ }
+
+ @Bean
+ public AccountService accountService(EfilingAccountService efilingAccountService, CreateAccountRequestMapper createAccountRequestMapper) {
+ return new AccountServiceImpl(efilingAccountService, createAccountRequestMapper);
+ }
+
+ @Bean
+ public BceidAccountMapper bceidAccountMapper() {
+ return new BceidAccountMapperImpl();
+ }
+
+ @Bean
+ public CsoAccountMapper csoAccountMapper() { return new CsoAccountMapperImpl(); }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/BceidAccountApiDelagateImpl.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/BceidAccountApiDelagateImpl.java
new file mode 100644
index 0000000000..d12a0e4996
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/BceidAccountApiDelagateImpl.java
@@ -0,0 +1,48 @@
+package ca.bc.gov.open.jag.efilingapi.account;
+
+import ca.bc.gov.open.bceid.starter.account.BCeIDAccountService;
+import ca.bc.gov.open.bceid.starter.account.GetAccountRequest;
+import ca.bc.gov.open.bceid.starter.account.models.IndividualIdentity;
+import ca.bc.gov.open.jag.efilingapi.account.mappers.BceidAccountMapper;
+import ca.bc.gov.open.jag.efilingapi.api.BceidAccountApiDelegate;
+import ca.bc.gov.open.jag.efilingapi.api.model.BceidAccount;
+import ca.bc.gov.open.jag.efilingapi.core.security.SecurityUtils;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+import java.util.UUID;
+
+@Service
+public class BceidAccountApiDelagateImpl implements BceidAccountApiDelegate {
+
+
+ private final BCeIDAccountService bCeIDAccountService;
+ private final BceidAccountMapper bceidAccountMapper;
+
+ public BceidAccountApiDelagateImpl(BCeIDAccountService bCeIDAccountService, BceidAccountMapper bceidAccountMapper) {
+ this.bCeIDAccountService = bCeIDAccountService;
+ this.bceidAccountMapper = bceidAccountMapper;
+ }
+
+ @Override
+ @PreAuthorize("hasRole('efiling-user')")
+ public ResponseEntity getBceidAccount(UUID xTransactionId) {
+
+ Optional userId = SecurityUtils.getUniversalIdFromContext();
+
+ if(!userId.isPresent())
+ return new ResponseEntity(HttpStatus.FORBIDDEN);
+
+ Optional individualIdentity = bCeIDAccountService.getIndividualIdentity(
+ GetAccountRequest.IndividualSelfRequest(userId.get().toString().replace("-", "").toUpperCase()));
+
+ if(!individualIdentity.isPresent())
+ return new ResponseEntity(HttpStatus.NOT_FOUND);
+
+ return ResponseEntity.ok(bceidAccountMapper.toBceidAccount(individualIdentity.get()));
+
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/CsoAccountApiDelegateImpl.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/CsoAccountApiDelegateImpl.java
new file mode 100644
index 0000000000..31de5d754c
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/CsoAccountApiDelegateImpl.java
@@ -0,0 +1,128 @@
+package ca.bc.gov.open.jag.efilingapi.account;
+
+import ca.bc.gov.open.jag.efilingapi.account.mappers.CsoAccountMapper;
+import ca.bc.gov.open.jag.efilingapi.account.service.AccountService;
+import ca.bc.gov.open.jag.efilingapi.api.CsoAccountApiDelegate;
+import ca.bc.gov.open.jag.efilingapi.api.model.CreateCsoAccountRequest;
+import ca.bc.gov.open.jag.efilingapi.api.model.CsoAccount;
+import ca.bc.gov.open.jag.efilingapi.api.model.CsoAccountUpdateRequest;
+import ca.bc.gov.open.jag.efilingapi.core.security.SecurityUtils;
+import ca.bc.gov.open.jag.efilingapi.error.*;
+import ca.bc.gov.open.jag.efilingcommons.exceptions.EfilingAccountServiceException;
+import ca.bc.gov.open.jag.efilingcommons.model.AccountDetails;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Service;
+
+import java.util.Optional;
+import java.util.UUID;
+
+/**
+ * Suite of services to manage cso account
+ */
+@Service
+public class CsoAccountApiDelegateImpl implements CsoAccountApiDelegate {
+
+ private static final String CREATE_ACCOUNT_EXCEPTION = "Error Creating CSO account.";
+ private static final String INVALID_UNIVERSAL_ID = "Invalid universal id.";
+ private static final String MISSING_IDENTITY_PROVIDER = "identityProviderAlias claim missing in jwt token.";
+ private static final String MISSING_UNIVERSAL_ID = "universal-id claim missing in jwt token.";
+ private static final String UPDATE_CLIENT_EXCEPTION = "Error Updating CSO client account.";
+
+ Logger logger = LoggerFactory.getLogger(CsoAccountApiDelegateImpl.class);
+
+ private final AccountService accountService;
+ private final CsoAccountMapper csoAccountMapper;
+
+
+ public CsoAccountApiDelegateImpl(AccountService accountService, CsoAccountMapper csoAccountMapper) {
+ this.accountService = accountService;
+ this.csoAccountMapper = csoAccountMapper;
+ }
+
+
+ @Override
+ @PreAuthorize("hasRole('efiling-user')")
+ public ResponseEntity createAccount(UUID xTransactionId, CreateCsoAccountRequest createAccountRequest) {
+
+ Optional universalId = SecurityUtils.getUniversalIdFromContext();
+
+ if(!universalId.isPresent())
+ throw new MissingUniversalIdException(MISSING_UNIVERSAL_ID);
+
+ Optional identityProvider = SecurityUtils.getIdentityProvider();
+
+ if(!identityProvider.isPresent())
+ throw new MissingIdentityProviderException(MISSING_IDENTITY_PROVIDER);
+
+ try {
+
+ logger.debug("attempting to create a cso account");
+
+ AccountDetails accountDetails = accountService.createAccount(universalId.get(), identityProvider.get(),createAccountRequest);
+
+ logger.info("Account successfully created");
+
+ return new ResponseEntity<>(csoAccountMapper.toCsoAccount(accountDetails), HttpStatus.CREATED);
+
+ } catch (EfilingAccountServiceException e) {
+
+ logger.error("Exception while trying to create a CSO Account", e);
+ throw new CreateAccountException(CREATE_ACCOUNT_EXCEPTION);
+ }
+
+ }
+
+ @Override
+ @PreAuthorize("hasRole('efiling-user')")
+ public ResponseEntity getCsoAccount(UUID xTransactionId) {
+
+ Optional universalId = SecurityUtils.getUniversalIdFromContext();
+
+ if(!universalId.isPresent()) return new ResponseEntity(HttpStatus.FORBIDDEN);
+
+ AccountDetails accountDetails = accountService.getCsoAccountDetails(universalId.get());
+
+ if(accountDetails == null) return new ResponseEntity(HttpStatus.NOT_FOUND);
+
+ return ResponseEntity.ok(csoAccountMapper.toCsoAccount(accountDetails));
+
+ }
+
+
+ @Override
+ @PreAuthorize("hasRole('efiling-user')")
+ public ResponseEntity updateCsoAccount(UUID xTransactionId, CsoAccountUpdateRequest clientUpdateRequest) {
+
+ Optional universalId = SecurityUtils.getUniversalIdFromContext();
+
+ if(!universalId.isPresent())
+ throw new InvalidUniversalException(INVALID_UNIVERSAL_ID);
+
+ ResponseEntity response;
+
+ try {
+
+ AccountDetails accountDetails = accountService.getCsoAccountDetails(universalId.get());
+
+ if(accountDetails == null) {
+ throw new InvalidUniversalException(INVALID_UNIVERSAL_ID);
+ }
+
+ accountDetails.updateInternalClientNumber(clientUpdateRequest.getInternalClientNumber());
+
+ accountService.updateClient(accountDetails);
+
+ response = ResponseEntity.ok(csoAccountMapper.toCsoAccount(accountDetails));
+ } catch (EfilingAccountServiceException e) {
+ logger.warn(e.getMessage(), e);
+ throw new UpdateClientException(UPDATE_CLIENT_EXCEPTION);
+ }
+
+ return response;
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/mappers/BceidAccountMapper.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/mappers/BceidAccountMapper.java
new file mode 100644
index 0000000000..d3f9150566
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/mappers/BceidAccountMapper.java
@@ -0,0 +1,16 @@
+package ca.bc.gov.open.jag.efilingapi.account.mappers;
+
+import ca.bc.gov.open.bceid.starter.account.models.IndividualIdentity;
+import ca.bc.gov.open.jag.efilingapi.api.model.BceidAccount;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+
+@Mapper
+public interface BceidAccountMapper {
+
+ @Mapping(target = "firstName", source = "name.firstName")
+ @Mapping(target = "lastName", source = "name.surname")
+ @Mapping(target = "middleName", source = "name.middleName")
+ BceidAccount toBceidAccount(IndividualIdentity individualIdentity);
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/mappers/CreateAccountRequestMapper.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/mappers/CreateAccountRequestMapper.java
new file mode 100644
index 0000000000..426985d5b6
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/mappers/CreateAccountRequestMapper.java
@@ -0,0 +1,12 @@
+package ca.bc.gov.open.jag.efilingapi.account.mappers;
+
+import ca.bc.gov.open.jag.efilingapi.api.model.CreateCsoAccountRequest;
+import ca.bc.gov.open.jag.efilingcommons.model.CreateAccountRequest;
+import org.mapstruct.Mapper;
+
+@Mapper
+public interface CreateAccountRequestMapper {
+
+ CreateAccountRequest toCreateAccountRequest(String universalId, String identityProvider,CreateCsoAccountRequest createCsoAccountRequest);
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/mappers/CsoAccountMapper.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/mappers/CsoAccountMapper.java
new file mode 100644
index 0000000000..117fd8591c
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/mappers/CsoAccountMapper.java
@@ -0,0 +1,12 @@
+package ca.bc.gov.open.jag.efilingapi.account.mappers;
+
+import ca.bc.gov.open.jag.efilingapi.api.model.CsoAccount;
+import ca.bc.gov.open.jag.efilingcommons.model.AccountDetails;
+import org.mapstruct.Mapper;
+
+@Mapper
+public interface CsoAccountMapper {
+
+ CsoAccount toCsoAccount(AccountDetails accountDetails);
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/service/AccountService.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/service/AccountService.java
new file mode 100644
index 0000000000..78f0c5ff8d
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/service/AccountService.java
@@ -0,0 +1,14 @@
+package ca.bc.gov.open.jag.efilingapi.account.service;
+
+import ca.bc.gov.open.jag.efilingapi.api.model.CreateCsoAccountRequest;
+import ca.bc.gov.open.jag.efilingcommons.model.AccountDetails;
+
+public interface AccountService {
+
+ AccountDetails getCsoAccountDetails(String universalId);
+
+ void updateClient(AccountDetails accountDetails);
+
+ AccountDetails createAccount(String universalId, String identityProvider,CreateCsoAccountRequest createAccountRequest);
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/service/AccountServiceImpl.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/service/AccountServiceImpl.java
new file mode 100644
index 0000000000..9858dfa7c9
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/account/service/AccountServiceImpl.java
@@ -0,0 +1,36 @@
+package ca.bc.gov.open.jag.efilingapi.account.service;
+
+import ca.bc.gov.open.jag.efilingapi.account.mappers.CreateAccountRequestMapper;
+import ca.bc.gov.open.jag.efilingapi.api.model.CreateCsoAccountRequest;
+import ca.bc.gov.open.jag.efilingcommons.model.AccountDetails;
+import ca.bc.gov.open.jag.efilingcommons.service.EfilingAccountService;
+import org.springframework.cache.annotation.Cacheable;
+
+public class AccountServiceImpl implements AccountService {
+
+ private final EfilingAccountService efilingAccountService;
+ private final CreateAccountRequestMapper createAccountRequestMapper;
+
+ public AccountServiceImpl(EfilingAccountService efilingAccountService, CreateAccountRequestMapper createAccountRequestMapper) {
+ this.efilingAccountService = efilingAccountService;
+ this.createAccountRequestMapper = createAccountRequestMapper;
+ }
+
+ @Override
+ @Cacheable(cacheNames = "accountDetails", key = "#universalId", cacheManager = "accountDetailsCacheManager", unless = "#result == null || #result.getInternalClientNumber() == null")
+ public AccountDetails getCsoAccountDetails(String universalId) {
+ return efilingAccountService.getAccountDetails(universalId);
+ }
+
+ @Override
+ public void updateClient(AccountDetails accountDetails) {
+ efilingAccountService.updateClient(accountDetails);
+ }
+
+ @Override
+ @Cacheable(cacheNames = "accountDetails", key = "#universalId", cacheManager = "accountDetailsCacheManager", unless = "#result == null || #result.getInternalClientNumber() == null")
+ public AccountDetails createAccount(String universalId, String identityProvider, CreateCsoAccountRequest createAccountRequest) {
+ return efilingAccountService.createAccount(createAccountRequestMapper.toCreateAccountRequest(universalId, identityProvider, createAccountRequest));
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/cache/CacheConfiguration.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/cache/CacheConfiguration.java
index e0f3705d90..a93411ef59 100644
--- a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/cache/CacheConfiguration.java
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/cache/CacheConfiguration.java
@@ -2,6 +2,9 @@
import ca.bc.gov.open.jag.efilingapi.submission.models.Submission;
+import ca.bc.gov.open.jag.efilingcommons.model.AccountDetails;
+import ca.bc.gov.open.jag.efilingcommons.model.DocumentTypeDetails;
+import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -10,6 +13,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
@@ -20,6 +24,7 @@
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
+import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
@@ -89,7 +94,10 @@ private List createSentinels(RedisProperties.Sentinel sentinel) {
* @return
*/
@Bean(name = "submissionCacheManager")
- public CacheManager submissionCacheManager(JedisConnectionFactory jedisConnectionFactory, Jackson2JsonRedisSerializer jackson2JsonRedisSerializer) {
+ @Primary
+ public CacheManager submissionCacheManager(
+ JedisConnectionFactory jedisConnectionFactory,
+ @Qualifier("submissionSerializer") Jackson2JsonRedisSerializer jackson2JsonRedisSerializer) {
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
@@ -103,10 +111,83 @@ public CacheManager submissionCacheManager(JedisConnectionFactory jedisConnectio
.cacheDefaults(redisCacheConfiguration).build();
}
- @Bean
+ @Bean(name = "submissionSerializer")
+ @Primary
public Jackson2JsonRedisSerializer jackson2JsonRedisSerializer() {
return new Jackson2JsonRedisSerializer(Submission.class);
}
+ /**
+ * Configures the cache manager
+ * @param jedisConnectionFactory A jedisConnectionFactory
+ * @return
+ */
+ @Bean(name = "documentCacheManager")
+ public CacheManager documentCacheManager(
+ JedisConnectionFactory jedisConnectionFactory) {
+
+ RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
+ .disableCachingNullValues()
+ .entryTtl(Duration.ofHours(24));
+
+ redisCacheConfiguration.usePrefix();
+
+ return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(jedisConnectionFactory)
+ .cacheDefaults(redisCacheConfiguration).build();
+ }
+
+ /**
+ * Configures the cache manager
+ * @param jedisConnectionFactory A jedisConnectionFactory
+ * @return
+ */
+ @Bean(name = "documentTypeDetailsCacheManager")
+ public CacheManager documentTypeDetailsCacheManager(
+ JedisConnectionFactory jedisConnectionFactory,
+ @Qualifier("documentTypeDetailsSerializer") Jackson2JsonRedisSerializer documentTypeDetailsSerializer) {
+
+ RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
+ .disableCachingNullValues()
+ .entryTtl(Duration.ofHours(24))
+ .serializeValuesWith(RedisSerializationContext
+ .SerializationPair.fromSerializer(documentTypeDetailsSerializer));
+
+ redisCacheConfiguration.usePrefix();
+
+ return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(jedisConnectionFactory)
+ .cacheDefaults(redisCacheConfiguration).build();
+ }
+
+ @Bean(name = "documentTypeDetailsSerializer")
+ public Jackson2JsonRedisSerializer documentTypeDetailsSerializer() {
+ return new Jackson2JsonRedisSerializer(DocumentTypeDetails.class);
+ }
+
+ /**
+ * Configures the cache manager
+ * @param jedisConnectionFactory A jedisConnectionFactory
+ * @return
+ */
+ @Bean(name = "accountDetailsCacheManager")
+ public CacheManager accountDetailsCacheManager(
+ JedisConnectionFactory jedisConnectionFactory,
+ @Qualifier("accountDetailsSerializer") Jackson2JsonRedisSerializer accountDetailsSerializer) {
+
+ RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
+ .disableCachingNullValues()
+ .entryTtl(Duration.ofMinutes(15))
+ .serializeValuesWith(RedisSerializationContext
+ .SerializationPair.fromSerializer(accountDetailsSerializer));;
+
+ redisCacheConfiguration.usePrefix();
+
+ return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(jedisConnectionFactory)
+ .cacheDefaults(redisCacheConfiguration).build();
+ }
+
+ @Bean(name = "accountDetailsSerializer")
+ public Jackson2JsonRedisSerializer accountDetailsSerializer() {
+ return new Jackson2JsonRedisSerializer(AccountDetails.class);
+ }
}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/ApplicationConfiguration.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/ApplicationConfiguration.java
deleted file mode 100644
index 7e09f370d5..0000000000
--- a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/ApplicationConfiguration.java
+++ /dev/null
@@ -1,37 +0,0 @@
-package ca.bc.gov.open.jag.efilingapi.config;
-
-import io.opentracing.Tracer;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.CorsRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-
-/**
- * Global Application Configuration
- */
-@Configuration
-public class ApplicationConfiguration {
-
- /**
- * Configures CORS for enabling javascript applications to connect.
- */
- @Bean
- public WebMvcConfigurer corsConfigurer() {
- return new WebMvcConfigurer() {
- @Override
- public void addCorsMappings(CorsRegistry registry) {
- registry.addMapping("/**").allowedMethods("*").allowedOrigins("*");
- }
- };
- }
-
- /**
- * Configures Jeager tracer.
- */
- @Bean
- public Tracer jaegerTracer() {
- return new io.jaegertracing.Configuration("spring-boot")
- .getTracer();
- }
-
-}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/KeycloakJwtAuthConverter.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/KeycloakJwtAuthConverter.java
new file mode 100644
index 0000000000..516a7c25d8
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/KeycloakJwtAuthConverter.java
@@ -0,0 +1,79 @@
+package ca.bc.gov.open.jag.efilingapi.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.lang.NonNull;
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.oauth2.jwt.Jwt;
+import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
+import org.springframework.security.oauth2.server.resource.authentication.JwtGrantedAuthoritiesConverter;
+import org.springframework.stereotype.Component;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * A Converter implementation (specific to Keycloak) that can convert a Keycloak
+ * JWT into a AbstractAuthenticationToken that can be used by Spring Security.
+ */
+@Component
+public class KeycloakJwtAuthConverter implements Converter {
+
+ public static final String KEYCLOAK_PRINCIPLE_ATTRIBUTE = "preferred_username";
+ public static final String KEYCLOAK_RESOURCE_ATTRIBUTE = "resource_access";
+ public static final String KEYCLOAK_ROLE_ATTRIBUTE = "roles";
+
+ private String resourceId;
+
+ public KeycloakJwtAuthConverter(@Value("${jwt.auth.converter.resource-id}") String resourceId) {
+ this.resourceId = resourceId;
+ }
+
+ @Override
+ public AbstractAuthenticationToken convert(@NonNull Jwt jwt) {
+ JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+
+ Collection authorities = Stream
+ .concat(jwtGrantedAuthoritiesConverter.convert(jwt).stream(), extractResourceRoles(jwt).stream())
+ .collect(Collectors.toSet());
+
+ return new JwtAuthenticationToken(jwt, authorities, getPrincipleClaimName(jwt));
+ }
+
+ /**
+ * Extract the principle claim name (preferred_username) from the JWT.
+ */
+ public static String getPrincipleClaimName(Jwt jwt) {
+ return jwt.getClaim(KEYCLOAK_PRINCIPLE_ATTRIBUTE);
+ }
+
+ /**
+ * Extracts the resource roles from the JWT.
+ */
+ @SuppressWarnings("unchecked")
+ private Collection extends GrantedAuthority> extractResourceRoles(Jwt jwt) {
+ Map resourceAccess = jwt.getClaim(KEYCLOAK_RESOURCE_ATTRIBUTE);
+ if (resourceAccess == null) {
+ return Set.of();
+ }
+
+ Map resource = (Map) resourceAccess.get(resourceId);
+ if (resource == null) {
+ return Set.of();
+ }
+
+ Collection resourceRoles = (Collection) resource.get(KEYCLOAK_ROLE_ATTRIBUTE);
+ if (resourceRoles == null) {
+ return Set.of();
+ }
+
+ return resourceRoles.stream().map(role -> new SimpleGrantedAuthority("ROLE_" + role))
+ .collect(Collectors.toSet());
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/NavigationProperties.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/NavigationProperties.java
index ae90e32078..900f736527 100644
--- a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/NavigationProperties.java
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/NavigationProperties.java
@@ -9,6 +9,9 @@
public class NavigationProperties {
private String baseUrl;
+
+ private String csoBaseUrl;
+
/**
* Returns the base url to create a secure upload url
* @return
@@ -21,4 +24,11 @@ public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
+ public String getCsoBaseUrl() {
+ return csoBaseUrl;
+ }
+
+ public void setCsoBaseUrl(String csoBaseUrl) {
+ this.csoBaseUrl = csoBaseUrl;
+ }
}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/SecurityConfig.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/SecurityConfig.java
new file mode 100644
index 0000000000..feb582b875
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/config/SecurityConfig.java
@@ -0,0 +1,68 @@
+package ca.bc.gov.open.jag.efilingapi.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.session.SessionRegistryImpl;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy;
+import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.CorsConfigurationSource;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+
+import static org.springframework.security.web.util.matcher.AntPathRequestMatcher.antMatcher;
+
+@Configuration
+@EnableWebSecurity
+@EnableMethodSecurity
+class SecurityConfig {
+
+ private final KeycloakJwtAuthConverter keycloakJwtAuthConverter;
+
+ public SecurityConfig(KeycloakJwtAuthConverter keycloakJwtAuthConverter) {
+ this.keycloakJwtAuthConverter = keycloakJwtAuthConverter;
+ }
+
+ @Bean
+ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+
+ http.cors(cors -> cors.configurationSource(corsConfigurationSource()));
+
+ http.csrf(AbstractHttpConfigurer::disable);
+
+ http.authorizeHttpRequests(requests -> requests
+ .requestMatchers(antMatcher("/actuator/**")).permitAll()
+ .anyRequest().authenticated());
+
+ http.oauth2ResourceServer((oauth2) -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(keycloakJwtAuthConverter)));
+
+ http.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
+
+ return http.build();
+ }
+
+ protected CorsConfigurationSource corsConfigurationSource() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration corsConfiguration = new CorsConfiguration();
+ corsConfiguration.applyPermitDefaultValues();
+ corsConfiguration.addAllowedMethod(HttpMethod.GET);
+ corsConfiguration.addAllowedMethod(HttpMethod.POST);
+ corsConfiguration.addAllowedMethod(HttpMethod.PUT);
+ corsConfiguration.addAllowedMethod(HttpMethod.DELETE);
+ corsConfiguration.addAllowedMethod(HttpMethod.OPTIONS);
+ source.registerCorsConfiguration("/**", corsConfiguration);
+ return source;
+ }
+
+ @Bean
+ protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
+ return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/core/mdc/MdcFilter.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/core/mdc/MdcFilter.java
new file mode 100644
index 0000000000..91554bc8c9
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/core/mdc/MdcFilter.java
@@ -0,0 +1,89 @@
+package ca.bc.gov.open.jag.efilingapi.core.mdc;
+
+import ca.bc.gov.open.jag.efilingapi.Keys;
+import ca.bc.gov.open.jag.efilingapi.core.security.SecurityUtils;
+import jakarta.servlet.*;
+import jakarta.servlet.http.HttpServletRequest;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+/**
+ * The MdcFilter class sets the context for any http request handled by the efiling api
+ * It adds all the header (except authorization) and value of interest from the jwt token
+ */
+@Component
+public class MdcFilter implements Filter {
+
+ private Logger logger = LoggerFactory.getLogger(MdcFilter.class);
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
+
+ List mdcKeys = new ArrayList<>();
+
+ mdcKeys.addAll(setMDCHeaders((HttpServletRequest) servletRequest));
+
+ mdcKeys.addAll(setMDCToken());
+
+ filterChain.doFilter(servletRequest, servletResponse);
+
+ mdcKeys.stream().forEach(MDC::remove);
+
+ }
+
+ private List setMDCHeaders(HttpServletRequest httpRequest) {
+
+ List result = new ArrayList<>();
+
+ Enumeration headerNames = httpRequest.getHeaderNames();
+
+ if (headerNames == null) return result;
+
+ while (headerNames.hasMoreElements()) {
+
+ String header = headerNames.nextElement();
+
+ if (StringUtils.equalsIgnoreCase("authorization", header)) continue;
+
+ String mdcKey = MessageFormat.format("{0}.{1}", Keys.MDC_EFILING_REQUEST_HEADERS, header);
+ result.add(mdcKey);
+
+ logger.debug("{}:{}", mdcKey, httpRequest.getHeader(header));
+ MDC.put(mdcKey, httpRequest.getHeader(header));
+
+ }
+
+ return result;
+ }
+
+ private List setMDCToken() {
+
+ List result = new ArrayList<>();
+
+ SecurityUtils.getClientId().ifPresent(value -> result.add(setJwtValue("clientId", value)));
+ SecurityUtils.getUniversalIdFromContext().ifPresent(value -> result.add(setJwtValue("universalId", value)));
+ SecurityUtils.getApplicationCode().ifPresent(value -> result.add(setJwtValue("applicationCode", value)));
+ SecurityUtils.getIdentityProvider().ifPresent(value -> result.add(setJwtValue("identityProvider", value)));
+
+ return result;
+
+ }
+
+ private String setJwtValue( String key, String value) {
+ String mdcKey = MessageFormat.format("{0}.{1}", Keys.MDC_EFILING_JWT, key);
+ logger.debug("{}:{}", key, value);
+ MDC.put(mdcKey, value);
+ return mdcKey;
+ }
+
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/core/security/SecurityUtils.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/core/security/SecurityUtils.java
new file mode 100644
index 0000000000..d769fb246c
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/core/security/SecurityUtils.java
@@ -0,0 +1,60 @@
+package ca.bc.gov.open.jag.efilingapi.core.security;
+
+import ca.bc.gov.open.jag.efilingapi.Keys;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.oauth2.jwt.Jwt;
+
+import java.util.Optional;
+
+public class SecurityUtils {
+
+ private SecurityUtils() {
+ }
+
+ public static Optional getClientId() {
+ try {
+ Jwt jwt = (Jwt) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+
+ return Optional.of(jwt.getId());
+ } catch (Exception e) {
+ return Optional.empty();
+ }
+ }
+
+ public static Optional getUniversalIdFromContext() {
+ return getOtherClaim(Keys.UNIVERSAL_ID_CLAIM_KEY);
+ }
+
+ public static Optional getApplicationCode() {
+ return getOtherClaim(Keys.CSO_APPLICATION_CLAIM_KEY);
+ }
+
+ public static Optional getIdentityProvider() {
+ return getOtherClaim(Keys.IDENTITY_PROVIDER_CLAIM_KEY);
+ }
+
+ private static Optional getOtherClaim(String claim) {
+ try {
+ Jwt jwt = (Jwt) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
+ return Optional.of(jwt.getClaim(claim));
+ } catch (Exception e) {
+ return Optional.empty();
+ }
+ }
+
+ public static boolean isEarlyAdopter() {
+ return isInRole("ROLE_early-adopters");
+ }
+
+ public static boolean isInRole(String role) {
+ try {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+
+ return authentication.getAuthorities().stream()
+ .anyMatch(r -> r.getAuthority().equals(role));
+ } catch (Exception e) {
+ return false;
+ }
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/CourtConfig.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/CourtConfig.java
new file mode 100644
index 0000000000..7a36c64311
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/CourtConfig.java
@@ -0,0 +1,18 @@
+package ca.bc.gov.open.jag.efilingapi.court;
+
+import ca.bc.gov.open.jag.efilingapi.court.services.CourtService;
+import ca.bc.gov.open.jag.efilingapi.court.services.CourtServiceImpl;
+import ca.bc.gov.open.jag.efilingcommons.service.EfilingCourtService;
+import ca.bc.gov.open.jag.efilingcommons.service.EfilingSearchService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class CourtConfig {
+
+ @Bean
+ public CourtService courtService(EfilingCourtService efilingCourtService, EfilingSearchService efilingSearchService) {
+ return new CourtServiceImpl(efilingCourtService, efilingSearchService);
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/models/GetCourtDetailsRequest.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/models/GetCourtDetailsRequest.java
new file mode 100644
index 0000000000..85bb840b07
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/models/GetCourtDetailsRequest.java
@@ -0,0 +1,59 @@
+package ca.bc.gov.open.jag.efilingapi.court.models;
+
+public class GetCourtDetailsRequest {
+
+ private String courtLocation;
+ private String courtLevel;
+ private String courtClassification;
+
+ public String getCourtLocation() {
+ return courtLocation;
+ }
+
+ public String getCourtLevel() {
+ return courtLevel;
+ }
+
+ public String getCourtClassification() {
+ return courtClassification;
+ }
+
+ public GetCourtDetailsRequest(Builder builder) {
+ this.courtClassification = builder.courtClassification;
+ this.courtLevel = builder.courtLevel;
+ this.courtLocation = builder.courtLocation;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private String courtLocation;
+ private String courtClassification;
+ private String courtLevel;
+
+ public Builder courtLocation(String courtLocation) {
+ this.courtLocation = courtLocation;
+ return this;
+ }
+
+ public Builder courtClassification(String courtClassification) {
+ this.courtClassification = courtClassification;
+ return this;
+ }
+
+ public Builder courtLevel(String courtLevel) {
+ this.courtLevel = courtLevel;
+ return this;
+ }
+
+ public GetCourtDetailsRequest create() {
+ return new GetCourtDetailsRequest(this);
+ }
+
+ }
+
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/models/IsValidCourtFileNumberRequest.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/models/IsValidCourtFileNumberRequest.java
new file mode 100644
index 0000000000..8ae14af0c6
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/models/IsValidCourtFileNumberRequest.java
@@ -0,0 +1,84 @@
+package ca.bc.gov.open.jag.efilingapi.court.models;
+
+import java.math.BigDecimal;
+
+public class IsValidCourtFileNumberRequest {
+
+ private String fileNumber;
+ private BigDecimal courtId;
+ private String courtLevel;
+ private String courtClassification;
+ private String applicationCode;
+
+ public String getFileNumber() {
+ return fileNumber;
+ }
+
+ public BigDecimal getCourtId() {
+ return courtId;
+ }
+
+ public String getCourtLevel() {
+ return courtLevel;
+ }
+
+ public String getCourtClassification() {
+ return courtClassification;
+ }
+
+ public String getApplicationCode() {
+ return applicationCode;
+ }
+
+ public IsValidCourtFileNumberRequest(Builder builder) {
+ this.fileNumber = builder.fileNumber;
+ this.courtId = builder.courtId;
+ this.courtLevel = builder.courtLevel;
+ this.courtClassification = builder.courtClassification;
+ this.applicationCode = builder.applicationCode;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private String fileNumber;
+ private BigDecimal courtId;
+ private String courtLevel;
+ private String courtClassification;
+ private String applicationCode;
+
+ public Builder applicationCode(String applicationCode) {
+ this.applicationCode = applicationCode;
+ return this;
+ }
+
+ public Builder fileNumber(String fileNumber) {
+ this.fileNumber = fileNumber;
+ return this;
+ }
+
+ public Builder courtId(BigDecimal courtId) {
+ this.courtId = courtId;
+ return this;
+ }
+
+ public Builder courtLevel(String courtLevel) {
+ this.courtLevel = courtLevel;
+ return this;
+ }
+
+ public Builder courtClassification(String courtClassification) {
+ this.courtClassification = courtClassification;
+ return this;
+ }
+
+ public IsValidCourtFileNumberRequest create() {
+ return new IsValidCourtFileNumberRequest(this);
+ }
+
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/models/IsValidCourtRequest.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/models/IsValidCourtRequest.java
new file mode 100644
index 0000000000..8e26ba8fbd
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/models/IsValidCourtRequest.java
@@ -0,0 +1,72 @@
+package ca.bc.gov.open.jag.efilingapi.court.models;
+
+import java.math.BigDecimal;
+
+public class IsValidCourtRequest {
+
+ private BigDecimal courtId;
+ private String courtLevel;
+ private String courtClassification;
+ private String applicationCode;
+
+ public BigDecimal getCourtId() {
+ return courtId;
+ }
+
+ public String getCourtLevel() {
+ return courtLevel;
+ }
+
+ public String getCourtClassification() {
+ return courtClassification;
+ }
+
+ public String getApplicationCode() {
+ return applicationCode;
+ }
+
+ public IsValidCourtRequest(Builder builder) {
+ this.applicationCode = builder.applicationCode;
+ this.courtId = builder.courtId;
+ this.courtClassification = builder.courtClassification;
+ this.courtLevel = builder.courtLevel;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private BigDecimal courtId;
+ private String courtLevel;
+ private String courtClassification;
+ private String applicationCode;
+
+ public Builder courtId(BigDecimal courtId) {
+ this.courtId = courtId;
+ return this;
+ }
+
+ public Builder courtLevel(String courtLevel) {
+ this.courtLevel = courtLevel;
+ return this;
+ }
+
+ public Builder courtClassification(String courtClassification) {
+ this.courtClassification = courtClassification;
+ return this;
+ }
+
+ public Builder applicationCode(String applicationCode) {
+ this.applicationCode = applicationCode;
+ return this;
+ }
+
+ public IsValidCourtRequest create() {
+ return new IsValidCourtRequest(this);
+ }
+
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/services/CourtService.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/services/CourtService.java
new file mode 100644
index 0000000000..01f842f6d3
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/services/CourtService.java
@@ -0,0 +1,17 @@
+package ca.bc.gov.open.jag.efilingapi.court.services;
+
+import ca.bc.gov.open.jag.efilingapi.court.models.GetCourtDetailsRequest;
+import ca.bc.gov.open.jag.efilingapi.court.models.IsValidCourtFileNumberRequest;
+import ca.bc.gov.open.jag.efilingapi.court.models.IsValidCourtRequest;
+import ca.bc.gov.open.jag.efilingcommons.model.CourtDetails;
+
+import java.util.Optional;
+
+public interface CourtService {
+
+ boolean isValidCourt(IsValidCourtRequest isValidCourtRequest);
+
+ Optional getCourtDetails(GetCourtDetailsRequest getCourtDetailsRequest);
+
+ boolean isValidCourtFileNumber(IsValidCourtFileNumberRequest isValidCourtFileNumberRequest);
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/services/CourtServiceImpl.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/services/CourtServiceImpl.java
new file mode 100644
index 0000000000..6aaf3125d1
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/court/services/CourtServiceImpl.java
@@ -0,0 +1,61 @@
+package ca.bc.gov.open.jag.efilingapi.court.services;
+
+import ca.bc.gov.open.jag.efilingapi.court.models.GetCourtDetailsRequest;
+import ca.bc.gov.open.jag.efilingapi.court.models.IsValidCourtFileNumberRequest;
+import ca.bc.gov.open.jag.efilingapi.court.models.IsValidCourtRequest;
+import ca.bc.gov.open.jag.efilingcommons.model.CourtDetails;
+import ca.bc.gov.open.jag.efilingcommons.service.EfilingCourtService;
+import ca.bc.gov.open.jag.efilingcommons.service.EfilingSearchService;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.Optional;
+
+public class CourtServiceImpl implements CourtService {
+
+ private final EfilingCourtService efilingCourtService;
+ private final EfilingSearchService efilingSearchService;
+
+ public CourtServiceImpl(EfilingCourtService efilingCourtService, EfilingSearchService efilingSearchService) {
+ this.efilingCourtService = efilingCourtService;
+ this.efilingSearchService = efilingSearchService;
+ }
+
+ @Override
+ public boolean isValidCourt(IsValidCourtRequest isValidCourtRequest) {
+ return this.efilingCourtService.checkValidLevelClassLocation(
+ isValidCourtRequest.getCourtId(),
+ isValidCourtRequest.getCourtLevel(),
+ isValidCourtRequest.getCourtClassification(),
+ isValidCourtRequest.getApplicationCode()
+ );
+ }
+
+ @Override
+ public Optional getCourtDetails(GetCourtDetailsRequest getCourtDetailsRequest) {
+
+ return this.efilingCourtService.getCourtDescription(
+ getCourtDetailsRequest.getCourtLocation(),
+ getCourtDetailsRequest.getCourtLevel(),
+ getCourtDetailsRequest.getCourtClassification());
+
+ }
+
+ @Override
+ public boolean isValidCourtFileNumber(IsValidCourtFileNumberRequest isValidCourtFileNumberRequest){
+
+ if (StringUtils.equalsIgnoreCase("A", isValidCourtFileNumberRequest.getCourtLevel())) {
+ return this.efilingSearchService.caseNumberExists(isValidCourtFileNumberRequest.getFileNumber());
+ } else {
+ return efilingCourtService.checkValidCourtFileNumber(
+ isValidCourtFileNumberRequest.getFileNumber(),
+ isValidCourtFileNumberRequest.getCourtId(),
+ isValidCourtFileNumberRequest.getCourtLevel(),
+ isValidCourtFileNumberRequest.getCourtClassification(),
+ isValidCourtFileNumberRequest.getApplicationCode()
+ );
+ }
+
+
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/courts/CourtsApiDelegateImpl.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/courts/CourtsApiDelegateImpl.java
new file mode 100644
index 0000000000..d727008f0c
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/courts/CourtsApiDelegateImpl.java
@@ -0,0 +1,51 @@
+package ca.bc.gov.open.jag.efilingapi.courts;
+
+import ca.bc.gov.open.jag.efilingapi.api.CourtsApiDelegate;
+import ca.bc.gov.open.jag.efilingapi.api.model.CourtLocation;
+import ca.bc.gov.open.jag.efilingapi.api.model.CourtLocations;
+import ca.bc.gov.open.jag.efilingapi.courts.mappers.CourtLocationMapper;
+import ca.bc.gov.open.jag.efilingapi.error.CourtLocationException;
+import ca.bc.gov.open.jag.efilingcommons.court.EfilingCourtLocationService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+
+@Service
+public class CourtsApiDelegateImpl implements CourtsApiDelegate {
+
+ private static final String COURT_LOCATION_ERROR = "Error while retrieving court locations.";
+
+ Logger logger = LoggerFactory.getLogger(CourtsApiDelegateImpl.class);
+
+ private final EfilingCourtLocationService efilingCourtLocationService;
+
+ private final CourtLocationMapper courtLocationMapper;
+
+ public CourtsApiDelegateImpl(EfilingCourtLocationService efilingCourtLocationService, CourtLocationMapper courtLocationMapper) {
+ this.efilingCourtLocationService = efilingCourtLocationService;
+ this.courtLocationMapper = courtLocationMapper;
+ }
+
+ @Override
+ @PreAuthorize("hasRole('efiling-client') || hasRole('efiling-admin')")
+ public ResponseEntity getCourtLocations(String courtLevel) {
+
+ logger.info("Request for court level received {}", courtLevel);
+ List courtLocationsList = courtLocationMapper.toCourtLocationList(efilingCourtLocationService.getCourtLocations(courtLevel));
+ if (courtLocationsList == null)
+ throw new CourtLocationException(COURT_LOCATION_ERROR);
+
+ CourtLocations courtLocations = new CourtLocations();
+ courtLocations.setCourts(courtLocationsList);
+ return ResponseEntity.ok(courtLocations);
+
+ }
+
+
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/courts/CourtsConfiguration.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/courts/CourtsConfiguration.java
new file mode 100644
index 0000000000..9253775c3d
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/courts/CourtsConfiguration.java
@@ -0,0 +1,17 @@
+package ca.bc.gov.open.jag.efilingapi.courts;
+
+
+import ca.bc.gov.open.jag.efilingapi.courts.mappers.CourtLocationMapper;
+import ca.bc.gov.open.jag.efilingapi.courts.mappers.CourtLocationMapperImpl;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class CourtsConfiguration {
+
+ @Bean
+ public CourtLocationMapper courtLocationMapper() {
+ return new CourtLocationMapperImpl();
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/courts/mappers/CourtLocationMapper.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/courts/mappers/CourtLocationMapper.java
new file mode 100644
index 0000000000..9fa60c5472
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/courts/mappers/CourtLocationMapper.java
@@ -0,0 +1,13 @@
+package ca.bc.gov.open.jag.efilingapi.courts.mappers;
+
+import ca.bc.gov.open.jag.efilingapi.api.model.CourtLocation;
+import ca.bc.gov.open.jag.efilingcommons.model.InternalCourtLocation;
+import org.mapstruct.Mapper;
+
+import java.util.List;
+
+@Mapper
+public interface CourtLocationMapper {
+
+ List toCourtLocationList(List courtLocations);
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentApiDelegateImpl.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentApiDelegateImpl.java
new file mode 100644
index 0000000000..c429e0cc77
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentApiDelegateImpl.java
@@ -0,0 +1,51 @@
+package ca.bc.gov.open.jag.efilingapi.document;
+
+import ca.bc.gov.open.jag.efilingapi.Keys;
+import ca.bc.gov.open.jag.efilingapi.api.DocumentsApiDelegate;
+import ca.bc.gov.open.jag.efilingapi.api.model.CourtClassification;
+import ca.bc.gov.open.jag.efilingapi.api.model.CourtLevel;
+import ca.bc.gov.open.jag.efilingapi.api.model.DocumentType;
+import ca.bc.gov.open.jag.efilingapi.error.DocumentTypeException;
+import ca.bc.gov.open.jag.efilingcommons.exceptions.EfilingDocumentServiceException;
+import ca.bc.gov.open.jag.efilingcommons.model.DocumentTypeDetails;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Service;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Service
+public class DocumentApiDelegateImpl implements DocumentsApiDelegate {
+ Logger logger = LoggerFactory.getLogger(DocumentApiDelegateImpl.class);
+
+ private static final String DOCUMENT_TYPE_ERROR = "Error while retrieving documents";
+ private final DocumentStore documentStore;
+
+ public DocumentApiDelegateImpl(DocumentStore documentStore) {
+ this.documentStore = documentStore;
+ }
+
+ @Override
+ @PreAuthorize("hasRole('" + Keys.EFILING_USER_ROLE + "') || hasRole('"+ Keys.EFILING_CLIENT_ROLE +"')")
+ public ResponseEntity> getDocumentTypes(@NotNull @Valid CourtLevel courtLevel, @NotNull @Valid CourtClassification courtClassification) {
+ try {
+ return ResponseEntity.ok(documentStore.getDocumentTypes(courtLevel.getValue(), courtClassification.getValue()).stream()
+ .map(this::toDocumentType).collect(Collectors.toList()));
+ } catch (EfilingDocumentServiceException e) {
+ logger.warn(e.getMessage(), e);
+ throw new DocumentTypeException(DOCUMENT_TYPE_ERROR);
+ }
+ }
+
+ private DocumentType toDocumentType(DocumentTypeDetails documentTypeDetails) {
+ DocumentType outDocumentType = new DocumentType();
+ outDocumentType.setType(documentTypeDetails.getType());
+ outDocumentType.setDescription(documentTypeDetails.getDescription());
+ return outDocumentType;
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentConfiguration.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentConfiguration.java
new file mode 100644
index 0000000000..b95713e8ca
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentConfiguration.java
@@ -0,0 +1,20 @@
+package ca.bc.gov.open.jag.efilingapi.document;
+
+import ca.bc.gov.open.jag.efilingcommons.service.EfilingDocumentService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class DocumentConfiguration {
+
+ @Bean
+ public DocumentStore documentStore(EfilingDocumentService efilingDocumentService) {
+ return new DocumentStoreImpl(efilingDocumentService);
+ }
+
+ @Bean
+ public DocumentService documentService(EfilingDocumentService efilingDocumentService) {
+ return new DocumentServiceImpl(efilingDocumentService);
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentService.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentService.java
new file mode 100644
index 0000000000..31890cc76a
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentService.java
@@ -0,0 +1,17 @@
+package ca.bc.gov.open.jag.efilingapi.document;
+
+import ca.bc.gov.open.jag.efilingapi.document.models.GetValidDocumentTypesRequest;
+import ca.bc.gov.open.jag.efilingcommons.model.DocumentTypeDetails;
+
+import java.util.List;
+
+public interface DocumentService {
+
+ /**
+ * Returns a list of valid document types
+ * @param getValidDocumentTypesRequest
+ * @return
+ */
+ List getValidDocumentTypes(GetValidDocumentTypesRequest getValidDocumentTypesRequest);
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentServiceImpl.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentServiceImpl.java
new file mode 100644
index 0000000000..420deedbe7
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentServiceImpl.java
@@ -0,0 +1,22 @@
+package ca.bc.gov.open.jag.efilingapi.document;
+
+import ca.bc.gov.open.jag.efilingapi.document.models.GetValidDocumentTypesRequest;
+import ca.bc.gov.open.jag.efilingcommons.model.DocumentTypeDetails;
+import ca.bc.gov.open.jag.efilingcommons.service.EfilingDocumentService;
+
+import java.util.List;
+
+public class DocumentServiceImpl implements DocumentService {
+
+ private final EfilingDocumentService efilingDocumentService;
+
+ public DocumentServiceImpl(EfilingDocumentService efilingDocumentService) {
+ this.efilingDocumentService = efilingDocumentService;
+ }
+
+ @Override
+ public List getValidDocumentTypes(GetValidDocumentTypesRequest getValidDocumentTypesRequest) {
+ return efilingDocumentService.getDocumentTypes(getValidDocumentTypesRequest.getCourtLevel(), getValidDocumentTypesRequest.getCourtClassification());
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentStore.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentStore.java
new file mode 100644
index 0000000000..972c6302dd
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentStore.java
@@ -0,0 +1,26 @@
+package ca.bc.gov.open.jag.efilingapi.document;
+
+import ca.bc.gov.open.jag.efilingapi.submission.SubmissionKey;
+import ca.bc.gov.open.jag.efilingcommons.model.DocumentTypeDetails;
+
+import java.util.List;
+
+public interface DocumentStore {
+
+ byte[] put(SubmissionKey submissionKey, String fileName, byte[] content);
+
+ byte[] get(SubmissionKey submissionKey, String fileName);
+
+ void evict(SubmissionKey submissionKey, String fileName);
+
+ DocumentTypeDetails getDocumentDetails(String courtLevel, String courtClass, String documentType);
+
+ List getDocumentTypes(String courtLevel, String courtClass);
+
+ byte[] putRushDocument(SubmissionKey submissionKey, String fileName, byte[] content);
+
+ byte[] getRushDocument(SubmissionKey submissionKey, String fileName);
+
+ void evictRushDocument(SubmissionKey submissionKey, String fileName);
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentStoreImpl.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentStoreImpl.java
new file mode 100644
index 0000000000..de1ed81b96
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/DocumentStoreImpl.java
@@ -0,0 +1,68 @@
+package ca.bc.gov.open.jag.efilingapi.document;
+
+import ca.bc.gov.open.jag.efilingapi.submission.SubmissionKey;
+import ca.bc.gov.open.jag.efilingcommons.model.DocumentTypeDetails;
+import ca.bc.gov.open.jag.efilingcommons.service.EfilingDocumentService;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+
+import java.util.List;
+
+public class DocumentStoreImpl implements DocumentStore {
+
+ private final EfilingDocumentService efilingDocumentService;
+
+ public DocumentStoreImpl(EfilingDocumentService efilingDocumentService) {
+ this.efilingDocumentService = efilingDocumentService;
+ }
+
+ @Override
+ @CachePut(cacheNames = "document", key = "{ #submissionKey.universalId, #submissionKey.submissionId, #submissionKey.transactionId, #fileName }", cacheManager = "documentCacheManager")
+ public byte[] put(SubmissionKey submissionKey, String fileName, byte[] content) {
+ return content;
+ }
+
+ @Override
+ @Cacheable(cacheNames = "document", key = "{ #submissionKey.universalId, #submissionKey.submissionId, #submissionKey.transactionId, #fileName }", cacheManager = "documentCacheManager", unless = "#result == null")
+ public byte[] get(SubmissionKey submissionKey, String fileName) {
+ return null;
+ }
+
+ @Override
+ @CacheEvict(cacheNames = "document", key = "{ #submissionKey.universalId, #submissionKey.submissionId, #submissionKey.transactionId, #fileName }", cacheManager = "documentCacheManager")
+ public void evict(SubmissionKey submissionKey, String fileName) {
+ //This implements Redis delete no code required
+ }
+
+ @Override
+ @Cacheable(cacheNames = "documentDetails", cacheManager = "documentTypeDetailsCacheManager", unless = "#result == null")
+ public DocumentTypeDetails getDocumentDetails(String courtLevel, String courtClass, String documentType) {
+ return this.efilingDocumentService.getDocumentTypeDetails(courtLevel, courtClass, documentType);
+ }
+
+ @Override
+ public List getDocumentTypes(String courtLevel, String courtClass) {
+ return this.efilingDocumentService.getDocumentTypes(courtLevel, courtClass);
+ }
+
+ @Override
+ @CachePut(cacheNames = "rushDocument", key = "{ #submissionKey.universalId, #submissionKey.submissionId, #submissionKey.transactionId, #fileName }", cacheManager = "documentCacheManager")
+ public byte[] putRushDocument(SubmissionKey submissionKey, String fileName, byte[] content) {
+ return content;
+ }
+
+ @Override
+ @Cacheable(cacheNames = "rushDocument", key = "{ #submissionKey.universalId, #submissionKey.submissionId, #submissionKey.transactionId, #fileName }", cacheManager = "documentCacheManager", unless = "#result == null")
+ public byte[] getRushDocument(SubmissionKey submissionKey, String fileName) {
+ return null;
+ }
+
+ @Override
+ @CacheEvict(cacheNames = "rushDocument", key = "{ #submissionKey.universalId, #submissionKey.submissionId, #submissionKey.transactionId, #fileName }", cacheManager = "documentCacheManager")
+ public void evictRushDocument(SubmissionKey submissionKey, String fileName) {
+ //This implements Redis delete no code required
+ }
+
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/models/GetValidDocumentTypesRequest.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/models/GetValidDocumentTypesRequest.java
new file mode 100644
index 0000000000..9cd879cc06
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/document/models/GetValidDocumentTypesRequest.java
@@ -0,0 +1,45 @@
+package ca.bc.gov.open.jag.efilingapi.document.models;
+
+public class GetValidDocumentTypesRequest {
+ private String courtLevel;
+ private String courtClassification;
+
+ public String getCourtLevel() {
+ return courtLevel;
+ }
+
+ public String getCourtClassification() {
+ return courtClassification;
+ }
+
+ public GetValidDocumentTypesRequest(Builder builder) {
+ this.courtLevel = builder.courtLevel;
+ this.courtClassification = builder.courtClassification;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+
+ private String courtLevel;
+ private String courtClassification;
+
+ public Builder courtClassification(String courtClassification) {
+ this.courtClassification = courtClassification;
+ return this;
+ }
+
+ public Builder courtLevel(String courtLevel) {
+ this.courtLevel = courtLevel;
+ return this;
+ }
+
+ public GetValidDocumentTypesRequest create() {
+ return new GetValidDocumentTypesRequest(this);
+ }
+
+ }
+
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/AccountException.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/AccountException.java
new file mode 100644
index 0000000000..3c3c2a077d
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/AccountException.java
@@ -0,0 +1,9 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+public class AccountException extends EfilingException {
+ private static final long serialVersionUID = 1L;
+
+ public AccountException(String message) {
+ super(message, ErrorCode.ACCOUNTEXCEPTION);
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/CacheException.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/CacheException.java
new file mode 100644
index 0000000000..7ce7916b56
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/CacheException.java
@@ -0,0 +1,7 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+public class CacheException extends EfilingException {
+ public CacheException(String message) {
+ super(message, ErrorCode.CACHE_ERROR);
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/CourtLocationException.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/CourtLocationException.java
new file mode 100644
index 0000000000..dbd9d0d0b2
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/CourtLocationException.java
@@ -0,0 +1,7 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+public class CourtLocationException extends EfilingException {
+ public CourtLocationException(String message) {
+ super(message,ErrorCode.COURT_LOCATION_ERROR);
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/CreateAccountException.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/CreateAccountException.java
new file mode 100644
index 0000000000..d88986de4a
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/CreateAccountException.java
@@ -0,0 +1,7 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+public class CreateAccountException extends EfilingException {
+ public CreateAccountException(String message) {
+ super(message, ErrorCode.CREATE_ACCOUNT_EXCEPTION);
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DeleteDocumentException.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DeleteDocumentException.java
new file mode 100644
index 0000000000..cb6e74488c
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DeleteDocumentException.java
@@ -0,0 +1,18 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+
+import org.springframework.http.HttpStatus;
+
+public class DeleteDocumentException extends EfilingException {
+
+ private final HttpStatus httpStatus;
+
+ public DeleteDocumentException(String message, HttpStatus httpStatus) {
+ super(message, ErrorCode.DELETE_DOCUMENT_ERROR);
+ this.httpStatus = httpStatus;
+ }
+
+ public HttpStatus getHttpStatus() {
+ return httpStatus;
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DocumentRequiredException.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DocumentRequiredException.java
new file mode 100644
index 0000000000..aa45eb8dcd
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DocumentRequiredException.java
@@ -0,0 +1,8 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+public class DocumentRequiredException extends EfilingException {
+
+ public DocumentRequiredException(String message) {
+ super(message, ErrorCode.DOCUMENT_REQUIRED);
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DocumentStorageException.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DocumentStorageException.java
new file mode 100644
index 0000000000..16449c1aa6
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DocumentStorageException.java
@@ -0,0 +1,8 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+public class DocumentStorageException extends EfilingException {
+
+ public DocumentStorageException(String message) {
+ super(message, ErrorCode.DOCUMENT_STORAGE_FAILURE);
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DocumentTypeException.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DocumentTypeException.java
new file mode 100644
index 0000000000..23ac01a2e5
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/DocumentTypeException.java
@@ -0,0 +1,8 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+public class DocumentTypeException extends EfilingException {
+
+ public DocumentTypeException(String message) {
+ super(message, ErrorCode.DOCUMENT_TYPE_ERROR);
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/EfilingException.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/EfilingException.java
new file mode 100644
index 0000000000..87c431ce7d
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/EfilingException.java
@@ -0,0 +1,17 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+public class EfilingException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ private final ErrorCode errorCode;
+
+ public EfilingException(String message, ErrorCode errorCode) {
+ super(message);
+ this.errorCode = errorCode;
+ }
+
+ public String getErrorCode() {
+ return errorCode.name();
+ }
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/ErrorCode.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/ErrorCode.java
new file mode 100644
index 0000000000..f5cbf85252
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/ErrorCode.java
@@ -0,0 +1,25 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+public enum ErrorCode {
+ ACCOUNTEXCEPTION,
+ CACHE_ERROR,
+ CREATE_ACCOUNT_EXCEPTION,
+ COURT_LOCATION_ERROR,
+ DELETE_DOCUMENT_ERROR,
+ DOCUMENT_REQUIRED,
+ DOCUMENT_STORAGE_FAILURE,
+ DOCUMENT_TYPE_ERROR,
+ FILE_TYPE_ERROR,
+ FILING_PACKAGE_NOT_FOUND,
+ INVALIDROLE,
+ INVALIDUNIVERSAL,
+ INVALID_INITIAL_SUBMISSION_PAYLOAD,
+ MISSING_APPLICATION_CODE,
+ MISSING_UNIVERSAL_ID,
+ MISSING_REGISTRY_NOTICE,
+ MISSING_IDENTITY_PROVIDER,
+ PAYMENT_FAILURE,
+ SUBMISSION_FAILURE,
+ UPDATE_CLIENT_EXCEPTION,
+ URL_GENERATION_FAILURE
+}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/ErrorResponse.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/ErrorResponse.java
deleted file mode 100644
index 6de9285371..0000000000
--- a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/ErrorResponse.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package ca.bc.gov.open.jag.efilingapi.error;
-
-public enum ErrorResponse {
- INVALIDROLE("User does not have a valid role for this request."),
- ACCOUNTEXCEPTION("Client has multiple CSO profiles."),
- GETPROFILESEXCEPTION("Calling CSO accountFacade.getProfiles caused an exception."),
- CACHE_ERROR("Cache related error.");
-
- private final String errorMessage;
-
- ErrorResponse(String errorMessage) {
- this.errorMessage = errorMessage;
- }
-
- public String getErrorCode() {
- return this.toString();
- }
-
- public String getErrorMessage() { return errorMessage; }
-}
diff --git a/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/ExceptionControllerAdvisor.java b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/ExceptionControllerAdvisor.java
new file mode 100644
index 0000000000..9a337b4e36
--- /dev/null
+++ b/src/backend/efiling-api/src/main/java/ca/bc/gov/open/jag/efilingapi/error/ExceptionControllerAdvisor.java
@@ -0,0 +1,127 @@
+package ca.bc.gov.open.jag.efilingapi.error;
+
+import ca.bc.gov.open.jag.efilingapi.api.model.EfilingError;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+
+@ControllerAdvice
+public class ExceptionControllerAdvisor {
+
+ @ExceptionHandler(AccountException.class)
+ public ResponseEntity