diff --git a/.docker-home/.gitignore b/.docker-home/.gitignore deleted file mode 100644 index c96a04f008e..00000000000 --- a/.docker-home/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore \ No newline at end of file diff --git a/.docker/Dockerfile-alpine b/.docker/Dockerfile-alpine index d3309736b2f..075a1a75328 100644 --- a/.docker/Dockerfile-alpine +++ b/.docker/Dockerfile-alpine @@ -1,8 +1,9 @@ -FROM alpine:3.16 +FROM alpine:3.20 RUN addgroup -S ory; \ - adduser -S ory -G ory -D -H -s /bin/nologin -RUN apk --no-cache --upgrade --latest add ca-certificates + adduser -S ory -G ory -D -H -s /bin/nologin && \ + apk upgrade --no-cache && \ + apk add --no-cache --upgrade ca-certificates COPY hydra /usr/bin/hydra diff --git a/.docker/Dockerfile-build b/.docker/Dockerfile-build index addd0f7c335..18cc454fba9 100644 --- a/.docker/Dockerfile-build +++ b/.docker/Dockerfile-build @@ -1,46 +1,32 @@ -FROM golang:1.19-alpine3.16 AS builder - -RUN apk -U --no-cache --upgrade --latest add build-base git gcc bash +FROM golang:1.22 AS builder WORKDIR /go/src/github.com/ory/hydra -RUN mkdir -p ./internal/httpclient + +RUN apt-get update && apt-get upgrade -y &&\ + mkdir -p /var/lib/sqlite &&\ + mkdir -p ./internal/httpclient COPY go.mod go.sum ./ -COPY internal/httpclient/go.* ./internal/httpclient +COPY internal/httpclient/go.* ./internal/httpclient/ -ENV GO111MODULE on -ENV CGO_ENABLED 1 +ENV CGO_ENABLED=1 RUN go mod download COPY . . +RUN go build -ldflags="-extldflags=-static" -tags sqlite,sqlite_omit_load_extension -o /usr/bin/hydra -RUN go build -tags sqlite,json1 -o /usr/bin/hydra +######################### -FROM alpine:3.15 - -RUN addgroup -S ory; \ - adduser -S ory -G ory -D -h /home/ory -s /bin/nologin; \ - chown -R ory:ory /home/ory +FROM gcr.io/distroless/static-debian12:nonroot AS runner +COPY --from=builder --chown=nonroot:nonroot /var/lib/sqlite /var/lib/sqlite COPY --from=builder /usr/bin/hydra /usr/bin/hydra -# By creating the sqlite folder as the ory user, the mounted volume will be owned by ory:ory, which -# is required for read/write of SQLite. -RUN mkdir -p /var/lib/sqlite && \ - chown ory:ory /var/lib/sqlite - VOLUME /var/lib/sqlite -# Exposing the ory home directory -VOLUME /home/ory - # Declare the standard ports used by hydra (4444 for public service endpoint, 4445 for admin service endpoint) EXPOSE 4444 4445 -USER ory - ENTRYPOINT ["hydra"] -CMD ["serve"] - - +CMD ["serve", "all"] diff --git a/.docker/Dockerfile-distroless-static b/.docker/Dockerfile-distroless-static new file mode 100644 index 00000000000..054c9c79758 --- /dev/null +++ b/.docker/Dockerfile-distroless-static @@ -0,0 +1,8 @@ +FROM gcr.io/distroless/static-debian12:nonroot + +COPY hydra /usr/bin/hydra +# Declare the standard ports used by hydra (4444 for public service endpoint, 4445 for admin service endpoint) +EXPOSE 4444 4445 + +ENTRYPOINT ["hydra"] +CMD ["serve", "all"] diff --git a/.docker/Dockerfile-hsm b/.docker/Dockerfile-hsm index fd20986fe1d..39cd1b1ad99 100644 --- a/.docker/Dockerfile-hsm +++ b/.docker/Dockerfile-hsm @@ -1,9 +1,10 @@ -FROM golang:1.19-alpine3.16 AS builder - -RUN apk -U --no-cache --upgrade --latest add build-base git gcc bash +FROM golang:1.22 AS builder WORKDIR /go/src/github.com/ory/hydra -RUN mkdir -p ./internal/httpclient + +RUN apt-get update && apt-get upgrade -y &&\ + mkdir -p /var/lib/sqlite &&\ + mkdir -p ./internal/httpclient COPY go.mod go.sum ./ COPY internal/httpclient/go.* ./internal/httpclient @@ -12,11 +13,14 @@ ENV GO111MODULE on ENV CGO_ENABLED 1 RUN go mod download - COPY . . +############################### + FROM builder as build-hydra -RUN go build -tags sqlite,json1,hsm -o /usr/bin/hydra +RUN go build -tags sqlite,hsm -o /usr/bin/hydra + +############################### FROM builder as test-hsm ENV HSM_ENABLED=true @@ -24,14 +28,21 @@ ENV HSM_LIBRARY=/usr/lib/softhsm/libsofthsm2.so ENV HSM_TOKEN_LABEL=hydra ENV HSM_PIN=1234 -RUN apk --no-cache --upgrade --latest add softhsm opensc; \ - pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot 0 --init-token --so-pin 0000 --init-pin --pin 1234 --label hydra; \ +RUN apt-get -y install softhsm opensc &&\ + pkcs11-tool --module "$HSM_LIBRARY" --slot 0 --init-token --so-pin 0000 --init-pin --pin "$HSM_PIN" --label "$HSM_TOKEN_LABEL" &&\ go test -p 1 -v -failfast -short -tags=sqlite,hsm ./... -FROM alpine:3.15 +############################### + +FROM gcr.io/distroless/base-nossl-debian12:debug-nonroot AS runner + +ENV HSM_ENABLED=true +ENV HSM_LIBRARY=/usr/lib/softhsm/libsofthsm2.so +ENV HSM_TOKEN_LABEL=hydra +ENV HSM_PIN=1234 -RUN apk --no-cache --upgrade --latest add softhsm opensc; \ - pkcs11-tool --module /usr/lib/softhsm/libsofthsm2.so --slot 0 --init-token --so-pin 0000 --init-pin --pin 1234 --label hydra +RUN apt-get -y install softhsm opensc &&\ + pkcs11-tool --module "$HSM_LIBRARY" --slot 0 --init-token --so-pin 0000 --init-pin --pin "$HSM_PIN" --label "$HSM_TOKEN_LABEL" RUN addgroup -S ory; \ adduser -S ory -G ory -D -h /home/ory -s /bin/nologin; \ diff --git a/.docker/Dockerfile-scratch b/.docker/Dockerfile-scratch index d3e510436a3..f262b7c6338 100644 --- a/.docker/Dockerfile-scratch +++ b/.docker/Dockerfile-scratch @@ -1,6 +1,7 @@ -FROM alpine:3.16 +FROM alpine:3.20 -RUN apk --no-cache --upgrade --latest add ca-certificates +RUN apk upgrade --no-cache && \ + apk add --no-cache --upgrade ca-certificates # set up nsswitch.conf for Go's "netgo" implementation # - https://github.com/golang/go/blob/go1.9.1/src/net/conf.go#L194-L275 diff --git a/.docker/Dockerfile-sqlite b/.docker/Dockerfile-sqlite index 83fd6a23215..a6813a197e5 100644 --- a/.docker/Dockerfile-sqlite +++ b/.docker/Dockerfile-sqlite @@ -1,4 +1,4 @@ -FROM alpine:3.16 +FROM alpine:3.20 # Because this image is built for SQLite, we create /home/ory and /home/ory/sqlite which is owned by the ory user # and declare /home/ory/sqlite a volume. @@ -10,7 +10,8 @@ FROM alpine:3.16 RUN addgroup -S ory; \ adduser -S ory -G ory -D -h /home/ory -s /bin/nologin; \ chown -R ory:ory /home/ory && \ - apk --no-cache --upgrade --latest add ca-certificates sqlite + apk upgrade --no-cache && \ + apk add --no-cache --upgrade --latest ca-certificates sqlite WORKDIR /home/ory diff --git a/.dockerignore b/.dockerignore index 4d913fbbc91..cf7558fc017 100644 --- a/.dockerignore +++ b/.dockerignore @@ -3,7 +3,6 @@ docs node_modules .circleci -.docker-home .github scripts sdk/js diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a65fa85549a..6bfed0c7ad5 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,3 +1,3 @@ -* @aeneasr +* @aeneasr @hperl @alnr /docs/ @ory/documenters diff --git a/.github/ISSUE_TEMPLATE/BUG-REPORT.yml b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml index 569061946b9..2f1841bc958 100644 --- a/.github/ISSUE_TEMPLATE/BUG-REPORT.yml +++ b/.github/ISSUE_TEMPLATE/BUG-REPORT.yml @@ -24,15 +24,21 @@ body: "I have read and am following this repository's [Contribution Guidelines](https://github.com/ory/hydra/blob/master/CONTRIBUTING.md)." required: true - - label: - "This issue affects my [Ory Network](https://www.ory.sh/) project." - label: "I have joined the [Ory Community Slack](https://slack.ory.sh)." - label: "I am signed up to the [Ory Security Patch - Newsletter](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53)." + Newsletter](https://www.ory.sh/l/sign-up-newsletter)." id: checklist type: checkboxes + - attributes: + description: + "Enter the slug or API URL of the affected Ory Network project. Leave + empty when you are self-hosting." + label: "Ory Network Project" + placeholder: "https://.projects.oryapis.com" + id: ory-network-project + type: input - attributes: description: "A clear and concise description of what the bug is." label: "Describe the bug" diff --git a/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml b/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml index 7712e775ef3..d4f478c7abd 100644 --- a/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml +++ b/.github/ISSUE_TEMPLATE/DESIGN-DOC.yml @@ -35,15 +35,21 @@ body: "I have read and am following this repository's [Contribution Guidelines](https://github.com/ory/hydra/blob/master/CONTRIBUTING.md)." required: true - - label: - "This issue affects my [Ory Network](https://www.ory.sh/) project." - label: "I have joined the [Ory Community Slack](https://slack.ory.sh)." - label: "I am signed up to the [Ory Security Patch - Newsletter](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53)." + Newsletter](https://www.ory.sh/l/sign-up-newsletter)." id: checklist type: checkboxes + - attributes: + description: + "Enter the slug or API URL of the affected Ory Network project. Leave + empty when you are self-hosting." + label: "Ory Network Project" + placeholder: "https://.projects.oryapis.com" + id: ory-network-project + type: input - attributes: description: | This section gives the reader a very rough overview of the landscape in which the new system is being built and what is actually being built. This isn’t a requirements doc. Keep it succinct! The goal is that readers are brought up to speed but some previous knowledge can be assumed and detailed info can be linked to. This section should be entirely focused on objective background facts. diff --git a/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml index 4053a53db82..4dc8b73daab 100644 --- a/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml +++ b/.github/ISSUE_TEMPLATE/FEATURE-REQUEST.yml @@ -28,15 +28,21 @@ body: "I have read and am following this repository's [Contribution Guidelines](https://github.com/ory/hydra/blob/master/CONTRIBUTING.md)." required: true - - label: - "This issue affects my [Ory Network](https://www.ory.sh/) project." - label: "I have joined the [Ory Community Slack](https://slack.ory.sh)." - label: "I am signed up to the [Ory Security Patch - Newsletter](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53)." + Newsletter](https://www.ory.sh/l/sign-up-newsletter)." id: checklist type: checkboxes + - attributes: + description: + "Enter the slug or API URL of the affected Ory Network project. Leave + empty when you are self-hosting." + label: "Ory Network Project" + placeholder: "https://.projects.oryapis.com" + id: ory-network-project + type: input - attributes: description: "Is your feature request related to a problem? Please describe." diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 498ed2510c8..fd87edb8c50 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,9 +23,9 @@ jobs: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. fetch-depth: 2 - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: - go-version: "1.19" + go-version: "1.22" - name: Start service run: ./test/conformance/start.sh - name: Run tests @@ -49,7 +49,7 @@ jobs: - sdk-generate services: postgres: - image: postgres:11.8 + image: postgres:16 env: POSTGRES_DB: postgres POSTGRES_PASSWORD: test @@ -57,7 +57,7 @@ jobs: ports: - 5432:5432 mysql: - image: mysql:8.0.26 + image: mysql:8.0 env: MYSQL_ROOT_PASSWORD: test ports: @@ -69,7 +69,7 @@ jobs: steps: - run: | docker create --name cockroach -p 26257:26257 \ - cockroachdb/cockroach:v22.1.10 start-single-node --insecure + cockroachdb/cockroach:latest-v24.1 start-single-node --insecure docker start cockroach name: Start CockroachDB - uses: ory/ci/checkout@master @@ -80,25 +80,26 @@ jobs: path: | internal/httpclient key: ${{ needs.sdk-generate.outputs.sdk-cache-key }} - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v4 with: - go-version: "1.19" + go-version: "1.22" - run: go list -json > go.list - name: Run nancy uses: sonatype-nexus-community/nancy-github-action@v1.0.2 + with: + nancyVersion: v1.0.42 - name: Run golangci-lint - uses: golangci/golangci-lint-action@v2 + uses: golangci/golangci-lint-action@v3 env: GOGC: 100 with: args: --timeout 10m0s - version: v1.47.3 - skip-go-installation: true + version: v1.61.0 skip-pkg-cache: true - name: Run go-acc (tests) run: | make .bin/go-acc - .bin/go-acc -o coverage.out ./... -- -failfast -timeout=20m -tags sqlite,json1 + .bin/go-acc -o coverage.out ./... -- -failfast -timeout=20m -tags sqlite,sqlite_omit_load_extension - name: Submit to Codecov run: | bash <(curl -s https://codecov.io/bash) @@ -122,9 +123,9 @@ jobs: path: | internal/httpclient key: ${{ needs.sdk-generate.outputs.sdk-cache-key }} - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: - go-version: "1.19" + go-version: "1.22" - name: Setup HSM libs and packages run: | sudo apt install -y softhsm opensc @@ -149,7 +150,7 @@ jobs: args: ["", "--jwt"] services: postgres: - image: postgres:11.8 + image: postgres:16 env: POSTGRES_DB: postgres POSTGRES_PASSWORD: test @@ -157,7 +158,7 @@ jobs: ports: - 5432:5432 mysql: - image: mysql:8.0.26 + image: mysql:8.0 env: MYSQL_ROOT_PASSWORD: test ports: @@ -169,13 +170,13 @@ jobs: steps: - run: | docker create --name cockroach -p 26257:26257 \ - cockroachdb/cockroach:v22.1.10 start-single-node --insecure + cockroachdb/cockroach:latest-v24.1 start-single-node --insecure docker start cockroach name: Start CockroachDB - uses: ory/ci/checkout@master - - uses: actions/setup-go@v2 + - uses: actions/setup-go@v3 with: - go-version: "1.19" + go-version: "1.22" - uses: actions/cache@v2 with: path: ./test/e2e/hydra @@ -254,7 +255,7 @@ jobs: steps: - uses: ory/ci/releaser/render-version-schema@master with: - schema-path: spec/config.json + schema-path: .schema/config.schema.json token: ${{ secrets.ORY_BOT_PAT }} newsletter-draft: diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index f4b6dd2b4d3..d0d8aa176c3 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -41,9 +41,14 @@ jobs: - run: git checkout HEAD^2 if: ${{ github.event_name == 'pull_request' }} + - uses: actions/setup-go@v4 + with: + go-version: "1.22" + - run: go version + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -54,7 +59,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v1 + uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl @@ -68,4 +73,4 @@ jobs: # make release - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/cve-scan.yaml b/.github/workflows/cve-scan.yaml index be50bee5ca5..6611006dc79 100644 --- a/.github/workflows/cve-scan.yaml +++ b/.github/workflows/cve-scan.yaml @@ -14,51 +14,80 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Env id: vars shell: bash run: | - echo "##[set-output name=branch;]$(echo ${GITHUB_REF#refs/heads/})" - echo "::set-output name=sha_short::$(git rev-parse --short HEAD)" + echo "SHA_SHORT=$(git rev-parse --short HEAD)" >> "${GITHUB_ENV}" - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 - name: Build images shell: bash run: | - touch hydra - DOCKER_BUILDKIT=1 docker build -f .docker/Dockerfile-alpine --build-arg=COMMIT=${{ steps.vars.outputs.sha_short }} -t oryd/hydra:${{ steps.vars.outputs.sha_short }} . - rm hydra + IMAGE_TAG="${{ env.SHA_SHORT }}" make docker - name: Anchore Scanner uses: anchore/scan-action@v3 id: grype-scan with: - image: oryd/hydra:${{ steps.vars.outputs.sha_short }} + image: oryd/hydra:${{ env.SHA_SHORT }}-sqlite fail-build: true severity-cutoff: high - debug: false - acs-report-enable: true + add-cpes-if-none: true + - name: Inspect action SARIF report + shell: bash + if: ${{ always() }} + run: | + echo "::group::Anchore Scan Details" + jq '.runs[0].results' ${{ steps.grype-scan.outputs.sarif }} + echo "::endgroup::" - name: Anchore upload scan SARIF report if: always() - uses: github/codeql-action/upload-sarif@v1 + uses: github/codeql-action/upload-sarif@v2 with: sarif_file: ${{ steps.grype-scan.outputs.sarif }} + - name: Kubescape scanner + uses: kubescape/github-action@main + id: kubescape + with: + image: oryd/hydra:${{ env.SHA_SHORT }}-sqlite + verbose: true + format: pretty-printer + # can't whitelist CVE yet: https://github.com/kubescape/kubescape/pull/1568 + severityThreshold: critical - name: Trivy Scanner uses: aquasecurity/trivy-action@master if: ${{ always() }} with: - image-ref: oryd/hydra:${{ steps.vars.outputs.sha_short }} + image-ref: oryd/hydra:${{ env.SHA_SHORT }}-sqlite format: "table" exit-code: "42" ignore-unfixed: true vuln-type: "os,library" severity: "CRITICAL,HIGH" + scanners: "vuln,secret,config" - name: Dockle Linter - uses: erzz/dockle-action@v1.3.1 + uses: erzz/dockle-action@v1.3.2 if: ${{ always() }} with: - image: oryd/hydra:${{ steps.vars.outputs.sha_short }} + image: oryd/hydra:${{ env.SHA_SHORT }}-sqlite exit-code: 42 - failure-threshold: fatal + failure-threshold: high + - name: Hadolint + uses: hadolint/hadolint-action@v3.1.0 + id: hadolint + if: ${{ always() }} + with: + dockerfile: .docker/Dockerfile-build + verbose: true + format: "json" + failure-threshold: "error" + - name: View Hadolint results + if: ${{ always() }} + shell: bash + run: | + echo "::group::Hadolint Scan Details" + echo "${HADOLINT_RESULTS}" | jq '.' + echo "::endgroup::" diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index a7a720ebc0a..87e1655bce8 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: 1.19 + go-version: "1.22" - run: make format - name: Indicate formatting issues run: git diff HEAD --exit-code --color diff --git a/.github/workflows/licenses.yml b/.github/workflows/licenses.yml index a4592c63ced..b07391389ce 100644 --- a/.github/workflows/licenses.yml +++ b/.github/workflows/licenses.yml @@ -11,10 +11,10 @@ jobs: check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v2 + - uses: actions/checkout@v3 + - uses: actions/setup-go@v3 with: - go-version: "1.18" + go-version: "1.22" - uses: actions/setup-node@v2 with: node-version: "18" diff --git a/.github/workflows/pm.yml b/.github/workflows/pm.yml new file mode 100644 index 00000000000..0c69d71b706 --- /dev/null +++ b/.github/workflows/pm.yml @@ -0,0 +1,29 @@ +name: Synchronize with product board + +on: + issues: + types: + - opened + pull_request: + types: + - opened + - ready_for_review + +jobs: + automate: + if: github.event.pull_request.head.repo.fork == false + name: Add issue to project + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: ory-corp/planning-automation-action@v0.1 + with: + organization: ory-corp + project: 5 + token: ${{ secrets.ORY_BOT_PAT }} + todoLabel: "Needs Triage" + statusName: Status + statusValue: "Needs Triage" + includeEffort: "false" + monthlyMilestoneName: Roadmap Monthly + quarterlyMilestoneName: Roadmap diff --git a/.gitignore b/.gitignore index cd6f8d1e4a7..9e2972ee8bd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .bin/ .idea/ +.vscode/ node_modules/ *.iml *.exe @@ -24,8 +25,10 @@ LICENSE.txt hydra-login-consent-node ./cypress/screenshots *-packr.go +consent/csrf_flagka.go packrd/ persistence/sql/migrations/schema.sql cypress/videos cypress/screenshots BENCHMARKS.md +*.sqlite diff --git a/.golangci.yml b/.golangci.yml index c3461c51f45..2dff48664e4 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -5,16 +5,12 @@ linters: - gosimple - bodyclose - staticcheck - # Disabled due to Go 1.19 changes and Go-Swagger incompatibility - # https://github.com/ory/hydra/issues/3227 - # - goimports + - goimports disable: - ineffassign - - deadcode - unused - - structcheck -run: - skip-files: +issues: + exclude-files: - ".+_test.go" - ".+_test_.+.go" diff --git a/.goreleaser.yml b/.goreleaser.yml index a2320feef2b..8be207b170b 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -5,9 +5,9 @@ includes: variables: brew_name: hydra brew_description: "The Ory OAuth2 and OpenID Connect Platform (Ory Hydra)" - buildinfo_hash: "github.com/ory/hydra/driver/config.Commit" - buildinfo_tag: "github.com/ory/hydra/driver/config.Version" - buildinfo_date: "github.com/ory/hydra/driver/config.Date" - dockerfile: ".docker/Dockerfile-alpine" - + buildinfo_hash: "github.com/ory/hydra/v2/driver/config.Commit" + buildinfo_tag: "github.com/ory/hydra/v2/driver/config.Version" + buildinfo_date: "github.com/ory/hydra/v2/driver/config.Date" + dockerfile_alpine: ".docker/Dockerfile-alpine" + dockerfile_static: ".docker/Dockerfile-distroless-static" project_name: hydra diff --git a/.grype.yml b/.grype.yml new file mode 100644 index 00000000000..56d262246ac --- /dev/null +++ b/.grype.yml @@ -0,0 +1,2 @@ +ignore: + - vulnerability: CVE-2023-2650 diff --git a/.orycli.yml b/.orycli.yml index 6d41798dba8..d59f9b0599d 100644 --- a/.orycli.yml +++ b/.orycli.yml @@ -1 +1,4 @@ project: hydra + +pre_release_hooks: + - ./script/render-schemas.sh diff --git a/.schema/config.schema.json b/.schema/config.schema.json new file mode 100644 index 00000000000..bc1d1476c08 --- /dev/null +++ b/.schema/config.schema.json @@ -0,0 +1,1230 @@ +{ + "$id": "https://github.com/ory/hydra/spec/config.json", + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Ory Hydra Configuration", + "type": "object", + "definitions": { + "http_method": { + "type": "string", + "enum": [ + "POST", + "GET", + "PUT", + "PATCH", + "DELETE", + "CONNECT", + "HEAD", + "OPTIONS", + "TRACE" + ] + }, + "portNumber": { + "description": "The port to listen on.", + "minimum": 1, + "maximum": 65535 + }, + "socket": { + "type": "object", + "additionalProperties": false, + "description": "Sets the permissions of the unix socket", + "properties": { + "owner": { + "type": "string", + "description": "Owner of unix socket. If empty, the owner will be the user running hydra.", + "default": "" + }, + "group": { + "type": "string", + "description": "Group of unix socket. If empty, the group will be the primary group of the user running hydra.", + "default": "" + }, + "mode": { + "type": "integer", + "description": "Mode of unix socket in numeric form, base 10.", + "default": 493, + "minimum": 0, + "maximum": 511 + } + } + }, + "cors": { + "type": "object", + "additionalProperties": false, + "description": "Configures Cross Origin Resource Sharing for public endpoints.", + "properties": { + "enabled": { + "type": "boolean", + "description": "Sets whether CORS is enabled.", + "default": false + }, + "allowed_origins": { + "type": "array", + "description": "A list of origins a cross-domain request can be executed from. If the special * value is present in the list, all origins will be allowed. An origin may contain a wildcard (*) to replace 0 or more characters (i.e.: http://*.domain.com). Only one wildcard can be used per origin.", + "items": { + "type": "string", + "minLength": 1, + "not": { + "type": "string", + "description": "does match all strings that contain two or more (*)", + "pattern": ".*\\*.*\\*.*" + }, + "anyOf": [ + { + "format": "uri" + }, + { + "const": "*" + } + ] + }, + "uniqueItems": true, + "default": [], + "examples": [ + [ + "*", + "https://example.com", + "https://*.example.com", + "https://*.foo.example.com" + ] + ] + }, + "allowed_methods": { + "type": "array", + "description": "A list of HTTP methods the user agent is allowed to use with cross-domain requests.", + "default": [ + "POST", + "GET", + "PUT", + "PATCH", + "DELETE", + "CONNECT", + "HEAD", + "OPTIONS", + "TRACE" + ], + "items": { + "type": "string", + "enum": [ + "POST", + "GET", + "PUT", + "PATCH", + "DELETE", + "CONNECT", + "HEAD", + "OPTIONS", + "TRACE" + ] + } + }, + "allowed_headers": { + "type": "array", + "description": "A list of non simple headers the client is allowed to use with cross-domain requests.", + "default": [ + "Accept", + "Content-Type", + "Content-Length", + "Accept-Language", + "Content-Language", + "Authorization" + ], + "items": { + "type": "string" + } + }, + "exposed_headers": { + "type": "array", + "description": "Sets which headers are safe to expose to the API of a CORS API specification.", + "default": [ + "Cache-Control", + "Expires", + "Last-Modified", + "Pragma", + "Content-Length", + "Content-Language", + "Content-Type" + ], + "items": { + "type": "string" + } + }, + "allow_credentials": { + "type": "boolean", + "description": "Sets whether the request can include user credentials like cookies, HTTP authentication or client side SSL certificates.", + "default": true + }, + "max_age": { + "type": "integer", + "description": "Sets how long (in seconds) the results of a preflight request can be cached. If set to 0, every request is preceded by a preflight request.", + "default": 0, + "minimum": 0 + }, + "debug": { + "type": "boolean", + "description": "Adds additional log output to debug server side CORS issues.", + "default": false + } + } + }, + "cidr": { + "description": "CIDR address range.", + "type": "string", + "oneOf": [ + { + "pattern": "^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8])$" + }, + { + "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}/([0-9]|[1-2][0-9]|3[0-2])$" + } + ], + "examples": ["127.0.0.1/32"] + }, + "pem_file": { + "type": "object", + "oneOf": [ + { + "properties": { + "path": { + "type": "string", + "description": "The path to the pem file.", + "examples": ["/path/to/file.pem"] + } + }, + "additionalProperties": false, + "required": ["path"] + }, + { + "properties": { + "base64": { + "type": "string", + "description": "The base64 encoded string (without padding).", + "contentEncoding": "base64", + "contentMediaType": "application/x-pem-file", + "examples": ["b3J5IGh5ZHJhIGlzIGF3ZXNvbWUK"] + } + }, + "additionalProperties": false, + "required": ["base64"] + } + ] + }, + "duration": { + "type": "string", + "pattern": "^(\\d+(ns|us|ms|s|m|h))+$", + "examples": [ + "1h", + "1h5m1s" + ] + }, + "tls_config": { + "type": "object", + "description": "Configures HTTPS (HTTP over TLS). If configured, the server automatically supports HTTP/2.", + "properties": { + "enabled": { + "type": "boolean", + "description": "Setting enabled to false drops the TLS requirement for the admin endpoint, even if TLS is enabled on the public endpoint." + }, + "key": { + "description": "Configures the private key (pem encoded).", + "allOf": [ + { + "$ref": "#/definitions/pem_file" + } + ] + }, + "cert": { + "description": "Configures the public certificate (pem encoded).", + "allOf": [ + { + "$ref": "#/definitions/pem_file" + } + ] + }, + "allow_termination_from": { + "type": "array", + "description": "Whitelist one or multiple CIDR address ranges and allow them to terminate TLS connections. Be aware that the X-Forwarded-Proto header must be set and must never be modifiable by anyone but your proxy / gateway / load balancer. Supports ipv4 and ipv6. Hydra serves http instead of https when this option is set.", + "items": { + "$ref": "#/definitions/cidr" + } + } + } + }, + "webhook_config": { + "type": "object", + "additionalProperties": false, + "description": "Configures a webhook.", + "required": ["url"], + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The URL to send the webhook to." + }, + "auth": { + "type": "object", + "additionalProperties": false, + "required": ["type", "config"], + "properties": { + "type": { + "const": "api_key" + }, + "config": { + "type": "object", + "additionalProperties": false, + "required": ["name", "value"], + "properties": { + "in": { + "enum": ["header", "cookie"] + }, + "name": { + "description": "The header or cookie name.", + "type": "string" + }, + "value": { + "description": "The header or cookie value.", + "type": "string" + } + } + } + } + } + } + } + }, + "properties": { + "db": { + "type": "object", + "additionalProperties": false, + "description": "Configures the database connection", + "properties": { + "ignore_unknown_table_columns": { + "type": "boolean", + "description": "Ignore scan errors when columns in the SQL result have no fields in the destination struct", + "default": false + } + } + }, + "log": { + "type": "object", + "additionalProperties": false, + "description": "Configures the logger", + "properties": { + "level": { + "type": "string", + "description": "Sets the log level.", + "enum": ["panic", "fatal", "error", "warn", "info", "debug", "trace"], + "default": "info" + }, + "leak_sensitive_values": { + "type": "boolean", + "description": "Logs sensitive values such as cookie and URL parameter.", + "default": false + }, + "redaction_text": { + "type": "string", + "title": "Sensitive log value redaction text", + "description": "Text to use, when redacting sensitive log value." + }, + "format": { + "type": "string", + "description": "Sets the log format.", + "enum": ["json", "json_pretty", "text"], + "default": "text" + } + } + }, + "serve": { + "type": "object", + "additionalProperties": false, + "description": "Controls the configuration for the http(s) daemon(s).", + "properties": { + "public": { + "type": "object", + "additionalProperties": false, + "description": "Controls the public daemon serving public API endpoints like /oauth2/auth, /oauth2/token, /.well-known/jwks.json", + "properties": { + "port": { + "default": 4444, + "type": "integer", + "allOf": [ + { + "$ref": "#/definitions/portNumber" + } + ] + }, + "host": { + "type": "string", + "description": "The interface or unix socket Ory Hydra should listen and handle public API requests on. Use the prefix `unix:` to specify a path to a unix socket. Leave empty to listen on all interfaces.", + "default": "", + "examples": ["localhost"] + }, + "cors": { + "$ref": "#/definitions/cors" + }, + "socket": { + "$ref": "#/definitions/socket" + }, + "request_log": { + "type": "object", + "additionalProperties": false, + "description": "Access Log configuration for public server.", + "properties": { + "disable_for_health": { + "type": "boolean", + "description": "Disable access log for health endpoints.", + "default": false + } + } + }, + "tls": { + "$ref": "#/definitions/tls_config" + } + } + }, + "admin": { + "type": "object", + "additionalProperties": false, + "properties": { + "port": { + "default": 4445, + "type": "integer", + "allOf": [ + { + "$ref": "#/definitions/portNumber" + } + ] + }, + "host": { + "type": "string", + "description": "The interface or unix socket Ory Hydra should listen and handle administrative API requests on. Use the prefix `unix:` to specify a path to a unix socket. Leave empty to listen on all interfaces.", + "default": "", + "examples": ["localhost"] + }, + "cors": { + "$ref": "#/definitions/cors" + }, + "socket": { + "$ref": "#/definitions/socket" + }, + "request_log": { + "type": "object", + "additionalProperties": false, + "description": "Access Log configuration for admin server.", + "properties": { + "disable_for_health": { + "type": "boolean", + "description": "Disable access log for health endpoints.", + "default": false + } + } + }, + "tls": { + "allOf": [ + { + "$ref": "#/definitions/tls_config" + } + ] + } + } + }, + "tls": { + "$ref": "#/definitions/tls_config" + }, + "cookies": { + "type": "object", + "additionalProperties": false, + "properties": { + "same_site_mode": { + "type": "string", + "description": "Specify the SameSite mode that cookies should be sent with.", + "enum": ["Strict", "Lax", "None"], + "default": "None" + }, + "same_site_legacy_workaround": { + "type": "boolean", + "description": "Some older browser versions don’t work with SameSite=None. This option enables the workaround defined in https://web.dev/samesite-cookie-recipes/ which essentially stores a second cookie without SameSite as a fallback.", + "default": false, + "examples": [ + true + ] + }, + "domain": { + "title": "HTTP Cookie Domain", + "description": "Sets the cookie domain for session and CSRF cookies. Useful when dealing with subdomains. Use with care!", + "type": "string" + }, + "secure": { + "title": "HTTP Cookie Secure Flag in Development Mode", + "description": "Sets the HTTP Cookie secure flag in development mode. HTTP Cookies always have the secure flag in production mode.", + "type": "boolean", + "default": false + }, + "names": { + "title": "Cookie Names", + "description": "Sets the session cookie name. Use with care!", + "type": "object", + "properties": { + "login_csrf": { + "type": "string", + "title": "CSRF Cookie Name", + "default": "ory_hydra_login_csrf" + }, + "consent_csrf": { + "type": "string", + "title": "CSRF Cookie Name", + "default": "ory_hydra_consent_csrf" + }, + "session": { + "type": "string", + "title": "Session Cookie Name", + "default": "ory_hydra_session" + } + } + }, + "paths": { + "title": "Cookie Paths", + "description": "Sets the path for which session cookie is scoped. Use with care!", + "type": "object", + "properties": { + "session": { + "type": "string", + "title": "Session Cookie Path", + "default": "/" + } + } + } + } + } + } + }, + "dsn": { + "type": "string", + "description": "Sets the data source name. This configures the backend where Ory Hydra persists data. If dsn is `memory`, data will be written to memory and is lost when you restart this instance. Ory Hydra supports popular SQL databases. For more detailed configuration information go to: https://www.ory.sh/docs/hydra/dependencies-environment#sql" + }, + "clients": { + "title": "Global outgoing network settings", + "description": "Configure how outgoing network calls behave.", + "type": "object", + "additionalProperties": false, + "properties": { + "http": { + "title": "Global HTTP client configuration", + "description": "Configure how outgoing HTTP calls behave.", + "type": "object", + "additionalProperties": false, + "properties": { + "disallow_private_ip_ranges": { + "title": "Disallow private IP ranges", + "description": "Disallow all outgoing HTTP calls to private IP ranges. This feature can help protect against SSRF attacks.", + "type": "boolean", + "default": false + }, + "private_ip_exception_urls": { + "title": "Add exempt URLs to private IP ranges", + "description": "Allows the given URLs to be called despite them being in the private IP range. URLs need to have an exact and case-sensitive match to be excempt.", + "type": "array", + "items": { + "type": "string", + "format": "uri-reference" + }, + "default": [] + } + } + } + } + }, + "hsm": { + "type": "object", + "additionalProperties": false, + "description": "Configures Hardware Security Module.", + "properties": { + "enabled": { + "type": "boolean" + }, + "library": { + "type": "string", + "description": "Full path (including file extension) of the HSM vendor PKCS#11 library" + }, + "pin": { + "type": "string", + "description": "PIN code for token operations" + }, + "slot": { + "type": "integer", + "description": "Slot ID of the token to use (if label is not specified)" + }, + "token_label": { + "type": "string", + "description": "Label of the token to use (if slot is not specified). If both slot and label are set, token label takes preference over slot. In this case first slot, that contains this label is used." + }, + "key_set_prefix": { + "type": "string", + "description": "Key set prefix can be used in case of multiple Ory Hydra instances need to store keys on the same HSM partition. For example if `hsm.key_set_prefix=app1.` then key set `hydra.openid.id-token` would be generated/requested/deleted on HSM with `CKA_LABEL=app1.hydra.openid.id-token`.", + "default": "" + } + } + }, + "webfinger": { + "type": "object", + "additionalProperties": false, + "description": "Configures ./well-known/ settings.", + "properties": { + "jwks": { + "type": "object", + "additionalProperties": false, + "description": "Configures the /.well-known/jwks.json endpoint.", + "properties": { + "broadcast_keys": { + "type": "array", + "description": "A list of JSON Web Keys that should be exposed at that endpoint. This is usually the public key for verifying OpenID Connect ID Tokens. However, you might want to add additional keys here as well.", + "items": { + "type": "string" + }, + "default": ["hydra.openid.id-token"], + "examples": ["hydra.jwt.access-token"] + } + } + }, + "oidc_discovery": { + "type": "object", + "additionalProperties": false, + "description": "Configures OpenID Connect Discovery (/.well-known/openid-configuration).", + "properties": { + "jwks_url": { + "type": "string", + "description": "Overwrites the JWKS URL", + "format": "uri-reference", + "examples": [ + "https://my-service.com/.well-known/jwks.json" + ] + }, + "token_url": { + "type": "string", + "description": "Overwrites the OAuth2 Token URL", + "format": "uri-reference", + "examples": [ + "https://my-service.com/oauth2/token" + ] + }, + "auth_url": { + "type": "string", + "description": "Overwrites the OAuth2 Auth URL", + "format": "uri-reference", + "examples": [ + "https://my-service.com/oauth2/auth" + ] + }, + "client_registration_url": { + "description": "Sets the OpenID Connect Dynamic Client Registration Endpoint", + "type": "string", + "format": "uri-reference", + "examples": [ + "https://my-service.com/clients" + ] + }, + "supported_claims": { + "type": "array", + "description": "A list of supported claims to be broadcasted. Claim `sub` is always included.", + "items": { + "type": "string" + }, + "examples": [["email", "username"]] + }, + "supported_scope": { + "type": "array", + "description": "The scope OAuth 2.0 Clients may request. Scope `offline`, `offline_access`, and `openid` are always included.", + "items": { + "type": "string" + }, + "examples": [["email", "whatever", "read.photos"]] + }, + "userinfo_url": { + "type": "string", + "description": "A URL of the userinfo endpoint to be advertised at the OpenID Connect Discovery endpoint /.well-known/openid-configuration. Defaults to Ory Hydra's userinfo endpoint at /userinfo. Set this value if you want to handle this endpoint yourself.", + "format": "uri-reference", + "examples": [ + "https://example.org/my-custom-userinfo-endpoint" + ] + } + } + } + } + }, + "oidc": { + "type": "object", + "additionalProperties": false, + "description": "Configures OpenID Connect features.", + "properties": { + "subject_identifiers": { + "type": "object", + "additionalProperties": false, + "description": "Configures the Subject Identifier algorithm. For more information please head over to the documentation: https://www.ory.sh/docs/hydra/advanced#subject-identifier-algorithms", + "properties": { + "supported_types": { + "type": "array", + "description": "A list of algorithms to enable.", + "default": ["public"], + "items": { + "type": "string", + "enum": ["public", "pairwise"] + } + }, + "pairwise": { + "type": "object", + "additionalProperties": false, + "description": "Configures the pairwise algorithm.", + "properties": { + "salt": { + "type": "string" + } + }, + "required": ["salt"] + } + }, + "anyOf": [ + { + "if": { + "properties": { + "supported_types": { + "contains": { + "const": "pairwise" + } + } + } + }, + "then": { + "required": [ + "pairwise" + ] + } + }, + { + "not": { + "required": ["supported_types"] + } + } + ], + "examples": [ + { + "supported_types": ["public", "pairwise"], + "pairwise": { + "salt": "some-random-salt" + } + } + ] + }, + "dynamic_client_registration": { + "type": "object", + "additionalProperties": false, + "description": "Configures OpenID Connect Dynamic Client Registration (exposed as admin endpoints /clients/...).", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable dynamic client registration.", + "default": false + }, + "default_scope": { + "type": "array", + "description": "The OpenID Connect Dynamic Client Registration specification has no concept of whitelisting OAuth 2.0 Scope. If you want to expose Dynamic Client Registration, you should set the default scope enabled for newly registered clients. Keep in mind that users can overwrite this default by setting the `scope` key in the registration payload, effectively disabling the concept of whitelisted scopes.", + "items": { + "type": "string" + }, + "examples": [["openid", "offline", "offline_access"]] + } + } + } + } + }, + "urls": { + "type": "object", + "additionalProperties": false, + "properties": { + "self": { + "type": "object", + "additionalProperties": false, + "properties": { + "issuer": { + "type": "string", + "description": "This value will be used as the `issuer` in access and ID tokens. It must be specified and using HTTPS protocol, unless --dev is set. This should typically be equal to the public value.", + "format": "uri", + "examples": ["https://localhost:4444/"] + }, + "public": { + "type": "string", + "description": "This is the base location of the public endpoints of your Ory Hydra installation. This should typically be equal to the issuer value. If left unspecified, it falls back to the issuer value.", + "format": "uri", + "examples": [ + "https://localhost:4444/" + ] + }, + "admin": { + "type": "string", + "description": "This is the base location of the admin endpoints of your Ory Hydra installation.", + "format": "uri", + "examples": [ + "https://localhost:4445/" + ] + } + } + }, + "login": { + "type": "string", + "description": "Sets the OAuth2 Login Endpoint URL of the OAuth2 User Login & Consent flow. Defaults to an internal fallback URL showing an error.", + "format": "uri-reference", + "examples": [ + "https://my-login.app/login", + "/ui/login" + ] + }, + "registration": { + "type": "string", + "description": "Sets the OAuth2 Registration Endpoint URL of the OAuth2 User Login & Consent flow. Defaults to the same value as `login`. The registration URL is used if the authorization request was started with the `prompt=registration` parameter.", + "format": "uri-reference", + "examples": [ + "https://my-login.app/registration", + "/ui/registration" + ] + }, + "consent": { + "type": "string", + "description": "Sets the consent endpoint of the User Login & Consent flow. Defaults to an internal fallback URL showing an error.", + "format": "uri-reference", + "examples": [ + "https://my-consent.app/consent", + "/ui/consent" + ] + }, + "logout": { + "type": "string", + "description": "Sets the logout endpoint. Defaults to an internal fallback URL showing an error.", + "format": "uri-reference", + "examples": [ + "https://my-logout.app/logout", + "/ui/logout" + ] + }, + "error": { + "type": "string", + "description": "Sets the error endpoint. The error ui will be shown when an OAuth2 error occurs that which can not be sent back to the client. Defaults to an internal fallback URL showing an error.", + "format": "uri-reference", + "examples": [ + "https://my-error.app/error", + "/ui/error" + ] + }, + "post_logout_redirect": { + "type": "string", + "description": "When a user agent requests to logout, it will be redirected to this url afterwards per default.", + "format": "uri-reference", + "examples": [ + "https://my-example.app/logout-successful", + "/ui" + ] + }, + "identity_provider": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "title": "The admin URL of the ORY Kratos instance.", + "description": "If set, ORY Hydra will use this URL to log out the user in addition to removing the Hydra session.", + "type": "string", + "format": "uri", + "examples": [ + "https://kratos.example.com/admin" + ] + }, + "publicUrl": { + "title": "The public URL of the ORY Kratos instance.", + "type": "string", + "format": "uri", + "examples": [ + "https://kratos.example.com/public" + ] + }, + "headers": { + "title": "HTTP Request Headers", + "description": "These headers will be passed in HTTP requests to the Identity Provider.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "Authorization": "Bearer some-token" + } + ] + } + } + } + } + }, + "strategies": { + "type": "object", + "additionalProperties": false, + "properties": { + "scope": { + "type": "string", + "description": "Defines how scopes are matched. For more details have a look at https://github.com/ory/fosite#scopes", + "enum": [ + "exact", + "wildcard" + ], + "default": "wildcard" + }, + "access_token": { + "type": "string", + "description": "Defines access token type. jwt is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens", + "enum": ["opaque", "jwt"], + "default": "opaque" + }, + "jwt": { + "type": "object", + "additionalProperties": false, + "properties": { + "scope_claim": { + "type": "string", + "description": "Defines how the scope claim is represented within a JWT access token", + "enum": ["list", "string", "both"], + "default": "list" + } + } + } + } + }, + "ttl": { + "type": "object", + "additionalProperties": false, + "description": "Configures time to live.", + "properties": { + "login_consent_request": { + "description": "Configures how long a user login and consent flow may take.", + "default": "30m", + "allOf": [ + { + "$ref": "#/definitions/duration" + } + ] + }, + "access_token": { + "description": "Configures how long access tokens are valid.", + "default": "1h", + "allOf": [ + { + "$ref": "#/definitions/duration" + } + ] + }, + "refresh_token": { + "description": "Configures how long refresh tokens are valid. Set to -1 for refresh tokens to never expire.", + "default": "720h", + "oneOf": [ + { + "$ref": "#/definitions/duration" + }, + { + "enum": [ + "-1", + -1 + ] + } + ] + }, + "id_token": { + "description": "Configures how long id tokens are valid.", + "default": "1h", + "allOf": [ + { + "$ref": "#/definitions/duration" + } + ] + }, + "auth_code": { + "description": "Configures how long auth codes are valid.", + "default": "10m", + "allOf": [ + { + "$ref": "#/definitions/duration" + } + ] + } + } + }, + "oauth2": { + "type": "object", + "additionalProperties": false, + "properties": { + "expose_internal_errors": { + "type": "boolean", + "description": "Set this to true if you want to share error debugging information with your OAuth 2.0 clients. Keep in mind that debug information is very valuable when dealing with errors, but might also expose database error codes and similar errors.", + "default": false, + "examples": [true] + }, + "session": { + "type": "object", + "properties": { + "encrypt_at_rest": { + "type": "boolean", + "default": true, + "title": "Encrypt OAuth2 Session", + "description": "If set to true (default) Ory Hydra encrypt OAuth2 and OpenID Connect session data using AES-GCM and the system secret before persisting it in the database." + } + } + }, + "exclude_not_before_claim": { + "type": "boolean", + "description": "Set to true if you want to exclude claim `nbf (not before)` part of access token.", + "default": false, + "examples": [true] + }, + "allowed_top_level_claims": { + "type": "array", + "description": "A list of custom claims which are allowed to be added top level to the Access Token. They cannot override reserved claims.", + "items": { + "type": "string" + }, + "examples": [["username", "email", "user_uuid"]] + }, + "mirror_top_level_claims": { + "type": "boolean", + "description": "Set to false if you don't want to mirror custom claims under 'ext'", + "default": true, + "examples": [false] + }, + "hashers": { + "type": "object", + "additionalProperties": false, + "description": "Configures hashing algorithms. Supports only BCrypt and PBKDF2 at the moment.", + "properties": { + "algorithm": { + "title": "Password hashing algorithm", + "description": "One of the values: pbkdf2, bcrypt.\n\nWarning! This value can not be changed once set as all existing OAuth 2.0 Clients will not be able to sign in any more.", + "type": "string", + "default": "pbkdf2", + "enum": [ + "pbkdf2", + "bcrypt" + ] + }, + "bcrypt": { + "type": "object", + "additionalProperties": false, + "description": "Configures the BCrypt hashing algorithm used for hashing OAuth 2.0 Client Secrets.", + "properties": { + "cost": { + "type": "integer", + "description": "Sets the BCrypt cost. The higher the value, the more CPU time is being used to generate hashes.", + "default": 10, + "minimum": 4, + "maximum": 31 + } + } + }, + "pbkdf2": { + "type": "object", + "additionalProperties": false, + "description": "Configures the PBKDF2 hashing algorithm used for hashing OAuth 2.0 Client Secrets.", + "properties": { + "iterations": { + "type": "integer", + "description": "Sets the PBKDF2 iterations. The higher the value, the more CPU time is being used to generate hashes.", + "default": 25000, + "minimum": 1 + } + } + } + } + }, + "pkce": { + "type": "object", + "additionalProperties": false, + "properties": { + "enforced": { + "type": "boolean", + "description": "Sets whether PKCE should be enforced for all clients.", + "examples": [true] + }, + "enforced_for_public_clients": { + "type": "boolean", + "description": "Sets whether PKCE should be enforced for public clients.", + "examples": [true] + } + } + }, + "client_credentials": { + "type": "object", + "additionalProperties": false, + "properties": { + "default_grant_allowed_scope": { + "type": "boolean", + "description": "Automatically grant authorized OAuth2 Scope in OAuth2 Client Credentials Flow. Each OAuth2 Client is allowed to request a predefined OAuth2 Scope (for example `read write`). If this option is enabled, the full\nscope is automatically granted when performing the OAuth2 Client Credentials flow.\n\nIf disabled, the OAuth2 Client has to request the scope in the OAuth2 request by providing the `scope` query parameter. Setting this option to true is common if you need compatibility with MITREid.", + "examples": [ + false + ] + } + } + }, + "grant": { + "type": "object", + "additionalProperties": false, + "properties": { + "jwt": { + "type": "object", + "additionalProperties": false, + "description": "Authorization Grants using JWT configuration", + "properties": { + "jti_optional": { + "type": "boolean", + "description": "Configures if the JSON Web Token ID (`jti`) claim is required in the JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants (RFC7523). If set to `false`, the `jti` claim is required. Set this value to `true` only after careful consideration.", + "default": false + }, + "iat_optional": { + "type": "boolean", + "description": "Configures if the issued at (`iat`) claim is required in the JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants (RFC7523). If set to `false`, the `iat` claim is required. Set this value to `true` only after careful consideration.", + "default": false + }, + "max_ttl": { + "description": "Configures what the maximum age of a JWT assertion used in the JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants (RFC7523) can be. This feature uses the `exp` claim and `iat` claim to calculate assertion age. Assertions exceeding the max age will be denied. Useful as a safety measure and recommended to keep below 720h. This governs the `grant.jwt.max_ttl` setting.", + "default": "720h", + "allOf": [ + { + "$ref": "#/definitions/duration" + } + ] + } + } + } + } + }, + "refresh_token_hook": { + "description": "Sets the refresh token hook endpoint. If set it will be called during token refresh to receive updated token claims.", + "examples": ["https://my-example.app/token-refresh-hook"], + "oneOf": [ + { + "type": "string", + "format": "uri" + }, + { + "$ref": "#/definitions/webhook_config" + } + ] + }, + "token_hook": { + "description": "Sets the token hook endpoint for all grant types. If set it will be called while providing token to customize claims.", + "examples": ["https://my-example.app/token-hook"], + "oneOf": [ + { + "type": "string", + "format": "uri" + }, + { + "$ref": "#/definitions/webhook_config" + } + ] + } + } + }, + "secrets": { + "type": "object", + "additionalProperties": false, + "description": "The secrets section configures secrets used for encryption and signing of several systems. All secrets can be rotated, for more information on this topic go to: https://www.ory.sh/docs/hydra/advanced#rotation-of-hmac-token-signing-and-database-and-cookie-encryption-keys", + "properties": { + "system": { + "description": "The system secret must be at least 16 characters long. If none is provided, one will be generated. They key is used to encrypt sensitive data using AES-GCM (256 bit) and validate HMAC signatures. The first item in the list is used for signing and encryption. The whole list is used for verifying signatures and decryption.", + "type": "array", + "items": { + "type": "string", + "minLength": 16 + }, + "examples": [ + [ + "this-is-the-primary-secret", + "this-is-an-old-secret", + "this-is-another-old-secret" + ] + ] + }, + "cookie": { + "type": "array", + "description": "A secret that is used to encrypt cookie sessions. Defaults to secrets.system. It is recommended to use a separate secret in production. The first item in the list is used for signing and encryption. The whole list is used for verifying signatures and decryption.", + "items": { + "type": "string", + "minLength": 16 + }, + "examples": [ + [ + "this-is-the-primary-secret", + "this-is-an-old-secret", + "this-is-another-old-secret" + ] + ] + } + } + }, + "profiling": { + "type": "string", + "description": "Enables profiling if set. For more details on profiling, head over to: https://blog.golang.org/profiling-go-programs", + "enum": ["cpu", "mem"], + "examples": ["cpu"] + }, + "tracing": { + "$ref": "https://raw.githubusercontent.com/ory/x/v0.0.612/otelx/config.schema.json" + }, + "sqa": { + "type": "object", + "additionalProperties": true, + "description": "Software Quality Assurance telemetry configuration section", + "properties": { + "opt_out": { + "type": "boolean", + "description": "Disables anonymized telemetry reports - for more information please visit https://www.ory.sh/docs/ecosystem/sqa", + "default": false, + "examples": [true] + } + }, + "examples": [ + { + "opt_out": true + } + ] + }, + "version": { + "type": "string", + "title": "The Hydra version this config is written for.", + "description": "SemVer according to https://semver.org/ prefixed with `v` as in our releases.", + "pattern": "^v(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" + }, + "cgroups": { + "type": "object", + "additionalProperties": false, + "description": "Ory Hydra can respect Linux container CPU quota", + "properties": { + "v1": { + "type": "object", + "additionalProperties": false, + "description": "Configures parameters using cgroups v1 hierarchy", + "properties": { + "auto_max_procs_enabled": { + "type": "boolean", + "description": "Set GOMAXPROCS automatically according to cgroups limits", + "default": false, + "examples": [true] + } + } + } + } + }, + "dev": { + "type": "boolean", + "title": "Enable development mode", + "description": "If true, disables critical security measures to allow easier local development. Do not use in production.", + "default": false + }, + "feature_flags": { + "title": "Feature flags", + "type": "object", + "additionalProperties": true + } + }, + "additionalProperties": false +} diff --git a/.schema/version.schema.json b/.schema/version.schema.json index 3fd14b35bd1..2ae286e1957 100644 --- a/.schema/version.schema.json +++ b/.schema/version.schema.json @@ -1,7 +1,126 @@ { - "$id": "https://github.com/ory/kratos/.schema/versions.config.schema.json", + "$id": "https://github.com/ory/hydra/.schema/versions.config.schema.json", "$schema": "http://json-schema.org/draft-07/schema#", "oneOf": [ + { + "allOf": [ + { + "properties": { + "version": { + "const": "v2.2.0" + } + }, + "required": [ + "version" + ] + }, + { + "$ref": "https://raw.githubusercontent.com/ory/hydra/v2.2.0/.schema/config.schema.json" + } + ] + }, + { + "allOf": [ + { + "properties": { + "version": { + "const": "v2.2.0-rc.3" + } + }, + "required": [ + "version" + ] + }, + { + "$ref": "https://raw.githubusercontent.com/ory/hydra/v2.2.0-rc.3/.schema/config.schema.json" + } + ] + }, + { + "allOf": [ + { + "properties": { + "version": { + "const": "v2.2.0-rc.2" + } + }, + "required": [ + "version" + ] + }, + { + "$ref": "https://raw.githubusercontent.com/ory/hydra/v2.2.0-rc.2/.schema/config.schema.json" + } + ] + }, + { + "allOf": [ + { + "properties": { + "version": { + "const": "v2.1.2" + } + }, + "required": [ + "version" + ] + }, + { + "$ref": "https://raw.githubusercontent.com/ory/hydra/v2.1.2/.schema/config.schema.json" + } + ] + }, + { + "allOf": [ + { + "properties": { + "version": { + "const": "v2.1.1" + } + }, + "required": [ + "version" + ] + }, + { + "$ref": "https://raw.githubusercontent.com/ory/hydra/v2.1.1/.schema/config.schema.json" + } + ] + }, + { + "allOf": [ + { + "properties": { + "version": { + "const": "v2.1.0" + } + }, + "required": [ + "version" + ] + }, + { + "$ref": "https://raw.githubusercontent.com/ory/hydra/v2.1.0/.schema/config.schema.json" + } + ] + }, + { + "allOf": [ + { + "properties": { + "version": { + "const": "v2.0.3" + } + }, + "required": [ + "version" + ] + }, + { + "$ref": "https://raw.githubusercontent.com/ory/hydra/v2.0.3/spec/config.json" + } + ] + }, { "allOf": [ { diff --git a/.trivyignore b/.trivyignore new file mode 100644 index 00000000000..73859219e24 --- /dev/null +++ b/.trivyignore @@ -0,0 +1 @@ +CVE-2023-2650 diff --git a/CHANGELOG.md b/CHANGELOG.md index ddeeeeb2f8c..f8e1cd40af6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,240 +4,291 @@ **Table of Contents** -- [0.0.0 (2022-12-07)](#000-2022-12-07) +- [0.0.0 (2024-08-22)](#000-2024-08-22) + - [Breaking Changes](#breaking-changes) - [Bug Fixes](#bug-fixes) - [Features](#features) -- [2.0.2 (2022-11-10)](#202-2022-11-10) + - [Unclassified](#unclassified) +- [2.2.0 (2024-02-12)](#220-2024-02-12) - [Bug Fixes](#bug-fixes-1) - [Code Generation](#code-generation) +- [2.2.0-pre.1 (2024-02-01)](#220-pre1-2024-02-01) + - [Bug Fixes](#bug-fixes-2) + - [Code Generation](#code-generation-1) - [Documentation](#documentation) - [Features](#features-1) +- [2.2.0-rc.3 (2023-08-16)](#220-rc3-2023-08-16) + - [Bug Fixes](#bug-fixes-3) + - [Code Generation](#code-generation-2) + - [Features](#features-2) +- [2.2.0-pre.0 (2023-06-22)](#220-pre0-2023-06-22) + - [Code Generation](#code-generation-3) + - [Features](#features-3) +- [2.2.0-rc.2 (2023-06-13)](#220-rc2-2023-06-13) + - [Bug Fixes](#bug-fixes-4) + - [Code Generation](#code-generation-4) + - [Features](#features-4) +- [2.2.0-rc.1 (2023-06-12)](#220-rc1-2023-06-12) + - [Breaking Changes](#breaking-changes-1) + - [Bug Fixes](#bug-fixes-5) + - [Code Generation](#code-generation-5) + - [Features](#features-5) + - [Unclassified](#unclassified-1) +- [2.1.2 (2023-05-24)](#212-2023-05-24) + - [Bug Fixes](#bug-fixes-6) + - [Code Generation](#code-generation-6) + - [Documentation](#documentation-1) + - [Features](#features-6) +- [2.1.1 (2023-04-11)](#211-2023-04-11) + - [Bug Fixes](#bug-fixes-7) + - [Code Generation](#code-generation-7) +- [2.1.0 (2023-04-06)](#210-2023-04-06) + - [Bug Fixes](#bug-fixes-8) + - [Code Generation](#code-generation-8) +- [2.1.0-pre.2 (2023-04-03)](#210-pre2-2023-04-03) + - [Code Generation](#code-generation-9) +- [2.1.0-pre.1 (2023-04-03)](#210-pre1-2023-04-03) + - [Code Generation](#code-generation-10) +- [2.1.0-pre.0 (2023-03-31)](#210-pre0-2023-03-31) + - [Bug Fixes](#bug-fixes-9) + - [Code Generation](#code-generation-11) + - [Documentation](#documentation-2) + - [Features](#features-7) +- [2.0.3 (2022-12-08)](#203-2022-12-08) + - [Bug Fixes](#bug-fixes-10) + - [Code Generation](#code-generation-12) + - [Features](#features-8) +- [2.0.2 (2022-11-10)](#202-2022-11-10) + - [Bug Fixes](#bug-fixes-11) + - [Code Generation](#code-generation-13) + - [Documentation](#documentation-3) + - [Features](#features-9) - [Tests](#tests) - [2.0.1 (2022-10-27)](#201-2022-10-27) - - [Bug Fixes](#bug-fixes-2) - - [Code Generation](#code-generation-1) - - [Documentation](#documentation-1) + - [Bug Fixes](#bug-fixes-12) + - [Code Generation](#code-generation-14) + - [Documentation](#documentation-4) - [2.0.0 (2022-10-27)](#200-2022-10-27) - - [Breaking Changes](#breaking-changes) - - [Bug Fixes](#bug-fixes-3) - - [Code Generation](#code-generation-2) + - [Breaking Changes](#breaking-changes-2) + - [Bug Fixes](#bug-fixes-13) + - [Code Generation](#code-generation-15) - [Code Refactoring](#code-refactoring) - - [Documentation](#documentation-2) - - [Features](#features-2) + - [Documentation](#documentation-5) + - [Features](#features-10) - [Tests](#tests-1) - - [Unclassified](#unclassified) + - [Unclassified](#unclassified-2) - [1.11.10 (2022-08-25)](#11110-2022-08-25) - - [Bug Fixes](#bug-fixes-4) - - [Code Generation](#code-generation-3) + - [Bug Fixes](#bug-fixes-14) + - [Code Generation](#code-generation-16) - [1.11.9 (2022-08-01)](#1119-2022-08-01) - - [Bug Fixes](#bug-fixes-5) - - [Code Generation](#code-generation-4) - - [Documentation](#documentation-3) - - [Features](#features-3) + - [Bug Fixes](#bug-fixes-15) + - [Code Generation](#code-generation-17) + - [Documentation](#documentation-6) + - [Features](#features-11) - [1.11.8 (2022-05-04)](#1118-2022-05-04) - - [Bug Fixes](#bug-fixes-6) - - [Code Generation](#code-generation-5) - - [Documentation](#documentation-4) - - [Features](#features-4) + - [Bug Fixes](#bug-fixes-16) + - [Code Generation](#code-generation-18) + - [Documentation](#documentation-7) + - [Features](#features-12) - [Tests](#tests-2) - [1.11.7 (2022-02-23)](#1117-2022-02-23) - - [Code Generation](#code-generation-6) + - [Code Generation](#code-generation-19) - [1.11.6 (2022-02-23)](#1116-2022-02-23) - - [Bug Fixes](#bug-fixes-7) - - [Code Generation](#code-generation-7) + - [Bug Fixes](#bug-fixes-17) + - [Code Generation](#code-generation-20) - [1.11.5 (2022-02-21)](#1115-2022-02-21) - - [Bug Fixes](#bug-fixes-8) - - [Code Generation](#code-generation-8) + - [Bug Fixes](#bug-fixes-18) + - [Code Generation](#code-generation-21) - [1.11.4 (2022-02-16)](#1114-2022-02-16) - - [Bug Fixes](#bug-fixes-9) - - [Code Generation](#code-generation-9) + - [Bug Fixes](#bug-fixes-19) + - [Code Generation](#code-generation-22) - [1.11.3 (2022-02-15)](#1113-2022-02-15) - - [Bug Fixes](#bug-fixes-10) - - [Code Generation](#code-generation-10) + - [Bug Fixes](#bug-fixes-20) + - [Code Generation](#code-generation-23) - [1.11.2 (2022-02-11)](#1112-2022-02-11) - - [Code Generation](#code-generation-11) + - [Code Generation](#code-generation-24) - [1.11.1 (2022-02-11)](#1111-2022-02-11) - - [Bug Fixes](#bug-fixes-11) - - [Code Generation](#code-generation-12) + - [Bug Fixes](#bug-fixes-21) + - [Code Generation](#code-generation-25) - [Code Refactoring](#code-refactoring-1) - - [Documentation](#documentation-5) + - [Documentation](#documentation-8) - [1.11.0 (2022-01-21)](#1110-2022-01-21) - - [Breaking Changes](#breaking-changes-1) - - [Bug Fixes](#bug-fixes-12) - - [Code Generation](#code-generation-13) - - [Documentation](#documentation-6) - - [Features](#features-5) + - [Breaking Changes](#breaking-changes-3) + - [Bug Fixes](#bug-fixes-22) + - [Code Generation](#code-generation-26) + - [Documentation](#documentation-9) + - [Features](#features-13) - [1.10.7 (2021-10-27)](#1107-2021-10-27) - - [Breaking Changes](#breaking-changes-2) - - [Bug Fixes](#bug-fixes-13) - - [Code Generation](#code-generation-14) + - [Breaking Changes](#breaking-changes-4) + - [Bug Fixes](#bug-fixes-23) + - [Code Generation](#code-generation-27) - [Code Refactoring](#code-refactoring-2) - - [Documentation](#documentation-7) - - [Features](#features-6) + - [Documentation](#documentation-10) + - [Features](#features-14) - [1.10.6 (2021-08-28)](#1106-2021-08-28) - - [Bug Fixes](#bug-fixes-14) - - [Code Generation](#code-generation-15) - - [Documentation](#documentation-8) + - [Bug Fixes](#bug-fixes-24) + - [Code Generation](#code-generation-28) + - [Documentation](#documentation-11) - [1.10.5 (2021-08-13)](#1105-2021-08-13) - - [Bug Fixes](#bug-fixes-15) - - [Code Generation](#code-generation-16) - - [Documentation](#documentation-9) - - [Features](#features-7) + - [Bug Fixes](#bug-fixes-25) + - [Code Generation](#code-generation-29) + - [Documentation](#documentation-12) + - [Features](#features-15) - [1.10.3 (2021-07-14)](#1103-2021-07-14) - - [Bug Fixes](#bug-fixes-16) - - [Code Generation](#code-generation-17) + - [Bug Fixes](#bug-fixes-26) + - [Code Generation](#code-generation-30) - [Code Refactoring](#code-refactoring-3) - - [Documentation](#documentation-10) - - [Features](#features-8) + - [Documentation](#documentation-13) + - [Features](#features-16) - [1.10.2 (2021-05-04)](#1102-2021-05-04) - - [Breaking Changes](#breaking-changes-3) - - [Bug Fixes](#bug-fixes-17) - - [Code Generation](#code-generation-18) + - [Breaking Changes](#breaking-changes-5) + - [Bug Fixes](#bug-fixes-27) + - [Code Generation](#code-generation-31) - [Code Refactoring](#code-refactoring-4) - - [Documentation](#documentation-11) - - [Features](#features-9) + - [Documentation](#documentation-14) + - [Features](#features-17) - [1.10.1 (2021-03-25)](#1101-2021-03-25) - - [Bug Fixes](#bug-fixes-18) - - [Code Generation](#code-generation-19) - - [Documentation](#documentation-12) - - [Features](#features-10) + - [Bug Fixes](#bug-fixes-28) + - [Code Generation](#code-generation-32) + - [Documentation](#documentation-15) + - [Features](#features-18) - [Tests](#tests-3) - - [Unclassified](#unclassified-1) + - [Unclassified](#unclassified-3) - [1.9.2 (2021-01-29)](#192-2021-01-29) - - [Code Generation](#code-generation-20) - - [Features](#features-11) + - [Code Generation](#code-generation-33) + - [Features](#features-19) - [1.9.1 (2021-01-27)](#191-2021-01-27) - - [Code Generation](#code-generation-21) - - [Documentation](#documentation-13) + - [Code Generation](#code-generation-34) + - [Documentation](#documentation-16) - [1.9.0 (2021-01-12)](#190-2021-01-12) - - [Code Generation](#code-generation-22) + - [Code Generation](#code-generation-35) - [1.9.0-rc.0 (2021-01-12)](#190-rc0-2021-01-12) - - [Code Generation](#code-generation-23) + - [Code Generation](#code-generation-36) - [1.9.0-alpha.4.pre.0 (2021-01-12)](#190-alpha4pre0-2021-01-12) - - [Bug Fixes](#bug-fixes-19) - - [Code Generation](#code-generation-24) - - [Documentation](#documentation-14) + - [Bug Fixes](#bug-fixes-29) + - [Code Generation](#code-generation-37) + - [Documentation](#documentation-17) - [1.9.0-alpha.3 (2020-12-08)](#190-alpha3-2020-12-08) - - [Breaking Changes](#breaking-changes-4) - - [Bug Fixes](#bug-fixes-20) - - [Code Generation](#code-generation-25) + - [Breaking Changes](#breaking-changes-6) + - [Bug Fixes](#bug-fixes-30) + - [Code Generation](#code-generation-38) - [Code Refactoring](#code-refactoring-5) - - [Documentation](#documentation-15) - - [Features](#features-12) + - [Documentation](#documentation-18) + - [Features](#features-20) - [Tests](#tests-4) - - [Unclassified](#unclassified-2) + - [Unclassified](#unclassified-4) - [1.9.0-alpha.2 (2020-10-29)](#190-alpha2-2020-10-29) - - [Bug Fixes](#bug-fixes-21) - - [Code Generation](#code-generation-26) - - [Documentation](#documentation-16) - - [Features](#features-13) + - [Bug Fixes](#bug-fixes-31) + - [Code Generation](#code-generation-39) + - [Documentation](#documentation-19) + - [Features](#features-21) - [Tests](#tests-5) - [1.9.0-alpha.1 (2020-10-20)](#190-alpha1-2020-10-20) - - [Bug Fixes](#bug-fixes-22) - - [Code Generation](#code-generation-27) + - [Bug Fixes](#bug-fixes-32) + - [Code Generation](#code-generation-40) - [Code Refactoring](#code-refactoring-6) - - [Documentation](#documentation-17) - - [Features](#features-14) + - [Documentation](#documentation-20) + - [Features](#features-22) - [Tests](#tests-6) - [1.8.5 (2020-10-03)](#185-2020-10-03) - - [Code Generation](#code-generation-28) + - [Code Generation](#code-generation-41) - [1.8.0-pre.1 (2020-10-03)](#180-pre1-2020-10-03) - - [Bug Fixes](#bug-fixes-23) - - [Code Generation](#code-generation-29) - - [Features](#features-15) + - [Bug Fixes](#bug-fixes-33) + - [Code Generation](#code-generation-42) + - [Features](#features-23) - [1.8.0-pre.0 (2020-10-02)](#180-pre0-2020-10-02) - - [Breaking Changes](#breaking-changes-5) - - [Bug Fixes](#bug-fixes-24) - - [Code Generation](#code-generation-30) - - [Documentation](#documentation-18) - - [Features](#features-16) + - [Breaking Changes](#breaking-changes-7) + - [Bug Fixes](#bug-fixes-34) + - [Code Generation](#code-generation-43) + - [Documentation](#documentation-21) + - [Features](#features-24) - [1.7.4 (2020-08-31)](#174-2020-08-31) - - [Bug Fixes](#bug-fixes-25) - - [Code Generation](#code-generation-31) + - [Bug Fixes](#bug-fixes-35) + - [Code Generation](#code-generation-44) - [1.7.3 (2020-08-31)](#173-2020-08-31) - - [Code Generation](#code-generation-32) + - [Code Generation](#code-generation-45) - [1.7.1 (2020-08-31)](#171-2020-08-31) - - [Breaking Changes](#breaking-changes-6) - - [Bug Fixes](#bug-fixes-26) - - [Code Generation](#code-generation-33) + - [Breaking Changes](#breaking-changes-8) + - [Bug Fixes](#bug-fixes-36) + - [Code Generation](#code-generation-46) - [Code Refactoring](#code-refactoring-7) - - [Documentation](#documentation-19) - - [Features](#features-17) - - [Unclassified](#unclassified-3) + - [Documentation](#documentation-22) + - [Features](#features-25) + - [Unclassified](#unclassified-5) - [1.7.0 (2020-08-14)](#170-2020-08-14) - - [Breaking Changes](#breaking-changes-7) - - [Bug Fixes](#bug-fixes-27) - - [Code Generation](#code-generation-34) + - [Breaking Changes](#breaking-changes-9) + - [Bug Fixes](#bug-fixes-37) + - [Code Generation](#code-generation-47) - [Code Refactoring](#code-refactoring-8) - - [Documentation](#documentation-20) - - [Features](#features-18) - - [Unclassified](#unclassified-4) + - [Documentation](#documentation-23) + - [Features](#features-26) + - [Unclassified](#unclassified-6) - [1.6.0 (2020-07-20)](#160-2020-07-20) - - [Bug Fixes](#bug-fixes-28) - - [Code Generation](#code-generation-35) - - [Documentation](#documentation-21) - - [Unclassified](#unclassified-5) + - [Bug Fixes](#bug-fixes-38) + - [Code Generation](#code-generation-48) + - [Documentation](#documentation-24) + - [Unclassified](#unclassified-7) - [1.5.2 (2020-06-23)](#152-2020-06-23) - - [Bug Fixes](#bug-fixes-29) - - [Code Generation](#code-generation-36) - - [Features](#features-19) + - [Bug Fixes](#bug-fixes-39) + - [Code Generation](#code-generation-49) + - [Features](#features-27) - [1.5.1 (2020-06-16)](#151-2020-06-16) - - [Code Generation](#code-generation-37) + - [Code Generation](#code-generation-50) - [1.5.0 (2020-06-16)](#150-2020-06-16) - - [Bug Fixes](#bug-fixes-30) + - [Bug Fixes](#bug-fixes-40) - [Chores](#chores) - - [Documentation](#documentation-22) - - [Features](#features-20) - - [Unclassified](#unclassified-6) + - [Documentation](#documentation-25) + - [Features](#features-28) + - [Unclassified](#unclassified-8) - [1.5.0-beta.5 (2020-05-28)](#150-beta5-2020-05-28) - - [Bug Fixes](#bug-fixes-31) + - [Bug Fixes](#bug-fixes-41) - [Chores](#chores-1) - - [Documentation](#documentation-23) - - [Features](#features-21) + - [Documentation](#documentation-26) + - [Features](#features-29) - [1.5.0-beta.3 (2020-05-23)](#150-beta3-2020-05-23) - [Chores](#chores-2) - [1.5.0-beta.2 (2020-05-23)](#150-beta2-2020-05-23) - - [Bug Fixes](#bug-fixes-32) + - [Bug Fixes](#bug-fixes-42) - [Chores](#chores-3) - [Code Refactoring](#code-refactoring-9) - - [Documentation](#documentation-24) + - [Documentation](#documentation-27) - [1.5.0-beta.1 (2020-04-30)](#150-beta1-2020-04-30) - - [Breaking Changes](#breaking-changes-8) + - [Breaking Changes](#breaking-changes-10) - [Chores](#chores-4) - [Code Refactoring](#code-refactoring-10) - [1.4.10 (2020-04-30)](#1410-2020-04-30) - - [Bug Fixes](#bug-fixes-33) + - [Bug Fixes](#bug-fixes-43) - [Chores](#chores-5) - - [Documentation](#documentation-25) - - [Unclassified](#unclassified-7) + - [Documentation](#documentation-28) + - [Unclassified](#unclassified-9) - [1.4.9 (2020-04-25)](#149-2020-04-25) - - [Bug Fixes](#bug-fixes-34) + - [Bug Fixes](#bug-fixes-44) - [Chores](#chores-6) - [1.4.8 (2020-04-24)](#148-2020-04-24) - - [Bug Fixes](#bug-fixes-35) + - [Bug Fixes](#bug-fixes-45) - [Chores](#chores-7) - - [Documentation](#documentation-26) - - [Features](#features-22) + - [Documentation](#documentation-29) + - [Features](#features-30) - [1.4.7 (2020-04-24)](#147-2020-04-24) - - [Bug Fixes](#bug-fixes-36) + - [Bug Fixes](#bug-fixes-46) - [Chores](#chores-8) - - [Documentation](#documentation-27) + - [Documentation](#documentation-30) - [1.4.6 (2020-04-17)](#146-2020-04-17) - - [Bug Fixes](#bug-fixes-37) - - [Documentation](#documentation-28) + - [Bug Fixes](#bug-fixes-47) + - [Documentation](#documentation-31) - [1.4.5 (2020-04-16)](#145-2020-04-16) - - [Bug Fixes](#bug-fixes-38) - - [Documentation](#documentation-29) + - [Bug Fixes](#bug-fixes-48) + - [Documentation](#documentation-32) - [1.4.3 (2020-04-16)](#143-2020-04-16) - - [Bug Fixes](#bug-fixes-39) + - [Bug Fixes](#bug-fixes-49) - [Code Refactoring](#code-refactoring-11) - - [Documentation](#documentation-30) - - [Features](#features-23) + - [Documentation](#documentation-33) + - [Features](#features-31) - [1.4.2 (2020-04-03)](#142-2020-04-03) - [Chores](#chores-9) - - [Documentation](#documentation-31) + - [Documentation](#documentation-34) - [1.4.1 (2020-04-02)](#141-2020-04-02) - - [Bug Fixes](#bug-fixes-40) + - [Bug Fixes](#bug-fixes-50) - [1.4.0 (2020-04-02)](#140-2020-04-02) - [GHSA-3p3g-vpw6-4w66](#ghsa-3p3g-vpw6-4w66) - [Impact](#impact) @@ -246,7 +297,7 @@ - [Workarounds](#workarounds) - [References](#references) - [Upstream](#upstream) - - [Breaking Changes](#breaking-changes-9) + - [Breaking Changes](#breaking-changes-11) - [GHSA-3p3g-vpw6-4w66](#ghsa-3p3g-vpw6-4w66-1) - [Impact](#impact-1) - [Severity](#severity-1) @@ -254,49 +305,49 @@ - [Workarounds](#workarounds-1) - [References](#references-1) - [Upstream](#upstream-1) - - [Bug Fixes](#bug-fixes-41) + - [Bug Fixes](#bug-fixes-51) - [Code Refactoring](#code-refactoring-12) - - [Documentation](#documentation-32) - - [Features](#features-24) - - [Unclassified](#unclassified-8) + - [Documentation](#documentation-35) + - [Features](#features-32) + - [Unclassified](#unclassified-10) - [1.3.2 (2020-02-17)](#132-2020-02-17) - - [Bug Fixes](#bug-fixes-42) + - [Bug Fixes](#bug-fixes-52) - [Chores](#chores-10) - - [Documentation](#documentation-33) + - [Documentation](#documentation-36) - [1.3.1 (2020-02-16)](#131-2020-02-16) - [Continuous Integration](#continuous-integration) - [1.3.0 (2020-02-14)](#130-2020-02-14) - - [Bug Fixes](#bug-fixes-43) - - [Documentation](#documentation-34) - - [Features](#features-25) - - [Unclassified](#unclassified-9) + - [Bug Fixes](#bug-fixes-53) + - [Documentation](#documentation-37) + - [Features](#features-33) + - [Unclassified](#unclassified-11) - [1.2.3 (2020-01-31)](#123-2020-01-31) - - [Unclassified](#unclassified-10) + - [Unclassified](#unclassified-12) - [1.2.2 (2020-01-23)](#122-2020-01-23) - - [Documentation](#documentation-35) - - [Unclassified](#unclassified-11) + - [Documentation](#documentation-38) + - [Unclassified](#unclassified-13) - [1.2.1 (2020-01-15)](#121-2020-01-15) - - [Unclassified](#unclassified-12) + - [Unclassified](#unclassified-14) - [1.2.0 (2020-01-08)](#120-2020-01-08) - - [Unclassified](#unclassified-13) + - [Unclassified](#unclassified-15) - [1.2.0-alpha.3 (2020-01-08)](#120-alpha3-2020-01-08) - - [Unclassified](#unclassified-14) + - [Unclassified](#unclassified-16) - [1.2.0-alpha.2 (2020-01-08)](#120-alpha2-2020-01-08) - [Continuous Integration](#continuous-integration-1) - [1.2.0-alpha.1 (2020-01-07)](#120-alpha1-2020-01-07) - - [Documentation](#documentation-36) - - [Unclassified](#unclassified-15) + - [Documentation](#documentation-39) + - [Unclassified](#unclassified-17) - [1.1.1 (2019-12-19)](#111-2019-12-19) - - [Documentation](#documentation-37) - - [Unclassified](#unclassified-16) + - [Documentation](#documentation-40) + - [Unclassified](#unclassified-18) - [1.1.0 (2019-12-16)](#110-2019-12-16) - - [Documentation](#documentation-38) - - [Unclassified](#unclassified-17) + - [Documentation](#documentation-41) + - [Unclassified](#unclassified-19) - [1.0.9 (2019-11-02)](#109-2019-11-02) - - [Documentation](#documentation-39) - - [Unclassified](#unclassified-18) + - [Documentation](#documentation-42) + - [Unclassified](#unclassified-20) - [1.0.8 (2019-10-04)](#108-2019-10-04) - - [Unclassified](#unclassified-19) + - [Unclassified](#unclassified-21) - [1.0.7 (2019-09-29)](#107-2019-09-29) - [Continuous Integration](#continuous-integration-2) - [1.0.6 (2019-09-29)](#106-2019-09-29) @@ -304,372 +355,910 @@ - [1.0.5 (2019-09-28)](#105-2019-09-28) - [Continuous Integration](#continuous-integration-4) - [1.0.4 (2019-09-26)](#104-2019-09-26) - - [Unclassified](#unclassified-20) + - [Unclassified](#unclassified-22) - [1.0.3 (2019-09-23)](#103-2019-09-23) - - [Unclassified](#unclassified-21) + - [Unclassified](#unclassified-23) - [1.0.2 (2019-09-18)](#102-2019-09-18) - - [Unclassified](#unclassified-22) + - [Unclassified](#unclassified-24) - [1.0.1 (2019-09-04)](#101-2019-09-04) - - [Documentation](#documentation-40) - - [Unclassified](#unclassified-23) + - [Documentation](#documentation-43) + - [Unclassified](#unclassified-25) - [1.0.0 (2019-06-24)](#100-2019-06-24) - - [Documentation](#documentation-41) - - [Unclassified](#unclassified-24) + - [Documentation](#documentation-44) + - [Unclassified](#unclassified-26) - [1.0.0-rc.16 (2019-06-13)](#100-rc16-2019-06-13) - - [Documentation](#documentation-42) - - [Unclassified](#unclassified-25) + - [Documentation](#documentation-45) + - [Unclassified](#unclassified-27) - [1.0.0-rc.15 (2019-06-05)](#100-rc15-2019-06-05) - - [Documentation](#documentation-43) - - [Unclassified](#unclassified-26) + - [Documentation](#documentation-46) + - [Unclassified](#unclassified-28) - [1.0.0-rc.14 (2019-05-18)](#100-rc14-2019-05-18) - [Continuous Integration](#continuous-integration-5) - - [Documentation](#documentation-44) - - [Unclassified](#unclassified-27) + - [Documentation](#documentation-47) + - [Unclassified](#unclassified-29) - [1.0.0-rc.12 (2019-05-10)](#100-rc12-2019-05-10) - - [Unclassified](#unclassified-28) + - [Unclassified](#unclassified-30) - [0.0.1 (2019-05-08)](#001-2019-05-08) - - [Documentation](#documentation-45) - - [Unclassified](#unclassified-29) + - [Documentation](#documentation-48) + - [Unclassified](#unclassified-31) - [1.0.0-rc.11 (2019-05-02)](#100-rc11-2019-05-02) - - [Documentation](#documentation-46) - - [Unclassified](#unclassified-30) + - [Documentation](#documentation-49) + - [Unclassified](#unclassified-32) - [1.0.0-rc.10 (2019-04-29)](#100-rc10-2019-04-29) - - [Documentation](#documentation-47) - - [Unclassified](#unclassified-31) + - [Documentation](#documentation-50) + - [Unclassified](#unclassified-33) - [1.0.0-rc.9+oryOS.10 (2019-04-18)](#100-rc9oryos10-2019-04-18) - - [Documentation](#documentation-48) - - [Unclassified](#unclassified-32) + - [Documentation](#documentation-51) + - [Unclassified](#unclassified-34) - [1.0.0-rc.8+oryOS.10 (2019-04-03)](#100-rc8oryos10-2019-04-03) - [Continuous Integration](#continuous-integration-6) - - [Documentation](#documentation-49) + - [Documentation](#documentation-52) - [1.0.0-rc.7+oryOS.10 (2019-04-02)](#100-rc7oryos10-2019-04-02) - [Continuous Integration](#continuous-integration-7) - - [Documentation](#documentation-50) - - [Unclassified](#unclassified-33) + - [Documentation](#documentation-53) + - [Unclassified](#unclassified-35) - [1.0.0-rc.6+oryOS.10 (2018-12-18)](#100-rc6oryos10-2018-12-18) - - [Documentation](#documentation-51) - - [Unclassified](#unclassified-34) + - [Documentation](#documentation-54) + - [Unclassified](#unclassified-36) - [1.0.0-rc.5+oryOS.10 (2018-12-13)](#100-rc5oryos10-2018-12-13) - - [Documentation](#documentation-52) - - [Unclassified](#unclassified-35) + - [Documentation](#documentation-55) + - [Unclassified](#unclassified-37) - [1.0.0-rc.4+oryOS.9 (2018-12-12)](#100-rc4oryos9-2018-12-12) - - [Documentation](#documentation-53) - - [Unclassified](#unclassified-36) + - [Documentation](#documentation-56) + - [Unclassified](#unclassified-38) - [1.0.0-rc.3+oryOS.9 (2018-12-06)](#100-rc3oryos9-2018-12-06) - - [Documentation](#documentation-54) - - [Unclassified](#unclassified-37) + - [Documentation](#documentation-57) + - [Unclassified](#unclassified-39) - [1.0.0-rc.2+oryOS.9 (2018-11-21)](#100-rc2oryos9-2018-11-21) - - [Documentation](#documentation-55) - - [Unclassified](#unclassified-38) + - [Documentation](#documentation-58) + - [Unclassified](#unclassified-40) - [1.0.0-rc.1+oryOS.9 (2018-11-21)](#100-rc1oryos9-2018-11-21) - [Build System](#build-system) - - [Documentation](#documentation-56) - - [Unclassified](#unclassified-39) + - [Documentation](#documentation-59) + - [Unclassified](#unclassified-41) - [1.0.0-beta.9 (2018-09-01)](#100-beta9-2018-09-01) - - [Documentation](#documentation-57) - - [Unclassified](#unclassified-40) + - [Documentation](#documentation-60) + - [Unclassified](#unclassified-42) - [1.0.0-beta.8 (2018-08-10)](#100-beta8-2018-08-10) - - [Documentation](#documentation-58) - - [Unclassified](#unclassified-41) + - [Documentation](#documentation-61) + - [Unclassified](#unclassified-43) - [1.0.0-beta.7 (2018-07-16)](#100-beta7-2018-07-16) - - [Documentation](#documentation-59) - - [Unclassified](#unclassified-42) + - [Documentation](#documentation-62) + - [Unclassified](#unclassified-44) - [1.0.0-beta.6 (2018-07-11)](#100-beta6-2018-07-11) - - [Documentation](#documentation-60) - - [Unclassified](#unclassified-43) + - [Documentation](#documentation-63) + - [Unclassified](#unclassified-45) - [1.0.0-beta.5 (2018-07-07)](#100-beta5-2018-07-07) - - [Documentation](#documentation-61) - - [Unclassified](#unclassified-44) + - [Documentation](#documentation-64) + - [Unclassified](#unclassified-46) - [1.0.0-beta.4 (2018-06-13)](#100-beta4-2018-06-13) - - [Documentation](#documentation-62) + - [Documentation](#documentation-65) - [1.0.0-beta.3 (2018-06-13)](#100-beta3-2018-06-13) - [Continuous Integration](#continuous-integration-8) - - [Documentation](#documentation-63) - - [Unclassified](#unclassified-45) + - [Documentation](#documentation-66) + - [Unclassified](#unclassified-47) - [1.0.0-beta.2 (2018-05-29)](#100-beta2-2018-05-29) - [Continuous Integration](#continuous-integration-9) - [1.0.0-beta.1 (2018-05-29)](#100-beta1-2018-05-29) - [Build System](#build-system-1) - - [Documentation](#documentation-64) - - [Unclassified](#unclassified-46) + - [Documentation](#documentation-67) + - [Unclassified](#unclassified-48) - [0.11.10 (2018-03-19)](#01110-2018-03-19) - - [Documentation](#documentation-65) - - [Unclassified](#unclassified-47) + - [Documentation](#documentation-68) + - [Unclassified](#unclassified-49) - [0.11.12 (2018-04-08)](#01112-2018-04-08) - - [Documentation](#documentation-66) - - [Unclassified](#unclassified-48) + - [Documentation](#documentation-69) + - [Unclassified](#unclassified-50) - [0.11.9 (2018-03-10)](#0119-2018-03-10) - - [Unclassified](#unclassified-49) + - [Unclassified](#unclassified-51) - [0.11.7 (2018-03-03)](#0117-2018-03-03) - - [Unclassified](#unclassified-50) + - [Unclassified](#unclassified-52) - [0.11.6 (2018-02-07)](#0116-2018-02-07) - - [Unclassified](#unclassified-51) + - [Unclassified](#unclassified-53) - [0.11.10 (2018-03-19)](#01110-2018-03-19-1) - - [Documentation](#documentation-67) - - [Unclassified](#unclassified-52) + - [Documentation](#documentation-70) + - [Unclassified](#unclassified-54) - [0.11.9 (2018-03-10)](#0119-2018-03-10-1) - - [Unclassified](#unclassified-53) + - [Unclassified](#unclassified-55) - [0.11.7 (2018-03-03)](#0117-2018-03-03-1) - - [Unclassified](#unclassified-54) + - [Unclassified](#unclassified-56) - [0.11.6 (2018-02-07)](#0116-2018-02-07-1) - - [Unclassified](#unclassified-55) + - [Unclassified](#unclassified-57) - [0.11.4 (2018-01-23)](#0114-2018-01-23) - - [Documentation](#documentation-68) + - [Documentation](#documentation-71) - [0.11.3 (2018-01-23)](#0113-2018-01-23) - - [Documentation](#documentation-69) - - [Unclassified](#unclassified-56) + - [Documentation](#documentation-72) + - [Unclassified](#unclassified-58) - [0.11.2 (2018-01-22)](#0112-2018-01-22) - - [Unclassified](#unclassified-57) + - [Unclassified](#unclassified-59) - [0.11.1 (2018-01-18)](#0111-2018-01-18) - - [Unclassified](#unclassified-58) + - [Unclassified](#unclassified-60) - [0.11.0 (2018-01-08)](#0110-2018-01-08) - - [Documentation](#documentation-70) - - [Unclassified](#unclassified-59) + - [Documentation](#documentation-73) + - [Unclassified](#unclassified-61) - [0.10.10 (2017-12-16)](#01010-2017-12-16) - - [Documentation](#documentation-71) - - [Unclassified](#unclassified-60) + - [Documentation](#documentation-74) + - [Unclassified](#unclassified-62) - [0.10.9 (2017-12-13)](#0109-2017-12-13) - - [Documentation](#documentation-72) - - [Unclassified](#unclassified-61) + - [Documentation](#documentation-75) + - [Unclassified](#unclassified-63) - [0.10.8 (2017-12-12)](#0108-2017-12-12) - - [Documentation](#documentation-73) - - [Unclassified](#unclassified-62) + - [Documentation](#documentation-76) + - [Unclassified](#unclassified-64) - [0.10.7 (2017-12-09)](#0107-2017-12-09) - - [Documentation](#documentation-74) - - [Unclassified](#unclassified-63) + - [Documentation](#documentation-77) + - [Unclassified](#unclassified-65) - [0.10.6 (2017-12-09)](#0106-2017-12-09) - - [Unclassified](#unclassified-64) + - [Unclassified](#unclassified-66) - [0.10.5 (2017-12-09)](#0105-2017-12-09) - - [Documentation](#documentation-75) - - [Unclassified](#unclassified-65) + - [Documentation](#documentation-78) + - [Unclassified](#unclassified-67) - [0.10.4 (2017-12-09)](#0104-2017-12-09) - - [Documentation](#documentation-76) - - [Unclassified](#unclassified-66) + - [Documentation](#documentation-79) + - [Unclassified](#unclassified-68) - [0.10.3 (2017-12-08)](#0103-2017-12-08) - - [Documentation](#documentation-77) + - [Documentation](#documentation-80) - [0.10.2 (2017-12-08)](#0102-2017-12-08) - [Continuous Integration](#continuous-integration-10) - [0.10.1 (2017-12-08)](#0101-2017-12-08) - [Continuous Integration](#continuous-integration-11) - [0.10.0 (2017-12-08)](#0100-2017-12-08) - [Continuous Integration](#continuous-integration-12) - - [Documentation](#documentation-78) - - [Unclassified](#unclassified-67) + - [Documentation](#documentation-81) + - [Unclassified](#unclassified-69) - [0.10.0-alpha.21 (2017-11-27)](#0100-alpha21-2017-11-27) - - [Unclassified](#unclassified-68) + - [Unclassified](#unclassified-70) - [0.10.0-alpha.20 (2017-11-26)](#0100-alpha20-2017-11-26) - - [Unclassified](#unclassified-69) + - [Unclassified](#unclassified-71) - [0.10.0-alpha.19 (2017-11-26)](#0100-alpha19-2017-11-26) - - [Documentation](#documentation-79) - - [Unclassified](#unclassified-70) + - [Documentation](#documentation-82) + - [Unclassified](#unclassified-72) - [0.10.0-alpha.18 (2017-11-06)](#0100-alpha18-2017-11-06) - [Continuous Integration](#continuous-integration-13) - [0.10.0-alpha.17 (2017-11-06)](#0100-alpha17-2017-11-06) - [Continuous Integration](#continuous-integration-14) - [0.10.0-alpha.16 (2017-11-06)](#0100-alpha16-2017-11-06) - [Continuous Integration](#continuous-integration-15) - - [Documentation](#documentation-80) - - [Unclassified](#unclassified-71) + - [Documentation](#documentation-83) + - [Unclassified](#unclassified-73) - [0.10.0-alpha.15 (2017-11-06)](#0100-alpha15-2017-11-06) - - [Unclassified](#unclassified-72) + - [Unclassified](#unclassified-74) - [0.10.0-alpha.14 (2017-11-06)](#0100-alpha14-2017-11-06) - - [Unclassified](#unclassified-73) + - [Unclassified](#unclassified-75) - [0.10.0-alpha.13 (2017-11-06)](#0100-alpha13-2017-11-06) - - [Unclassified](#unclassified-74) + - [Unclassified](#unclassified-76) - [0.10.0-alpha.12 (2017-11-06)](#0100-alpha12-2017-11-06) - - [Documentation](#documentation-81) - - [Unclassified](#unclassified-75) + - [Documentation](#documentation-84) + - [Unclassified](#unclassified-77) - [0.10.0-alpha.10 (2017-10-26)](#0100-alpha10-2017-10-26) - [Continuous Integration](#continuous-integration-16) - - [Documentation](#documentation-82) + - [Documentation](#documentation-85) - [0.10.0-alpha.9 (2017-10-25)](#0100-alpha9-2017-10-25) - - [Documentation](#documentation-83) - - [Unclassified](#unclassified-76) + - [Documentation](#documentation-86) + - [Unclassified](#unclassified-78) - [0.10.0-alpha.8 (2017-10-18)](#0100-alpha8-2017-10-18) - - [Documentation](#documentation-84) - - [Unclassified](#unclassified-77) + - [Documentation](#documentation-87) + - [Unclassified](#unclassified-79) - [0.9.14 (2017-10-06)](#0914-2017-10-06) - - [Documentation](#documentation-85) - - [Unclassified](#unclassified-78) + - [Documentation](#documentation-88) + - [Unclassified](#unclassified-80) - [0.10.0-alpha.7 (2017-10-06)](#0100-alpha7-2017-10-06) - - [Unclassified](#unclassified-79) + - [Unclassified](#unclassified-81) - [0.10.0-alpha.6 (2017-10-05)](#0100-alpha6-2017-10-05) - - [Unclassified](#unclassified-80) + - [Unclassified](#unclassified-82) - [0.10.0-alpha.5 (2017-10-05)](#0100-alpha5-2017-10-05) - - [Unclassified](#unclassified-81) + - [Unclassified](#unclassified-83) - [0.10.0-alpha.4 (2017-10-05)](#0100-alpha4-2017-10-05) - - [Unclassified](#unclassified-82) + - [Unclassified](#unclassified-84) - [0.10.0-alpha.3 (2017-10-05)](#0100-alpha3-2017-10-05) - - [Unclassified](#unclassified-83) + - [Unclassified](#unclassified-85) - [0.10.0-alpha.2 (2017-10-05)](#0100-alpha2-2017-10-05) - - [Documentation](#documentation-86) - - [Unclassified](#unclassified-84) + - [Documentation](#documentation-89) + - [Unclassified](#unclassified-86) - [0.10.0-alpha.1 (2017-10-05)](#0100-alpha1-2017-10-05) - - [Documentation](#documentation-87) - - [Unclassified](#unclassified-85) + - [Documentation](#documentation-90) + - [Unclassified](#unclassified-87) - [0.9.13 (2017-09-26)](#0913-2017-09-26) - - [Documentation](#documentation-88) - - [Unclassified](#unclassified-86) + - [Documentation](#documentation-91) + - [Unclassified](#unclassified-88) - [0.9.12 (2017-07-06)](#0912-2017-07-06) - - [Documentation](#documentation-89) - - [Unclassified](#unclassified-87) + - [Documentation](#documentation-92) + - [Unclassified](#unclassified-89) - [0.9.11 (2017-06-30)](#0911-2017-06-30) - - [Documentation](#documentation-90) - - [Unclassified](#unclassified-88) + - [Documentation](#documentation-93) + - [Unclassified](#unclassified-90) - [0.9.10 (2017-06-29)](#0910-2017-06-29) - - [Documentation](#documentation-91) - - [Unclassified](#unclassified-89) + - [Documentation](#documentation-94) + - [Unclassified](#unclassified-91) - [0.9.9 (2017-06-17)](#099-2017-06-17) - - [Unclassified](#unclassified-90) + - [Unclassified](#unclassified-92) - [0.9.8 (2017-06-17)](#098-2017-06-17) - - [Documentation](#documentation-92) - - [Unclassified](#unclassified-91) + - [Documentation](#documentation-95) + - [Unclassified](#unclassified-93) - [0.9.7 (2017-06-16)](#097-2017-06-16) - - [Documentation](#documentation-93) - - [Unclassified](#unclassified-92) + - [Documentation](#documentation-96) + - [Unclassified](#unclassified-94) - [0.9.6 (2017-06-15)](#096-2017-06-15) - - [Unclassified](#unclassified-93) + - [Unclassified](#unclassified-95) - [0.9.5 (2017-06-15)](#095-2017-06-15) - - [Unclassified](#unclassified-94) + - [Unclassified](#unclassified-96) - [0.9.4 (2017-06-14)](#094-2017-06-14) - - [Documentation](#documentation-94) - - [Unclassified](#unclassified-95) + - [Documentation](#documentation-97) + - [Unclassified](#unclassified-97) - [0.9.3 (2017-06-14)](#093-2017-06-14) - - [Documentation](#documentation-95) - - [Unclassified](#unclassified-96) + - [Documentation](#documentation-98) + - [Unclassified](#unclassified-98) - [0.9.2 (2017-06-13)](#092-2017-06-13) - - [Unclassified](#unclassified-97) + - [Unclassified](#unclassified-99) - [0.9.1 (2017-06-12)](#091-2017-06-12) - - [Unclassified](#unclassified-98) + - [Unclassified](#unclassified-100) - [0.9.0 (2017-06-07)](#090-2017-06-07) - - [Documentation](#documentation-96) - - [Unclassified](#unclassified-99) + - [Documentation](#documentation-99) + - [Unclassified](#unclassified-101) - [0.8.7 (2017-06-05)](#087-2017-06-05) - - [Unclassified](#unclassified-100) + - [Unclassified](#unclassified-102) - [0.8.6 (2017-06-05)](#086-2017-06-05) - - [Documentation](#documentation-97) - - [Unclassified](#unclassified-101) + - [Documentation](#documentation-100) + - [Unclassified](#unclassified-103) - [0.8.5 (2017-06-01)](#085-2017-06-01) - - [Unclassified](#unclassified-102) + - [Unclassified](#unclassified-104) - [0.8.4 (2017-05-24)](#084-2017-05-24) - - [Documentation](#documentation-98) - - [Unclassified](#unclassified-103) + - [Documentation](#documentation-101) + - [Unclassified](#unclassified-105) - [0.8.3 (2017-05-23)](#083-2017-05-23) - - [Documentation](#documentation-99) - - [Unclassified](#unclassified-104) + - [Documentation](#documentation-102) + - [Unclassified](#unclassified-106) - [0.8.2 (2017-05-10)](#082-2017-05-10) - - [Unclassified](#unclassified-105) + - [Unclassified](#unclassified-107) - [0.8.1 (2017-05-08)](#081-2017-05-08) - [Continuous Integration](#continuous-integration-17) - [0.8.0 (2017-05-07)](#080-2017-05-07) - [Continuous Integration](#continuous-integration-18) - - [Documentation](#documentation-100) - - [Unclassified](#unclassified-106) + - [Documentation](#documentation-103) + - [Unclassified](#unclassified-108) - [0.7.13 (2017-05-03)](#0713-2017-05-03) - - [Documentation](#documentation-101) - - [Unclassified](#unclassified-107) + - [Documentation](#documentation-104) + - [Unclassified](#unclassified-109) - [0.7.12 (2017-04-30)](#0712-2017-04-30) - - [Unclassified](#unclassified-108) + - [Unclassified](#unclassified-110) - [0.7.11 (2017-04-28)](#0711-2017-04-28) - - [Unclassified](#unclassified-109) + - [Unclassified](#unclassified-111) - [0.7.10 (2017-04-14)](#0710-2017-04-14) - - [Documentation](#documentation-102) - - [Unclassified](#unclassified-110) + - [Documentation](#documentation-105) + - [Unclassified](#unclassified-112) - [0.7.9 (2017-04-02)](#079-2017-04-02) - - [Unclassified](#unclassified-111) + - [Unclassified](#unclassified-113) - [0.7.8 (2017-03-24)](#078-2017-03-24) - - [Documentation](#documentation-103) - - [Unclassified](#unclassified-112) + - [Documentation](#documentation-106) + - [Unclassified](#unclassified-114) - [0.7.7 (2017-02-11)](#077-2017-02-11) - - [Unclassified](#unclassified-113) + - [Unclassified](#unclassified-115) - [0.7.6 (2017-02-11)](#076-2017-02-11) - - [Unclassified](#unclassified-114) + - [Unclassified](#unclassified-116) - [0.7.3 (2017-01-22)](#073-2017-01-22) - - [Unclassified](#unclassified-115) + - [Unclassified](#unclassified-117) - [0.7.2 (2017-01-02)](#072-2017-01-02) - - [Unclassified](#unclassified-116) + - [Unclassified](#unclassified-118) - [0.7.1 (2016-12-30)](#071-2016-12-30) - - [Unclassified](#unclassified-117) + - [Unclassified](#unclassified-119) - [0.7.0 (2016-12-30)](#070-2016-12-30) - - [Documentation](#documentation-104) - - [Unclassified](#unclassified-118) + - [Documentation](#documentation-107) + - [Unclassified](#unclassified-120) - [0.6.10 (2016-12-26)](#0610-2016-12-26) - - [Unclassified](#unclassified-119) + - [Unclassified](#unclassified-121) - [0.6.9 (2016-12-20)](#069-2016-12-20) - - [Documentation](#documentation-105) - - [Unclassified](#unclassified-120) + - [Documentation](#documentation-108) + - [Unclassified](#unclassified-122) - [0.6.8 (2016-12-06)](#068-2016-12-06) - - [Unclassified](#unclassified-121) + - [Unclassified](#unclassified-123) - [0.6.7 (2016-12-04)](#067-2016-12-04) - - [Unclassified](#unclassified-122) + - [Unclassified](#unclassified-124) - [0.6.6 (2016-12-04)](#066-2016-12-04) - - [Documentation](#documentation-106) - - [Unclassified](#unclassified-123) + - [Documentation](#documentation-109) + - [Unclassified](#unclassified-125) - [0.6.5 (2016-11-28)](#065-2016-11-28) - - [Unclassified](#unclassified-124) + - [Unclassified](#unclassified-126) - [0.6.4 (2016-11-22)](#064-2016-11-22) - - [Unclassified](#unclassified-125) + - [Unclassified](#unclassified-127) - [0.6.3 (2016-11-17)](#063-2016-11-17) - - [Documentation](#documentation-107) - - [Unclassified](#unclassified-126) + - [Documentation](#documentation-110) + - [Unclassified](#unclassified-128) - [0.6.2 (2016-11-05)](#062-2016-11-05) - - [Unclassified](#unclassified-127) + - [Unclassified](#unclassified-129) - [0.6.1 (2016-10-26)](#061-2016-10-26) - - [Documentation](#documentation-108) - - [Unclassified](#unclassified-128) + - [Documentation](#documentation-111) + - [Unclassified](#unclassified-130) - [0.6.0 (2016-10-25)](#060-2016-10-25) - - [Unclassified](#unclassified-129) + - [Unclassified](#unclassified-131) - [0.5.8 (2016-10-06)](#058-2016-10-06) - - [Unclassified](#unclassified-130) + - [Unclassified](#unclassified-132) - [0.5.7 (2016-10-04)](#057-2016-10-04) - - [Unclassified](#unclassified-131) + - [Unclassified](#unclassified-133) - [0.5.6 (2016-10-03)](#056-2016-10-03) - - [Unclassified](#unclassified-132) + - [Unclassified](#unclassified-134) - [0.5.5 (2016-09-29)](#055-2016-09-29) - - [Unclassified](#unclassified-133) + - [Unclassified](#unclassified-135) - [0.5.4 (2016-09-29)](#054-2016-09-29) - - [Unclassified](#unclassified-134) + - [Unclassified](#unclassified-136) - [0.5.3 (2016-09-29)](#053-2016-09-29) - - [Documentation](#documentation-109) - - [Unclassified](#unclassified-135) + - [Documentation](#documentation-112) + - [Unclassified](#unclassified-137) - [0.5.2 (2016-09-23)](#052-2016-09-23) - - [Unclassified](#unclassified-136) + - [Unclassified](#unclassified-138) - [0.5.1 (2016-09-22)](#051-2016-09-22) - - [Documentation](#documentation-110) - - [Unclassified](#unclassified-137) + - [Documentation](#documentation-113) + - [Unclassified](#unclassified-139) - [0.4.3 (2016-09-03)](#043-2016-09-03) - - [Unclassified](#unclassified-138) + - [Unclassified](#unclassified-140) - [0.4.2-alpha.3 (2016-09-02)](#042-alpha3-2016-09-02) - - [Unclassified](#unclassified-139) + - [Unclassified](#unclassified-141) - [0.4.2-alpha.2 (2016-09-01)](#042-alpha2-2016-09-01) - - [Unclassified](#unclassified-140) + - [Unclassified](#unclassified-142) - [0.4.2-alpha.1 (2016-09-01)](#042-alpha1-2016-09-01) - - [Unclassified](#unclassified-141) + - [Unclassified](#unclassified-143) - [0.4.2-alpha (2016-09-01)](#042-alpha-2016-09-01) - - [Documentation](#documentation-111) - - [Unclassified](#unclassified-142) + - [Documentation](#documentation-114) + - [Unclassified](#unclassified-144) - [0.4.1 (2016-08-18)](#041-2016-08-18) - - [Unclassified](#unclassified-143) + - [Unclassified](#unclassified-145) - [0.3.1 (2016-08-17)](#031-2016-08-17) - - [Documentation](#documentation-112) - - [Unclassified](#unclassified-144) + - [Documentation](#documentation-115) + - [Unclassified](#unclassified-146) - [0.3.0 (2016-08-09)](#030-2016-08-09) - - [Unclassified](#unclassified-145) + - [Unclassified](#unclassified-147) - [0.2.0 (2016-08-09)](#020-2016-08-09) - - [Documentation](#documentation-113) - - [Unclassified](#unclassified-146) + - [Documentation](#documentation-116) + - [Unclassified](#unclassified-148) -# [0.0.0](https://github.com/ory/hydra/compare/v2.0.2...v0.0.0) (2022-12-07) +# [0.0.0](https://github.com/ory/hydra/compare/v2.2.0...v0.0.0) (2024-08-22) +## Breaking Changes + +Deleting consents no longer returns 404 in certain edge cases but instead always 204. + ### Bug Fixes -* Add `client_id` and `client_secret` to `revokeOAuth2Token` ([#3373](https://github.com/ory/hydra/issues/3373)) ([93bac07](https://github.com/ory/hydra/commit/93bac074b3f7bd347c329377bf8c14aed7f43c00)) -* Introspect command CLI example ([#3353](https://github.com/ory/hydra/issues/3353)) ([4ee4456](https://github.com/ory/hydra/commit/4ee4456d884ef6925a74c26768537e9a1ca8a9a6)) -* Prevent multiple redirections to post logout url ([#3366](https://github.com/ory/hydra/issues/3366)) ([50666b9](https://github.com/ory/hydra/commit/50666b96ef28a019f5dfd9758f50c0023ad4ae05)), closes [#3342](https://github.com/ory/hydra/issues/3342) -* Strip `public` from schema ([#3374](https://github.com/ory/hydra/issues/3374)) ([3831b44](https://github.com/ory/hydra/commit/3831b4482a525cf67b519064bfefd45fe9f3cbd3)), closes [#3367](https://github.com/ory/hydra/issues/3367) +* Broken JSON round-tripping for custom claims ([b36b701](https://github.com/ory/hydra/commit/b36b701026d7d7324b0b04529f134d3ed1eb9eb7)): + + Adding custom claims with numerical types (think JavaScript Number) previously did not + round-trip through Hydra correctly. For example, passing UNIX timestamps in custom claims + would end up as floating points in exponential notation in the final token. That, in turn, + confused or broke downstream consumers of the token, including Kratos. + + Ref https://github.com/go-jose/go-jose/issues/144 + +* Correctly pass multiple token audiences and prompt parameters when performing the authorization code flow from the CLI ([#3736](https://github.com/ory/hydra/issues/3736)) ([632faef](https://github.com/ory/hydra/commit/632faef15228c2d0a2caedfc3d7c6a3782c2e131)) +* Do not iteratively delete records ([#3766](https://github.com/ory/hydra/issues/3766)) ([5ef20a2](https://github.com/ory/hydra/commit/5ef20a2a2bc91ccde79517667ae4bf4a36c833ba)): + + Resolves performance issues on some databases when deleting consent. + +* Do not retry sending responses ([#3764](https://github.com/ory/hydra/issues/3764)) ([1bbfdb5](https://github.com/ory/hydra/commit/1bbfdb56e55525c5bc0526726fa901cf10af59e4)) +* **docs:** Adjust note about SDK support on oauth2 flow endpoints ([#3812](https://github.com/ory/hydra/issues/3812)) ([d0e047c](https://github.com/ory/hydra/commit/d0e047ccc822972cf44ae6ec35c8f6e8507fe3ae)) +* Error log when RP responds with status code 204 ([#3731](https://github.com/ory/hydra/issues/3731)) ([153e4b5](https://github.com/ory/hydra/commit/153e4b56e6de645ee44e4e7833c32a3890e43c54)) +* Faster GetPublicKeys ([#3787](https://github.com/ory/hydra/issues/3787)) ([04c34aa](https://github.com/ory/hydra/commit/04c34aaf2e3c523f4658910d570de80de328d138)): + + GetPublicKeys used to fetch all keys in a set, even if they were actually not being used. This patch fixes that. + + + +* Incorrect context passthru ([fa50e3e](https://github.com/ory/hydra/commit/fa50e3e999ef962fb522dfa2f9a1f6ffa20848bf)) +* Incorrect indices ([#3778](https://github.com/ory/hydra/issues/3778)) ([cb0004b](https://github.com/ory/hydra/commit/cb0004b67b2818b3bca397e98c1bb5bcbb62296f)) +* Upgrade fosite and improve webhook integration ([#3727](https://github.com/ory/hydra/issues/3727)) ([89323e2](https://github.com/ory/hydra/commit/89323e24de470c2b0f3037e0cf8f99bc4373d4fd)) +* Use docker compose rather than docker-compose ([#3815](https://github.com/ory/hydra/issues/3815)) ([ffdfb73](https://github.com/ory/hydra/commit/ffdfb7362a8de6f6f0608879bf034602f01ea250)) +* Wrap authorize response in transaction ([#3763](https://github.com/ory/hydra/issues/3763)) ([5b106aa](https://github.com/ory/hydra/commit/5b106aadb0e71add56e3cc68e5a9e33cdb81dd39)) +* Wrap token handler in transaction ([#3730](https://github.com/ory/hydra/issues/3730)) ([67a85cc](https://github.com/ory/hydra/commit/67a85cc799b5c6ef278db93aba131e695fd761e9)) + +### Features + +* Add access token strategy parameter to cli ([#3718](https://github.com/ory/hydra/issues/3718)) ([7862dc3](https://github.com/ory/hydra/commit/7862dc337aba2899bdb945e94eb79d3ab3509202)), closes [#3717](https://github.com/ory/hydra/issues/3717) +* Add id parameter to create oauth2-client cli ([#3725](https://github.com/ory/hydra/issues/3725)) ([b372fd2](https://github.com/ory/hydra/commit/b372fd20169156efd7c34710f823e0c5b5dbf183)): + + Fixes https://github.com/ory/hydra/issues/3724 + +* Add Inspect option to registry ([2013450](https://github.com/ory/hydra/commit/2013450a9a55af26523554c3aa01fc5243573f2c)) +* Improve persistence logic ([#3756](https://github.com/ory/hydra/issues/3756)) ([50301e0](https://github.com/ory/hydra/commit/50301e0022ca64c9d0823544c7b664309620c70e)) + +### Unclassified + +* update doc example for get oauth2-client ([5e70cde](https://github.com/ory/hydra/commit/5e70cde872f74758e22e89466c5b41e54d475533)) + + +# [2.2.0](https://github.com/ory/hydra/compare/v2.2.0-pre.1...v2.2.0) (2024-02-12) + +![Ory Hydra 2.2.0](http://ory.sh/images/newsletter/hydra-2.2.0/banner.png) + +Ory Hydra, the OAuth2 and OpenID Connect server designed for web-scale deployments introduces its most advanced update with version 2.2! + +Want to check out Ory Hydra yourself? Try common OAuth2 flows in the [Ory OAuth2 Get Started guide](https://www.ory.sh/docs/getting-started/ory-network-oauth2)! + +This version significantly enhances performance, supporting six times more authorization flows than version 2.1, thanks to architectural improvements that minimize database interactions for login and consent processes. + +Key improvements include: + +- Enhanced integration with Ory Kratos, ensuring seamless synchronization of login and logout states across both services. Users logged out from Ory Hydra will automatically log out from Ory Kratos, enhancing security and user experience. +- The ability to bypass the logout consent screen for specific clients, streamlining the logout process. +- Simplified migration with the new feature to import OAuth2 Client IDs, making the transition to Ory Hydra smoother. +- Support for the OIDC Verifiable Credentials specification, expanding the server's capabilities in identity verification. + +Thank all contributors who have made this release available! + + + + + +### Bug Fixes + +* Return empty slice if requested_scope or audience is null ([#3711](https://github.com/ory/hydra/issues/3711)) ([65165e7](https://github.com/ory/hydra/commit/65165e77718b37ee720a493f2fb6be20e6b04af6)) + +### Code Generation + +* Pin v2.2.0 release commit ([57096be](https://github.com/ory/hydra/commit/57096be9befbde4a1436ef48338d253a248c91c4)) + + +# [2.2.0-pre.1](https://github.com/ory/hydra/compare/v2.2.0-rc.3...v2.2.0-pre.1) (2024-02-01) + +autogen: pin v2.2.0-pre.1 release commit + + + + + +### Bug Fixes + +* Correct id token type in token exchange response ([#3625](https://github.com/ory/hydra/issues/3625)) ([d1f9ba8](https://github.com/ory/hydra/commit/d1f9ba8edee45323e1f13dcf9c67eefbd524dc81)): + + Closes https://github.com/ory/client-go/issues/2 + +* Dropped persistence/sql test errors ([#3670](https://github.com/ory/hydra/issues/3670)) ([22f0119](https://github.com/ory/hydra/commit/22f0119ad300c1e09c03e966a3d3411e57db444f)) +* Handle logout double-submit gracefully ([#3675](https://github.com/ory/hydra/issues/3675)) ([5133cf9](https://github.com/ory/hydra/commit/5133cf972ecfca18d7799c00a7afeae6a4386fbf)) +* Handle subject mismatch gracefully ([#3619](https://github.com/ory/hydra/issues/3619)) ([af0d477](https://github.com/ory/hydra/commit/af0d477e0eb1e336b01fa8d1321e9dce098c82a8)): + + We now redirect to the original request URL if the subjects between + the remembered Hydra session and what was confirmed by the login + screen does not match. + +* Handle token hook auth config ([#3677](https://github.com/ory/hydra/issues/3677)) ([1a40833](https://github.com/ory/hydra/commit/1a40833e2c87c98541d053f7c54b38f791dbb448)): + + * fix: handle token hook auth config + + * fix: bump golangci-lint + +* Improved SSRF protection ([#3669](https://github.com/ory/hydra/issues/3669)) ([24c3be5](https://github.com/ory/hydra/commit/24c3be574a11a76e69f09a24754f20cf644b624c)) +* Incorrect down migration ([#3708](https://github.com/ory/hydra/issues/3708)) ([8812e0e](https://github.com/ory/hydra/commit/8812e0e67b1f192de4ab6819c8f2bb98e6a5b7a7)), closes [/github.com/ory/hydra/pull/3705#discussion_r1471514014](https://github.com//github.com/ory/hydra/pull/3705/issues/discussion_r1471514014) +* Remove required mark ([#3693](https://github.com/ory/hydra/issues/3693)) ([3a764a0](https://github.com/ory/hydra/commit/3a764a053a3d7eab698668cf63d387ea76c1db40)) +* Timeout in jwt-bearer grants when too many grants are available ([#3692](https://github.com/ory/hydra/issues/3692)) ([a748797](https://github.com/ory/hydra/commit/a748797761f5503b048df1b57bcc406f16cd40a3)) +* Verifiable credentials JWT format ([#3614](https://github.com/ory/hydra/issues/3614)) ([0176adc](https://github.com/ory/hydra/commit/0176adc17848ab1dd021910ea31202dbdcd51737)) + +### Code Generation + +* Pin v2.2.0-pre.1 release commit ([8168ee3](https://github.com/ory/hydra/commit/8168ee31161784b8a5e686a9a2c42f323e40b7bf)) + +### Documentation + +* Fix typo ([#3649](https://github.com/ory/hydra/issues/3649)) ([f0501d2](https://github.com/ory/hydra/commit/f0501d2cd7f30c550cc07f6f583118efc9f12a5f)) + +### Features + +* Add --skip-logout-consent flag to CLI ([#3709](https://github.com/ory/hydra/issues/3709)) ([f502d6e](https://github.com/ory/hydra/commit/f502d6e38747986cca2ce42b0854f194e85ed103)) +* Add authentication options to hooks ([#3633](https://github.com/ory/hydra/issues/3633)) ([5c8e792](https://github.com/ory/hydra/commit/5c8e7923ed22f6d231ca748bb76e4261a87afb08)) +* Add flag to export public keys ([#3684](https://github.com/ory/hydra/issues/3684)) ([62c006b](https://github.com/ory/hydra/commit/62c006b916351e7f74fb00e0006ea112801143d7)) +* Add missing index for jwk table ([#3691](https://github.com/ory/hydra/issues/3691)) ([39ee5e1](https://github.com/ory/hydra/commit/39ee5e1f0cfa7fae5c4f9e1663a930cb5b8c2bc9)) +* Add prompt=registration ([#3636](https://github.com/ory/hydra/issues/3636)) ([19857d2](https://github.com/ory/hydra/commit/19857d20b1d7d3b918de5388f17076de0660a6be)): + + Ory Hydra now supports a `registration` value for the `prompt` parameter of + the authorization request. When specifying `prompt=registration`, Ory Hydra + will redirect the user to the URL found under `urls.registration` + (instead of `urls.login`). + +* Add skip_logout_consent option to clients ([#3705](https://github.com/ory/hydra/issues/3705)) ([2a653e6](https://github.com/ory/hydra/commit/2a653e66803ddb03de02d981dbc8ea57b2ac0936)): + + Adds a special field which disables the logout consent screen when performing OIDC logout. + +* Allow injecting extra fosite strategies ([#3646](https://github.com/ory/hydra/issues/3646)) ([88b0b7c](https://github.com/ory/hydra/commit/88b0b7cfdf1a1968bf3a720cb2e6640451e2956b)) +* Re-enable legacy client IDs ([#3628](https://github.com/ory/hydra/issues/3628)) ([5dd7d30](https://github.com/ory/hydra/commit/5dd7d306ba8181b1fff1225d056a2ee69183392e)): + + This patch changes the primary key of the `hydra_client` table. We do not expect issues, as that table is probably not overly huge in any deployment. We do however highly recommend to test the migration performance on a staging environment with a similar database setup. + +* Remove flow cookie ([#3639](https://github.com/ory/hydra/issues/3639)) ([cde3a30](https://github.com/ory/hydra/commit/cde3a30a92bc30cf072763503e9780a79ba44e43)): + + This patch removes the flow cookie. All information is already tracked in the request query parameters as part of the {login|consent}_{challenge|verifier}. + +* Remove login session cookie during consent flow ([#3667](https://github.com/ory/hydra/issues/3667)) ([5f41949](https://github.com/ory/hydra/commit/5f41949ad209c90d114dc427bd6ccde5e08f05da)) +* Support multiple token URLs ([#3676](https://github.com/ory/hydra/issues/3676)) ([95cc273](https://github.com/ory/hydra/commit/95cc2735ed18374cc01d625c66417e42b600778d)) + + +# [2.2.0-rc.3](https://github.com/ory/hydra/compare/v2.2.0-pre.0...v2.2.0-rc.3) (2023-08-16) + +Introduces logout compatibility with Ory Kratos. + + + + + +### Bug Fixes + +* Add exceptions for internal IP addresses ([#3608](https://github.com/ory/hydra/issues/3608)) ([1f1121c](https://github.com/ory/hydra/commit/1f1121caef6dd2c99c2ab551bfeb82e3cd2d8cf2)) +* Add kid to verifiable credential header ([#3606](https://github.com/ory/hydra/issues/3606)) ([9f1c8d1](https://github.com/ory/hydra/commit/9f1c8d192004e0e7d7f5c3383d4dd1df222dec81)) +* Deflake ttl test ([6741a49](https://github.com/ory/hydra/commit/6741a49f7b4d55a270f3eb968921894b1e5f2989)) +* Docker build ([#3609](https://github.com/ory/hydra/issues/3609)) ([01ff9da](https://github.com/ory/hydra/commit/01ff9da87e231a3cef8933c16a28ed425daa3355)) +* Enable CORS with hot-reloaded origins ([#3601](https://github.com/ory/hydra/issues/3601)) ([6f592fc](https://github.com/ory/hydra/commit/6f592fc8425887fb403516cbb03838b63f85f87e)) +* Only query access tokens by hashed signature ([a21e945](https://github.com/ory/hydra/commit/a21e94519416cc7801995b0804696348b18fa844)) +* Racy random string generation ([#3555](https://github.com/ory/hydra/issues/3555)) ([1b26c4c](https://github.com/ory/hydra/commit/1b26c4cb96400b333fe214d2da892fc045bbc69f)) +* Reject invalid JWKS in client configuration / dependency cleanup and bump ([#3603](https://github.com/ory/hydra/issues/3603)) ([1d73d83](https://github.com/ory/hydra/commit/1d73d83eb03e4ceef6edb4bd0738959007053118)) +* Restore ability to override auth and token urls for exemplary app ([#3590](https://github.com/ory/hydra/issues/3590)) ([dfb129a](https://github.com/ory/hydra/commit/dfb129a5b7c8ae01e1c490fce1a127697abc7bee)) +* Return proper error when the grant request cannot be parsed ([#3558](https://github.com/ory/hydra/issues/3558)) ([26f2d34](https://github.com/ory/hydra/commit/26f2d34459f55444e880e6e27e081c002d630246)) +* Use correct tracer in middleware ([#3567](https://github.com/ory/hydra/issues/3567)) ([807cbd2](https://github.com/ory/hydra/commit/807cbd209af376b9b2d18c278cc927d1c43e6865)) + +### Code Generation + +* Pin v2.2.0-rc.3 release commit ([ad8a4ba](https://github.com/ory/hydra/commit/ad8a4bab63b352c0b259a97d7b3f23247b0238b1)) + +### Features + +* Add `hydra migrate status` subcommand ([#3579](https://github.com/ory/hydra/issues/3579)) ([749eb8d](https://github.com/ory/hydra/commit/749eb8db40fb8b2d6333d917fac6c25b6e5574ef)) +* Add more resolution to events and collect client metrics ([#3568](https://github.com/ory/hydra/issues/3568)) ([466e66b](https://github.com/ory/hydra/commit/466e66bd1df7bf589c5a74ad5be399b1eaa80d9b)) +* Add state override ([b8b9154](https://github.com/ory/hydra/commit/b8b9154077963492dad3ed0350a4d93d09a95602)) +* Add support for OIDC VC ([#3575](https://github.com/ory/hydra/issues/3575)) ([219a7c0](https://github.com/ory/hydra/commit/219a7c068fa0ec423923f157553f430c80934c45)): + + This adds initial support for issuing verifiable credentials + as specified in https://openid.net/specs/openid-connect-userinfo-vc-1_0.html. + + Because the spec is still in draft, public identifiers are + suffixed with `draft_00`. + +* Allow additional SQL migrations ([#3587](https://github.com/ory/hydra/issues/3587)) ([8900cbb](https://github.com/ory/hydra/commit/8900cbb770d6f39a5c3322fce488675ca6d0138a)) +* Allow Go migrations ([#3602](https://github.com/ory/hydra/issues/3602)) ([8eed306](https://github.com/ory/hydra/commit/8eed306800fa330a1cda752dbb11ddf09faf25ad)) +* Allow to disable claim mirroring ([#3563](https://github.com/ory/hydra/issues/3563)) ([c72a316](https://github.com/ory/hydra/commit/c72a31641ee79f090a2ac1b64a276be58312b2ee)): + + This PR introduces another config option called `oauth2:mirror_top_level_claims` which may be used to disable the mirroring of custom claims into the `ext` claim of the jwt. + This new config option is an opt-in. If unused the behavior remains as-is to ensure backwards compatibility. + + Example: + + ```yaml + oauth2: + allowed_top_level_claims: + - test_claim + mirror_top_level_claims: false # -> this will prevent test_claim to be mirrored within ext + ``` + + Closes https://github.com/ory/hydra/issues/3348 + +* Bump fosite and add some more tracing ([0b56f53](https://github.com/ory/hydra/commit/0b56f53a491e165f68a53f013989328ce86928ba)) +* **cmd:** Add route that redirects to the auth code url ([4db6416](https://github.com/ory/hydra/commit/4db64161699e4301c003b2787baecae22c912c17)) +* Parallel generation of JSON web key set ([#3561](https://github.com/ory/hydra/issues/3561)) ([5bd9002](https://github.com/ory/hydra/commit/5bd9002db7baa2fe2c2529fee38825d66a68991f)) +* Propagate logout to identity provider ([#3596](https://github.com/ory/hydra/issues/3596)) ([c004fee](https://github.com/ory/hydra/commit/c004fee69497a5a0f8af5ccb6a2ab8d104fd9249)): + + * feat: propagate logout to identity provider + + This commit improves the integration between Hydra and Kratos when logging + out the user. + + This adds a new configuration key for configuring a Kratos admin URL. + Additionally, Kratos can send a session ID when accepting a login request. + If a session ID was specified and a Kratos admin URL was configured, + Hydra will disable the corresponding Kratos session through the admin API + if a frontchannel or backchannel logout was triggered. + + * fix: add special case for MySQL + + * chore: update sdk + + * chore: consistent naming + + * fix: cleanup persister + +* Support different jwt scope claim strategies ([#3531](https://github.com/ory/hydra/issues/3531)) ([45da11e](https://github.com/ory/hydra/commit/45da11e4fb4f0a2f939f11682c095b8dbfcddb78)) + + +# [2.2.0-pre.0](https://github.com/ory/hydra/compare/v2.2.0-rc.2...v2.2.0-pre.0) (2023-06-22) + +Test release + + + + + + +### Code Generation + +* Pin v2.2.0-pre.0 release commit ([116c1e8](https://github.com/ory/hydra/commit/116c1e89c423eebc333e2a9ff3e582090c5798a5)) + +### Features + +* Add distroless docker image ([#3539](https://github.com/ory/hydra/issues/3539)) ([c1e1a56](https://github.com/ory/hydra/commit/c1e1a569621d88365dceee7372ca49ecd119f939)) +* Add event tracing ([#3546](https://github.com/ory/hydra/issues/3546)) ([44ed0ac](https://github.com/ory/hydra/commit/44ed0ac89558bd83513e5240e8c937c908514d76)) + + +# [2.2.0-rc.2](https://github.com/ory/hydra/compare/v2.2.0-rc.1...v2.2.0-rc.2) (2023-06-13) + +This release optimizes the performance of authorization code grant flows by minimizing the number of database queries. We acheive this by storing the flow in an AEAD-encoded cookie and AEAD-encoded request parameters for the authentication and consent screens. + +BREAKING CHANGE: + +* The client that is used as part of the authorization grant flow is stored in the AEAD-encoding. Therefore, running flows will not observe updates to the client after they were started. +* Because the login and consent challenge values now include the AEAD-encoded flow, their size increased to around 1kB for a flow without any metadata (and increases linearly with the amount of metadata). Please adjust your ingress / gateway accordingly. + + + + + +### Bug Fixes + +* Version clash in apk install ([24ebdd3](https://github.com/ory/hydra/commit/24ebdd3feb302f655000a243dad032b04cf25afc)) + +### Code Generation + +* Pin v2.2.0-rc.2 release commit ([b183040](https://github.com/ory/hydra/commit/b183040a0d6c33abd4db01eb21a1bb0e141ea9ec)) + +### Features + +* Hot-reload Oauth2 CORS settings ([#3537](https://github.com/ory/hydra/issues/3537)) ([a8ecf80](https://github.com/ory/hydra/commit/a8ecf807b2c6bfa6cc2d8b474f527a2fda12daef)) +* Sqa metrics v2 ([#3533](https://github.com/ory/hydra/issues/3533)) ([3ec683d](https://github.com/ory/hydra/commit/3ec683d7cf582443f29bd93c4c88392b3ce692a4)) + + +# [2.2.0-rc.1](https://github.com/ory/hydra/compare/v2.1.2...v2.2.0-rc.1) (2023-06-12) + +This release optimizes the performance of authorization code grant flows by minimizing the number of database queries. We acheive this by storing the flow in an AEAD-encoded cookie and AEAD-encoded request parameters for the authentication and consent screens. + +BREAKING CHANGE: + +* The client that is used as part of the authorization grant flow is stored in the AEAD-encoding. Therefore, running flows will not observe updates to the client after they were started. +* Because the login and consent challenge values now include the AEAD-encoded flow, their size increased to around 1kB for a flow without any metadata (and increases linearly with the amount of metadata). Please adjust your ingress / gateway accordingly. + + + +## Breaking Changes + +* The client that is used as part of the authorization grant flow is stored in the AEAD-encoding. Therefore, running flows will not observe updates to the client after they were started. +* Because the login and consent challenge values now include the AEAD-encoded flow, their size increased to around 1kB for a flow without any metadata (and increases linearly with the amount of metadata). Please adjust your ingress / gateway accordingly. + + + +### Bug Fixes + +* Cockroach migration error when hydra upgrades v2 ([#3536](https://github.com/ory/hydra/issues/3536)) ([be6e005](https://github.com/ory/hydra/commit/be6e005e8eb245d3844eba133d1f78f9e21b0d0d)): + + Referring to issue https://github.com/ory/hydra/issues/3535 this PR is + intended to fix the Cockroach migration bug when upgrading Hydra from + v1.11.10 to v2. + + +### Code Generation + +* Pin v2.2.0-rc.1 release commit ([262ebbb](https://github.com/ory/hydra/commit/262ebbb5a7a585a26117a8c0fba6c257fc97b7b4)) + +### Features + +* Add metrics to disabled access log ([#3526](https://github.com/ory/hydra/issues/3526)) ([fc7af90](https://github.com/ory/hydra/commit/fc7af904407b27d1b5c0e5e62f82fd81ab81ecb2)) +* Stateless authorization code flow ([#3515](https://github.com/ory/hydra/issues/3515)) ([f29fe3a](https://github.com/ory/hydra/commit/f29fe3af97fb72061f2d6d7a2fc454cea5e870e9)): + + This patch optimizes the performance of authorization code grant flows by minimizing the number of database queries. We acheive this by storing the flow in an AEAD-encoded cookie and AEAD-encoded request parameters for the authentication and consent screens. + + +### Unclassified + +* Revert "fix: cockroach migration error when hydra upgrades v2 (#3536)" (#3542) ([4d8622f](https://github.com/ory/hydra/commit/4d8622fedcd54308c2e3a402a54f9f6eb751c9ce)), closes [#3536](https://github.com/ory/hydra/issues/3536) [#3542](https://github.com/ory/hydra/issues/3542): + + This reverts commit be6e005e8eb245d3844eba133d1f78f9e21b0d0d. + + + +# [2.1.2](https://github.com/ory/hydra/compare/v2.1.1...v2.1.2) (2023-05-24) + +We are excited to announce the next Ory Hydra release! This release includes the following important changes: + +- Fixed a memory leak in the OpenTelemetry implementation, improving overall memory usage and stability. +- Added a missing index for faster janitor cleanup, resulting in quicker and more efficient cleanup operations. +- Fixed a bug related to SameSite in dev mode, ensuring proper functionality and consistency in handling SameSite attributes during development. + +We appreciate your continuous support and feedback. Please feel free to reach out to us with any further suggestions or issues. + + + + + +### Bug Fixes + +* Add index on requested_at for refresh tokens and use it in janitor ([#3516](https://github.com/ory/hydra/issues/3516)) ([5b8e712](https://github.com/ory/hydra/commit/5b8e7121c49a0dfed6312b599a617e692f324fdb)) +* Disable health check request logs ([#3496](https://github.com/ory/hydra/issues/3496)) ([eddf7f3](https://github.com/ory/hydra/commit/eddf7f3867e8977e58d09681c583e99bca503448)) +* Do not use prepared SQL statements and bump deps ([#3506](https://github.com/ory/hydra/issues/3506)) ([31b9e66](https://github.com/ory/hydra/commit/31b9e663b183f8244d86ddd1ae9f55267e190a69)) +* Proper SameSite=None in dev mode ([#3502](https://github.com/ory/hydra/issues/3502)) ([5751fae](https://github.com/ory/hydra/commit/5751fae7b37a2692ad484c785356e702928f1b9b)) +* Sqa config values unified across projects ([#3490](https://github.com/ory/hydra/issues/3490)) ([1b1899e](https://github.com/ory/hydra/commit/1b1899e9472fecfbdeb07f5e99c27713b82478e5)) +* **sql:** Incorrect JWK query ([#3499](https://github.com/ory/hydra/issues/3499)) ([13ce0d6](https://github.com/ory/hydra/commit/13ce0d6f39febed83c6b1e10b45b0be2ed75a415)): + + `persister_grant_jwk` had an OR statement without bracket leading to not using the last part of the query. + + +### Code Generation + +* Pin v2.1.2 release commit ([d94ed6e](https://github.com/ory/hydra/commit/d94ed6e4486ee270d8903e6e9376134931a742d9)) + +### Documentation + +* Incorrect json output format example ([#3497](https://github.com/ory/hydra/issues/3497)) ([b71a36b](https://github.com/ory/hydra/commit/b71a36bf5c063a719a9e31ff348af594d87dc794)) + +### Features + +* Add --skip-consent flag to hydra cli ([#3492](https://github.com/ory/hydra/issues/3492)) ([083d518](https://github.com/ory/hydra/commit/083d518cf51240c8977f0d9226897a9886cfbb50)) + + +# [2.1.1](https://github.com/ory/hydra/compare/v2.1.0...v2.1.1) (2023-04-11) + +Resolve a regression in looking up access and refresh tokens. + + + + + +### Bug Fixes + +* Double-hashed access token signatures ([#3486](https://github.com/ory/hydra/issues/3486)) ([8720b25](https://github.com/ory/hydra/commit/8720b250b92b49c651d87f6e727beda31c227dfe)), closes [#3485](https://github.com/ory/hydra/issues/3485) + +### Code Generation + +* Pin v2.1.1 release commit ([6efae7c](https://github.com/ory/hydra/commit/6efae7cfa7430cecaa145e2e71958699a2394115)) + + +# [2.1.0](https://github.com/ory/hydra/compare/v2.1.0-pre.2...v2.1.0) (2023-04-06) + +We are excited to share this year's Q1 release of Ory Hydra: v2.1.0! + +Highlights: + +* Support for Datadog tracing (#3431). +* Ability to skip consent for trusted clients (#3451). +* Setting access token type in the OAuth2 Client is now possible (#3446). +* Revoke login sessions by SessionID (#3450). +* Session lifespan extended on session refresh (#3464). +* Token request hooks added for all grant types (#3427). +* Reduced SQL tracing noise (#3481). + +Don't want to run the upgrade yourself? Switch to [Ory Network](https://console.ory.sh/registration?flow=d1ae4761-3493-4dd9-b0ce-3200916b38aa)! + + + + + +### Bug Fixes + +* Reduce SQL tracing noise ([#3481](https://github.com/ory/hydra/issues/3481)) ([6e1f545](https://github.com/ory/hydra/commit/6e1f5454be3ff00b0016e3d72b121701ccd23625)) + +### Code Generation + +* Pin v2.1.0 release commit ([3649832](https://github.com/ory/hydra/commit/3649832421bff09b5e4c172b37dc61027dac0869)) + + +# [2.1.0-pre.2](https://github.com/ory/hydra/compare/v2.1.0-pre.1...v2.1.0-pre.2) (2023-04-03) + +autogen: pin v2.1.0-pre.2 release commit + + + + + +### Code Generation + +* Pin v2.1.0-pre.2 release commit ([3b1d87e](https://github.com/ory/hydra/commit/3b1d87e3a16dd4b4b55725c5c78eb062fefc8f2f)) + + +# [2.1.0-pre.1](https://github.com/ory/hydra/compare/v2.1.0-pre.0...v2.1.0-pre.1) (2023-04-03) + +autogen: pin v2.1.0-pre.1 release commit + + + + + +### Code Generation + +* Pin v2.1.0-pre.1 release commit ([2289e6b](https://github.com/ory/hydra/commit/2289e6b8159becde96b31fc99aa2a218631d70ea)) + + +# [2.1.0-pre.0](https://github.com/ory/hydra/compare/v2.0.3...v2.1.0-pre.0) (2023-03-31) + +autogen: pin v2.1.0-pre.0 release commit + + + + + +### Bug Fixes + +* Append /v2 to module path ([f56e5fa](https://github.com/ory/hydra/commit/f56e5fad74632c1f0c5f3768a0de8465f351a533)) +* Broken OIDC compliance images ([#3454](https://github.com/ory/hydra/issues/3454)) ([50bc1b4](https://github.com/ory/hydra/commit/50bc1b4267045a19845816af295b638179be9c2c)) +* Clean up unused code ([488f930](https://github.com/ory/hydra/commit/488f930e4f2c39386b1c1ff68dd60d1aaf968cb9)) +* Ensure RSA key length fullfills 4096bit requirement ([#2905](https://github.com/ory/hydra/issues/2905)) ([#3402](https://github.com/ory/hydra/issues/3402)) ([a663927](https://github.com/ory/hydra/commit/a6639277fcdee7ee2101bc6e40ab7facd7265d54)) +* Migration typo ([#3453](https://github.com/ory/hydra/issues/3453)) ([ed27c10](https://github.com/ory/hydra/commit/ed27c1016fe8f8fea5a99a0e2203552c3bdc0ab3)) +* No longer use separate public and private keys in HSM key manager ([#3401](https://github.com/ory/hydra/issues/3401)) ([375bd5a](https://github.com/ory/hydra/commit/375bd5a69c0ece3aea0714ab7374ff8d09672c10)) +* Pin nancy ([0156556](https://github.com/ory/hydra/commit/0156556bb35278fcbc416b02504bc04511c468a7)) +* Release issue ([115da11](https://github.com/ory/hydra/commit/115da11930ed3723c53a1334eca47fd5ab6160ac)) +* Support allowed_cors_origins with client_secret_post ([#3457](https://github.com/ory/hydra/issues/3457)) ([ffe4943](https://github.com/ory/hydra/commit/ffe49430e31eee98ace65e829be5db3188c8fd4b)), closes [#3456](https://github.com/ory/hydra/issues/3456) +* Use correct default value ([#3469](https://github.com/ory/hydra/issues/3469)) ([2796d53](https://github.com/ory/hydra/commit/2796d53798c3a2fa36738fe40d287f93480f08d7)), closes [#3420](https://github.com/ory/hydra/issues/3420) + +### Code Generation + +* Pin v2.1.0-pre.0 release commit ([61f342c](https://github.com/ory/hydra/commit/61f342c2d9f266774885cf1242db796cb671ecad)) + +### Documentation + +* Update security email ([#3465](https://github.com/ory/hydra/issues/3465)) ([751c8e8](https://github.com/ory/hydra/commit/751c8e8a2f7393c52cd395e899b8852595f8682a)) + +### Features + +* Add ability to revoke login sessions by SessionID ([#3450](https://github.com/ory/hydra/issues/3450)) ([b42482b](https://github.com/ory/hydra/commit/b42482b7260d4e1771d01fc719e8216f5961ce65)), closes [#3448](https://github.com/ory/hydra/issues/3448): + + API `revokeOAuth2LoginSessions` can now revoke a single session by a SessionID (`sid` claim in the id_token) and execute an OpenID Connect Back-channel logout. + +* Add session cookie path configuration ([#3475](https://github.com/ory/hydra/issues/3475)) ([af9fa81](https://github.com/ory/hydra/commit/af9fa81ac0b3a877fe1a67505b6ae54d4ef58c00)), closes [#3473](https://github.com/ory/hydra/issues/3473) +* Add token request hooks for all grant types ([#3427](https://github.com/ory/hydra/issues/3427)) ([9bdf225](https://github.com/ory/hydra/commit/9bdf225d8f04c0b16dcdc4bbcc2d7bebc7534b4d)), closes [#3244](https://github.com/ory/hydra/issues/3244): + + Added a generic token hook that is called for all grant types and includes `payload` with a single allowed value - `assertion` to cover the `jwt-bearer` grant type customization. + + The existing `refresh token hook` is left unchanged and is considered to be deprecated in favor of the new hook logic. The `refresh token hook` will at some point be removed. + +* Allow setting access token type in client ([#3446](https://github.com/ory/hydra/issues/3446)) ([a6beed4](https://github.com/ory/hydra/commit/a6beed4659febd0917379d6da1e51d8ef75bc859)): + + The access token type (`jwt` or `opaque`) can now be set in the client configuration. The value set here will overwrite the global value for all flows concerning that client. + +* Allow skipping consent for trusted clients ([#3451](https://github.com/ory/hydra/issues/3451)) ([4f65365](https://github.com/ory/hydra/commit/4f65365f14ea28f979ebab7eb9c3396cbb25d619)): + + This adds a new boolean parameter `skip_consent` to the admin APIs of + the OAuth clients. This parameter will be forwarded to the consent app + as `client.skip_consent`. + + It is up to the consent app to act on this parameter, but the canonical + implementation accepts the consent on the user's behalf, similar to + when `skip` is set. + +* Extend session lifespan on session refresh ([#3464](https://github.com/ory/hydra/issues/3464)) ([7511436](https://github.com/ory/hydra/commit/751143644dbc842c5928b1961d2c04d55b76b06b)), closes [#1690](https://github.com/ory/hydra/issues/1690) [#1557](https://github.com/ory/hydra/issues/1557) [#2246](https://github.com/ory/hydra/issues/2246) [#2848](https://github.com/ory/hydra/issues/2848): + + It is now possible to extend session lifespans when accepting login challenges. + +* Render complete config schema during CI ([#3433](https://github.com/ory/hydra/issues/3433)) ([ae3e781](https://github.com/ory/hydra/commit/ae3e7811ae2ba031fc4f1569a889d8b4ba0c96fd)): + + * chore: bump ory/x + + * chore: script to render the complete config + +* Support datadog tracing ([#3431](https://github.com/ory/hydra/issues/3431)) ([3ea014f](https://github.com/ory/hydra/commit/3ea014f98f72b1456909838e8f7c40ceade7b2f6)) + + +# [2.0.3](https://github.com/ory/hydra/compare/v2.0.2...v2.0.3) (2022-12-08) + +Bugfixes for migration and pagination regressions and a new endpoint. + + + + + +### Bug Fixes + +* Add `client_id` and `client_secret` to `revokeOAuth2Token` ([#3373](https://github.com/ory/hydra/issues/3373)) ([93bac07](https://github.com/ory/hydra/commit/93bac074b3f7bd347c329377bf8c14aed7f43c00)) +* Docker build ([48217bd](https://github.com/ory/hydra/commit/48217bd203af9467eae570b2c47c777a6c1e929b)) +* Introspect command CLI example ([#3353](https://github.com/ory/hydra/issues/3353)) ([4ee4456](https://github.com/ory/hydra/commit/4ee4456d884ef6925a74c26768537e9a1ca8a9a6)) +* Invalidate tokens with inconsistent state ([#3385](https://github.com/ory/hydra/issues/3385)) ([542ea77](https://github.com/ory/hydra/commit/542ea771c9740a1ebf5bc0006cb59e9eaff688d2)), closes [#3346](https://github.com/ory/hydra/issues/3346): + + This patch includes SQL migrations targeting environments which have not yet migrated to Ory Hydra 2.0. It removes inconsistent records which resolves issues during the migrations process. Please be aware that some users might be affected by this change. They might need to re-authorize certain apps. However, most active records should not be affected by this. + + Installations already on Ory Hydra 2.0 will not be affected by this change. + +* No longer auto-generate system secret ([c5fe043](https://github.com/ory/hydra/commit/c5fe0433be88dc3cbcd09b8c85c3a90819109681)): + + This patch changes Ory Hydra's behavior to no longer auto-generate a temporary secret when no global secret was set. The APIs now return an error instead. + + See https://github.com/ory/network/issues/185 + +* Prevent multiple redirections to post logout url ([#3366](https://github.com/ory/hydra/issues/3366)) ([50666b9](https://github.com/ory/hydra/commit/50666b96ef28a019f5dfd9758f50c0023ad4ae05)), closes [#3342](https://github.com/ory/hydra/issues/3342) +* Strip `public` from schema ([#3374](https://github.com/ory/hydra/issues/3374)) ([3831b44](https://github.com/ory/hydra/commit/3831b4482a525cf67b519064bfefd45fe9f3cbd3)), closes [#3367](https://github.com/ory/hydra/issues/3367) +* Token pagination ([#3384](https://github.com/ory/hydra/issues/3384)) ([e8d8de9](https://github.com/ory/hydra/commit/e8d8de9072fda61b6d651107005d12f7bac0cba7)), closes [#3362](https://github.com/ory/hydra/issues/3362) + +### Code Generation + +* Pin v2.0.3 release commit ([16831c5](https://github.com/ory/hydra/commit/16831c55c41e64dd73637e8e2ca8f22202fc7d87)) ### Features diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 4861c9d1844..9cebaf358e3 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -39,6 +39,16 @@ Examples of unacceptable behavior include: - Other conduct which could reasonably be considered inappropriate in a professional setting +## Open Source Community Support + +Ory Open source software is collaborative and based on contributions by +developers in the Ory community. There is no obligation from Ory to help with +individual problems. If Ory open source software is used in production in a +for-profit company or enterprise environment, we mandate a paid support contract +where Ory is obligated under their service level agreements (SLAs) to offer a +defined level of availability and responsibility. For more information about +paid support please contact us at sales@ory.sh. + ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0911efc6a8d..125600eec6d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -64,7 +64,7 @@ won't clash with Ory Hydra's direction. A great way to do this is via [a Contributors License Agreement?](https://cla-assistant.io/ory/hydra) - I would like updates about new versions of Ory Hydra. - [How are new releases announced?](https://ory.us10.list-manage.com/subscribe?u=ffb1a878e4ec6c0ed312a3480&id=f605a41b53) + [How are new releases announced?](https://www.ory.sh/l/sign-up-newsletter) ## How can I contribute? @@ -144,10 +144,12 @@ checklist to contribute an example: not get mixed up. 1. Add a descriptive prefix to commits. This ensures a uniform commit history and helps structure the changelog. Please refer to this - [list of prefixes for Hydra](https://github.com/ory/hydra/blob/master/.github/semantic.yml) - for an overview. + [Convential Commits configuration](https://github.com/ory/hydra/blob/master/.github/workflows/conventional_commits.yml) + for the list of accepted prefixes. You can read more about the Conventional + Commit specification + [at their site](https://www.conventionalcommits.org/en/v1.0.0/). 1. Create a `README.md` that explains how to use the example. (Use - [the README template](https://github.com/ory/examples/blob/master/_common/README)). + [the README template](https://github.com/ory/examples/blob/master/_common/README.md)). 1. Open a pull request and maintainers will review and merge your example. ## Contribute code @@ -172,8 +174,10 @@ request, go through this checklist: 1. Run `make format` 1. Add a descriptive prefix to commits. This ensures a uniform commit history and helps structure the changelog. Please refer to this - [list of prefixes for Hydra](https://github.com/ory/hydra/blob/master/.github/semantic.yml) - for an overview. + [Convential Commits configuration](https://github.com/ory/hydra/blob/master/.github/workflows/conventional_commits.yml) + for the list of accepted prefixes. You can read more about the Conventional + Commit specification + [at their site](https://www.conventionalcommits.org/en/v1.0.0/). If a pull request is not ready to be reviewed yet [it should be marked as a "Draft"](https://docs.github.com/en/github/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request). diff --git a/Makefile b/Makefile index 0ab06a3f542..75b912e0521 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,16 @@ SHELL=/bin/bash -o pipefail -export GO111MODULE := on -export PATH := .bin:${PATH} -export PWD := $(shell pwd) +export GO111MODULE := on +export PATH := .bin:${PATH} +export PWD := $(shell pwd) +export IMAGE_TAG := $(if $(IMAGE_TAG),$(IMAGE_TAG),latest) + +GOLANGCI_LINT_VERSION = 1.61.0 GO_DEPENDENCIES = github.com/ory/go-acc \ github.com/golang/mock/mockgen \ - github.com/go-swagger/go-swagger/cmd/swagger \ - github.com/go-bindata/go-bindata/go-bindata + golang.org/x/tools/cmd/goimports \ + github.com/go-swagger/go-swagger/cmd/swagger define make-go-dependency # go install is responsible for not re-building when the code hasn't changed @@ -15,8 +18,9 @@ define make-go-dependency GOBIN=$(PWD)/.bin/ go install $1 endef -.bin/golangci-lint: Makefile - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b .bin v1.46.2 +.bin/golangci-lint-$(GOLANGCI_LINT_VERSION): + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b .bin v$(GOLANGCI_LINT_VERSION) + mv .bin/golangci-lint .bin/golangci-lint-$(GOLANGCI_LINT_VERSION) $(foreach dep, $(GO_DEPENDENCIES), $(eval $(call make-go-dependency, $(dep)))) @@ -34,25 +38,22 @@ node_modules: package-lock.json docs/cli: .bin/clidoc clidoc . -.bin/goimports: go.sum Makefile - GOBIN=$(shell pwd)/.bin go install golang.org/x/tools/cmd/goimports@latest - .bin/licenses: Makefile curl https://raw.githubusercontent.com/ory/ci/master/licenses/install | sh .bin/ory: Makefile - curl https://raw.githubusercontent.com/ory/meta/master/install.sh | bash -s -- -b .bin ory v0.1.48 + curl https://raw.githubusercontent.com/ory/meta/master/install.sh | bash -s -- -b .bin ory v0.2.2 touch .bin/ory .PHONY: lint -lint: .bin/golangci-lint - golangci-lint run -v ./... +lint: .bin/golangci-lint-$(GOLANGCI_LINT_VERSION) + .bin/golangci-lint-$(GOLANGCI_LINT_VERSION) run -v ./... # Runs full test suite including tests where databases are enabled .PHONY: test test: .bin/go-acc make test-resetdb - source scripts/test-env.sh && go-acc ./... -- -failfast -timeout=20m -tags sqlite,json1 + source scripts/test-env.sh && go-acc ./... -- -failfast -timeout=20m -tags sqlite,sqlite_omit_load_extension docker rm -f hydra_test_database_mysql docker rm -f hydra_test_database_postgres docker rm -f hydra_test_database_cockroach @@ -60,20 +61,17 @@ test: .bin/go-acc # Resets the test databases .PHONY: test-resetdb test-resetdb: node_modules - docker kill hydra_test_database_mysql || true - docker kill hydra_test_database_postgres || true - docker kill hydra_test_database_cockroach || true - docker rm -f hydra_test_database_mysql || true - docker rm -f hydra_test_database_postgres || true - docker rm -f hydra_test_database_cockroach || true - docker run --rm --name hydra_test_database_mysql --platform linux/amd64 -p 3444:3306 -e MYSQL_ROOT_PASSWORD=secret -d mysql:8.0.26 - docker run --rm --name hydra_test_database_postgres --platform linux/amd64 -p 3445:5432 -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=postgres -d postgres:11.8 - docker run --rm --name hydra_test_database_cockroach --platform linux/amd64 -p 3446:26257 -d cockroachdb/cockroach:v22.1.10 start-single-node --insecure + docker rm --force --volumes hydra_test_database_mysql || true + docker rm --force --volumes hydra_test_database_postgres || true + docker rm --force --volumes hydra_test_database_cockroach || true + docker run --rm --name hydra_test_database_mysql -p 3444:3306 -e MYSQL_ROOT_PASSWORD=secret -d mysql:8.0 + docker run --rm --name hydra_test_database_postgres -p 3445:5432 -e POSTGRES_PASSWORD=secret -e POSTGRES_DB=postgres -d postgres:16 + docker run --rm --name hydra_test_database_cockroach -p 3446:26257 -d cockroachdb/cockroach:latest-v24.1 start-single-node --insecure # Build local docker images .PHONY: docker docker: - docker build -f .docker/Dockerfile-build -t oryd/hydra:latest-sqlite . + DOCKER_BUILDKIT=1 DOCKER_CONTENT_TRUST=1 docker build --progress=plain -f .docker/Dockerfile-build -t oryd/hydra:${IMAGE_TAG}-sqlite . .PHONY: e2e e2e: node_modules test-resetdb @@ -86,11 +84,15 @@ e2e: node_modules test-resetdb # Runs tests in short mode, without database adapters .PHONY: quicktest quicktest: - go test -failfast -short -tags sqlite,json1 ./... + go test -failfast -short -tags sqlite,sqlite_omit_load_extension ./... .PHONY: quicktest-hsm quicktest-hsm: - docker build --progress=plain -f .docker/Dockerfile-hsm --target test-hsm . + DOCKER_BUILDKIT=1 DOCKER_CONTENT_TRUST=1 docker build --progress=plain -f .docker/Dockerfile-hsm --target test-hsm -t oryd/hydra:${IMAGE_TAG} --target test-hsm . + +.PHONY: refresh +refresh: + UPDATE_SNAPSHOTS=true go test -failfast -short -tags sqlite,sqlite_omit_load_extension ./... authors: # updates the AUTHORS file curl https://raw.githubusercontent.com/ory/ci/master/authors/authors.sh | env PRODUCT="Ory Hydra" bash @@ -113,12 +115,13 @@ mocks: .bin/mockgen .PHONY: sdk sdk: .bin/swagger .bin/ory node_modules swagger generate spec -m -o spec/swagger.json \ - -c github.com/ory/hydra/client \ - -c github.com/ory/hydra/consent \ - -c github.com/ory/hydra/health \ - -c github.com/ory/hydra/jwk \ - -c github.com/ory/hydra/oauth2 \ - -c github.com/ory/hydra/x \ + -c github.com/ory/hydra/v2/client \ + -c github.com/ory/hydra/v2/consent \ + -c github.com/ory/hydra/v2/flow \ + -c github.com/ory/hydra/v2/health \ + -c github.com/ory/hydra/v2/jwk \ + -c github.com/ory/hydra/v2/oauth2 \ + -c github.com/ory/hydra/v2/x \ -c github.com/ory/x/healthx \ -c github.com/ory/x/openapix \ -c github.com/ory/x/pagination \ @@ -142,8 +145,10 @@ sdk: .bin/swagger .bin/ory node_modules -g go \ -o "internal/httpclient" \ --git-user-id ory \ - --git-repo-id hydra-client-go \ - --git-host github.com + --git-repo-id hydra-client-go/v2 \ + --git-host github.com \ + --api-name-suffix "API" \ + --global-property apiTests=false make format @@ -172,15 +177,15 @@ $(MIGRATIONS_DST_DIR:%/=%-clean): $(MIGRATION_CLEAN_TARGETS) install-stable: HYDRA_LATEST=$$(git describe --abbrev=0 --tags) git checkout $$HYDRA_LATEST - GO111MODULE=on go install \ - -tags sqlite,json1 \ - -ldflags "-X github.com/ory/hydra/driver/config.Version=$$HYDRA_LATEST -X github.com/ory/hydra/driver/config.Date=`TZ=UTC date -u '+%Y-%m-%dT%H:%M:%SZ'` -X github.com/ory/hydra/driver/config.Commit=`git rev-parse HEAD`" \ + go install \ + -tags sqlite,sqlite_omit_load_extension \ + -ldflags "-X github.com/ory/hydra/v2/driver/config.Version=$$HYDRA_LATEST -X github.com/ory/hydra/v2/driver/config.Date=`TZ=UTC date -u '+%Y-%m-%dT%H:%M:%SZ'` -X github.com/ory/hydra/v2/driver/config.Commit=`git rev-parse HEAD`" \ . git checkout master .PHONY: install install: - GO111MODULE=on go install -tags sqlite,json1 . + go install -tags sqlite,sqlite_omit_load_extension . .PHONY: post-release post-release: .bin/yq diff --git a/README.md b/README.md index b8772d74ca2..5e41be64e22 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@

Chat | Discussions | - Newsletter

+ Newsletter

Guide | API Docs | Code Docs

- Support this project!

+ Support this project!

Work in Open Source, Ory is hiring!

@@ -36,6 +36,46 @@ provided. Ory Hydra can use [Ory Kratos](https://github.com/ory/kratos) as its identity server. +## Ory Hydra on the Ory Network + +The [Ory Network](https://www.ory.sh/cloud) is the fastest, most secure and +worry-free way to use Ory's Services. **Ory OAuth2 & OpenID Connect** is powered +by the Ory Hydra open source federation server, and it's fully API-compatible. + +The Ory Network provides the infrastructure for modern end-to-end security: + +- Identity & credential management scaling to billions of users and devices +- Registration, Login and Account management flows for passkey, biometric, + social, SSO and multi-factor authentication +- **Pre-built login, registration and account management pages and components** +- **OAuth2 and OpenID provider for single sign on, API access and + machine-to-machine authorization** +- Low-latency permission checks based on Google's Zanzibar model and with + built-in support for the Ory Permission Language + +It's fully managed, highly available, developer & compliance-friendly! + +- GDPR-friendly secure storage with data locality +- Cloud-native APIs, compatible with Ory's Open Source servers +- Comprehensive admin tools with the web-based Ory Console and the Ory Command + Line Interface (CLI) +- Extensive documentation, straightforward examples and easy-to-follow guides +- Fair, usage-based [pricing](https://www.ory.sh/pricing) + +Sign up for a +[**free developer account**](https://console.ory.sh/registration?utm_source=github&utm_medium=banner&utm_campaign=kratos-readme) +today! + +## Ory Network Hybrid Support Plan + +Ory offers a support plan for Ory Network Hybrid, including Ory on private cloud +deployments. If you have a self-hosted solution and would like help, consider a +support plan! The team at Ory has years of experience in cloud computing. Ory's +offering is the only official program for qualified support from the +maintainers. For more information see the +**[website](https://www.ory.sh/support/)** or +**[book a meeting](https://www.ory.sh/contact/)**! + ## Get Started You can use @@ -171,20 +211,17 @@ authentication. The Ory community stands on the shoulders of individuals, companies, and -maintainers. We thank everyone involved - from submitting bug reports and -feature requests, to contributing patches, to sponsoring our work. Our community -is 1000+ strong and growing rapidly. The Ory stack protects 16.000.000.000+ API -requests every month with over 250.000+ active service nodes. We would have -never been able to achieve this without each and everyone of you! +maintainers. The Ory team thanks everyone involved - from submitting bug reports +and feature requests, to contributing patches and documentation. The Ory +community counts more than 33.000 members and is growing rapidly. The Ory stack +protects 60.000.000.000+ API requests every month with over 400.000+ active +service nodes. None of this would have been possible without each and everyone +of you! The following list represents companies that have accompanied us along the way and that have made outstanding contributions to our ecosystem. _If you think that your company deserves a spot here, reach out to -office-muc@ory.sh now_! - -**Please consider giving back by becoming a sponsor of our open source work on -Patreon or -Open Collective.** +office@ory.sh now_! @@ -197,7 +234,7 @@ that your company deserves a spot here, reach out to - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + +
SponsorAdopter * Raspberry PI Foundation @@ -208,7 +245,7 @@ that your company deserves a spot here, reach out to raspberrypi.org
ContributorAdopter * Kyma Project @@ -219,7 +256,7 @@ that your company deserves a spot here, reach out to kyma-project.io
SponsorAdopter * Tulip @@ -230,7 +267,7 @@ that your company deserves a spot here, reach out to tulip.com
SponsorAdopter * Cashdeck / All My Funds @@ -241,7 +278,7 @@ that your company deserves a spot here, reach out to cashdeck.com.au
ContributorAdopter * Hootsuite @@ -384,7 +421,7 @@ that your company deserves a spot here, reach out to nortal.com
SponsorAdopter * OrderMyGear @@ -395,7 +432,7 @@ that your company deserves a spot here, reach out to ordermygear.com
SponsorAdopter * Spiri.bo @@ -406,7 +443,7 @@ that your company deserves a spot here, reach out to spiri.bo
SponsorAdopter * Strivacity @@ -538,22 +575,59 @@ that your company deserves a spot here, reach out to dyrector.io
Adopter *Stackspin + + + stackspin.net + + stackspin.net
Adopter *Amplitude + + + amplitude.com + + amplitude.com
Adopter *Pinniped + + + pinniped.dev + + pinniped.dev
Adopter *Pvotal + + + pvotal.tech + + pvotal.tech
-We also want to thank all individual contributors +Many thanks to all individual contributors -as well as all of our backers - - - -and past & current supporters (in alphabetical order) on -[Patreon](https://www.patreon.com/_ory): Alexander Alimovs, Billy, Chancy -Kennedy, Drozzy, Edwin Trejos, Howard Edidin, Ken Adler Oz Haven, Stefan Hans, -TheCrealm. - \* Uses one of Ory's major projects in production. @@ -687,8 +761,9 @@ with more details on cryptography and security concepts. Read ### Disclosing vulnerabilities If you think you found a security vulnerability, please refrain from posting it -publicly on the forums, the chat, or GitHub and send us an email to -[hi@ory.am](mailto:hi@ory.sh) instead. +publicly on the forums, the chat, or GitHub. You can find all info for +responsible disclosure in our +[security.txt](https://www.ory.sh/.well-known/security.txt). ## Benchmarks @@ -774,24 +849,24 @@ It is recommended to use the make file to run your tests using `make quicktest` **Please note**: All tests run against a sqlite in-memory database, thus it is required to use -the `-tags sqlite,json1` build tag. +the `-tags sqlite` build tag. Short tests run fairly quickly. You can either test all of the code at once: ```shell script -go test -v -failfast -short -tags sqlite,json1 ./... +go test -v -failfast -short -tags sqlite ./... ``` or test just a specific module: ```shell script -go test -v -failfast -short -tags sqlite,json1 ./client +go test -v -failfast -short -tags sqlite ./client ``` or a specific test: ```shell script -go test -v -failfast -short -tags sqlite,json1 -run ^TestName$ ./... +go test -v -failfast -short -tags sqlite -run ^TestName$ ./... ``` ##### Regular Tests diff --git a/SECURITY.md b/SECURITY.md index 7a05c1cfc62..6104514805c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,30 +1,56 @@ - - - -- [Security Policy](#security-policy) - - [Supported Versions](#supported-versions) - - [Reporting a Vulnerability](#reporting-a-vulnerability) - - - -# Security Policy - -## Supported Versions - -We release patches for security vulnerabilities. Which versions are eligible for -receiving such patches depends on the CVSS v3.0 Rating: - -| CVSS v3.0 | Supported Versions | -| --------- | ----------------------------------------- | -| 9.0-10.0 | Releases within the previous three months | -| 4.0-8.9 | Most recent release | +# Ory Security Policy + +This policy outlines Ory's security commitments and practices for users across +different licensing and deployment models. + +To learn more about Ory's security service level agreements (SLAs) and +processes, please [contact us](https://www.ory.sh/contact/). + +## Ory Network Users + +- **Security SLA:** Ory addresses vulnerabilities in the Ory Network according + to the following guidelines: + - Critical: Typically addressed within 14 days. + - High: Typically addressed within 30 days. + - Medium: Typically addressed within 90 days. + - Low: Typically addressed within 180 days. + - Informational: Addressed as necessary. + These timelines are targets and may vary based on specific circumstances. +- **Release Schedule:** Updates are deployed to the Ory Network as + vulnerabilities are resolved. +- **Version Support:** The Ory Network always runs the latest version, ensuring + up-to-date security fixes. + +## Ory Enterprise License Customers + +- **Security SLA:** Ory addresses vulnerabilities based on their severity: + - Critical: Typically addressed within 14 days. + - High: Typically addressed within 30 days. + - Medium: Typically addressed within 90 days. + - Low: Typically addressed within 180 days. + - Informational: Addressed as necessary. + These timelines are targets and may vary based on specific circumstances. +- **Release Schedule:** Updates are made available as vulnerabilities are + resolved. Ory works closely with enterprise customers to ensure timely updates + that align with their operational needs. +- **Version Support:** Ory may provide security support for multiple versions, + depending on the terms of the enterprise agreement. + +## Apache 2.0 License Users + +- **Security SLA:** Ory does not provide a formal SLA for security issues under + the Apache 2.0 License. +- **Release Schedule:** Releases prioritize new functionality and include fixes + for known security vulnerabilities at the time of release. While major + releases typically occur one to two times per year, Ory does not guarantee a + fixed release schedule. +- **Version Support:** Security patches are only provided for the latest release + version. ## Reporting a Vulnerability -Please report (suspected) security vulnerabilities to -**[security@ory.sh](mailto:security@ory.sh)**. You will receive a response from -us within 48 hours. If the issue is confirmed, we will release a patch as soon -as possible depending on complexity but historically within a few days. +For details on how to report security vulnerabilities, visit our +[security policy documentation](https://www.ory.sh/docs/ecosystem/security). diff --git a/aead/aead.go b/aead/aead.go new file mode 100644 index 00000000000..a3cb8b89ffe --- /dev/null +++ b/aead/aead.go @@ -0,0 +1,28 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package aead + +import ( + "context" + + "github.com/ory/fosite" +) + +// Cipher provides AEAD (authenticated encryption with associated data). The +// ciphertext is returned base64url-encoded. +type Cipher interface { + // Encrypt encrypts and encodes the given plaintext, optionally using + // additiona data. + Encrypt(ctx context.Context, plaintext, additionalData []byte) (ciphertext string, err error) + + // Decrypt decodes, decrypts, and verifies the plaintext and additional data + // from the ciphertext. The ciphertext must be given in the form as returned + // by Encrypt. + Decrypt(ctx context.Context, ciphertext string, additionalData []byte) (plaintext []byte, err error) +} + +type Dependencies interface { + fosite.GlobalSecretProvider + fosite.RotatedGlobalSecretsProvider +} diff --git a/aead/aead_test.go b/aead/aead_test.go new file mode 100644 index 00000000000..4cb93f5c3e7 --- /dev/null +++ b/aead/aead_test.go @@ -0,0 +1,154 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package aead_test + +import ( + "context" + "crypto/rand" + "fmt" + "io" + "testing" + + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + + "github.com/pborman/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func secret(t *testing.T) string { + bytes := make([]byte, 32) + _, err := io.ReadFull(rand.Reader, bytes) + require.NoError(t, err) + return fmt.Sprintf("%X", bytes) +} + +func TestAEAD(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + name string + new func(aead.Dependencies) aead.Cipher + }{ + {"AES-GCM", func(d aead.Dependencies) aead.Cipher { return aead.NewAESGCM(d) }}, + {"XChaChaPoly", func(d aead.Dependencies) aead.Cipher { return aead.NewXChaCha20Poly1305(d) }}, + } { + tc := tc + + t.Run("cipher="+tc.name, func(t *testing.T) { + NewCipher := tc.new + + t.Run("case=without-rotation", func(t *testing.T) { + t.Parallel() + ctx := context.Background() + c := internal.NewConfigurationWithDefaults() + c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t)}) + a := NewCipher(c) + + plain := []byte(uuid.New()) + ct, err := a.Encrypt(ctx, plain, nil) + assert.NoError(t, err) + + ct2, err := a.Encrypt(ctx, plain, nil) + assert.NoError(t, err) + assert.NotEqual(t, ct, ct2, "ciphertexts for the same plaintext must be different each time") + + res, err := a.Decrypt(ctx, ct, nil) + assert.NoError(t, err) + assert.Equal(t, plain, res) + }) + + t.Run("case=wrong-secret", func(t *testing.T) { + t.Parallel() + ctx := context.Background() + c := internal.NewConfigurationWithDefaults() + c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t)}) + a := NewCipher(c) + + ct, err := a.Encrypt(ctx, []byte(uuid.New()), nil) + require.NoError(t, err) + + c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t)}) + _, err = a.Decrypt(ctx, ct, nil) + require.Error(t, err) + }) + + t.Run("case=with-rotation", func(t *testing.T) { + t.Parallel() + ctx := context.Background() + c := internal.NewConfigurationWithDefaults() + old := secret(t) + c.MustSet(ctx, config.KeyGetSystemSecret, []string{old}) + a := NewCipher(c) + + plain := []byte(uuid.New()) + ct, err := a.Encrypt(ctx, plain, nil) + require.NoError(t, err) + + // Sets the old secret as a rotated secret and creates a new one. + c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t), old}) + res, err := a.Decrypt(ctx, ct, nil) + require.NoError(t, err) + assert.Equal(t, plain, res) + + // THis should also work when we re-encrypt the same plain text. + ct2, err := a.Encrypt(ctx, plain, nil) + require.NoError(t, err) + assert.NotEqual(t, ct2, ct) + + res, err = a.Decrypt(ctx, ct, nil) + require.NoError(t, err) + assert.Equal(t, plain, res) + }) + + t.Run("case=with-rotation-wrong-secret", func(t *testing.T) { + t.Parallel() + ctx := context.Background() + c := internal.NewConfigurationWithDefaults() + c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t)}) + a := NewCipher(c) + + plain := []byte(uuid.New()) + ct, err := a.Encrypt(ctx, plain, nil) + require.NoError(t, err) + + // When the secrets do not match, an error should be thrown during decryption. + c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t), secret(t)}) + _, err = a.Decrypt(ctx, ct, nil) + require.Error(t, err) + }) + + t.Run("suite=with additional data", func(t *testing.T) { + t.Parallel() + ctx := context.Background() + c := internal.NewConfigurationWithDefaults() + c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t)}) + a := NewCipher(c) + + plain := []byte(uuid.New()) + ct, err := a.Encrypt(ctx, plain, []byte("additional data")) + assert.NoError(t, err) + + t.Run("case=additional data matches", func(t *testing.T) { + res, err := a.Decrypt(ctx, ct, []byte("additional data")) + assert.NoError(t, err) + assert.Equal(t, plain, res) + }) + + t.Run("case=additional data does not match", func(t *testing.T) { + res, err := a.Decrypt(ctx, ct, []byte("wrong data")) + assert.Error(t, err) + assert.Nil(t, res) + }) + + t.Run("case=missing additional data", func(t *testing.T) { + res, err := a.Decrypt(ctx, ct, nil) + assert.Error(t, err) + assert.Nil(t, res) + }) + }) + }) + } +} diff --git a/aead/aesgcm.go b/aead/aesgcm.go new file mode 100644 index 00000000000..86ae12839ec --- /dev/null +++ b/aead/aesgcm.go @@ -0,0 +1,126 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package aead + +import ( + "context" + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "io" + + "github.com/pkg/errors" + + "github.com/ory/x/errorsx" +) + +type AESGCM struct { + c Dependencies +} + +func NewAESGCM(c Dependencies) *AESGCM { + return &AESGCM{c: c} +} + +func aeadKey(key []byte) *[32]byte { + var result [32]byte + copy(result[:], key[:32]) + return &result +} + +func (c *AESGCM) Encrypt(ctx context.Context, plaintext, additionalData []byte) (string, error) { + key, err := encryptionKey(ctx, c.c, 32) + if err != nil { + return "", err + } + + ciphertext, err := aesGCMEncrypt(plaintext, aeadKey(key), additionalData) + if err != nil { + return "", errorsx.WithStack(err) + } + + return base64.URLEncoding.EncodeToString(ciphertext), nil +} + +func (c *AESGCM) Decrypt(ctx context.Context, ciphertext string, aad []byte) (plaintext []byte, err error) { + msg, err := base64.URLEncoding.DecodeString(ciphertext) + if err != nil { + return nil, errorsx.WithStack(err) + } + + keys, err := allKeys(ctx, c.c) + if err != nil { + return nil, errorsx.WithStack(err) + } + + for _, key := range keys { + if plaintext, err = c.decrypt(msg, key, aad); err == nil { + return plaintext, nil + } + } + + return nil, err +} + +func (c *AESGCM) decrypt(ciphertext []byte, key, additionalData []byte) ([]byte, error) { + if len(key) != 32 { + return nil, errors.Errorf("key must be exactly 32 long bytes, got %d bytes", len(key)) + } + + plaintext, err := aesGCMDecrypt(ciphertext, aeadKey(key), additionalData) + if err != nil { + return nil, errorsx.WithStack(err) + } + + return plaintext, nil +} + +// aesGCMEncrypt encrypts data using 256-bit AES-GCM. This both hides the content of +// the data and provides a check that it hasn't been altered. Output takes the +// form nonce|ciphertext|tag where '|' indicates concatenation. +func aesGCMEncrypt(plaintext []byte, key *[32]byte, additionalData []byte) (ciphertext []byte, err error) { + block, err := aes.NewCipher(key[:]) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonce := make([]byte, gcm.NonceSize()) + _, err = io.ReadFull(rand.Reader, nonce) + if err != nil { + return nil, err + } + + return gcm.Seal(nonce, nonce, plaintext, additionalData), nil +} + +// aesGCMDecrypt decrypts data using 256-bit AES-GCM. This both hides the content of +// the data and provides a check that it hasn't been altered. Expects input +// form nonce|ciphertext|tag where '|' indicates concatenation. +func aesGCMDecrypt(ciphertext []byte, key *[32]byte, additionalData []byte) (plaintext []byte, err error) { + block, err := aes.NewCipher(key[:]) + if err != nil { + return nil, err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + if len(ciphertext) < gcm.NonceSize() { + return nil, errors.New("malformed ciphertext") + } + + return gcm.Open(nil, + ciphertext[:gcm.NonceSize()], + ciphertext[gcm.NonceSize():], + additionalData, + ) +} diff --git a/aead/helpers.go b/aead/helpers.go new file mode 100644 index 00000000000..7acd06c3a0d --- /dev/null +++ b/aead/helpers.go @@ -0,0 +1,41 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package aead + +import ( + "context" + "fmt" +) + +func encryptionKey(ctx context.Context, d Dependencies, keySize int) ([]byte, error) { + keys, err := allKeys(ctx, d) + if err != nil { + return nil, err + } + + key := keys[0] + if len(key) != keySize { + return nil, fmt.Errorf("key must be exactly %d bytes long, got %d bytes", keySize, len(key)) + } + + return key, nil +} + +func allKeys(ctx context.Context, d Dependencies) ([][]byte, error) { + global, err := d.GetGlobalSecret(ctx) + if err != nil { + return nil, err + } + + rotated, err := d.GetRotatedGlobalSecrets(ctx) + if err != nil { + return nil, err + } + + keys := append([][]byte{global}, rotated...) + if len(keys) == 0 { + return nil, fmt.Errorf("at least one encryption key must be defined but none were") + } + return keys, nil +} diff --git a/aead/xchacha20.go b/aead/xchacha20.go new file mode 100644 index 00000000000..25b0076054d --- /dev/null +++ b/aead/xchacha20.go @@ -0,0 +1,86 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package aead + +import ( + "context" + "crypto/cipher" + cryptorand "crypto/rand" + "encoding/base64" + "fmt" + "math" + + "golang.org/x/crypto/chacha20poly1305" + + "github.com/ory/x/errorsx" +) + +var _ Cipher = (*XChaCha20Poly1305)(nil) + +type ( + XChaCha20Poly1305 struct { + d Dependencies + } +) + +func NewXChaCha20Poly1305(d Dependencies) *XChaCha20Poly1305 { + return &XChaCha20Poly1305{d} +} + +func (x *XChaCha20Poly1305) Encrypt(ctx context.Context, plaintext, additionalData []byte) (string, error) { + key, err := encryptionKey(ctx, x.d, chacha20poly1305.KeySize) + if err != nil { + return "", err + } + + aead, err := chacha20poly1305.NewX(key) + if err != nil { + return "", errorsx.WithStack(err) + } + + // Make sure the size calculation does not overflow. + if len(plaintext) > math.MaxInt-aead.NonceSize()-aead.Overhead() { + return "", errorsx.WithStack(fmt.Errorf("plaintext too large")) + } + + nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead()) + _, err = cryptorand.Read(nonce) + if err != nil { + return "", errorsx.WithStack(err) + } + + ciphertext := aead.Seal(nonce, nonce, plaintext, additionalData) + return base64.URLEncoding.EncodeToString(ciphertext), nil +} + +func (x *XChaCha20Poly1305) Decrypt(ctx context.Context, ciphertext string, aad []byte) (plaintext []byte, err error) { + msg, err := base64.URLEncoding.DecodeString(ciphertext) + if err != nil { + return nil, errorsx.WithStack(err) + } + + if len(msg) < chacha20poly1305.NonceSizeX { + return nil, errorsx.WithStack(fmt.Errorf("malformed ciphertext: too short")) + } + nonce, ciphered := msg[:chacha20poly1305.NonceSizeX], msg[chacha20poly1305.NonceSizeX:] + + keys, err := allKeys(ctx, x.d) + if err != nil { + return nil, errorsx.WithStack(err) + } + + var aead cipher.AEAD + for _, key := range keys { + aead, err = chacha20poly1305.NewX(key) + if err != nil { + continue + } + plaintext, err = aead.Open(nil, nonce, ciphered, aad) + if err == nil { + return plaintext, nil + } + } + + return nil, errorsx.WithStack(err) +} diff --git a/client/.snapshots/TestClientSDK-case=id_can_not_be_set.json b/client/.snapshots/TestClientSDK-case=id_can_not_be_set.json deleted file mode 100644 index 01826781960..00000000000 --- a/client/.snapshots/TestClientSDK-case=id_can_not_be_set.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "error": "The request was malformed or contained invalid parameters", - "error_description": "It is no longer possible to set an OAuth2 Client ID as a user. The system will generate a unique ID for you." -} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=0-description=basic_dynamic_client_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=0-description=basic_dynamic_client_registration.json index ddbf114aa9d..15cff8f77d2 100644 --- a/client/.snapshots/TestHandler-common-case=create_clients-case=0-description=basic_dynamic_client_registration.json +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=0-description=basic_dynamic_client_registration.json @@ -20,6 +20,8 @@ "token_endpoint_auth_method": "client_secret_basic", "userinfo_signed_response_alg": "none", "metadata": {}, + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": null, "authorization_code_grant_id_token_lifespan": null, "authorization_code_grant_refresh_token_lifespan": null, diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=1-description=basic_admin_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=1-description=basic_admin_registration.json index 06a5bf42d57..7956cbdb0bb 100644 --- a/client/.snapshots/TestHandler-common-case=create_clients-case=1-description=basic_admin_registration.json +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=1-description=basic_admin_registration.json @@ -23,6 +23,8 @@ "metadata": { "foo": "bar" }, + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": null, "authorization_code_grant_id_token_lifespan": null, "authorization_code_grant_refresh_token_lifespan": null, diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=6-description=basic_dynamic_client_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=1-description=basic_dynamic_client_registration.json similarity index 100% rename from client/.snapshots/TestHandler-common-case=create_clients-case=6-description=basic_dynamic_client_registration.json rename to client/.snapshots/TestHandler-common-case=create_clients-case=1-description=basic_dynamic_client_registration.json diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=10-description=empty_ID_succeeds.json b/client/.snapshots/TestHandler-common-case=create_clients-case=10-description=empty_ID_succeeds.json new file mode 100644 index 00000000000..bf89ac9fbb8 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=10-description=empty_ID_succeeds.json @@ -0,0 +1,35 @@ +{ + "client_name": "", + "client_secret": "averylongsecret", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "skip_consent": false, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=10-description=setting_skip_logout_consent_succeeds_for_admin_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=10-description=setting_skip_logout_consent_succeeds_for_admin_registration.json new file mode 100644 index 00000000000..80b03c03c1e --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=10-description=setting_skip_logout_consent_succeeds_for_admin_registration.json @@ -0,0 +1,36 @@ +{ + "client_name": "", + "client_secret": "2SKZkBf2P5g4toAXXnCrr~_sDM", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "skip_consent": false, + "skip_logout_consent": true, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=11-description=basic_dynamic_client_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=11-description=basic_dynamic_client_registration.json new file mode 100644 index 00000000000..7fb3d90325c --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=11-description=basic_dynamic_client_registration.json @@ -0,0 +1,4 @@ +{ + "error": "The request was malformed or contained invalid parameters", + "error_description": "It is not allowed to choose your own OAuth2 Client secret." +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=12-description=empty_ID_succeeds.json b/client/.snapshots/TestHandler-common-case=create_clients-case=12-description=empty_ID_succeeds.json new file mode 100644 index 00000000000..51c70ec465c --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=12-description=empty_ID_succeeds.json @@ -0,0 +1,36 @@ +{ + "client_name": "", + "client_secret": "averylongsecret", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "skip_consent": false, + "skip_logout_consent": null, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=empty_ID_succeeds.json b/client/.snapshots/TestHandler-common-case=create_clients-case=2-description=empty_ID_succeeds.json similarity index 100% rename from client/.snapshots/TestHandler-common-case=create_clients-case=7-description=empty_ID_succeeds.json rename to client/.snapshots/TestHandler-common-case=create_clients-case=2-description=empty_ID_succeeds.json diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=2-description=metadata_fails_for_dynamic_client_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=2-description=metadata_fails_for_dynamic_client_registration.json index 378b2243d22..b0ec7b11720 100644 --- a/client/.snapshots/TestHandler-common-case=create_clients-case=2-description=metadata_fails_for_dynamic_client_registration.json +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=2-description=metadata_fails_for_dynamic_client_registration.json @@ -1,4 +1,4 @@ { "error": "invalid_client_metadata", - "error_description": "The value of one of the Client Metadata fields is invalid and the server has rejected this request. Note that an Authorization Server MAY choose to substitute a valid value for any requested parameter of a Client's Metadata. metadata cannot be set for dynamic client registration'" + "error_description": "The value of one of the Client Metadata fields is invalid and the server has rejected this request. Note that an Authorization Server MAY choose to substitute a valid value for any requested parameter of a Client's Metadata. 'metadata' cannot be set for dynamic client registration" } diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=4-description=non-uuid_fails.json b/client/.snapshots/TestHandler-common-case=create_clients-case=4-description=non-uuid_fails.json deleted file mode 100644 index 01826781960..00000000000 --- a/client/.snapshots/TestHandler-common-case=create_clients-case=4-description=non-uuid_fails.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "error": "The request was malformed or contained invalid parameters", - "error_description": "It is no longer possible to set an OAuth2 Client ID as a user. The system will generate a unique ID for you." -} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=4-description=non-uuid_works.json b/client/.snapshots/TestHandler-common-case=create_clients-case=4-description=non-uuid_works.json new file mode 100644 index 00000000000..f2b7a739e55 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=4-description=non-uuid_works.json @@ -0,0 +1,38 @@ +{ + "client_id": "not-a-uuid", + "client_name": "", + "client_secret": "averylongsecret", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "registration_client_uri": "http://localhost:4444/oauth2/register/not-a-uuid", + "skip_consent": false, + "skip_logout_consent": null, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=5-description=setting_client_id_as_uuid_works.json b/client/.snapshots/TestHandler-common-case=create_clients-case=5-description=setting_client_id_as_uuid_works.json new file mode 100644 index 00000000000..8726a5b41a0 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=5-description=setting_client_id_as_uuid_works.json @@ -0,0 +1,38 @@ +{ + "client_id": "98941dac-f963-4468-8a23-9483b1e04e3c", + "client_name": "", + "client_secret": "not too short", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "registration_client_uri": "http://localhost:4444/oauth2/register/98941dac-f963-4468-8a23-9483b1e04e3c", + "skip_consent": false, + "skip_logout_consent": null, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=5-description=setting_client_id_fails.json b/client/.snapshots/TestHandler-common-case=create_clients-case=5-description=setting_client_id_fails.json deleted file mode 100644 index 01826781960..00000000000 --- a/client/.snapshots/TestHandler-common-case=create_clients-case=5-description=setting_client_id_fails.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "error": "The request was malformed or contained invalid parameters", - "error_description": "It is no longer possible to set an OAuth2 Client ID as a user. The system will generate a unique ID for you." -} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=6-description=setting_access_token_strategy_fails.json b/client/.snapshots/TestHandler-common-case=create_clients-case=6-description=setting_access_token_strategy_fails.json new file mode 100644 index 00000000000..a7db27c2f95 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=6-description=setting_access_token_strategy_fails.json @@ -0,0 +1,4 @@ +{ + "error": "The request was malformed or contained invalid parameters", + "error_description": "It is not allowed to choose your own access token strategy." +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=6-description=setting_skip_consent_fails_for_dynamic_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=6-description=setting_skip_consent_fails_for_dynamic_registration.json new file mode 100644 index 00000000000..4b65ecee3f1 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=6-description=setting_skip_consent_fails_for_dynamic_registration.json @@ -0,0 +1,4 @@ +{ + "error": "invalid_request", + "error_description": "'skip_consent' cannot be set for dynamic client registration" +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=basic_dynamic_client_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=basic_dynamic_client_registration.json new file mode 100644 index 00000000000..7fb3d90325c --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=basic_dynamic_client_registration.json @@ -0,0 +1,4 @@ +{ + "error": "The request was malformed or contained invalid parameters", + "error_description": "It is not allowed to choose your own OAuth2 Client secret." +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=setting_skip_consent_fails_for_dynamic_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=setting_skip_consent_fails_for_dynamic_registration.json new file mode 100644 index 00000000000..4b65ecee3f1 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=setting_skip_consent_fails_for_dynamic_registration.json @@ -0,0 +1,4 @@ +{ + "error": "invalid_request", + "error_description": "'skip_consent' cannot be set for dynamic client registration" +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=setting_skip_consent_suceeds_for_admin_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=setting_skip_consent_suceeds_for_admin_registration.json new file mode 100644 index 00000000000..96fa08bab16 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=7-description=setting_skip_consent_suceeds_for_admin_registration.json @@ -0,0 +1,35 @@ +{ + "client_name": "", + "client_secret": "2SKZkBf2P5g4toAXXnCrr~_sDM", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "skip_consent": true, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=basic_dynamic_client_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=basic_dynamic_client_registration.json new file mode 100644 index 00000000000..7fb3d90325c --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=basic_dynamic_client_registration.json @@ -0,0 +1,4 @@ +{ + "error": "The request was malformed or contained invalid parameters", + "error_description": "It is not allowed to choose your own OAuth2 Client secret." +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=empty_ID_succeeds.json b/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=empty_ID_succeeds.json new file mode 100644 index 00000000000..c21aa5b3710 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=empty_ID_succeeds.json @@ -0,0 +1,34 @@ +{ + "client_name": "", + "client_secret": "averylongsecret", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=setting_skip_consent_succeeds_for_admin_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=setting_skip_consent_succeeds_for_admin_registration.json new file mode 100644 index 00000000000..08bfd968627 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=setting_skip_consent_succeeds_for_admin_registration.json @@ -0,0 +1,36 @@ +{ + "client_name": "", + "client_secret": "2SKZkBf2P5g4toAXXnCrr~_sDM", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "skip_consent": true, + "skip_logout_consent": null, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=setting_skip_consent_suceeds_for_admin_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=setting_skip_consent_suceeds_for_admin_registration.json new file mode 100644 index 00000000000..96fa08bab16 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=8-description=setting_skip_consent_suceeds_for_admin_registration.json @@ -0,0 +1,35 @@ +{ + "client_name": "", + "client_secret": "2SKZkBf2P5g4toAXXnCrr~_sDM", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "skip_consent": true, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=9-description=basic_dynamic_client_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=9-description=basic_dynamic_client_registration.json new file mode 100644 index 00000000000..7fb3d90325c --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=9-description=basic_dynamic_client_registration.json @@ -0,0 +1,4 @@ +{ + "error": "The request was malformed or contained invalid parameters", + "error_description": "It is not allowed to choose your own OAuth2 Client secret." +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=9-description=empty_ID_succeeds.json b/client/.snapshots/TestHandler-common-case=create_clients-case=9-description=empty_ID_succeeds.json new file mode 100644 index 00000000000..bf89ac9fbb8 --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=9-description=empty_ID_succeeds.json @@ -0,0 +1,35 @@ +{ + "client_name": "", + "client_secret": "averylongsecret", + "redirect_uris": [ + "http://localhost:3000/cb" + ], + "grant_types": null, + "response_types": null, + "scope": "offline_access offline openid", + "audience": [], + "owner": "", + "policy_uri": "", + "allowed_cors_origins": [], + "tos_uri": "", + "client_uri": "", + "logo_uri": "", + "contacts": null, + "client_secret_expires_at": 0, + "subject_type": "public", + "jwks": {}, + "token_endpoint_auth_method": "client_secret_basic", + "userinfo_signed_response_alg": "none", + "metadata": {}, + "skip_consent": false, + "authorization_code_grant_access_token_lifespan": null, + "authorization_code_grant_id_token_lifespan": null, + "authorization_code_grant_refresh_token_lifespan": null, + "client_credentials_grant_access_token_lifespan": null, + "implicit_grant_access_token_lifespan": null, + "implicit_grant_id_token_lifespan": null, + "jwt_bearer_grant_access_token_lifespan": null, + "refresh_token_grant_id_token_lifespan": null, + "refresh_token_grant_access_token_lifespan": null, + "refresh_token_grant_refresh_token_lifespan": null +} diff --git a/client/.snapshots/TestHandler-common-case=create_clients-case=9-description=setting_skip_logout_consent_fails_for_dynamic_registration.json b/client/.snapshots/TestHandler-common-case=create_clients-case=9-description=setting_skip_logout_consent_fails_for_dynamic_registration.json new file mode 100644 index 00000000000..0d6da85531a --- /dev/null +++ b/client/.snapshots/TestHandler-common-case=create_clients-case=9-description=setting_skip_logout_consent_fails_for_dynamic_registration.json @@ -0,0 +1,4 @@ +{ + "error": "invalid_request", + "error_description": "'skip_logout_consent' cannot be set for dynamic client registration" +} diff --git a/client/.snapshots/TestHandler-common-case=fetching_existing_client-endpoint=admin.json b/client/.snapshots/TestHandler-common-case=fetching_existing_client-endpoint=admin.json index 483ce3be627..7ac99ae55c2 100644 --- a/client/.snapshots/TestHandler-common-case=fetching_existing_client-endpoint=admin.json +++ b/client/.snapshots/TestHandler-common-case=fetching_existing_client-endpoint=admin.json @@ -21,6 +21,8 @@ "token_endpoint_auth_method": "client_secret_basic", "userinfo_signed_response_alg": "none", "metadata": {}, + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": null, "authorization_code_grant_id_token_lifespan": null, "authorization_code_grant_refresh_token_lifespan": null, diff --git a/client/.snapshots/TestHandler-common-case=fetching_existing_client-endpoint=selfservice.json b/client/.snapshots/TestHandler-common-case=fetching_existing_client-endpoint=selfservice.json index 2c35fefcccf..6f80f123353 100644 --- a/client/.snapshots/TestHandler-common-case=fetching_existing_client-endpoint=selfservice.json +++ b/client/.snapshots/TestHandler-common-case=fetching_existing_client-endpoint=selfservice.json @@ -20,6 +20,8 @@ "jwks": {}, "token_endpoint_auth_method": "client_secret_basic", "userinfo_signed_response_alg": "none", + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": null, "authorization_code_grant_id_token_lifespan": null, "authorization_code_grant_refresh_token_lifespan": null, diff --git a/client/.snapshots/TestHandler-common-case=update_the_lifespans_of_an_OAuth2_client.json b/client/.snapshots/TestHandler-common-case=update_the_lifespans_of_an_OAuth2_client.json index 33549433840..4472241967d 100644 --- a/client/.snapshots/TestHandler-common-case=update_the_lifespans_of_an_OAuth2_client.json +++ b/client/.snapshots/TestHandler-common-case=update_the_lifespans_of_an_OAuth2_client.json @@ -21,6 +21,8 @@ "token_endpoint_auth_method": "client_secret_basic", "userinfo_signed_response_alg": "none", "metadata": {}, + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": "31h0m0s", "authorization_code_grant_id_token_lifespan": "32h0m0s", "authorization_code_grant_refresh_token_lifespan": "33h0m0s", diff --git a/client/.snapshots/TestHandler-common-case=updating_existing_client-endpoint=admin.json b/client/.snapshots/TestHandler-common-case=updating_existing_client-endpoint=admin.json index 070c4259ca5..12b431ec4b2 100644 --- a/client/.snapshots/TestHandler-common-case=updating_existing_client-endpoint=admin.json +++ b/client/.snapshots/TestHandler-common-case=updating_existing_client-endpoint=admin.json @@ -23,6 +23,8 @@ "token_endpoint_auth_method": "client_secret_basic", "userinfo_signed_response_alg": "none", "metadata": {}, + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": null, "authorization_code_grant_id_token_lifespan": null, "authorization_code_grant_refresh_token_lifespan": null, diff --git a/client/.snapshots/TestHandler-common-case=updating_existing_client-endpoint=dynamic_client_registration.json b/client/.snapshots/TestHandler-common-case=updating_existing_client-endpoint=dynamic_client_registration.json index 1b2a3fd88dd..24b0eecfeb7 100644 --- a/client/.snapshots/TestHandler-common-case=updating_existing_client-endpoint=dynamic_client_registration.json +++ b/client/.snapshots/TestHandler-common-case=updating_existing_client-endpoint=dynamic_client_registration.json @@ -22,6 +22,8 @@ "token_endpoint_auth_method": "client_secret_basic", "userinfo_signed_response_alg": "none", "metadata": {}, + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": null, "authorization_code_grant_id_token_lifespan": null, "authorization_code_grant_refresh_token_lifespan": null, diff --git a/client/.snapshots/TestHandler-common-case=updating_existing_client_fails_with_metadata_on_self_service.json b/client/.snapshots/TestHandler-common-case=updating_existing_client_fails_with_metadata_on_self_service.json index 4564a266965..d227f6befa1 100644 --- a/client/.snapshots/TestHandler-common-case=updating_existing_client_fails_with_metadata_on_self_service.json +++ b/client/.snapshots/TestHandler-common-case=updating_existing_client_fails_with_metadata_on_self_service.json @@ -1,7 +1,7 @@ { "body": { "error": "invalid_client_metadata", - "error_description": "The value of one of the Client Metadata fields is invalid and the server has rejected this request. Note that an Authorization Server MAY choose to substitute a valid value for any requested parameter of a Client's Metadata. metadata cannot be set for dynamic client registration'" + "error_description": "The value of one of the Client Metadata fields is invalid and the server has rejected this request. Note that an Authorization Server MAY choose to substitute a valid value for any requested parameter of a Client's Metadata. 'metadata' cannot be set for dynamic client registration" }, "status": 400 } diff --git a/client/.snapshots/TestHandler-create_client_registration_tokens-case=0-dynamic=true.json b/client/.snapshots/TestHandler-create_client_registration_tokens-case=0-dynamic=true.json index eadba6cabf9..281b21ecdbf 100644 --- a/client/.snapshots/TestHandler-create_client_registration_tokens-case=0-dynamic=true.json +++ b/client/.snapshots/TestHandler-create_client_registration_tokens-case=0-dynamic=true.json @@ -16,6 +16,8 @@ "subject_type": "", "jwks": {}, "metadata": {}, + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": null, "authorization_code_grant_id_token_lifespan": null, "authorization_code_grant_refresh_token_lifespan": null, diff --git a/client/.snapshots/TestHandler-create_client_registration_tokens-case=1-dynamic=false.json b/client/.snapshots/TestHandler-create_client_registration_tokens-case=1-dynamic=false.json index eadba6cabf9..281b21ecdbf 100644 --- a/client/.snapshots/TestHandler-create_client_registration_tokens-case=1-dynamic=false.json +++ b/client/.snapshots/TestHandler-create_client_registration_tokens-case=1-dynamic=false.json @@ -16,6 +16,8 @@ "subject_type": "", "jwks": {}, "metadata": {}, + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": null, "authorization_code_grant_id_token_lifespan": null, "authorization_code_grant_refresh_token_lifespan": null, diff --git a/client/.snapshots/TestHandler-create_client_registration_tokens-case=2-dynamic=false.json b/client/.snapshots/TestHandler-create_client_registration_tokens-case=2-dynamic=false.json index ea1bf694195..0718f2d2227 100644 --- a/client/.snapshots/TestHandler-create_client_registration_tokens-case=2-dynamic=false.json +++ b/client/.snapshots/TestHandler-create_client_registration_tokens-case=2-dynamic=false.json @@ -17,6 +17,8 @@ "subject_type": "", "jwks": {}, "metadata": {}, + "skip_consent": false, + "skip_logout_consent": null, "authorization_code_grant_access_token_lifespan": null, "authorization_code_grant_id_token_lifespan": null, "authorization_code_grant_refresh_token_lifespan": null, diff --git a/client/client.go b/client/client.go index 0a56836253c..52ee86b558d 100644 --- a/client/client.go +++ b/client/client.go @@ -4,18 +4,22 @@ package client import ( + "database/sql" + "strconv" "strings" "time" - "github.com/ory/x/stringsx" + "github.com/twmb/murmur3" "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" - jose "gopkg.in/square/go-jose.v2" // Naming the dependency jose is important for go-swagger to work, see https://github.com/go-swagger/go-swagger/issues/1587 + "github.com/ory/hydra/v2/driver/config" + + "github.com/go-jose/go-jose/v3" "github.com/ory/fosite" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/ory/x/sqlxx" ) @@ -31,13 +35,16 @@ var ( // // swagger:model oAuth2Client type Client struct { - ID uuid.UUID `json:"-" db:"pk"` NID uuid.UUID `db:"nid" faker:"-" json:"-"` // OAuth 2.0 Client ID // - // The ID is autogenerated and immutable. - LegacyClientID string `json:"client_id" db:"id"` + // The ID is immutable. If no ID is provided, a UUID4 will be generated. + ID string `json:"client_id" db:"id"` + + // DEPRECATED: This field is deprecated and will be removed. It serves + // no purpose except the database not complaining. + PK sql.NullString `json:"-" db:"pk" faker:"-"` // DEPRECATED: This field is deprecated and will be removed. It serves // no purpose except the database not complaining. @@ -195,10 +202,12 @@ type Client struct { // // Requested Client Authentication method for the Token Endpoint. The options are: // - // - `client_secret_post`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. - // - `client_secret_basic`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. + // - `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. + // - `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. // - `private_key_jwt`: Use JSON Web Tokens to authenticate the client. // - `none`: Used for public clients (native apps, mobile apps) which can not have secrets. + // + // default: client_secret_basic TokenEndpointAuthMethod string `json:"token_endpoint_auth_method,omitempty" db:"token_endpoint_auth_method" faker:"len=25"` // OAuth 2.0 Token Endpoint Signing Algorithm @@ -291,6 +300,21 @@ type Client struct { // RegistrationClientURI is the URL used to update, get, or delete the OAuth2 Client. RegistrationClientURI string `json:"registration_client_uri,omitempty" db:"-"` + // OAuth 2.0 Access Token Strategy + // + // AccessTokenStrategy is the strategy used to generate access tokens. + // Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens + // Setting the stragegy here overrides the global setting in `strategies.access_token`. + AccessTokenStrategy string `json:"access_token_strategy,omitempty" db:"access_token_strategy" faker:"-"` + + // SkipConsent skips the consent screen for this client. This field can only + // be set from the admin API. + SkipConsent bool `json:"skip_consent" db:"skip_consent" faker:"-"` + + // SkipLogoutConsent skips the logout consent screen for this client. This field can only + // be set from the admin API. + SkipLogoutConsent sqlxx.NullBool `json:"skip_logout_consent" db:"skip_logout_consent" faker:"-"` + Lifespans } @@ -392,7 +416,7 @@ func (c *Client) BeforeSave(_ *pop.Connection) error { } func (c *Client) GetID() string { - return stringsx.Coalesce(c.LegacyClientID, c.ID.String()) + return c.ID } func (c *Client) GetRedirectURIs() []string { @@ -404,7 +428,7 @@ func (c *Client) GetHashedSecret() []byte { } func (c *Client) GetScopes() fosite.Arguments { - return fosite.Arguments(strings.Fields(c.Scope)) + return strings.Fields(c.Scope) } func (c *Client) GetAudience() fosite.Arguments { @@ -532,3 +556,27 @@ func (c *Client) GetEffectiveLifespan(gt fosite.GrantType, tt fosite.TokenType, } return *cl } + +func (c *Client) GetAccessTokenStrategy() config.AccessTokenStrategyType { + // We ignore the error here, because the empty string will default to + // the global access token strategy. + s, _ := config.ToAccessTokenStrategyType(c.AccessTokenStrategy) + return s +} + +func AccessTokenStrategySource(client fosite.Client) config.AccessTokenStrategySource { + if source, ok := client.(config.AccessTokenStrategySource); ok { + return source + } + return nil +} + +func (c *Client) CookieSuffix() string { + return CookieSuffix(c) +} + +type IDer interface{ GetID() string } + +func CookieSuffix(client IDer) string { + return strconv.Itoa(int(murmur3.Sum32([]byte(client.GetID())))) +} diff --git a/client/client_test.go b/client/client_test.go index b51527a050c..d4cad720614 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -16,7 +16,7 @@ var _ fosite.Client = new(Client) func TestClient(t *testing.T) { c := &Client{ - LegacyClientID: "foo", + ID: "foo", RedirectURIs: []string{"foo"}, Scope: "foo bar", TokenEndpointAuthMethod: "none", diff --git a/client/error.go b/client/error.go index 45fd03925cf..d64c7a65ec7 100644 --- a/client/error.go +++ b/client/error.go @@ -20,3 +20,9 @@ var ErrInvalidRedirectURI = &fosite.RFC6749Error{ ErrorField: "invalid_redirect_uri", CodeField: http.StatusBadRequest, } + +var ErrInvalidRequest = &fosite.RFC6749Error{ + DescriptionField: "The request is missing a required parameter, includes an unsupported parameter value (other than grant type), repeats a parameter, includes multiple credentials, utilizes more than one mechanism for authenticating the client, or is otherwise malformed.", + ErrorField: "invalid_request", + CodeField: http.StatusBadRequest, +} diff --git a/client/handler.go b/client/handler.go index 5f020f23b4e..a3bcdc90985 100644 --- a/client/handler.go +++ b/client/handler.go @@ -12,26 +12,19 @@ import ( "strings" "time" - "github.com/ory/x/pagination/tokenpagination" + "github.com/julienschmidt/httprouter" + "github.com/pkg/errors" + "github.com/ory/fosite" + "github.com/ory/herodot" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/errorsx" "github.com/ory/x/httprouterx" - - "github.com/ory/x/openapix" - - "github.com/ory/x/uuidx" - "github.com/ory/x/jsonx" + "github.com/ory/x/openapix" + "github.com/ory/x/pagination/tokenpagination" "github.com/ory/x/urlx" - - "github.com/ory/fosite" - - "github.com/ory/x/errorsx" - - "github.com/ory/herodot" - "github.com/ory/hydra/x" - - "github.com/julienschmidt/httprouter" - "github.com/pkg/errors" + "github.com/ory/x/uuidx" ) type Handler struct { @@ -67,6 +60,8 @@ func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin, public *httprouterx. // OAuth 2.0 Client Creation Parameters // // swagger:parameters createOAuth2Client +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type createOAuth2Client struct { // OAuth 2.0 Client Request Body // @@ -97,7 +92,7 @@ type createOAuth2Client struct { func (h *Handler) createOAuth2Client(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { c, err := h.CreateClient(r, h.r.ClientValidator().Validate, false) if err != nil { - h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + h.r.Writer().WriteError(w, r, err) return } @@ -107,6 +102,8 @@ func (h *Handler) createOAuth2Client(w http.ResponseWriter, r *http.Request, _ h // OpenID Connect Dynamic Client Registration Parameters // // swagger:parameters createOidcDynamicClient +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type createOidcDynamicClient struct { // Dynamic Client Registration Request Body // @@ -160,22 +157,17 @@ func (h *Handler) createOidcDynamicClient(w http.ResponseWriter, r *http.Request func (h *Handler) CreateClient(r *http.Request, validator func(context.Context, *Client) error, isDynamic bool) (*Client, error) { var c Client if err := json.NewDecoder(r.Body).Decode(&c); err != nil { - return nil, err + return nil, errorsx.WithStack(herodot.ErrBadRequest.WithReasonf("Unable to decode the request body: %s", err)) } if isDynamic { if c.Secret != "" { return nil, errorsx.WithStack(herodot.ErrBadRequest.WithReasonf("It is not allowed to choose your own OAuth2 Client secret.")) } + // We do not allow to set the client ID for dynamic clients. + c.ID = uuidx.NewV4().String() } - if len(c.LegacyClientID) > 0 { - return nil, errorsx.WithStack(herodot.ErrBadRequest.WithReason("It is no longer possible to set an OAuth2 Client ID as a user. The system will generate a unique ID for you.")) - } - - c.ID = uuidx.NewV4() - c.LegacyClientID = c.ID.String() - if len(c.Secret) == 0 { secretb, err := x.GenerateSecret(26) if err != nil { @@ -214,6 +206,8 @@ func (h *Handler) CreateClient(r *http.Request, validator func(context.Context, // Set OAuth 2.0 Client Parameters // // swagger:parameters setOAuth2Client +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type setOAuth2Client struct { // OAuth 2.0 Client ID // @@ -260,7 +254,7 @@ func (h *Handler) setOAuth2Client(w http.ResponseWriter, r *http.Request, ps htt return } - c.LegacyClientID = ps.ByName("id") + c.ID = ps.ByName("id") if err := h.updateClient(r.Context(), &c, h.r.ClientValidator().Validate); err != nil { h.r.Writer().WriteError(w, r, err) return @@ -290,6 +284,8 @@ func (h *Handler) updateClient(ctx context.Context, c *Client, validator func(co // Set Dynamic Client Parameters // // swagger:parameters setOidcDynamicClient +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type setOidcDynamicClient struct { // OAuth 2.0 Client ID // @@ -371,7 +367,7 @@ func (h *Handler) setOidcDynamicClient(w http.ResponseWriter, r *http.Request, p c.RegistrationAccessToken = token c.RegistrationAccessTokenSignature = signature - c.LegacyClientID = client.GetID() + c.ID = client.GetID() if err := h.updateClient(r.Context(), &c, h.r.ClientValidator().ValidateDynamicRegistration); err != nil { h.r.Writer().WriteError(w, r, err) return @@ -383,6 +379,8 @@ func (h *Handler) setOidcDynamicClient(w http.ResponseWriter, r *http.Request, p // Patch OAuth 2.0 Client Parameters // // swagger:parameters patchOAuth2Client +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type patchOAuth2Client struct { // The id of the OAuth 2.0 Client. // @@ -460,6 +458,8 @@ func (h *Handler) patchOAuth2Client(w http.ResponseWriter, r *http.Request, ps h // Paginated OAuth2 Client List Response // // swagger:response listOAuth2Clients +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type listOAuth2ClientsResponse struct { tokenpagination.ResponseHeaders @@ -472,6 +472,8 @@ type listOAuth2ClientsResponse struct { // Paginated OAuth2 Client List Parameters // // swagger:parameters listOAuth2Clients +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type listOAuth2ClientsParameters struct { tokenpagination.RequestParameters @@ -540,6 +542,8 @@ func (h *Handler) listOAuth2Clients(w http.ResponseWriter, r *http.Request, ps h // Get OAuth2 Client Parameters // // swagger:parameters getOAuth2Client +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type adminGetOAuth2Client struct { // The id of the OAuth 2.0 Client. // @@ -583,6 +587,8 @@ func (h *Handler) Get(w http.ResponseWriter, r *http.Request, ps httprouter.Para // Get OpenID Connect Dynamic Client Parameters // // swagger:parameters getOidcDynamicClient +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type getOidcDynamicClient struct { // The id of the OAuth 2.0 Client. // @@ -644,6 +650,8 @@ func (h *Handler) getOidcDynamicClient(w http.ResponseWriter, r *http.Request, p // Delete OAuth2 Client Parameters // // swagger:parameters deleteOAuth2Client +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type deleteOAuth2Client struct { // The id of the OAuth 2.0 Client. // @@ -687,6 +695,8 @@ func (h *Handler) deleteOAuth2Client(w http.ResponseWriter, r *http.Request, ps // Set OAuth 2.0 Client Token Lifespans // // swagger:parameters setOAuth2ClientLifespans +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type setOAuth2ClientLifespans struct { // OAuth 2.0 Client ID // @@ -738,6 +748,8 @@ func (h *Handler) setOAuth2ClientLifespans(w http.ResponseWriter, r *http.Reques } // swagger:parameters deleteOidcDynamicClient +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type dynamicClientRegistrationDeleteOAuth2Client struct { // The id of the OAuth 2.0 Client. // @@ -806,13 +818,26 @@ func (h *Handler) ValidDynamicAuth(r *http.Request, ps httprouter.Params) (fosit } token := strings.TrimPrefix(fosite.AccessTokenFromRequest(r), "ory_at_") - if err := h.r.OAuth2HMACStrategy().Enigma.Validate(r.Context(), token); err != nil { + if err := h.r.OAuth2HMACStrategy().ValidateAccessToken( + r.Context(), + // The strategy checks the expiry time of the token. Registration tokens don't expire (we don't have a way of + // rotating them) so we set the expiry time to a time in the future. + &fosite.Request{ + Session: &fosite.DefaultSession{ + ExpiresAt: map[fosite.TokenType]time.Time{ + fosite.AccessToken: time.Now().Add(time.Hour), + }, + }, + RequestedAt: time.Now(), + }, + token, + ); err != nil { return nil, herodot.ErrUnauthorized. WithTrace(err). WithReason("The requested OAuth 2.0 client does not exist or you provided incorrect credentials.").WithDebug(err.Error()) } - signature := h.r.OAuth2HMACStrategy().Enigma.Signature(token) + signature := h.r.OAuth2EnigmaStrategy().Signature(token) if subtle.ConstantTimeCompare([]byte(c.RegistrationAccessTokenSignature), []byte(signature)) == 0 { return nil, errors.WithStack(herodot.ErrUnauthorized. WithReason("The requested OAuth 2.0 client does not exist or you provided incorrect credentials.").WithDebug("Registration access tokens do not match.")) diff --git a/client/handler_test.go b/client/handler_test.go index e8d060495ed..3047ad4c87b 100644 --- a/client/handler_test.go +++ b/client/handler_test.go @@ -13,6 +13,8 @@ import ( "net/http/httptest" "testing" + "github.com/ory/x/sqlxx" + "github.com/ory/x/httprouterx" "github.com/tidwall/sjson" @@ -20,9 +22,9 @@ import ( "github.com/gofrs/uuid" "github.com/tidwall/gjson" - "github.com/ory/hydra/internal/testhelpers" + "github.com/ory/hydra/v2/internal/testhelpers" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver/config" "github.com/ory/x/contextx" "github.com/julienschmidt/httprouter" @@ -32,8 +34,8 @@ import ( "github.com/stretchr/testify/require" - "github.com/ory/hydra/client" - "github.com/ory/hydra/internal" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/internal" ) type responseSnapshot struct { @@ -109,7 +111,7 @@ func TestHandler(t *testing.T) { t.Run("valid auth", func(t *testing.T) { actual, err := h.ValidDynamicAuth(&http.Request{Header: http.Header{"Authorization": {"Bearer " + expected.RegistrationAccessToken}}}, httprouter.Params{ - httprouter.Param{Key: "id", Value: expected.GetID()}, + {Key: "id", Value: expected.GetID()}, }) require.NoError(t, err, "authentication with registration access token works") assert.EqualValues(t, expected.GetID(), actual.GetID()) @@ -117,14 +119,14 @@ func TestHandler(t *testing.T) { t.Run("missing auth", func(t *testing.T) { _, err := h.ValidDynamicAuth(&http.Request{}, httprouter.Params{ - httprouter.Param{Key: "id", Value: expected.GetID()}, + {Key: "id", Value: expected.GetID()}, }) require.Error(t, err, "authentication without registration access token fails") }) t.Run("incorrect auth", func(t *testing.T) { _, err := h.ValidDynamicAuth(&http.Request{Header: http.Header{"Authorization": {"Bearer invalid"}}}, httprouter.Params{ - httprouter.Param{Key: "id", Value: expected.GetID()}, + {Key: "id", Value: expected.GetID()}, }) require.Error(t, err, "authentication with invalid registration access token fails") }) @@ -309,31 +311,78 @@ func TestHandler(t *testing.T) { statusCode: http.StatusBadRequest, }, { - d: "non-uuid fails", + d: "non-uuid works", + payload: &client.Client{ + ID: "not-a-uuid", + Secret: "averylongsecret", + RedirectURIs: []string{"http://localhost:3000/cb"}, + }, + path: client.ClientsHandlerPath, + statusCode: http.StatusCreated, + }, + { + d: "setting client id as uuid works", payload: &client.Client{ - LegacyClientID: "not-a-uuid", - Secret: "averylongsecret", - RedirectURIs: []string{"http://localhost:3000/cb"}, + ID: "98941dac-f963-4468-8a23-9483b1e04e3c", + Secret: "not too short", + RedirectURIs: []string{"http://localhost:3000/cb"}, }, path: client.ClientsHandlerPath, + statusCode: http.StatusCreated, + }, + { + d: "setting access token strategy fails", + payload: &client.Client{ + RedirectURIs: []string{"http://localhost:3000/cb"}, + AccessTokenStrategy: "jwt", + }, + path: client.DynClientsHandlerPath, + statusCode: http.StatusBadRequest, + }, + { + d: "setting skip_consent fails for dynamic registration", + payload: &client.Client{ + RedirectURIs: []string{"http://localhost:3000/cb"}, + SkipConsent: true, + }, + path: client.DynClientsHandlerPath, statusCode: http.StatusBadRequest, }, { - d: "setting client id fails", + d: "setting skip_consent succeeds for admin registration", payload: &client.Client{ - LegacyClientID: "98941dac-f963-4468-8a23-9483b1e04e3c", - Secret: "short", - RedirectURIs: []string{"http://localhost:3000/cb"}, + RedirectURIs: []string{"http://localhost:3000/cb"}, + Secret: "2SKZkBf2P5g4toAXXnCrr~_sDM", + SkipConsent: true, }, path: client.ClientsHandlerPath, + statusCode: http.StatusCreated, + }, + { + d: "setting skip_logout_consent fails for dynamic registration", + payload: &client.Client{ + RedirectURIs: []string{"http://localhost:3000/cb"}, + SkipLogoutConsent: sqlxx.NullBool{Bool: true, Valid: true}, + }, + path: client.DynClientsHandlerPath, statusCode: http.StatusBadRequest, }, + { + d: "setting skip_logout_consent succeeds for admin registration", + payload: &client.Client{ + RedirectURIs: []string{"http://localhost:3000/cb"}, + SkipLogoutConsent: sqlxx.NullBool{Bool: true, Valid: true}, + Secret: "2SKZkBf2P5g4toAXXnCrr~_sDM", + }, + path: client.ClientsHandlerPath, + statusCode: http.StatusCreated, + }, { d: "basic dynamic client registration", payload: &client.Client{ - LegacyClientID: "ead800c5-a316-4d0c-bf00-d25666ba72cf", - Secret: "averylongsecret", - RedirectURIs: []string{"http://localhost:3000/cb"}, + ID: "ead800c5-a316-4d0c-bf00-d25666ba72cf", + Secret: "averylongsecret", + RedirectURIs: []string{"http://localhost:3000/cb"}, }, path: client.DynClientsHandlerPath, statusCode: http.StatusBadRequest, @@ -355,7 +404,7 @@ func TestHandler(t *testing.T) { if tc.path == client.DynClientsHandlerPath { exclude = append(exclude, "client_id", "client_secret", "registration_client_uri") } - if tc.payload.LegacyClientID == "" { + if tc.payload.ID == "" { exclude = append(exclude, "client_id", "registration_client_uri") assert.NotEqual(t, uuid.Nil.String(), gjson.Get(body, "client_id").String(), body) } @@ -364,7 +413,7 @@ func TestHandler(t *testing.T) { assert.NotEmpty(t, gjson.Get(body, key).String(), "%s in %s", key, body) } } - snapshotx.SnapshotTExcept(t, json.RawMessage(body), exclude) + snapshotx.SnapshotT(t, json.RawMessage(body), snapshotx.ExceptPaths(exclude...)) }) } }) diff --git a/client/manager.go b/client/manager.go index ad8cca7df51..b4c54cb3b2a 100644 --- a/client/manager.go +++ b/client/manager.go @@ -31,7 +31,7 @@ type Filter struct { type Manager interface { Storage - Authenticate(ctx context.Context, id string, secret []byte) (*Client, error) + AuthenticateClient(ctx context.Context, id string, secret []byte) (*Client, error) } type Storage interface { @@ -49,3 +49,7 @@ type Storage interface { GetConcreteClient(ctx context.Context, id string) (*Client, error) } + +type ManagerProvider interface { + ClientManager() Manager +} diff --git a/client/manager_test_helpers.go b/client/manager_test_helpers.go index c3394ecf2d0..b47b78de88e 100644 --- a/client/manager_test_helpers.go +++ b/client/manager_test_helpers.go @@ -10,22 +10,19 @@ import ( "testing" "time" + "github.com/go-faker/faker/v4" + "github.com/go-jose/go-jose/v3" "github.com/gobuffalo/pop/v6" - "gopkg.in/square/go-jose.v2" - - "github.com/ory/x/assertx" - "github.com/ory/x/contextx" - "github.com/ory/x/sqlcon" - - "github.com/bxcodec/faker/v3" "github.com/gofrs/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ory/fosite" - - testhelpersuuid "github.com/ory/hydra/internal/testhelpers/uuid" - "github.com/ory/hydra/x" + testhelpersuuid "github.com/ory/hydra/v2/internal/testhelpers/uuid" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/assertx" + "github.com/ory/x/contextx" + "github.com/ory/x/sqlcon" ) func TestHelperClientAutoGenerateKey(k string, m Storage) func(t *testing.T) { @@ -36,12 +33,12 @@ func TestHelperClientAutoGenerateKey(k string, m Storage) func(t *testing.T) { RedirectURIs: []string{"http://redirect"}, TermsOfServiceURI: "foo", } - assert.NoError(t, m.CreateClient(ctx, c)) + require.NoError(t, m.CreateClient(ctx, c)) dbClient, err := m.GetClient(ctx, c.GetID()) - assert.NoError(t, err) + require.NoError(t, err) dbClientConcrete, ok := dbClient.(*Client) - assert.True(t, ok) - testhelpersuuid.AssertUUID(t, &dbClientConcrete.ID) + require.True(t, ok) + testhelpersuuid.AssertUUID(t, dbClientConcrete.ID) assert.NoError(t, m.DeleteClient(ctx, c.GetID())) } } @@ -50,15 +47,16 @@ func TestHelperClientAuthenticate(k string, m Manager) func(t *testing.T) { return func(t *testing.T) { ctx := context.TODO() require.NoError(t, m.CreateClient(ctx, &Client{ - LegacyClientID: "1234321", - Secret: "secret", - RedirectURIs: []string{"http://redirect"}, + ID: "1234321", + Secret: "secret", + RedirectURIs: []string{"http://redirect"}, })) - c, err := m.Authenticate(ctx, "1234321", []byte("secret1")) - require.NotNil(t, err) + c, err := m.AuthenticateClient(ctx, "1234321", []byte("secret1")) + require.Error(t, err) + require.Nil(t, c) - c, err = m.Authenticate(ctx, "1234321", []byte("secret")) + c, err = m.AuthenticateClient(ctx, "1234321", []byte("secret")) require.NoError(t, err) assert.Equal(t, "1234321", c.GetID()) } @@ -82,7 +80,7 @@ func testHelperUpdateClient(t *testing.T, ctx context.Context, network Storage, d, err := network.GetClient(ctx, "1234") assert.NoError(t, err) err = network.UpdateClient(ctx, &Client{ - LegacyClientID: "2-1234", + ID: "2-1234", Name: "name-new", Secret: "secret-new", RedirectURIs: []string{"http://redirect/new"}, @@ -166,7 +164,7 @@ func TestHelperCreateGetUpdateDeleteClientNext(t *testing.T, m Storage, networks for _, expected := range clients { c, err := m.GetClient(ctx, expected.GetID()) if check != original { - t.Run(fmt.Sprintf("case=must not find client %s", expected.ID), func(t *testing.T) { + t.Run(fmt.Sprintf("case=must not find client %s", expected.GetID()), func(t *testing.T) { require.ErrorIs(t, err, sqlcon.ErrNoRows) }) } else { @@ -208,8 +206,7 @@ func TestHelperCreateGetUpdateDeleteClient(k string, connection *pop.Connection, require.Error(t, err) t1c1 := &Client{ - ID: uuid.FromStringOrNil("96bfe52e-af88-4cba-ab00-ae7a8b082228"), - LegacyClientID: "1234", + ID: "1234", Name: "name", Secret: "secret", RedirectURIs: []string{"http://redirect", "http://redirect1"}, @@ -245,15 +242,12 @@ func TestHelperCreateGetUpdateDeleteClient(k string, connection *pop.Connection, { t2c1 := *t1c1 require.Error(t, connection.Create(&t2c1), "should not be able to create the same client in other manager/network; are they backed by the same database?") - t2c1.ID = uuid.Nil - require.NoError(t, t2.CreateClient(ctx, &t2c1), "we should be able to create a client with the same GetID() but different ID in other network") + require.NoError(t, t2.CreateClient(ctx, &t2c1), "we should be able to create a client with the same ID in other network") } t2c3 := *t1c1 { - pk, _ := uuid.NewV4() - t2c3.ID = pk - t2c3.LegacyClientID = "t2c2-1234" + t2c3.ID = "t2c2-1234" require.NoError(t, t2.CreateClient(ctx, &t2c3)) require.Error(t, t2.CreateClient(ctx, &t2c3)) } @@ -263,8 +257,7 @@ func TestHelperCreateGetUpdateDeleteClient(k string, connection *pop.Connection, } c2Template := &Client{ - ID: uuid.FromStringOrNil("a6bfe52e-af88-4cba-ab00-ae7a8b082228"), - LegacyClientID: "2-1234", + ID: "2-1234", Name: "name2", Secret: "secret", RedirectURIs: []string{"http://redirect"}, @@ -272,14 +265,13 @@ func TestHelperCreateGetUpdateDeleteClient(k string, connection *pop.Connection, SecretExpiresAt: 1, } assert.NoError(t, t1.CreateClient(ctx, c2Template)) - c2Template.ID = uuid.Nil assert.NoError(t, t2.CreateClient(ctx, c2Template)) d, err := t1.GetClient(ctx, "1234") require.NoError(t, err) cc := d.(*Client) - testhelpersuuid.AssertUUID(t, &cc.NID) + testhelpersuuid.AssertUUID(t, cc.NID) compare(t, t1c1, d, k) @@ -298,6 +290,7 @@ func TestHelperCreateGetUpdateDeleteClient(k string, connection *pop.Connection, ds, err = t1.GetClients(ctx, Filter{Limit: 100, Offset: 100}) assert.NoError(t, err) + assert.Empty(t, ds) // get by name ds, err = t1.GetClients(ctx, Filter{Limit: 100, Offset: 0, Name: "name"}) diff --git a/client/registry.go b/client/registry.go index 707be5c9f7e..bfec25ace91 100644 --- a/client/registry.go +++ b/client/registry.go @@ -4,12 +4,13 @@ package client import ( - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver/config" "github.com/ory/fosite" foauth2 "github.com/ory/fosite/handler/oauth2" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/x" + enigma "github.com/ory/fosite/token/hmac" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/x" ) type InternalRegistry interface { @@ -22,6 +23,7 @@ type Registry interface { ClientManager() Manager ClientHasher() fosite.Hasher OpenIDJWTStrategy() jwk.JWTSigner - OAuth2HMACStrategy() *foauth2.HMACSHAStrategy + OAuth2HMACStrategy() foauth2.CoreStrategy + OAuth2EnigmaStrategy() *enigma.HMACStrategy config.Provider } diff --git a/client/sdk_test.go b/client/sdk_test.go index 1e0b5af28d7..9db7ab7cddb 100644 --- a/client/sdk_test.go +++ b/client/sdk_test.go @@ -5,8 +5,6 @@ package client_test import ( "context" - "encoding/json" - "io" "net/http/httptest" "strings" "testing" @@ -15,50 +13,49 @@ import ( "github.com/ory/x/ioutilx" - "github.com/ory/x/snapshotx" - "github.com/ory/x/uuidx" "github.com/mohae/deepcopy" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" "github.com/ory/x/pointerx" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver/config" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/ory/hydra/internal" + "github.com/ory/hydra/v2/internal" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/client" + "github.com/ory/hydra/v2/client" ) func createTestClient(prefix string) hydra.OAuth2Client { return hydra.OAuth2Client{ - ClientName: pointerx.String(prefix + "name"), - ClientSecret: pointerx.String(prefix + "secret"), - ClientUri: pointerx.String(prefix + "uri"), + ClientName: pointerx.Ptr(prefix + "name"), + ClientSecret: pointerx.Ptr(prefix + "secret"), + ClientUri: pointerx.Ptr(prefix + "uri"), Contacts: []string{prefix + "peter", prefix + "pan"}, GrantTypes: []string{prefix + "client_credentials", prefix + "authorize_code"}, - LogoUri: pointerx.String(prefix + "logo"), - Owner: pointerx.String(prefix + "an-owner"), - PolicyUri: pointerx.String(prefix + "policy-uri"), - Scope: pointerx.String(prefix + "foo bar baz"), - TosUri: pointerx.String(prefix + "tos-uri"), + LogoUri: pointerx.Ptr(prefix + "logo"), + Owner: pointerx.Ptr(prefix + "an-owner"), + PolicyUri: pointerx.Ptr(prefix + "policy-uri"), + Scope: pointerx.Ptr(prefix + "foo bar baz"), + TosUri: pointerx.Ptr(prefix + "tos-uri"), ResponseTypes: []string{prefix + "id_token", prefix + "code"}, RedirectUris: []string{"https://" + prefix + "redirect-url", "https://" + prefix + "redirect-uri"}, - ClientSecretExpiresAt: pointerx.Int64(0), - TokenEndpointAuthMethod: pointerx.String("client_secret_basic"), - UserinfoSignedResponseAlg: pointerx.String("none"), - SubjectType: pointerx.String("public"), + ClientSecretExpiresAt: pointerx.Ptr[int64](0), + TokenEndpointAuthMethod: pointerx.Ptr("client_secret_basic"), + UserinfoSignedResponseAlg: pointerx.Ptr("none"), + SubjectType: pointerx.Ptr("public"), Metadata: map[string]interface{}{"foo": "bar"}, // because these values are not nullable in the SQL schema, we have to set them not nil AllowedCorsOrigins: []string{}, Audience: []string{}, Jwks: map[string]interface{}{}, + SkipConsent: pointerx.Ptr(false), } } @@ -83,11 +80,11 @@ func TestClientSDK(t *testing.T) { c.GetConfig().Servers = hydra.ServerConfigurations{{URL: server.URL}} t.Run("case=client default scopes are set", func(t *testing.T) { - result, _, err := c.OAuth2Api.CreateOAuth2Client(ctx).OAuth2Client(hydra.OAuth2Client{}).Execute() + result, _, err := c.OAuth2API.CreateOAuth2Client(ctx).OAuth2Client(hydra.OAuth2Client{}).Execute() require.NoError(t, err) assert.EqualValues(t, conf.DefaultClientScope(ctx), strings.Split(*result.Scope, " ")) - _, err = c.OAuth2Api.DeleteOAuth2Client(ctx, *result.ClientId).Execute() + _, err = c.OAuth2API.DeleteOAuth2Client(ctx, *result.ClientId).Execute() require.NoError(t, err) }) @@ -98,7 +95,7 @@ func TestClientSDK(t *testing.T) { // createClient.SecretExpiresAt = 10 // returned client is correct on Create - result, _, err := c.OAuth2Api.CreateOAuth2Client(ctx).OAuth2Client(createClient).Execute() + result, _, err := c.OAuth2API.CreateOAuth2Client(ctx).OAuth2Client(createClient).Execute() require.NoError(t, err) assert.NotEmpty(t, result.UpdatedAt) assert.NotEmpty(t, result.CreatedAt) @@ -111,32 +108,32 @@ func TestClientSDK(t *testing.T) { assert.EqualValues(t, "bar", result.Metadata.(map[string]interface{})["foo"]) // secret is not returned on GetOAuth2Client - compareClient.ClientSecret = x.ToPointer("") - gresult, _, err := c.OAuth2Api.GetOAuth2Client(context.Background(), *createClient.ClientId).Execute() + compareClient.ClientSecret = pointerx.Ptr("") + gresult, _, err := c.OAuth2API.GetOAuth2Client(context.Background(), *createClient.ClientId).Execute() require.NoError(t, err) assertx.EqualAsJSONExcept(t, compareClient, gresult, append(defaultIgnoreFields, "client_secret")) // get client will return The request could not be authorized - gresult, _, err = c.OAuth2Api.GetOAuth2Client(context.Background(), "unknown").Execute() + gresult, _, err = c.OAuth2API.GetOAuth2Client(context.Background(), "unknown").Execute() require.Error(t, err) assert.Empty(t, gresult) assert.True(t, strings.Contains(err.Error(), "404"), err.Error()) // listing clients returns the only added one - results, _, err := c.OAuth2Api.ListOAuth2Clients(context.Background()).PageSize(100).Execute() + results, _, err := c.OAuth2API.ListOAuth2Clients(context.Background()).PageSize(100).Execute() require.NoError(t, err) assert.Len(t, results, 1) assertx.EqualAsJSONExcept(t, compareClient, results[0], append(defaultIgnoreFields, "client_secret")) // SecretExpiresAt gets overwritten with 0 on Update compareClient.ClientSecret = createClient.ClientSecret - uresult, _, err := c.OAuth2Api.SetOAuth2Client(context.Background(), *createClient.ClientId).OAuth2Client(createClient).Execute() + uresult, _, err := c.OAuth2API.SetOAuth2Client(context.Background(), *createClient.ClientId).OAuth2Client(createClient).Execute() require.NoError(t, err) assertx.EqualAsJSONExcept(t, compareClient, uresult, append(defaultIgnoreFields, "client_secret")) // create another client updateClient := createTestClient("foo") - uresult, _, err = c.OAuth2Api.SetOAuth2Client(context.Background(), *createClient.ClientId).OAuth2Client(updateClient).Execute() + uresult, _, err = c.OAuth2API.SetOAuth2Client(context.Background(), *createClient.ClientId).OAuth2Client(updateClient).Execute() require.NoError(t, err) assert.NotEqual(t, updateClient.ClientId, uresult.ClientId) updateClient.ClientId = uresult.ClientId @@ -144,39 +141,39 @@ func TestClientSDK(t *testing.T) { // again, test if secret is not returned on Get compareClient = updateClient - compareClient.ClientSecret = x.ToPointer("") - gresult, _, err = c.OAuth2Api.GetOAuth2Client(context.Background(), *updateClient.ClientId).Execute() + compareClient.ClientSecret = pointerx.Ptr("") + gresult, _, err = c.OAuth2API.GetOAuth2Client(context.Background(), *updateClient.ClientId).Execute() require.NoError(t, err) assertx.EqualAsJSONExcept(t, compareClient, gresult, append(defaultIgnoreFields, "client_secret")) // client can not be found after being deleted - _, err = c.OAuth2Api.DeleteOAuth2Client(context.Background(), *updateClient.ClientId).Execute() + _, err = c.OAuth2API.DeleteOAuth2Client(context.Background(), *updateClient.ClientId).Execute() require.NoError(t, err) - _, _, err = c.OAuth2Api.GetOAuth2Client(context.Background(), *updateClient.ClientId).Execute() + _, _, err = c.OAuth2API.GetOAuth2Client(context.Background(), *updateClient.ClientId).Execute() require.Error(t, err) }) t.Run("case=public client is transmitted without secret", func(t *testing.T) { - result, _, err := c.OAuth2Api.CreateOAuth2Client(context.Background()).OAuth2Client(hydra.OAuth2Client{ - TokenEndpointAuthMethod: x.ToPointer("none"), + result, _, err := c.OAuth2API.CreateOAuth2Client(context.Background()).OAuth2Client(hydra.OAuth2Client{ + TokenEndpointAuthMethod: pointerx.Ptr("none"), }).Execute() require.NoError(t, err) - assert.Equal(t, "", x.FromPointer[string](result.ClientSecret)) + assert.Equal(t, "", pointerx.Deref(result.ClientSecret)) - result, _, err = c.OAuth2Api.CreateOAuth2Client(context.Background()).OAuth2Client(createTestClient("")).Execute() + result, _, err = c.OAuth2API.CreateOAuth2Client(context.Background()).OAuth2Client(createTestClient("")).Execute() require.NoError(t, err) - assert.Equal(t, "secret", x.FromPointer[string](result.ClientSecret)) + assert.Equal(t, "secret", pointerx.Deref(result.ClientSecret)) }) - t.Run("case=id can not be set", func(t *testing.T) { - _, res, err := c.OAuth2Api.CreateOAuth2Client(context.Background()).OAuth2Client(hydra.OAuth2Client{ClientId: x.ToPointer(uuidx.NewV4().String())}).Execute() - require.Error(t, err) - body, err := io.ReadAll(res.Body) + t.Run("case=id can be set", func(t *testing.T) { + id := uuidx.NewV4().String() + result, _, err := c.OAuth2API.CreateOAuth2Client(context.Background()).OAuth2Client(hydra.OAuth2Client{ClientId: pointerx.Ptr(id)}).Execute() require.NoError(t, err) - snapshotx.SnapshotT(t, json.RawMessage(body)) + + assert.Equal(t, id, pointerx.Deref(result.ClientId)) }) t.Run("case=patch client legally", func(t *testing.T) { @@ -184,15 +181,15 @@ func TestClientSDK(t *testing.T) { path := "/redirect_uris/-" value := "http://foo.bar" - client := createTestClient("") - created, _, err := c.OAuth2Api.CreateOAuth2Client(context.Background()).OAuth2Client(client).Execute() + cl := createTestClient("") + created, _, err := c.OAuth2API.CreateOAuth2Client(context.Background()).OAuth2Client(cl).Execute() require.NoError(t, err) - client.ClientId = created.ClientId + cl.ClientId = created.ClientId - expected := deepcopy.Copy(client).(hydra.OAuth2Client) + expected := deepcopy.Copy(cl).(hydra.OAuth2Client) expected.RedirectUris = append(expected.RedirectUris, value) - result, _, err := c.OAuth2Api.PatchOAuth2Client(context.Background(), *client.ClientId).JsonPatch([]hydra.JsonPatch{{Op: op, Path: path, Value: value}}).Execute() + result, _, err := c.OAuth2API.PatchOAuth2Client(context.Background(), *cl.ClientId).JsonPatch([]hydra.JsonPatch{{Op: op, Path: path, Value: value}}).Execute() require.NoError(t, err) expected.CreatedAt = result.CreatedAt expected.UpdatedAt = result.UpdatedAt @@ -207,11 +204,11 @@ func TestClientSDK(t *testing.T) { value := "foo" client := createTestClient("") - created, res, err := c.OAuth2Api.CreateOAuth2Client(context.Background()).OAuth2Client(client).Execute() + created, res, err := c.OAuth2API.CreateOAuth2Client(context.Background()).OAuth2Client(client).Execute() require.NoError(t, err, "%s", ioutilx.MustReadAll(res.Body)) client.ClientId = created.ClientId - _, _, err = c.OAuth2Api.PatchOAuth2Client(context.Background(), *client.ClientId).JsonPatch([]hydra.JsonPatch{{Op: op, Path: path, Value: value}}).Execute() + _, _, err = c.OAuth2API.PatchOAuth2Client(context.Background(), *client.ClientId).JsonPatch([]hydra.JsonPatch{{Op: op, Path: path, Value: value}}).Execute() require.Error(t, err) }) @@ -221,13 +218,13 @@ func TestClientSDK(t *testing.T) { value := "http://foo.bar" client := createTestClient("") - created, _, err := c.OAuth2Api.CreateOAuth2Client(context.Background()).OAuth2Client(client).Execute() + created, _, err := c.OAuth2API.CreateOAuth2Client(context.Background()).OAuth2Client(client).Execute() require.NoError(t, err) client.ClientId = created.ClientId - result1, _, err := c.OAuth2Api.PatchOAuth2Client(context.Background(), *client.ClientId).JsonPatch([]hydra.JsonPatch{{Op: op, Path: path, Value: value}}).Execute() + result1, _, err := c.OAuth2API.PatchOAuth2Client(context.Background(), *client.ClientId).JsonPatch([]hydra.JsonPatch{{Op: op, Path: path, Value: value}}).Execute() require.NoError(t, err) - result2, _, err := c.OAuth2Api.PatchOAuth2Client(context.Background(), *client.ClientId).JsonPatch([]hydra.JsonPatch{{Op: op, Path: path, Value: value}}).Execute() + result2, _, err := c.OAuth2API.PatchOAuth2Client(context.Background(), *client.ClientId).JsonPatch([]hydra.JsonPatch{{Op: op, Path: path, Value: value}}).Execute() require.NoError(t, err) // secret hashes shouldn't change between these PUT calls diff --git a/client/validator.go b/client/validator.go index a2d032cec1c..bedd9cde671 100644 --- a/client/validator.go +++ b/client/validator.go @@ -7,15 +7,17 @@ import ( "context" "encoding/json" "fmt" + "io" "net/url" "strings" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/x" - "github.com/ory/x/ipx" + "github.com/hashicorp/go-retryablehttp" + "github.com/ory/herodot" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/x" "github.com/ory/x/errorsx" - + "github.com/ory/x/ipx" "github.com/ory/x/stringslice" ) @@ -64,6 +66,14 @@ func (v *Validator) Validate(ctx context.Context, c *Client) error { return errorsx.WithStack(ErrInvalidClientMetadata.WithHint("Fields jwks and jwks_uri can not both be set, you must choose one.")) } + if c.JSONWebKeys != nil && c.JSONWebKeys.JSONWebKeySet != nil { + for _, k := range c.JSONWebKeys.Keys { + if !k.Valid() { + return errorsx.WithStack(ErrInvalidClientMetadata.WithHint("Invalid JSON web key in set.")) + } + } + } + if v.r.Config().ClientHTTPNoPrivateIPRanges() { values := map[string]string{ "jwks_uri": c.JSONWebKeysURI, @@ -140,14 +150,14 @@ func (v *Validator) Validate(ctx context.Context, c *Client) error { } if c.SubjectType != "" { - if !stringslice.Has(v.r.Config().SubjectTypesSupported(ctx), c.SubjectType) { - return errorsx.WithStack(ErrInvalidClientMetadata.WithHintf("Subject type %s is not supported by server, only %v are allowed.", c.SubjectType, v.r.Config().SubjectTypesSupported(ctx))) + if !stringslice.Has(v.r.Config().SubjectTypesSupported(ctx, c), c.SubjectType) { + return errorsx.WithStack(ErrInvalidClientMetadata.WithHintf("Subject type %s is not supported by server, only %v are allowed.", c.SubjectType, v.r.Config().SubjectTypesSupported(ctx, c))) } } else { - if stringslice.Has(v.r.Config().SubjectTypesSupported(ctx), "public") { + if stringslice.Has(v.r.Config().SubjectTypesSupported(ctx, c), "public") { c.SubjectType = "public" } else { - c.SubjectType = v.r.Config().SubjectTypesSupported(ctx)[0] + c.SubjectType = v.r.Config().SubjectTypesSupported(ctx, c)[0] } } @@ -173,15 +183,34 @@ func (v *Validator) Validate(ctx context.Context, c *Client) error { } } + if c.AccessTokenStrategy != "" { + s, err := config.ToAccessTokenStrategyType(c.AccessTokenStrategy) + if err != nil { + return errorsx.WithStack(ErrInvalidClientMetadata. + WithHintf("invalid access token strategy: %v", err)) + } + // Canonicalize, just in case. + c.AccessTokenStrategy = string(s) + } + return nil } func (v *Validator) ValidateDynamicRegistration(ctx context.Context, c *Client) error { if c.Metadata != nil { return errorsx.WithStack(ErrInvalidClientMetadata. - WithHint(`metadata cannot be set for dynamic client registration'`), + WithHint(`"metadata" cannot be set for dynamic client registration`), ) } + if c.AccessTokenStrategy != "" { + return errorsx.WithStack(herodot.ErrBadRequest.WithReasonf("It is not allowed to choose your own access token strategy.")) + } + if c.SkipConsent { + return errorsx.WithStack(ErrInvalidRequest.WithDescription(`"skip_consent" cannot be set for dynamic client registration`)) + } + if c.SkipLogoutConsent.Bool { + return errorsx.WithStack(ErrInvalidRequest.WithDescription(`"skip_logout_consent" cannot be set for dynamic client registration`)) + } return v.Validate(ctx, c) } @@ -196,11 +225,16 @@ func (v *Validator) ValidateSectorIdentifierURL(ctx context.Context, location st return errorsx.WithStack(ErrInvalidClientMetadata.WithDebug("Value sector_identifier_uri must be an HTTPS URL but it is not.")) } - response, err := v.r.HTTPClient(ctx).Get(location) + req, err := retryablehttp.NewRequestWithContext(ctx, "GET", location, nil) + if err != nil { + return errorsx.WithStack(ErrInvalidClientMetadata.WithDebugf("Value sector_identifier_uri must be an HTTPS URL but it is not: %s", err.Error())) + } + response, err := v.r.HTTPClient(ctx).Do(req) if err != nil { return errorsx.WithStack(ErrInvalidClientMetadata.WithDebug(fmt.Sprintf("Unable to connect to URL set by sector_identifier_uri: %s", err))) } defer response.Body.Close() + response.Body = io.NopCloser(io.LimitReader(response.Body, 5<<20 /* 5 MiB */)) var urls []string if err := json.NewDecoder(response.Body).Decode(&urls); err != nil { diff --git a/client/validator_test.go b/client/validator_test.go index 98be4ab4f94..09f69b26e30 100644 --- a/client/validator_test.go +++ b/client/validator_test.go @@ -5,26 +5,27 @@ package client_test import ( "context" + "encoding/json" "fmt" "net/http" "net/http/httptest" + "strings" "testing" "github.com/hashicorp/go-retryablehttp" - "github.com/ory/hydra/driver" + "github.com/ory/fosite" + "github.com/ory/hydra/v2/driver" "github.com/ory/x/httpx" - "github.com/gofrs/uuid" - + jose "github.com/go-jose/go-jose/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - jose "gopkg.in/square/go-jose.v2" - . "github.com/ory/hydra/client" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/x" + . "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" ) @@ -38,68 +39,98 @@ func TestValidate(t *testing.T) { testCtx := context.TODO() + dec := json.NewDecoder(strings.NewReader(validJWKS)) + dec.DisallowUnknownFields() + var goodJWKS jose.JSONWebKeySet + require.NoError(t, dec.Decode(&goodJWKS)) + for k, tc := range []struct { in *Client - check func(t *testing.T, c *Client) - expectErr bool - v func(t *testing.T) *Validator + check func(*testing.T, *Client) + assertErr func(t assert.TestingT, err error, msg ...interface{}) bool + v func(*testing.T) *Validator }{ { in: new(Client), check: func(t *testing.T, c *Client) { - assert.Equal(t, uuid.Nil.String(), c.GetID()) - assert.EqualValues(t, c.GetID(), c.ID.String()) - assert.Empty(t, c.LegacyClientID) + assert.Zero(t, c.GetID()) + assert.EqualValues(t, c.GetID(), c.ID) }, }, { - in: &Client{LegacyClientID: "foo"}, + in: &Client{ID: "foo"}, check: func(t *testing.T, c *Client) { - assert.EqualValues(t, c.GetID(), c.LegacyClientID) + assert.EqualValues(t, c.GetID(), c.ID) }, }, { - in: &Client{LegacyClientID: "foo"}, + in: &Client{ID: "foo"}, check: func(t *testing.T, c *Client) { - assert.EqualValues(t, c.GetID(), c.LegacyClientID) + assert.EqualValues(t, c.GetID(), c.ID) }, }, { - in: &Client{LegacyClientID: "foo", UserinfoSignedResponseAlg: "foo"}, - expectErr: true, + in: &Client{ID: "foo", UserinfoSignedResponseAlg: "foo"}, + assertErr: assert.Error, }, { - in: &Client{LegacyClientID: "foo", TokenEndpointAuthMethod: "private_key_jwt"}, - expectErr: true, + in: &Client{ID: "foo", TokenEndpointAuthMethod: "private_key_jwt"}, + assertErr: assert.Error, }, { - in: &Client{LegacyClientID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: new(jose.JSONWebKeySet)}, JSONWebKeysURI: "asdf", TokenEndpointAuthMethod: "private_key_jwt"}, - expectErr: true, + in: &Client{ID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: new(jose.JSONWebKeySet)}, JSONWebKeysURI: "asdf", TokenEndpointAuthMethod: "private_key_jwt"}, + assertErr: assert.Error, }, { - in: &Client{LegacyClientID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: new(jose.JSONWebKeySet)}, TokenEndpointAuthMethod: "private_key_jwt", TokenEndpointAuthSigningAlgorithm: "HS256"}, - expectErr: true, + in: &Client{ID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: new(jose.JSONWebKeySet)}, TokenEndpointAuthMethod: "private_key_jwt", TokenEndpointAuthSigningAlgorithm: "HS256"}, + assertErr: assert.Error, }, { - in: &Client{LegacyClientID: "foo", PostLogoutRedirectURIs: []string{"https://bar/"}, RedirectURIs: []string{"https://foo/"}}, - expectErr: true, + in: &Client{ID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: new(jose.JSONWebKeySet)}, JSONWebKeysURI: "https://example.org/jwks.json"}, + assertErr: func(t assert.TestingT, err error, msg ...interface{}) bool { + e := new(fosite.RFC6749Error) + assert.ErrorAs(t, err, &e) + assert.Contains(t, e.HintField, "jwks and jwks_uri can not both be set") + return true + }, }, { - in: &Client{LegacyClientID: "foo", PostLogoutRedirectURIs: []string{"http://foo/"}, RedirectURIs: []string{"https://foo/"}}, - expectErr: true, + in: &Client{ID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: &goodJWKS}}, + check: func(t *testing.T, c *Client) { + assert.Len(t, c.JSONWebKeys.Keys, 2) + assert.Equal(t, c.JSONWebKeys.Keys[0].KeyID, "1") + assert.Equal(t, c.JSONWebKeys.Keys[1].KeyID, "2011-04-29") + }, }, { - in: &Client{LegacyClientID: "foo", PostLogoutRedirectURIs: []string{"https://foo:1234/"}, RedirectURIs: []string{"https://foo/"}}, - expectErr: true, + in: &Client{ID: "foo", JSONWebKeys: &x.JoseJSONWebKeySet{JSONWebKeySet: &jose.JSONWebKeySet{Keys: []jose.JSONWebKey{{}}}}}, + assertErr: func(t assert.TestingT, err error, msg ...interface{}) bool { + e := new(fosite.RFC6749Error) + assert.ErrorAs(t, err, &e) + assert.Contains(t, e.HintField, "Invalid JSON web key in set") + return true + }, + }, + { + in: &Client{ID: "foo", PostLogoutRedirectURIs: []string{"https://bar/"}, RedirectURIs: []string{"https://foo/"}}, + assertErr: assert.Error, + }, + { + in: &Client{ID: "foo", PostLogoutRedirectURIs: []string{"http://foo/"}, RedirectURIs: []string{"https://foo/"}}, + assertErr: assert.Error, + }, + { + in: &Client{ID: "foo", PostLogoutRedirectURIs: []string{"https://foo:1234/"}, RedirectURIs: []string{"https://foo/"}}, + assertErr: assert.Error, }, { - in: &Client{LegacyClientID: "foo", PostLogoutRedirectURIs: []string{"https://foo/"}, RedirectURIs: []string{"https://foo/"}}, + in: &Client{ID: "foo", PostLogoutRedirectURIs: []string{"https://foo/"}, RedirectURIs: []string{"https://foo/"}}, check: func(t *testing.T, c *Client) { assert.Equal(t, []string{"https://foo/"}, []string(c.PostLogoutRedirectURIs)) }, }, { - in: &Client{LegacyClientID: "foo"}, + in: &Client{ID: "foo"}, check: func(t *testing.T, c *Client) { assert.Equal(t, "public", c.SubjectType) }, @@ -109,22 +140,23 @@ func TestValidate(t *testing.T) { c.MustSet(ctx, config.KeySubjectTypesSupported, []string{"pairwise"}) return NewValidator(reg) }, - in: &Client{LegacyClientID: "foo"}, + in: &Client{ID: "foo"}, check: func(t *testing.T, c *Client) { assert.Equal(t, "pairwise", c.SubjectType) }, }, { - in: &Client{LegacyClientID: "foo", SubjectType: "pairwise"}, + in: &Client{ID: "foo", SubjectType: "pairwise"}, check: func(t *testing.T, c *Client) { assert.Equal(t, "pairwise", c.SubjectType) }, }, { - in: &Client{LegacyClientID: "foo", SubjectType: "foo"}, - expectErr: true, + in: &Client{ID: "foo", SubjectType: "foo"}, + assertErr: assert.Error, }, } { + tc := tc t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { if tc.v == nil { tc.v = func(t *testing.T) *Validator { @@ -132,8 +164,8 @@ func TestValidate(t *testing.T) { } } err := tc.v(t).Validate(testCtx, tc.in) - if tc.expectErr { - require.Error(t, err) + if tc.assertErr != nil { + tc.assertErr(t, err) } else { require.NoError(t, err) tc.check(t, tc.in) @@ -148,7 +180,9 @@ type fakeHTTP struct { } func (f *fakeHTTP) HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client { - return httpx.NewResilientClient(httpx.ResilientClientWithClient(f.c)) + c := httpx.NewResilientClient(opts...) + c.HTTPClient = f.c + return c } func TestValidateSectorIdentifierURL(t *testing.T) { @@ -205,19 +239,46 @@ func TestValidateSectorIdentifierURL(t *testing.T) { } } +// from https://datatracker.ietf.org/doc/html/rfc7517#appendix-A.2 +const validJWKS = ` +{"keys": +[ + {"kty":"EC", + "crv":"P-256", + "x":"MKBCTNIcKUSDii11ySs3526iDZ8AiTo7Tu6KPAqv7D4", + "y":"4Etl6SRW2YiLUrN5vfvVHuhp7x8PxltmWWlbbM4IFyM", + "d":"870MB6gfuTJ4HtUnUvYMyJpr5eUZNP4Bk43bVdj3eAE", + "use":"enc", + "kid":"1"}, + + {"kty":"RSA", + "n":"0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw", + "e":"AQAB", + "d":"X4cTteJY_gn4FYPsXB8rdXix5vwsg1FLN5E3EaG6RJoVH-HLLKD9M7dx5oo7GURknchnrRweUkC7hT5fJLM0WbFAKNLWY2vv7B6NqXSzUvxT0_YSfqijwp3RTzlBaCxWp4doFk5N2o8Gy_nHNKroADIkJ46pRUohsXywbReAdYaMwFs9tv8d_cPVY3i07a3t8MN6TNwm0dSawm9v47UiCl3Sk5ZiG7xojPLu4sbg1U2jx4IBTNBznbJSzFHK66jT8bgkuqsk0GjskDJk19Z4qwjwbsnn4j2WBii3RL-Us2lGVkY8fkFzme1z0HbIkfz0Y6mqnOYtqc0X4jfcKoAC8Q", + "p":"83i-7IvMGXoMXCskv73TKr8637FiO7Z27zv8oj6pbWUQyLPQBQxtPVnwD20R-60eTDmD2ujnMt5PoqMrm8RfmNhVWDtjjMmCMjOpSXicFHj7XOuVIYQyqVWlWEh6dN36GVZYk93N8Bc9vY41xy8B9RzzOGVQzXvNEvn7O0nVbfs", + "q":"3dfOR9cuYq-0S-mkFLzgItgMEfFzB2q3hWehMuG0oCuqnb3vobLyumqjVZQO1dIrdwgTnCdpYzBcOfW5r370AFXjiWft_NGEiovonizhKpo9VVS78TzFgxkIdrecRezsZ-1kYd_s1qDbxtkDEgfAITAG9LUnADun4vIcb6yelxk", + "dp":"G4sPXkc6Ya9y8oJW9_ILj4xuppu0lzi_H7VTkS8xj5SdX3coE0oimYwxIi2emTAue0UOa5dpgFGyBJ4c8tQ2VF402XRugKDTP8akYhFo5tAA77Qe_NmtuYZc3C3m3I24G2GvR5sSDxUyAN2zq8Lfn9EUms6rY3Ob8YeiKkTiBj0", + "dq":"s9lAH9fggBsoFR8Oac2R_E2gw282rT2kGOAhvIllETE1efrA6huUUvMfBcMpn8lqeW6vzznYY5SSQF7pMdC_agI3nG8Ibp1BUb0JUiraRNqUfLhcQb_d9GF4Dh7e74WbRsobRonujTYN1xCaP6TO61jvWrX-L18txXw494Q_cgk", + "qi":"GyM_p6JrXySiz1toFgKbWV-JdI3jQ4ypu9rbMWx3rQJBfmt0FoYzgUIZEVFEcOqwemRN81zoDAaa-Bk0KWNGDjJHZDdDmFhW3AN7lI-puxk_mHZGJ11rxyR8O55XLSe3SPmRfKwZI6yU24ZxvQKFYItdldUKGzO6Ia6zTKhAVRU", + "alg":"RS256", + "kid":"2011-04-29"} +] +} +` + func TestValidateIPRanges(t *testing.T) { ctx := context.Background() c := internal.NewConfigurationWithDefaults() reg := internal.NewRegistryMemory(t, c, &contextx.Static{C: c.Source(ctx)}) v := NewValidator(reg) - c.MustSet(ctx, config.ViperKeyClientHTTPNoPrivateIPRanges, true) + c.MustSet(ctx, config.KeyClientHTTPNoPrivateIPRanges, true) require.NoError(t, v.ValidateDynamicRegistration(ctx, &Client{})) require.ErrorContains(t, v.ValidateDynamicRegistration(ctx, &Client{JSONWebKeysURI: "https://localhost:1234"}), "invalid_client_metadata") require.ErrorContains(t, v.ValidateDynamicRegistration(ctx, &Client{BackChannelLogoutURI: "https://localhost:1234"}), "invalid_client_metadata") require.ErrorContains(t, v.ValidateDynamicRegistration(ctx, &Client{RequestURIs: []string{"https://google", "https://localhost:1234"}}), "invalid_client_metadata") - c.MustSet(ctx, config.ViperKeyClientHTTPNoPrivateIPRanges, false) + c.MustSet(ctx, config.KeyClientHTTPNoPrivateIPRanges, false) require.NoError(t, v.ValidateDynamicRegistration(ctx, &Client{})) require.NoError(t, v.ValidateDynamicRegistration(ctx, &Client{JSONWebKeysURI: "https://localhost:1234"})) require.NoError(t, v.ValidateDynamicRegistration(ctx, &Client{BackChannelLogoutURI: "https://localhost:1234"})) @@ -241,7 +302,7 @@ func TestValidateDynamicRegistration(t *testing.T) { }{ { in: &Client{ - LegacyClientID: "foo", + ID: "foo", PostLogoutRedirectURIs: []string{"https://foo/"}, RedirectURIs: []string{"https://foo/"}, Metadata: []byte("{\"access_token_ttl\":10}"), @@ -250,7 +311,7 @@ func TestValidateDynamicRegistration(t *testing.T) { }, { in: &Client{ - LegacyClientID: "foo", + ID: "foo", PostLogoutRedirectURIs: []string{"https://foo/"}, RedirectURIs: []string{"https://foo/"}, Metadata: []byte("{\"id_token_ttl\":10}"), @@ -259,7 +320,7 @@ func TestValidateDynamicRegistration(t *testing.T) { }, { in: &Client{ - LegacyClientID: "foo", + ID: "foo", PostLogoutRedirectURIs: []string{"https://foo/"}, RedirectURIs: []string{"https://foo/"}, Metadata: []byte("{\"anything\":10}"), @@ -268,12 +329,12 @@ func TestValidateDynamicRegistration(t *testing.T) { }, { in: &Client{ - LegacyClientID: "foo", + ID: "foo", PostLogoutRedirectURIs: []string{"https://foo/"}, RedirectURIs: []string{"https://foo/"}, }, check: func(t *testing.T, c *Client) { - assert.EqualValues(t, "foo", c.LegacyClientID) + assert.EqualValues(t, "foo", c.ID) }, }, } { diff --git a/cmd/.snapshots/TestCreateClient-case=creates_successfully.json b/cmd/.snapshots/TestCreateClient-case=creates_successfully.json index 9281fa7d230..f20d01cd379 100644 --- a/cmd/.snapshots/TestCreateClient-case=creates_successfully.json +++ b/cmd/.snapshots/TestCreateClient-case=creates_successfully.json @@ -15,6 +15,8 @@ "code" ], "scope": "offline_access offline openid", + "skip_consent": false, + "skip_logout_consent": false, "subject_type": "public", "token_endpoint_auth_method": "client_secret_basic", "tos_uri": "", diff --git a/cmd/.snapshots/TestCreateClient-case=supports_encryption.json b/cmd/.snapshots/TestCreateClient-case=supports_encryption.json index 4bef1689f7e..984cedb2f2c 100644 --- a/cmd/.snapshots/TestCreateClient-case=supports_encryption.json +++ b/cmd/.snapshots/TestCreateClient-case=supports_encryption.json @@ -21,6 +21,8 @@ "code" ], "scope": "offline_access offline openid", + "skip_consent": false, + "skip_logout_consent": false, "subject_type": "public", "token_endpoint_auth_method": "client_secret_basic", "tos_uri": "", diff --git a/cmd/.snapshots/TestCreateClient-case=supports_setting_flags.json b/cmd/.snapshots/TestCreateClient-case=supports_setting_flags.json index 4bef1689f7e..984cedb2f2c 100644 --- a/cmd/.snapshots/TestCreateClient-case=supports_setting_flags.json +++ b/cmd/.snapshots/TestCreateClient-case=supports_setting_flags.json @@ -21,6 +21,8 @@ "code" ], "scope": "offline_access offline openid", + "skip_consent": false, + "skip_logout_consent": false, "subject_type": "public", "token_endpoint_auth_method": "client_secret_basic", "tos_uri": "", diff --git a/cmd/.snapshots/TestGetClient-case=gets_client.json b/cmd/.snapshots/TestGetClient-case=gets_client.json index 07ec29f7642..5c482bdb99a 100644 --- a/cmd/.snapshots/TestGetClient-case=gets_client.json +++ b/cmd/.snapshots/TestGetClient-case=gets_client.json @@ -8,6 +8,7 @@ "owner": "", "policy_uri": "", "scope": "", + "skip_consent": false, "subject_type": "", "token_endpoint_auth_method": "client_secret_post", "tos_uri": "" diff --git a/cmd/.snapshots/TestGetClient-case=gets_multiple_clients.json b/cmd/.snapshots/TestGetClient-case=gets_multiple_clients.json index 971096952d4..1685a7ccfd8 100644 --- a/cmd/.snapshots/TestGetClient-case=gets_multiple_clients.json +++ b/cmd/.snapshots/TestGetClient-case=gets_multiple_clients.json @@ -15,6 +15,7 @@ "redirect_uris": [], "response_types": [], "scope": "", + "skip_consent": false, "subject_type": "", "token_endpoint_auth_method": "client_secret_post", "tos_uri": "" @@ -35,6 +36,7 @@ "redirect_uris": [], "response_types": [], "scope": "", + "skip_consent": false, "subject_type": "", "token_endpoint_auth_method": "client_secret_post", "tos_uri": "" diff --git a/cmd/.snapshots/TestImportClient-case=imports_clients_from_single_file.json b/cmd/.snapshots/TestImportClient-case=imports_clients_from_single_file.json index 432a5b8ee48..6ca11ca6230 100644 --- a/cmd/.snapshots/TestImportClient-case=imports_clients_from_single_file.json +++ b/cmd/.snapshots/TestImportClient-case=imports_clients_from_single_file.json @@ -11,6 +11,7 @@ "owner": "", "policy_uri": "", "scope": "foo", + "skip_consent": false, "subject_type": "public", "token_endpoint_auth_method": "client_secret_basic", "tos_uri": "", @@ -28,6 +29,7 @@ "owner": "", "policy_uri": "", "scope": "bar", + "skip_consent": false, "subject_type": "public", "token_endpoint_auth_method": "client_secret_basic", "tos_uri": "", diff --git a/cmd/.snapshots/TestImportClient-case=performs_appropriate_error_reporting.json b/cmd/.snapshots/TestImportClient-case=performs_appropriate_error_reporting.json index 432a5b8ee48..6ca11ca6230 100644 --- a/cmd/.snapshots/TestImportClient-case=performs_appropriate_error_reporting.json +++ b/cmd/.snapshots/TestImportClient-case=performs_appropriate_error_reporting.json @@ -11,6 +11,7 @@ "owner": "", "policy_uri": "", "scope": "foo", + "skip_consent": false, "subject_type": "public", "token_endpoint_auth_method": "client_secret_basic", "tos_uri": "", @@ -28,6 +29,7 @@ "owner": "", "policy_uri": "", "scope": "bar", + "skip_consent": false, "subject_type": "public", "token_endpoint_auth_method": "client_secret_basic", "tos_uri": "", diff --git a/cmd/.snapshots/TestRevokeToken-case=revokes_valid_token_but_without_client_credentials.json b/cmd/.snapshots/TestRevokeToken-case=revokes_valid_token_but_without_client_credentials.json index 780e0a0b083..f68139c5e12 100644 --- a/cmd/.snapshots/TestRevokeToken-case=revokes_valid_token_but_without_client_credentials.json +++ b/cmd/.snapshots/TestRevokeToken-case=revokes_valid_token_but_without_client_credentials.json @@ -1 +1 @@ -"Usage:\n token the-token [flags]\n\nExamples:\n{{ .CommandPath }} --client-id a0184d6c-b313-4e70-a0b9-905b581e9218 --client-secret Hh1BjioNNm ciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNT\n\nFlags:\n --client-id string Use the provided OAuth 2.0 Client ID, defaults to environment variable OAUTH2_CLIENT_ID\n --client-secret string Use the provided OAuth 2.0 Client Secret, defaults to environment variable OAUTH2_CLIENT_SECRET\n -e, --endpoint string The API URL this command should target. Alternatively set using the ORY_SDK_URL environmental variable.\n --format string Set the output format. One of table, json, yaml, json-pretty, and jsonpath. (default \"default\")\n -h, --help help for token\n -H, --http-header : A list of additional HTTP headers to set. HTTP headers is separated by a : , for example: `-H 'Authorization: bearer some-token'`.\n -q, --quiet Be quiet with output printing.\n --skip-tls-verify Do not verify TLS certificates. Useful when dealing with self-signed certificates. Do not use in production!\n\n\nPlease provide a Client ID and Client Secret using flags --client-id and --client-secret, or environment variables OAUTH2_CLIENT_ID and OAUTH2_CLIENT_SECRET\n" +"Usage:\n token the-token [flags]\n\nExamples:\n{{ .CommandPath }} --client-id a0184d6c-b313-4e70-a0b9-905b581e9218 --client-secret Hh1BjioNNm ciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNT\n\nFlags:\n --client-id string Use the provided OAuth 2.0 Client ID, defaults to environment variable OAUTH2_CLIENT_ID\n --client-secret string Use the provided OAuth 2.0 Client Secret, defaults to environment variable OAUTH2_CLIENT_SECRET\n -e, --endpoint string The API URL this command should target. Alternatively set using the ORY_SDK_URL environmental variable.\n --format string Set the output format. One of table, json, yaml, json-pretty, jsonpath and jsonpointer. (default \"default\")\n -h, --help help for token\n -H, --http-header : A list of additional HTTP headers to set. HTTP headers is separated by a : , for example: `-H 'Authorization: bearer some-token'`.\n -q, --quiet Be quiet with output printing.\n --skip-tls-verify Do not verify TLS certificates. Useful when dealing with self-signed certificates. Do not use in production!\n\n\nPlease provide a Client ID and Client Secret using flags --client-id and --client-secret, or environment variables OAUTH2_CLIENT_ID and OAUTH2_CLIENT_SECRET\n" diff --git a/cmd/.snapshots/TestUpdateClient-case=creates_successfully.json b/cmd/.snapshots/TestUpdateClient-case=creates_successfully.json index 368b9960eff..c62158c5d9d 100644 --- a/cmd/.snapshots/TestUpdateClient-case=creates_successfully.json +++ b/cmd/.snapshots/TestUpdateClient-case=creates_successfully.json @@ -15,6 +15,8 @@ "code" ], "scope": "offline_access offline openid", + "skip_consent": false, + "skip_logout_consent": false, "subject_type": "public", "token_endpoint_auth_method": "client_secret_basic", "tos_uri": "", diff --git a/cmd/.snapshots/TestUpdateClient-case=supports_encryption.json b/cmd/.snapshots/TestUpdateClient-case=supports_encryption.json index 368b9960eff..c62158c5d9d 100644 --- a/cmd/.snapshots/TestUpdateClient-case=supports_encryption.json +++ b/cmd/.snapshots/TestUpdateClient-case=supports_encryption.json @@ -15,6 +15,8 @@ "code" ], "scope": "offline_access offline openid", + "skip_consent": false, + "skip_logout_consent": false, "subject_type": "public", "token_endpoint_auth_method": "client_secret_basic", "tos_uri": "", diff --git a/cmd/.snapshots/TestUpdateClient-case=updates_from_file-file=from_disk.json b/cmd/.snapshots/TestUpdateClient-case=updates_from_file-file=from_disk.json new file mode 100644 index 00000000000..e9a42532a2f --- /dev/null +++ b/cmd/.snapshots/TestUpdateClient-case=updates_from_file-file=from_disk.json @@ -0,0 +1,24 @@ +{ + "client_name": "updated through file from disk", + "client_secret_expires_at": 0, + "client_uri": "", + "grant_types": [ + "implicit" + ], + "jwks": {}, + "logo_uri": "", + "metadata": {}, + "owner": "", + "policy_uri": "", + "request_object_signing_alg": "RS256", + "response_types": [ + "code" + ], + "scope": "offline_access offline openid", + "skip_consent": false, + "skip_logout_consent": false, + "subject_type": "public", + "token_endpoint_auth_method": "client_secret_basic", + "tos_uri": "", + "userinfo_signed_response_alg": "none" +} diff --git a/cmd/.snapshots/TestUpdateClient-case=updates_from_file-file=stdin.json b/cmd/.snapshots/TestUpdateClient-case=updates_from_file-file=stdin.json new file mode 100644 index 00000000000..4491f0eed55 --- /dev/null +++ b/cmd/.snapshots/TestUpdateClient-case=updates_from_file-file=stdin.json @@ -0,0 +1,24 @@ +{ + "client_name": "updated through file stdin", + "client_secret_expires_at": 0, + "client_uri": "", + "grant_types": [ + "implicit" + ], + "jwks": {}, + "logo_uri": "", + "metadata": {}, + "owner": "", + "policy_uri": "", + "request_object_signing_alg": "RS256", + "response_types": [ + "code" + ], + "scope": "offline_access offline openid", + "skip_consent": false, + "skip_logout_consent": false, + "subject_type": "public", + "token_endpoint_auth_method": "client_secret_basic", + "tos_uri": "", + "userinfo_signed_response_alg": "none" +} diff --git a/cmd/cli/handler.go b/cmd/cli/handler.go index bc452ab15d6..da2d3746452 100644 --- a/cmd/cli/handler.go +++ b/cmd/cli/handler.go @@ -4,7 +4,7 @@ package cli import ( - "github.com/ory/hydra/driver" + "github.com/ory/hydra/v2/driver" "github.com/ory/x/configx" "github.com/ory/x/servicelocatorx" ) @@ -16,7 +16,7 @@ type Handler struct { func NewHandler(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *Handler { return &Handler{ - Migration: newMigrateHandler(), + Migration: newMigrateHandler(slOpts, dOpts, cOpts), Janitor: NewJanitorHandler(slOpts, dOpts, cOpts), } } diff --git a/cmd/cli/handler_janitor.go b/cmd/cli/handler_janitor.go index bec0401fe36..69035148b6e 100644 --- a/cmd/cli/handler_janitor.go +++ b/cmd/cli/handler_janitor.go @@ -6,11 +6,12 @@ package cli import ( "context" "fmt" + "io" "time" "github.com/ory/x/servicelocatorx" - "github.com/ory/hydra/persistence" + "github.com/ory/hydra/v2/persistence" "github.com/pkg/errors" @@ -18,8 +19,8 @@ import ( "github.com/spf13/cobra" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" "github.com/ory/x/configx" "github.com/ory/x/errorsx" ) @@ -52,12 +53,13 @@ func NewJanitorHandler(slOpts []servicelocatorx.Option, dOpts []driver.OptionsMo } } -func (_ *JanitorHandler) Args(cmd *cobra.Command, args []string) error { +func (*JanitorHandler) Args(cmd *cobra.Command, args []string) error { if len(args) == 0 && !flagx.MustGetBool(cmd, ReadFromEnv) && len(flagx.MustGetStringSlice(cmd, Config)) == 0 { fmt.Printf("%s\n", cmd.UsageString()) + //lint:ignore ST1005 formatted error string used in CLI output return fmt.Errorf("%s\n%s\n%s\n", "A DSN is required as a positional argument when not passing any of the following flags:", "- Using the environment variable with flag -e, --read-from-env", @@ -65,6 +67,7 @@ func (_ *JanitorHandler) Args(cmd *cobra.Command, args []string) error { } if !flagx.MustGetBool(cmd, OnlyTokens) && !flagx.MustGetBool(cmd, OnlyRequests) && !flagx.MustGetBool(cmd, OnlyGrants) { + //lint:ignore ST1005 formatted error string used in CLI output return fmt.Errorf("%s\n%s\n", cmd.UsageString(), "Janitor requires at least one of --tokens, --requests or --grants to be set") } @@ -72,10 +75,12 @@ func (_ *JanitorHandler) Args(cmd *cobra.Command, args []string) error { limit := flagx.MustGetInt(cmd, Limit) batchSize := flagx.MustGetInt(cmd, BatchSize) if limit <= 0 || batchSize <= 0 { + //lint:ignore ST1005 formatted error string used in CLI output return fmt.Errorf("%s\n%s\n", cmd.UsageString(), "Values for --limit and --batch-size should both be greater than 0") } if batchSize > limit { + //lint:ignore ST1005 formatted error string used in CLI output return fmt.Errorf("%s\n%s\n", cmd.UsageString(), "Value for --batch-size must not be greater than value for --limit") } @@ -130,6 +135,7 @@ func purge(cmd *cobra.Command, args []string, sl *servicelocatorx.Options, dOpts } if len(d.Config().DSN()) == 0 { + //lint:ignore ST1005 formatted error string used in CLI output return fmt.Errorf("%s\n%s\n%s\n", cmd.UsageString(), "When using flag -e, environment variable DSN must be set.", "When using flag -c, the dsn property should be set.") @@ -154,20 +160,20 @@ func purge(cmd *cobra.Command, args []string, sl *servicelocatorx.Options, dOpts routineFlags = append(routineFlags, OnlyGrants) } - return cleanupRun(cmd.Context(), notAfter, limit, batchSize, addRoutine(p, routineFlags...)...) + return cleanupRun(cmd.Context(), notAfter, limit, batchSize, addRoutine(cmd.OutOrStdout(), p, routineFlags...)...) } -func addRoutine(p persistence.Persister, names ...string) []cleanupRoutine { +func addRoutine(out io.Writer, p persistence.Persister, names ...string) []cleanupRoutine { var routines []cleanupRoutine for _, n := range names { switch n { case OnlyTokens: - routines = append(routines, cleanup(p.FlushInactiveAccessTokens, "access tokens")) - routines = append(routines, cleanup(p.FlushInactiveRefreshTokens, "refresh tokens")) + routines = append(routines, cleanup(out, p.FlushInactiveAccessTokens, "access tokens")) + routines = append(routines, cleanup(out, p.FlushInactiveRefreshTokens, "refresh tokens")) case OnlyRequests: - routines = append(routines, cleanup(p.FlushInactiveLoginConsentRequests, "login-consent requests")) + routines = append(routines, cleanup(out, p.FlushInactiveLoginConsentRequests, "login-consent requests")) case OnlyGrants: - routines = append(routines, cleanup(p.FlushInactiveGrants, "grants")) + routines = append(routines, cleanup(out, p.FlushInactiveGrants, "grants")) } } return routines @@ -175,12 +181,12 @@ func addRoutine(p persistence.Persister, names ...string) []cleanupRoutine { type cleanupRoutine func(ctx context.Context, notAfter time.Time, limit int, batchSize int) error -func cleanup(cr cleanupRoutine, routineName string) cleanupRoutine { +func cleanup(out io.Writer, cr cleanupRoutine, routineName string) cleanupRoutine { return func(ctx context.Context, notAfter time.Time, limit int, batchSize int) error { if err := cr(ctx, notAfter, limit, batchSize); err != nil { return errors.Wrap(errorsx.WithStack(err), fmt.Sprintf("Could not cleanup inactive %s", routineName)) } - fmt.Printf("Successfully completed Janitor run on %s\n", routineName) + fmt.Fprintf(out, "Successfully completed Janitor run on %s\n", routineName) return nil } } diff --git a/cmd/cli/handler_janitor_test.go b/cmd/cli/handler_janitor_test.go index c99440c23b1..7806f7c5471 100644 --- a/cmd/cli/handler_janitor_test.go +++ b/cmd/cli/handler_janitor_test.go @@ -9,14 +9,14 @@ import ( "testing" "time" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/spf13/cobra" "github.com/stretchr/testify/require" - "github.com/ory/hydra/cmd/cli" - "github.com/ory/hydra/internal/testhelpers" + "github.com/ory/hydra/v2/cmd/cli" + "github.com/ory/hydra/v2/internal/testhelpers" "github.com/ory/x/cmdx" ) @@ -48,7 +48,7 @@ func TestJanitorHandler_PurgeTokenNotAfter(t *testing.T) { fmt.Sprintf("--%s=%s", cli.AccessLifespan, jt.GetAccessTokenLifespan(ctx).String()), fmt.Sprintf("--%s=%s", cli.RefreshLifespan, jt.GetRefreshTokenLifespan(ctx).String()), fmt.Sprintf("--%s", cli.OnlyTokens), - jt.GetDSN(ctx), + jt.GetDSN(), ) }) @@ -80,13 +80,13 @@ func TestJanitorHandler_PurgeLoginConsentNotAfter(t *testing.T) { fmt.Sprintf("--%s=%s", cli.KeepIfYounger, v.String()), fmt.Sprintf("--%s=%s", cli.ConsentRequestLifespan, jt.GetConsentRequestLifespan(ctx).String()), fmt.Sprintf("--%s", cli.OnlyRequests), - jt.GetDSN(ctx), + jt.GetDSN(), ) }) notAfter := time.Now().Round(time.Second).Add(-v) consentLifespan := time.Now().Round(time.Second).Add(-jt.GetConsentRequestLifespan(ctx)) - t.Run("step=validate", jt.LoginConsentNotAfterValidate(ctx, notAfter, consentLifespan, reg.ConsentManager())) + t.Run("step=validate", jt.LoginConsentNotAfterValidate(ctx, notAfter, consentLifespan, reg)) }) } @@ -107,14 +107,14 @@ func TestJanitorHandler_PurgeLoginConsent(t *testing.T) { require.NoError(t, err) // setup - t.Run("step=setup", jt.LoginTimeoutSetup(ctx, reg.ConsentManager(), reg.ClientManager())) + t.Run("step=setup", jt.LoginTimeoutSetup(ctx, reg)) // cleanup t.Run("step=cleanup", func(t *testing.T) { cmdx.ExecNoErr(t, newJanitorCmd(), "janitor", fmt.Sprintf("--%s", cli.OnlyRequests), - jt.GetDSN(ctx), + jt.GetDSN(), ) }) @@ -129,14 +129,14 @@ func TestJanitorHandler_PurgeLoginConsent(t *testing.T) { require.NoError(t, err) // setup - t.Run("step=setup", jt.ConsentTimeoutSetup(ctx, reg.ConsentManager(), reg.ClientManager())) + t.Run("step=setup", jt.ConsentTimeoutSetup(ctx, reg)) // run cleanup t.Run("step=cleanup", func(t *testing.T) { cmdx.ExecNoErr(t, newJanitorCmd(), "janitor", fmt.Sprintf("--%s", cli.OnlyRequests), - jt.GetDSN(ctx), + jt.GetDSN(), ) }) @@ -155,14 +155,14 @@ func TestJanitorHandler_PurgeLoginConsent(t *testing.T) { require.NoError(t, err) // setup - t.Run("step=setup", jt.LoginRejectionSetup(ctx, reg.ConsentManager(), reg.ClientManager())) + t.Run("step=setup", jt.LoginRejectionSetup(ctx, reg)) // cleanup t.Run("step=cleanup", func(t *testing.T) { cmdx.ExecNoErr(t, newJanitorCmd(), "janitor", fmt.Sprintf("--%s", cli.OnlyRequests), - jt.GetDSN(ctx), + jt.GetDSN(), ) }) @@ -176,14 +176,14 @@ func TestJanitorHandler_PurgeLoginConsent(t *testing.T) { require.NoError(t, err) // setup - t.Run("step=setup", jt.ConsentRejectionSetup(ctx, reg.ConsentManager(), reg.ClientManager())) + t.Run("step=setup", jt.ConsentRejectionSetup(ctx, reg)) // cleanup t.Run("step=cleanup", func(t *testing.T) { cmdx.ExecNoErr(t, newJanitorCmd(), "janitor", fmt.Sprintf("--%s", cli.OnlyRequests), - jt.GetDSN(ctx), + jt.GetDSN(), ) }) @@ -279,7 +279,7 @@ func TestJanitorHandler_PurgeGrantNotAfter(t *testing.T) { require.NoError(t, err) // setup test - t.Run("step=setup", jt.GrantNotAfterSetup(ctx, reg.ClientManager(), reg.GrantManager())) + t.Run("step=setup", jt.GrantNotAfterSetup(ctx, reg.GrantManager())) // run the cleanup routine t.Run("step=cleanup", func(t *testing.T) { @@ -287,7 +287,7 @@ func TestJanitorHandler_PurgeGrantNotAfter(t *testing.T) { "janitor", fmt.Sprintf("--%s=%s", cli.KeepIfYounger, v.String()), fmt.Sprintf("--%s", cli.OnlyGrants), - jt.GetDSN(ctx), + jt.GetDSN(), ) }) diff --git a/cmd/cli/handler_jwk.go b/cmd/cli/handler_jwk.go index 0845fe5c1fe..aaecd433bea 100644 --- a/cmd/cli/handler_jwk.go +++ b/cmd/cli/handler_jwk.go @@ -4,7 +4,7 @@ package cli import ( - jose "gopkg.in/square/go-jose.v2" + jose "github.com/go-jose/go-jose/v3" ) func ToSDKFriendlyJSONWebKey(key interface{}, kid, use string) jose.JSONWebKey { diff --git a/cmd/cli/handler_migrate.go b/cmd/cli/handler_migrate.go index 23d3c8ad925..dd064ab7170 100644 --- a/cmd/cli/handler_migrate.go +++ b/cmd/cli/handler_migrate.go @@ -5,7 +5,6 @@ package cli import ( "bytes" - "context" "fmt" "io" "io/fs" @@ -14,27 +13,35 @@ import ( "regexp" "strings" + "github.com/ory/x/popx" "github.com/ory/x/servicelocatorx" "github.com/pkg/errors" "github.com/ory/x/configx" - "github.com/ory/x/errorsx" - "github.com/ory/x/cmdx" "github.com/spf13/cobra" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/persistence" "github.com/ory/x/flagx" ) -type MigrateHandler struct{} +type MigrateHandler struct { + slOpts []servicelocatorx.Option + dOpts []driver.OptionsModifier + cOpts []configx.OptionModifier +} -func newMigrateHandler() *MigrateHandler { - return &MigrateHandler{} +func newMigrateHandler(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *MigrateHandler { + return &MigrateHandler{ + slOpts: slOpts, + dOpts: dOpts, + cOpts: cOpts, + } } const ( @@ -259,37 +266,37 @@ func (h *MigrateHandler) MigrateGen(cmd *cobra.Command, args []string) { os.Exit(0) } -func (h *MigrateHandler) MigrateSQL(cmd *cobra.Command, args []string) (err error) { +func (h *MigrateHandler) makePersister(cmd *cobra.Command, args []string) (p persistence.Persister, err error) { var d driver.Registry if flagx.MustGetBool(cmd, "read-from-env") { d, err = driver.New( cmd.Context(), servicelocatorx.NewOptions(), - []driver.OptionsModifier{ + append([]driver.OptionsModifier{ driver.WithOptions( configx.SkipValidation(), configx.WithFlags(cmd.Flags())), driver.DisableValidation(), driver.DisablePreloading(), driver.SkipNetworkInit(), - }) + }, h.dOpts...)) if err != nil { - return err + return nil, err } if len(d.Config().DSN()) == 0 { _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "When using flag -e, environment variable DSN must be set.") - return cmdx.FailSilently(cmd) + return nil, cmdx.FailSilently(cmd) } } else { if len(args) != 1 { _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Please provide the database URL.") - return cmdx.FailSilently(cmd) + return nil, cmdx.FailSilently(cmd) } d, err = driver.New( cmd.Context(), servicelocatorx.NewOptions(), - []driver.OptionsModifier{ + append([]driver.OptionsModifier{ driver.WithOptions( configx.WithFlags(cmd.Flags()), configx.SkipValidation(), @@ -298,54 +305,34 @@ func (h *MigrateHandler) MigrateSQL(cmd *cobra.Command, args []string) (err erro driver.DisableValidation(), driver.DisablePreloading(), driver.SkipNetworkInit(), - }) + }, h.dOpts...)) if err != nil { - return err + return nil, err } } + return d.Persister(), nil +} - p := d.Persister() - conn := p.Connection(context.Background()) - if conn == nil { - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "Migrations can only be executed against a SQL-compatible driver but DSN is not a SQL source.") - return cmdx.FailSilently(cmd) - } - - if err := conn.Open(); err != nil { - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not open the database connection:\n%+v\n", err) - return cmdx.FailSilently(cmd) - } - - // convert migration tables - if err := p.PrepareMigration(context.Background()); err != nil { - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not convert the migration table:\n%+v\n", err) - return cmdx.FailSilently(cmd) - } - - // print migration status - _, _ = fmt.Fprintln(cmd.OutOrStdout(), "The following migration is planned:") - - status, err := p.MigrationStatus(context.Background()) +func (h *MigrateHandler) MigrateSQLUp(cmd *cobra.Command, args []string) (err error) { + p, err := h.makePersister(cmd, args) if err != nil { - fmt.Fprintf(cmd.ErrOrStderr(), "Could not get the migration status:\n%+v\n", errorsx.WithStack(err)) - return cmdx.FailSilently(cmd) + return err } - _ = status.Write(os.Stdout) + return popx.MigrateSQLUp(cmd, p) +} - if !flagx.MustGetBool(cmd, "yes") { - _, _ = fmt.Fprintln(cmd.ErrOrStderr(), "To skip the next question use flag --yes (at your own risk).") - if !cmdx.AskForConfirmation("Do you wish to execute this migration plan?", nil, nil) { - _, _ = fmt.Fprintln(cmd.OutOrStdout(), "Migration aborted.") - return nil - } +func (h *MigrateHandler) MigrateSQLDown(cmd *cobra.Command, args []string) (err error) { + p, err := h.makePersister(cmd, args) + if err != nil { + return err } + return popx.MigrateSQLDown(cmd, p) +} - // apply migrations - if err := p.MigrateUp(context.Background()); err != nil { - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not apply migrations:\n%+v\n", errorsx.WithStack(err)) - return cmdx.FailSilently(cmd) +func (h *MigrateHandler) MigrateStatus(cmd *cobra.Command, args []string) error { + p, err := h.makePersister(cmd, args) + if err != nil { + return err } - - _, _ = fmt.Fprintln(cmd.OutOrStdout(), "Successfully applied migrations!") - return nil + return popx.MigrateStatus(cmd, p) } diff --git a/cmd/clidoc/main.go b/cmd/clidoc/main.go index 4987677e34d..82c136ab66d 100644 --- a/cmd/clidoc/main.go +++ b/cmd/clidoc/main.go @@ -9,7 +9,7 @@ import ( "github.com/ory/x/clidoc" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" ) func main() { diff --git a/cmd/cmd_create_client.go b/cmd/cmd_create_client.go index 84a1a61c6c0..4d72b22f1ab 100644 --- a/cmd/cmd_create_client.go +++ b/cmd/cmd_create_client.go @@ -8,18 +8,22 @@ import ( "github.com/spf13/cobra" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" "github.com/ory/x/flagx" "github.com/ory/x/pointerx" - "github.com/ory/hydra/cmd/cli" + "github.com/ory/hydra/v2/cmd/cli" ) const ( + flagFile = "file" + + flagClientAccessTokenStrategy = "access-token-strategy" flagClientAllowedCORSOrigin = "allowed-cors-origin" flagClientAudience = "audience" flagClientBackchannelLogoutCallback = "backchannel-logout-callback" + flagClientId = "id" flagClientName = "name" flagClientClientURI = "client-uri" flagClientContact = "contact" @@ -38,6 +42,8 @@ const ( flagClientResponseType = "response-type" flagClientScope = "scope" flagClientSectorIdentifierURI = "sector-identifier-uri" + flagClientSkipConsent = "skip-consent" + flagClientLogoutSkipConsent = "skip-logout-consent" flagClientSubjectType = "subject-type" flagClientTokenEndpointAuthMethod = "token-endpoint-auth-method" flagClientSecret = "secret" @@ -53,7 +59,7 @@ func NewCreateClientsCommand() *cobra.Command { Args: cobra.NoArgs, Example: `{{ .CommandPath }} -n "my app" -c http://localhost/cb -g authorization_code -r code -a core,foobar -Use the tool jq (or any other JSON tool) to get the OAuth2 Client ID and and Secret: +Use the tool jq (or any other JSON tool) to get the OAuth2 Client ID and Secret: client=$({{ .CommandPath }} \ --format json \ @@ -83,14 +89,20 @@ To encrypt an auto-generated OAuth2 Client Secret, use flags ` + "`--pgp-key`" + } secret := flagx.MustGetString(cmd, flagClientSecret) + cl, err := clientFromFlags(cmd) + if err != nil { + return err + } + cl.ClientId = pointerx.Ptr(flagx.MustGetString(cmd, flagClientId)) + //nolint:bodyclose - client, _, err := m.OAuth2Api.CreateOAuth2Client(cmd.Context()).OAuth2Client(clientFromFlags(cmd)).Execute() + client, _, err := m.OAuth2API.CreateOAuth2Client(cmd.Context()).OAuth2Client(cl).Execute() if err != nil { return cmdx.PrintOpenAPIError(cmd, err) } if client.ClientSecret == nil && len(secret) > 0 { - client.ClientSecret = pointerx.String(secret) + client.ClientSecret = pointerx.Ptr(secret) } if encryptSecret && client.ClientSecret != nil { @@ -100,7 +112,7 @@ To encrypt an auto-generated OAuth2 Client Secret, use flags ` + "`--pgp-key`" + return cmdx.FailSilently(cmd) } - client.ClientSecret = pointerx.String(enc.Base64Encode()) + client.ClientSecret = pointerx.Ptr(enc.Base64Encode()) } cmdx.PrintRow(cmd, (*outputOAuth2Client)(client)) @@ -108,5 +120,6 @@ To encrypt an auto-generated OAuth2 Client Secret, use flags ` + "`--pgp-key`" + }, } registerClientFlags(cmd.Flags()) + cmd.Flags().String(flagClientId, "", "Provide the client's id.") return cmd } diff --git a/cmd/cmd_create_client_test.go b/cmd/cmd_create_client_test.go index 8e21f4f221d..585d3433bbb 100644 --- a/cmd/cmd_create_client_test.go +++ b/cmd/cmd_create_client_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" "github.com/ory/x/snapshotx" ) diff --git a/cmd/cmd_create_jwks.go b/cmd/cmd_create_jwks.go index ab30a1d53bc..6358cf05e7d 100644 --- a/cmd/cmd_create_jwks.go +++ b/cmd/cmd_create_jwks.go @@ -6,10 +6,12 @@ package cmd import ( "context" + "github.com/ory/hydra/v2/jwk" + "github.com/spf13/cobra" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" "github.com/ory/x/flagx" ) @@ -37,7 +39,7 @@ func NewCreateJWKSCmd() *cobra.Command { } //nolint:bodyclose - jwks, _, err := m.JwkApi.CreateJsonWebKeySet(context.Background(), args[0]).CreateJsonWebKeySet(hydra.CreateJsonWebKeySet{ + jwks, _, err := m.JwkAPI.CreateJsonWebKeySet(context.Background(), args[0]).CreateJsonWebKeySet(hydra.CreateJsonWebKeySet{ Alg: flagx.MustGetString(cmd, alg), Kid: kid, Use: flagx.MustGetString(cmd, use), @@ -46,12 +48,20 @@ func NewCreateJWKSCmd() *cobra.Command { return cmdx.PrintOpenAPIError(cmd, err) } + if flagx.MustGetBool(cmd, "public") { + jwks.Keys, err = jwk.OnlyPublicSDKKeys(jwks.Keys) + if err != nil { + return err + } + } + cmdx.PrintTable(cmd, &outputJSONWebKeyCollection{Keys: jwks.Keys, Set: args[0]}) return nil }, } - cmd.Root().Name() + cmd.Flags().String(alg, "RS256", "The algorithm to be used to generated they key. Supports: RS256, RS512, ES256, ES512, EdDSA") cmd.Flags().String(use, "sig", "The intended use of this key. Supports: sig, enc") + cmd.Flags().Bool("public", false, "Only return public keys") return cmd } diff --git a/cmd/cmd_create_jwks_test.go b/cmd/cmd_create_jwks_test.go index d9e07d51d24..bfacdb51721 100644 --- a/cmd/cmd_create_jwks_test.go +++ b/cmd/cmd_create_jwks_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" ) @@ -33,4 +33,12 @@ func TestCreateJWKS(t *testing.T) { require.NoError(t, err) assert.Equal(t, expected.Keys[0].KeyID, actual.Get("keys.0.kid").String()) }) + + t.Run("case=gets jwks public", func(t *testing.T) { + set := uuid.Must(uuid.NewV4()).String() + actual := gjson.Parse(cmdx.ExecNoErr(t, c, set, "--use", "enc", "--alg", "RS256", "--public")) + + assert.NotEmptyf(t, actual.Get("keys.0.kid").String(), "Expected kid to be set but got: %s", actual.Raw) + assert.Empty(t, actual.Get("keys.0.p").String(), "public key should not contain private key components: %s", actual.Raw) + }) } diff --git a/cmd/cmd_delete_client.go b/cmd/cmd_delete_client.go index ad129c74eb6..3eae17bda76 100644 --- a/cmd/cmd_delete_client.go +++ b/cmd/cmd_delete_client.go @@ -6,7 +6,7 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" ) @@ -34,7 +34,7 @@ To delete OAuth 2.0 Clients with the owner of "foo@bar.com", run: ) for _, c := range args { - _, err := m.OAuth2Api.DeleteOAuth2Client(cmd.Context(), c).Execute() //nolint:bodyclose + _, err := m.OAuth2API.DeleteOAuth2Client(cmd.Context(), c).Execute() //nolint:bodyclose if err != nil { failed[c] = cmdx.PrintOpenAPIError(cmd, err) continue diff --git a/cmd/cmd_delete_client_test.go b/cmd/cmd_delete_client_test.go index 4acc8f850a5..1aa04b3d41b 100644 --- a/cmd/cmd_delete_client_test.go +++ b/cmd/cmd_delete_client_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/assertx" "github.com/ory/x/cmdx" "github.com/ory/x/snapshotx" diff --git a/cmd/cmd_delete_jwks.go b/cmd/cmd_delete_jwks.go index d9165422103..22bba778481 100644 --- a/cmd/cmd_delete_jwks.go +++ b/cmd/cmd_delete_jwks.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" ) @@ -32,7 +32,7 @@ func NewDeleteJWKSCommand() *cobra.Command { ) for _, c := range args { - _, err = m.JwkApi.DeleteJsonWebKeySet(context.Background(), c).Execute() //nolint:bodyclose + _, err = m.JwkAPI.DeleteJsonWebKeySet(context.Background(), c).Execute() //nolint:bodyclose if err != nil { return cmdx.PrintOpenAPIError(cmd, err) } diff --git a/cmd/cmd_delete_jwks_test.go b/cmd/cmd_delete_jwks_test.go index 91fe3feee4a..630d53f9ffc 100644 --- a/cmd/cmd_delete_jwks_test.go +++ b/cmd/cmd_delete_jwks_test.go @@ -12,11 +12,11 @@ import ( "github.com/gofrs/uuid" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/stretchr/testify/assert" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/assertx" "github.com/ory/x/cmdx" ) diff --git a/cmd/cmd_delete_tokens.go b/cmd/cmd_delete_tokens.go index 59c9d917fc2..f8add90c7ce 100644 --- a/cmd/cmd_delete_tokens.go +++ b/cmd/cmd_delete_tokens.go @@ -6,7 +6,7 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" ) @@ -23,7 +23,7 @@ func NewDeleteAccessTokensCmd() *cobra.Command { } clientID := args[0] - _, err = client.OAuth2Api.DeleteOAuth2Token(cmd.Context()).ClientId(clientID).Execute() //nolint:bodyclose + _, err = client.OAuth2API.DeleteOAuth2Token(cmd.Context()).ClientId(clientID).Execute() //nolint:bodyclose if err != nil { return cmdx.PrintOpenAPIError(cmd, err) } diff --git a/cmd/cmd_delete_tokens_test.go b/cmd/cmd_delete_tokens_test.go index f965aa7cbf5..b420bf3c84a 100644 --- a/cmd/cmd_delete_tokens_test.go +++ b/cmd/cmd_delete_tokens_test.go @@ -10,7 +10,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" ) diff --git a/cmd/cmd_get_client.go b/cmd/cmd_get_client.go index c5588b165d1..0a7841a327e 100644 --- a/cmd/cmd_get_client.go +++ b/cmd/cmd_get_client.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" ) @@ -18,9 +18,9 @@ func NewGetClientsCmd() *cobra.Command { Args: cobra.MinimumNArgs(1), Short: "Get one or more OAuth 2.0 Clients by their ID(s)", Long: `This command gets all the details about an OAuth 2.0 Client. You can use this command in combination with jq.`, - Example: `To get the OAuth 2.0 Client's secret, run: + Example: `To get the OAuth 2.0 Client's name, run: - {{ .CommandPath }} --json | jq -r '.client_secret'`, + {{ .CommandPath }} --format json | jq -r '.client_name'`, RunE: func(cmd *cobra.Command, args []string) error { m, _, err := cliclient.NewClient(cmd) if err != nil { @@ -29,7 +29,7 @@ func NewGetClientsCmd() *cobra.Command { clients := make([]hydra.OAuth2Client, 0, len(args)) for _, id := range args { - client, _, err := m.OAuth2Api.GetOAuth2Client(cmd.Context(), id).Execute() //nolint:bodyclose + client, _, err := m.OAuth2API.GetOAuth2Client(cmd.Context(), id).Execute() //nolint:bodyclose if err != nil { return cmdx.PrintOpenAPIError(cmd, err) } diff --git a/cmd/cmd_get_client_test.go b/cmd/cmd_get_client_test.go index 05b0686cfc0..5586452548f 100644 --- a/cmd/cmd_get_client_test.go +++ b/cmd/cmd_get_client_test.go @@ -12,7 +12,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" "github.com/ory/x/snapshotx" ) @@ -24,7 +24,7 @@ func TestGetClient(t *testing.T) { expected := createClient(t, reg, nil) t.Run("case=gets client", func(t *testing.T) { - actual := gjson.Parse(cmdx.ExecNoErr(t, c, expected.ID.String())) + actual := gjson.Parse(cmdx.ExecNoErr(t, c, expected.GetID())) assert.NotEmpty(t, actual.Get("client_id").String()) assert.Empty(t, actual.Get("client_secret").String()) @@ -36,7 +36,7 @@ func TestGetClient(t *testing.T) { }) t.Run("case=gets multiple clients", func(t *testing.T) { - actual := gjson.Parse(cmdx.ExecNoErr(t, c, expected.ID.String(), expected.ID.String())) + actual := gjson.Parse(cmdx.ExecNoErr(t, c, expected.GetID(), expected.ID)) snapshotx.SnapshotT(t, json.RawMessage(actual.Raw), snapshotExcludedClientFields...) }) } diff --git a/cmd/cmd_get_jwks.go b/cmd/cmd_get_jwks.go index 327fc8420c9..f9d1a754885 100644 --- a/cmd/cmd_get_jwks.go +++ b/cmd/cmd_get_jwks.go @@ -6,20 +6,28 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/x/flagx" + + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" ) func NewGetJWKSCmd() *cobra.Command { - return &cobra.Command{ + cmd := &cobra.Command{ Use: "jwk set-1 [set-2] ...", Aliases: []string{"jwks"}, Args: cobra.MinimumNArgs(1), Short: "Get one or more JSON Web Key Set by its ID(s)", Long: `This command gets all the details about an JSON Web Key. You can use this command in combination with jq.`, - Example: `To get the JSON Web Key Set's secret, run: + Example: `To get the JSON Web Key Set's use, run: + + {{ .CommandPath }} | jq -r '.[].use' - {{ .CommandPath }} | jq -r '.[].use'`, +To get the JSON Web Key Set as only public keys: + + {{ .CommandPath }} --public ' +`, RunE: func(cmd *cobra.Command, args []string) error { m, _, err := cliclient.NewClient(cmd) if err != nil { @@ -28,7 +36,7 @@ func NewGetJWKSCmd() *cobra.Command { var sets outputJSONWebKeyCollection for _, set := range args { - key, _, err := m.JwkApi.GetJsonWebKeySet(cmd.Context(), set).Execute() //nolint:bodyclose + key, _, err := m.JwkAPI.GetJsonWebKeySet(cmd.Context(), set).Execute() //nolint:bodyclose if err != nil { return cmdx.PrintOpenAPIError(cmd, err) } @@ -36,6 +44,13 @@ func NewGetJWKSCmd() *cobra.Command { sets.Keys = append(sets.Keys, key.Keys...) } + if flagx.MustGetBool(cmd, "public") { + sets.Keys, err = jwk.OnlyPublicSDKKeys(sets.Keys) + if err != nil { + return err + } + } + if len(sets.Keys) == 1 { cmdx.PrintRow(cmd, outputJsonWebKey{Set: args[0], JsonWebKey: sets.Keys[0]}) } else if len(sets.Keys) > 1 { @@ -45,4 +60,6 @@ func NewGetJWKSCmd() *cobra.Command { return nil }, } + cmd.Flags().Bool("public", false, "Only return public keys") + return cmd } diff --git a/cmd/cmd_get_jwks_test.go b/cmd/cmd_get_jwks_test.go index 8b37e61ecd9..7f60d15119d 100644 --- a/cmd/cmd_get_jwks_test.go +++ b/cmd/cmd_get_jwks_test.go @@ -13,11 +13,11 @@ import ( "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" ) -func TestGetJwks(t *testing.T) { +func TestGetJWKS(t *testing.T) { ctx := context.Background() c := cmd.NewGetJWKSCmd() reg := setup(t, c) @@ -34,4 +34,16 @@ func TestGetJwks(t *testing.T) { assert.Equal(t, expected.Keys[0].KeyID, actual.Get("kid").String()) }) + + t.Run("case=gets jwks public", func(t *testing.T) { + actual := gjson.Parse(cmdx.ExecNoErr(t, c, set, "--public")) + + expected, err := reg.KeyManager().GetKeySet(ctx, set) + require.NoError(t, err) + + assert.Equal(t, expected.Keys[0].KeyID, actual.Get("kid").String()) + + assert.NotEmptyf(t, actual.Get("kid").String(), "Expected kid to be set but got: %s", actual.Raw) + assert.Empty(t, actual.Get("p").String(), "public key should not contain private key components: %s", actual.Raw) + }) } diff --git a/cmd/cmd_helper_client.go b/cmd/cmd_helper_client.go index 0248c621d94..ca28fafa12a 100644 --- a/cmd/cmd_helper_client.go +++ b/cmd/cmd_helper_client.go @@ -5,46 +5,68 @@ package cmd import ( "encoding/json" + "fmt" + "os" "strings" "github.com/spf13/cobra" "github.com/spf13/pflag" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/cmd/cli" + "github.com/ory/hydra/v2/cmd/cli" "github.com/ory/x/flagx" "github.com/ory/x/pointerx" ) -func clientFromFlags(cmd *cobra.Command) hydra.OAuth2Client { +func clientFromFlags(cmd *cobra.Command) (hydra.OAuth2Client, error) { + if filename := flagx.MustGetString(cmd, flagFile); filename != "" { + src := cmd.InOrStdin() + if filename != "-" { + f, err := os.Open(filename) + if err != nil { + return hydra.OAuth2Client{}, fmt.Errorf("unable to open file %q: %w", filename, err) + } + defer f.Close() + src = f + } + client := hydra.OAuth2Client{} + if err := json.NewDecoder(src).Decode(&client); err != nil { + return hydra.OAuth2Client{}, fmt.Errorf("unable to decode JSON: %w", err) + } + return client, nil + } + return hydra.OAuth2Client{ + AccessTokenStrategy: pointerx.Ptr(flagx.MustGetString(cmd, flagClientAccessTokenStrategy)), AllowedCorsOrigins: flagx.MustGetStringSlice(cmd, flagClientAllowedCORSOrigin), Audience: flagx.MustGetStringSlice(cmd, flagClientAudience), - BackchannelLogoutSessionRequired: pointerx.Bool(flagx.MustGetBool(cmd, flagClientBackChannelLogoutSessionRequired)), - BackchannelLogoutUri: pointerx.String(flagx.MustGetString(cmd, flagClientBackchannelLogoutCallback)), - ClientName: pointerx.String(flagx.MustGetString(cmd, flagClientName)), - ClientSecret: pointerx.String(flagx.MustGetString(cmd, flagClientSecret)), - ClientUri: pointerx.String(flagx.MustGetString(cmd, flagClientClientURI)), + BackchannelLogoutSessionRequired: pointerx.Ptr(flagx.MustGetBool(cmd, flagClientBackChannelLogoutSessionRequired)), + BackchannelLogoutUri: pointerx.Ptr(flagx.MustGetString(cmd, flagClientBackchannelLogoutCallback)), + ClientName: pointerx.Ptr(flagx.MustGetString(cmd, flagClientName)), + ClientSecret: pointerx.Ptr(flagx.MustGetString(cmd, flagClientSecret)), + ClientUri: pointerx.Ptr(flagx.MustGetString(cmd, flagClientClientURI)), Contacts: flagx.MustGetStringSlice(cmd, flagClientContact), - FrontchannelLogoutSessionRequired: pointerx.Bool(flagx.MustGetBool(cmd, flagClientFrontChannelLogoutSessionRequired)), - FrontchannelLogoutUri: pointerx.String(flagx.MustGetString(cmd, flagClientFrontChannelLogoutCallback)), + FrontchannelLogoutSessionRequired: pointerx.Ptr(flagx.MustGetBool(cmd, flagClientFrontChannelLogoutSessionRequired)), + FrontchannelLogoutUri: pointerx.Ptr(flagx.MustGetString(cmd, flagClientFrontChannelLogoutCallback)), GrantTypes: flagx.MustGetStringSlice(cmd, flagClientGrantType), - JwksUri: pointerx.String(flagx.MustGetString(cmd, flagClientJWKSURI)), - LogoUri: pointerx.String(flagx.MustGetString(cmd, flagClientLogoURI)), + JwksUri: pointerx.Ptr(flagx.MustGetString(cmd, flagClientJWKSURI)), + LogoUri: pointerx.Ptr(flagx.MustGetString(cmd, flagClientLogoURI)), Metadata: json.RawMessage(flagx.MustGetString(cmd, flagClientMetadata)), - Owner: pointerx.String(flagx.MustGetString(cmd, flagClientOwner)), - PolicyUri: pointerx.String(flagx.MustGetString(cmd, flagClientPolicyURI)), + Owner: pointerx.Ptr(flagx.MustGetString(cmd, flagClientOwner)), + PolicyUri: pointerx.Ptr(flagx.MustGetString(cmd, flagClientPolicyURI)), PostLogoutRedirectUris: flagx.MustGetStringSlice(cmd, flagClientPostLogoutCallback), RedirectUris: flagx.MustGetStringSlice(cmd, flagClientRedirectURI), - RequestObjectSigningAlg: pointerx.String(flagx.MustGetString(cmd, flagClientRequestObjectSigningAlg)), + RequestObjectSigningAlg: pointerx.Ptr(flagx.MustGetString(cmd, flagClientRequestObjectSigningAlg)), RequestUris: flagx.MustGetStringSlice(cmd, flagClientRequestURI), ResponseTypes: flagx.MustGetStringSlice(cmd, flagClientResponseType), - Scope: pointerx.String(strings.Join(flagx.MustGetStringSlice(cmd, flagClientScope), " ")), - SectorIdentifierUri: pointerx.String(flagx.MustGetString(cmd, flagClientSectorIdentifierURI)), - SubjectType: pointerx.String(flagx.MustGetString(cmd, flagClientSubjectType)), - TokenEndpointAuthMethod: pointerx.String(flagx.MustGetString(cmd, flagClientTokenEndpointAuthMethod)), - TosUri: pointerx.String(flagx.MustGetString(cmd, flagClientTOSURI)), - } + Scope: pointerx.Ptr(strings.Join(flagx.MustGetStringSlice(cmd, flagClientScope), " ")), + SkipConsent: pointerx.Ptr(flagx.MustGetBool(cmd, flagClientSkipConsent)), + SkipLogoutConsent: pointerx.Ptr(flagx.MustGetBool(cmd, flagClientLogoutSkipConsent)), + SectorIdentifierUri: pointerx.Ptr(flagx.MustGetString(cmd, flagClientSectorIdentifierURI)), + SubjectType: pointerx.Ptr(flagx.MustGetString(cmd, flagClientSubjectType)), + TokenEndpointAuthMethod: pointerx.Ptr(flagx.MustGetString(cmd, flagClientTokenEndpointAuthMethod)), + TosUri: pointerx.Ptr(flagx.MustGetString(cmd, flagClientTOSURI)), + }, nil } func registerEncryptFlags(flags *pflag.FlagSet) { @@ -55,6 +77,8 @@ func registerEncryptFlags(flags *pflag.FlagSet) { } func registerClientFlags(flags *pflag.FlagSet) { + flags.String(flagFile, "", "Read a JSON file representing a client from this location. If set, the other client flags are ignored.") + flags.String(flagClientMetadata, "{}", "Metadata is an arbitrary JSON String of your choosing.") flags.String(flagClientOwner, "", "The owner of this client, typically email addresses or a user ID.") flags.StringSlice(flagClientContact, nil, "A list representing ways to contact people responsible for this client, typically email addresses.") @@ -77,6 +101,9 @@ func registerClientFlags(flags *pflag.FlagSet) { flags.String(flagClientSecret, "", "Provide the client's secret.") flags.String(flagClientName, "", "The client's name.") flags.StringSlice(flagClientPostLogoutCallback, []string{}, "List of allowed URLs to be redirected to after a logout.") + flags.Bool(flagClientSkipConsent, false, "Boolean flag specifying whether to skip the consent screen for this client. If omitted, the default value is false.") + flags.Bool(flagClientLogoutSkipConsent, false, "Boolean flag specifying whether to skip the logout consent screen for this client. If omitted, the default value is false.") + flags.String(flagClientAccessTokenStrategy, "", "The strategy used to generate access tokens. Valid options are `opaque` and `jwt`.") // back-channel logout options flags.Bool(flagClientBackChannelLogoutSessionRequired, false, "Boolean flag specifying whether the client requires that a sid (session ID) Claim be included in the Logout Token to identify the client session with the OP when the backchannel-logout-callback is used. If omitted, the default value is false.") diff --git a/cmd/cmd_helper_test.go b/cmd/cmd_helper_test.go index bec0041e023..da386b4865d 100644 --- a/cmd/cmd_helper_test.go +++ b/cmd/cmd_helper_test.go @@ -12,15 +12,15 @@ import ( "github.com/gofrs/uuid" - "gopkg.in/square/go-jose.v2" + "github.com/go-jose/go-jose/v3" "github.com/spf13/cobra" "github.com/stretchr/testify/require" - "github.com/ory/hydra/client" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/internal/testhelpers" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/internal/testhelpers" "github.com/ory/x/cmdx" "github.com/ory/x/contextx" "github.com/ory/x/snapshotx" diff --git a/cmd/cmd_import_client.go b/cmd/cmd_import_client.go index 5b3279d42e0..166b5d898d7 100644 --- a/cmd/cmd_import_client.go +++ b/cmd/cmd_import_client.go @@ -14,8 +14,8 @@ import ( "github.com/spf13/cobra" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/cmd/cli" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cli" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" "github.com/ory/x/pointerx" ) @@ -101,7 +101,7 @@ Please be aware that this command does not update existing clients. If the clien for src, cc := range clients { for _, c := range cc { - result, _, err := m.OAuth2Api.CreateOAuth2Client(cmd.Context()).OAuth2Client(c).Execute() //nolint:bodyclose + result, _, err := m.OAuth2API.CreateOAuth2Client(cmd.Context()).OAuth2Client(c).Execute() //nolint:bodyclose if err != nil { failed[src] = cmdx.PrintOpenAPIError(cmd, err) continue diff --git a/cmd/cmd_import_client_test.go b/cmd/cmd_import_client_test.go index 6728c7d4c12..cc82b1aa69e 100644 --- a/cmd/cmd_import_client_test.go +++ b/cmd/cmd_import_client_test.go @@ -8,6 +8,7 @@ import ( "context" "encoding/json" "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" @@ -15,7 +16,7 @@ import ( "github.com/tidwall/gjson" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" "github.com/ory/x/pointerx" "github.com/ory/x/snapshotx" @@ -23,14 +24,12 @@ import ( func writeTempFile(t *testing.T, contents interface{}) string { t.Helper() - ij, err := json.Marshal(contents) - require.NoError(t, err) - f, err := os.CreateTemp(t.TempDir(), "") - require.NoError(t, err) - _, err = f.Write(ij) + fn := filepath.Join(t.TempDir(), "content.json") + f, err := os.Create(fn) require.NoError(t, err) + require.NoError(t, json.NewEncoder(f).Encode(contents)) require.NoError(t, f.Close()) - return f.Name() + return fn } func TestImportClient(t *testing.T) { @@ -38,8 +37,8 @@ func TestImportClient(t *testing.T) { c := cmd.NewImportClientCmd() reg := setup(t, c) - file1 := writeTempFile(t, []hydra.OAuth2Client{{Scope: pointerx.String("foo")}, {Scope: pointerx.String("bar"), ClientSecret: pointerx.String("some-secret")}}) - file2 := writeTempFile(t, []hydra.OAuth2Client{{Scope: pointerx.String("baz")}, {Scope: pointerx.String("zab"), ClientSecret: pointerx.String("some-secret")}}) + file1 := writeTempFile(t, []hydra.OAuth2Client{{Scope: pointerx.Ptr("foo")}, {Scope: pointerx.Ptr("bar"), ClientSecret: pointerx.Ptr("some-secret")}}) + file2 := writeTempFile(t, []hydra.OAuth2Client{{Scope: pointerx.Ptr("baz")}, {Scope: pointerx.Ptr("zab"), ClientSecret: pointerx.Ptr("some-secret")}}) t.Run("case=imports clients from single file", func(t *testing.T) { actual := gjson.Parse(cmdx.ExecNoErr(t, c, file1)) @@ -77,7 +76,7 @@ func TestImportClient(t *testing.T) { t.Run("case=imports clients from multiple files and stdin", func(t *testing.T) { var stdin bytes.Buffer - require.NoError(t, json.NewEncoder(&stdin).Encode([]hydra.OAuth2Client{{Scope: pointerx.String("oof")}, {Scope: pointerx.String("rab"), ClientSecret: pointerx.String("some-secret")}})) + require.NoError(t, json.NewEncoder(&stdin).Encode([]hydra.OAuth2Client{{Scope: pointerx.Ptr("oof")}, {Scope: pointerx.Ptr("rab"), ClientSecret: pointerx.Ptr("some-secret")}})) stdout, _, err := cmdx.Exec(t, c, &stdin, file1, file2) require.NoError(t, err) @@ -93,7 +92,7 @@ func TestImportClient(t *testing.T) { }) t.Run("case=performs appropriate error reporting", func(t *testing.T) { - file3 := writeTempFile(t, []hydra.OAuth2Client{{ClientSecret: pointerx.String("short")}}) + file3 := writeTempFile(t, []hydra.OAuth2Client{{ClientSecret: pointerx.Ptr("short")}}) stdout, stderr, err := cmdx.Exec(t, c, nil, file1, file3) require.Error(t, err) actual := gjson.Parse(stdout) diff --git a/cmd/cmd_import_jwk.go b/cmd/cmd_import_jwk.go index e73dda2ed7c..05b08069f6a 100644 --- a/cmd/cmd_import_jwk.go +++ b/cmd/cmd_import_jwk.go @@ -14,8 +14,8 @@ import ( "github.com/spf13/cobra" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/cmd/cli" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cli" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" "github.com/ory/x/flagx" "github.com/ory/x/josex" @@ -73,15 +73,18 @@ the imported keys will be added to that set. Otherwise, a new set will be create key = cli.ToSDKFriendlyJSONWebKey(key, "", "") - var buf bytes.Buffer - var jsonWebKey hydra.JsonWebKey + type jwk hydra.JsonWebKey // opt out of OpenAPI-generated UnmarshalJSON + var ( + buf bytes.Buffer + jsonWebKey jwk + ) if err := json.NewEncoder(&buf).Encode(key); err != nil { _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not encode key from `%s` to JSON: %s", src, err) return cmdx.FailSilently(cmd) } if err := json.NewDecoder(&buf).Decode(&jsonWebKey); err != nil { - _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not decode key from `%s` to JSON: %s", src, err) + _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Could not decode key from `%s` from JSON: %s", src, err) return cmdx.FailSilently(cmd) } @@ -107,14 +110,14 @@ the imported keys will be added to that set. Otherwise, a new set will be create return cmdx.FailSilently(cmd) } - keys[src] = append(keys[src], jsonWebKey) + keys[src] = append(keys[src], hydra.JsonWebKey(jsonWebKey)) } imported := make([]hydra.JsonWebKey, 0, len(keys)) failed := make(map[string]error) for src, kk := range keys { for _, k := range kk { - result, _, err := m.JwkApi.SetJsonWebKey(cmd.Context(), set, k.Kid).JsonWebKey(k).Execute() //nolint:bodyclose + result, _, err := m.JwkAPI.SetJsonWebKey(cmd.Context(), set, k.Kid).JsonWebKey(k).Execute() //nolint:bodyclose if err != nil { failed[src] = cmdx.PrintOpenAPIError(cmd, err) continue diff --git a/cmd/cmd_import_jwk_test.go b/cmd/cmd_import_jwk_test.go index c7584489dd8..0272e4671d0 100644 --- a/cmd/cmd_import_jwk_test.go +++ b/cmd/cmd_import_jwk_test.go @@ -19,7 +19,7 @@ import ( _ "embed" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" ) diff --git a/cmd/cmd_introspect_token.go b/cmd/cmd_introspect_token.go index c8024af960e..c1e558bc3f4 100644 --- a/cmd/cmd_introspect_token.go +++ b/cmd/cmd_introspect_token.go @@ -6,7 +6,7 @@ package cmd import ( "strings" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" "github.com/ory/x/flagx" @@ -25,7 +25,7 @@ func NewIntrospectTokenCmd() *cobra.Command { return err } - result, _, err := client.OAuth2Api.IntrospectOAuth2Token(cmd.Context()). + result, _, err := client.OAuth2API.IntrospectOAuth2Token(cmd.Context()). Token(args[0]). Scope(strings.Join(flagx.MustGetStringSlice(cmd, "scope"), " ")).Execute() //nolint:bodyclose if err != nil { diff --git a/cmd/cmd_introspect_token_test.go b/cmd/cmd_introspect_token_test.go index 77f32275caa..63519ea644f 100644 --- a/cmd/cmd_introspect_token_test.go +++ b/cmd/cmd_introspect_token_test.go @@ -13,7 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" ) diff --git a/cmd/cmd_list_clients.go b/cmd/cmd_list_clients.go index f848a5c1dfd..615aec0e846 100644 --- a/cmd/cmd_list_clients.go +++ b/cmd/cmd_list_clients.go @@ -8,7 +8,7 @@ import ( "github.com/spf13/cobra" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" ) @@ -31,15 +31,15 @@ func NewListClientsCmd() *cobra.Command { return err } - list, resp, err := m.OAuth2Api.ListOAuth2Clients(cmd.Context()).PageSize(int64(pageSize)).PageToken(pageToken).Execute() + // nolint:bodyclose + list, resp, err := m.OAuth2API.ListOAuth2Clients(cmd.Context()).PageSize(int64(pageSize)).PageToken(pageToken).Execute() if err != nil { return cmdx.PrintOpenAPIError(cmd, err) } + defer resp.Body.Close() var collection outputOAuth2ClientCollection - for k := range list { - collection.clients = append(collection.clients, list[k]) - } + collection.clients = append(collection.clients, list...) interfaceList := make([]interface{}, len(list)) for k := range collection.clients { diff --git a/cmd/cmd_list_clients_test.go b/cmd/cmd_list_clients_test.go index 87f875d7a3f..ac5c6b4fc1f 100644 --- a/cmd/cmd_list_clients_test.go +++ b/cmd/cmd_list_clients_test.go @@ -8,12 +8,12 @@ import ( "github.com/stretchr/testify/require" - "github.com/ory/hydra/client" + "github.com/ory/hydra/v2/client" "github.com/stretchr/testify/assert" "github.com/tidwall/gjson" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" ) diff --git a/cmd/cmd_perform_authorization_code.go b/cmd/cmd_perform_authorization_code.go index f077efda32c..bb996131a3a 100644 --- a/cmd/cmd_perform_authorization_code.go +++ b/cmd/cmd_perform_authorization_code.go @@ -4,39 +4,106 @@ package cmd import ( + "bytes" "context" "crypto/rand" "crypto/rsa" "crypto/tls" + "encoding/json" "fmt" "html/template" + "io" "net/http" + "net/url" "os" "strconv" "strings" "time" - "github.com/ory/hydra/cmd/cliclient" - - "github.com/pkg/errors" - - "github.com/ory/graceful" - "github.com/julienschmidt/httprouter" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/toqueteos/webbrowser" "golang.org/x/oauth2" + "github.com/ory/graceful" + openapi "github.com/ory/hydra-client-go/v2" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" "github.com/ory/x/flagx" + "github.com/ory/x/pointerx" "github.com/ory/x/randx" "github.com/ory/x/tlsx" "github.com/ory/x/urlx" ) +var tokenUserLogin = template.Must(template.New("").Parse(` + +

Login step

+
+ + + Remember login
+ Revoke previous consents
+ + +
+{{ if .Skip }} + user authenticated, could skip login UI. +{{ else }} + User unknown. +{{ end }} +
+

Complete login request

+
{{ .Raw }}
+ +`)) + +var tokenUserConsent = template.Must(template.New("").Parse(` + +

Consent step

+
+ + {{ if not .Audiences }} + No token audiences requested. + {{ else }} +

Requested audiences:

+
    + {{ range .Audiences }} +
  • {{ . }}
  • + {{ end }} +
+ {{ end }} + {{ if not .Scopes }} + No scopes requested. + {{ else }} +

Requested scopes:

+ {{ range .Scopes }} + {{ . }}
+ {{ end }} + {{ end }} +
+ Remember consent
+ + +
+{{ if .Skip }} + Consent established, could skip consent UI. +{{ else }} + No previous matching consent found, or client has requested re-consent. +{{ end }} +
+

Previous consents for this login session ({{ .SessionID }})

+
{{ .PreviousConsents }}
+
+

Complete consent request

+
{{ .Raw }}
+ +`)) + var tokenUserWelcome = template.Must(template.New("").Parse(` -

Welcome to the exemplary OAuth 2.0 Consumer!

+

Welcome to the example OAuth 2.0 Consumer!

This is an example app which emulates an OAuth 2.0 consumer application. Usually, this would be your web or mobile application and would use an OAuth 2.0 or OpenID Connect library.

@@ -63,7 +130,7 @@ var tokenUserResult = template.Must(template.New("").Parse(`
  • Access Token: {{ .AccessToken }}
  • Refresh Token: {{ .RefreshToken }}
  • -
  • Expires in: {{ .Expiry }}
  • +
  • Expires at: {{ .Expiry }}
  • ID Token: {{ .IDToken }}
{{ if .DisplayBackButton }} @@ -76,8 +143,8 @@ func NewPerformAuthorizationCodeCmd() *cobra.Command { cmd := &cobra.Command{ Use: "authorization-code", Example: "{{ .CommandPath }} --client-id ... --client-secret ...", - Short: "An exemplary OAuth 2.0 Client performing the OAuth 2.0 Authorize Code Flow", - Long: `Starts an exemplary web server that acts as an OAuth 2.0 Client performing the Authorize Code Flow. + Short: "Example OAuth 2.0 Client performing the OAuth 2.0 Authorize Code Flow", + Long: `Starts an example web server that acts as an OAuth 2.0 Client performing the Authorize Code Flow. This command will help you to see if Ory Hydra has been configured properly. This command must not be used for anything else than manual testing or demo purposes. The server will terminate on error @@ -90,15 +157,18 @@ and success, unless if the --no-shutdown flag is provided.`, endpoint = cliclient.GetOAuth2URLOverride(cmd, endpoint) - ctx := context.WithValue(cmd.Context(), oauth2.HTTPClient, client) isSSL := flagx.MustGetBool(cmd, "https") port := flagx.MustGetInt(cmd, "port") scopes := flagx.MustGetStringSlice(cmd, "scope") prompt := flagx.MustGetStringSlice(cmd, "prompt") maxAge := flagx.MustGetInt(cmd, "max-age") redirectUrl := flagx.MustGetString(cmd, "redirect") + authUrl := flagx.MustGetString(cmd, "auth-url") + tokenUrl := flagx.MustGetString(cmd, "token-url") audience := flagx.MustGetStringSlice(cmd, "audience") noShutdown := flagx.MustGetBool(cmd, "no-shutdown") + skip := flagx.MustGetBool(cmd, "skip") + responseMode := flagx.MustGetString(cmd, "response-mode") clientID := flagx.MustGetString(cmd, "client-id") if clientID == "" { @@ -118,53 +188,61 @@ and success, unless if the --no-shutdown flag is provided.`, redirectUrl = serverLocation + "callback" } - if err != nil { - return err + if authUrl == "" { + authUrl = urlx.AppendPaths(endpoint, "/oauth2/auth").String() } + + if tokenUrl == "" { + tokenUrl = urlx.AppendPaths(endpoint, "/oauth2/token").String() + } + conf := oauth2.Config{ ClientID: clientID, ClientSecret: clientSecret, Endpoint: oauth2.Endpoint{ - TokenURL: urlx.AppendPaths(endpoint, "/oauth2/token").String(), - AuthURL: urlx.AppendPaths(endpoint, "/oauth2/auth").String(), + AuthURL: authUrl, + TokenURL: tokenUrl, }, RedirectURL: redirectUrl, Scopes: scopes, } - var generateAuthCodeURL = func() (string, []rune) { - state, err := randx.RuneSequence(24, randx.AlphaLower) - cmdx.Must(err, "Could not generate random state: %s", err) + var generateAuthCodeURL = func() (string, string) { + state := flagx.MustGetString(cmd, "state") + if len(state) == 0 { + generatedState, err := randx.RuneSequence(24, randx.AlphaLower) + cmdx.Must(err, "Could not generate random state: %s", err) + state = string(generatedState) + } nonce, err := randx.RuneSequence(24, randx.AlphaLower) cmdx.Must(err, "Could not generate random state: %s", err) - authCodeURL := conf.AuthCodeURL( - string(state), - oauth2.SetAuthURLParam("audience", strings.Join(audience, "+")), - oauth2.SetAuthURLParam("nonce", string(nonce)), - oauth2.SetAuthURLParam("prompt", strings.Join(prompt, "+")), - oauth2.SetAuthURLParam("max_age", strconv.Itoa(maxAge)), - ) + opts := []oauth2.AuthCodeOption{oauth2.SetAuthURLParam("nonce", string(nonce))} + if len(audience) > 0 { + opts = append(opts, oauth2.SetAuthURLParam("audience", strings.Join(audience, " "))) + } + if len(prompt) > 0 { + opts = append(opts, oauth2.SetAuthURLParam("prompt", strings.Join(prompt, " "))) + } + if maxAge >= 0 { + opts = append(opts, oauth2.SetAuthURLParam("max_age", strconv.Itoa(maxAge))) + } + if responseMode != "" { + opts = append(opts, oauth2.SetAuthURLParam("response_mode", responseMode)) + } + + authCodeURL := conf.AuthCodeURL(state, opts...) return authCodeURL, state } authCodeURL, state := generateAuthCodeURL() - if !flagx.MustGetBool(cmd, "no-open") { - _ = webbrowser.Open(serverLocation) // ignore errors - } - - _, _ = fmt.Fprintln(os.Stderr, "Setting up home route on "+serverLocation) - _, _ = fmt.Fprintln(os.Stderr, "Setting up callback listener on "+serverLocation+"callback") - _, _ = fmt.Fprintln(os.Stderr, "Press ctrl + c on Linux / Windows or cmd + c on OSX to end the process.") - _, _ = fmt.Fprintf(os.Stderr, "If your browser does not open automatically, navigate to:\n\n\t%s\n\n", serverLocation) - r := httprouter.New() var tlsc *tls.Config if isSSL { key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Unable to generate RSA key pair: %s", err) + _, _ = fmt.Fprintf(cmd.ErrOrStderr(), "Unable to generate RSA key pair: %s", err) return cmdx.FailSilently(cmd) } @@ -185,85 +263,48 @@ and success, unless if the --no-shutdown flag is provided.`, defer cancel() _ = server.Shutdown(ctx) } - var onDone = func() { - if !noShutdown { - go shutdown() - } else { - // regenerate because we don't want to shutdown and we don't want to reuse nonce & state - authCodeURL, state = generateAuthCodeURL() - } - } r.GET("/", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { _ = tokenUserWelcome.Execute(w, &struct{ URL string }{URL: authCodeURL}) }) - type ed struct { - Name string - Description string - Hint string - Debug string - } - - r.GET("/callback", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - if len(r.URL.Query().Get("error")) > 0 { - _, _ = fmt.Fprintf(os.Stderr, "Got error: %s\n", r.URL.Query().Get("error_description")) - - w.WriteHeader(http.StatusInternalServerError) - _ = tokenUserError.Execute(w, &ed{ - Name: r.URL.Query().Get("error"), - Description: r.URL.Query().Get("error_description"), - Hint: r.URL.Query().Get("error_hint"), - Debug: r.URL.Query().Get("error_debug"), - }) - - onDone() - return - } + r.GET("/perform-flow", func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + http.Redirect(w, r, authCodeURL, http.StatusFound) + }) - if r.URL.Query().Get("state") != string(state) { - _, _ = fmt.Fprintf(os.Stderr, "States do not match. Expected %s, got %s\n", string(state), r.URL.Query().Get("state")) + rt := router{ + cl: client, + skip: skip, + cmd: cmd, + state: &state, + conf: &conf, + onDone: func() { + if !noShutdown { + go shutdown() + } else { + // regenerate because we don't want to shutdown and we don't want to reuse nonce & state + authCodeURL, state = generateAuthCodeURL() + } + }, + serverLocation: serverLocation, + noShutdown: noShutdown, + } - w.WriteHeader(http.StatusInternalServerError) - _ = tokenUserError.Execute(w, &ed{ - Name: "States do not match", - Description: "Expected state " + string(state) + " but got " + r.URL.Query().Get("state"), - }) - onDone() - return - } + r.GET("/login", rt.loginGET) + r.POST("/login", rt.loginPOST) + r.GET("/consent", rt.consentGET) + r.POST("/consent", rt.consentPOST) + r.GET("/callback", rt.callback) + r.POST("/callback", rt.callbackPOSTForm) - code := r.URL.Query().Get("code") - token, err := conf.Exchange(ctx, code) - if err != nil { - _, _ = fmt.Fprintf(os.Stderr, "Unable to exchange code for token: %s\n", err) - - w.WriteHeader(http.StatusInternalServerError) - _ = tokenUserError.Execute(w, &ed{ - Name: err.Error(), - }) - onDone() - return - } + if !flagx.MustGetBool(cmd, "no-open") { + _ = webbrowser.Open(serverLocation) // ignore errors + } - cmdx.PrintRow(cmd, outputOAuth2Token(*token)) - _ = tokenUserResult.Execute(w, struct { - AccessToken string - RefreshToken string - Expiry string - IDToken string - BackURL string - DisplayBackButton bool - }{ - AccessToken: token.AccessToken, - RefreshToken: token.RefreshToken, - Expiry: token.Expiry.Format(time.RFC1123), - IDToken: fmt.Sprintf("%s", token.Extra("id_token")), - BackURL: serverLocation, - DisplayBackButton: noShutdown, - }) - onDone() - }) + _, _ = fmt.Fprintln(rt.cmd.ErrOrStderr(), "Setting up home route on "+serverLocation) + _, _ = fmt.Fprintln(rt.cmd.ErrOrStderr(), "Setting up callback listener on "+serverLocation+"callback") + _, _ = fmt.Fprintln(rt.cmd.ErrOrStderr(), "Press ctrl + c on Linux / Windows or cmd + c on OSX to end the process.") + _, _ = fmt.Fprintf(rt.cmd.ErrOrStderr(), "If your browser does not open automatically, navigate to:\n\n\t%s\n\n", serverLocation) if isSSL { err = server.ListenAndServeTLS("", "") @@ -285,17 +326,335 @@ and success, unless if the --no-shutdown flag is provided.`, cmd.Flags().IntP("port", "p", 4446, "The port on which the server should run") cmd.Flags().StringSlice("scope", []string{"offline", "openid"}, "Request OAuth2 scope") cmd.Flags().StringSlice("prompt", []string{}, "Set the OpenID Connect prompt parameter") - cmd.Flags().Int("max-age", 0, "Set the OpenID Connect max_age parameter") + cmd.Flags().Int("max-age", -1, "Set the OpenID Connect max_age parameter. -1 means no max_age parameter will be used.") cmd.Flags().Bool("no-shutdown", false, "Do not terminate on success/error. State and nonce will be regenerated when auth flow has completed (either due to an error or success).") cmd.Flags().String("client-id", os.Getenv("OAUTH2_CLIENT_ID"), "Use the provided OAuth 2.0 Client ID, defaults to environment variable OAUTH2_CLIENT_ID") cmd.Flags().String("client-secret", os.Getenv("OAUTH2_CLIENT_SECRET"), "Use the provided OAuth 2.0 Client Secret, defaults to environment variable OAUTH2_CLIENT_SECRET") + cmd.Flags().String("state", "", "Force a state value (insecure)") cmd.Flags().String("redirect", "", "Force a redirect url") cmd.Flags().StringSlice("audience", []string{}, "Request a specific OAuth 2.0 Access Token Audience") cmd.Flags().String("auth-url", "", "Usually it is enough to specify the `endpoint` flag, but if you want to force the authorization url, use this flag") cmd.Flags().String("token-url", "", "Usually it is enough to specify the `endpoint` flag, but if you want to force the token url, use this flag") cmd.Flags().Bool("https", false, "Sets up HTTPS for the endpoint using a self-signed certificate which is re-generated every time you start this command") + cmd.Flags().Bool("skip", false, "Skip login and/or consent steps if possible. Only effective if you have configured the Login and Consent UI URLs to point to this server.") + cmd.Flags().String("response-mode", "", "Set the response mode. Can be query (default) or form_post.") return cmd } + +type router struct { + cl *openapi.APIClient + skip bool + cmd *cobra.Command + state *string + conf *oauth2.Config + onDone func() + serverLocation string + noShutdown bool +} + +func (rt *router) loginGET(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + req, raw, err := rt.cl.OAuth2API.GetOAuth2LoginRequest(r.Context()). + LoginChallenge(r.URL.Query().Get("login_challenge")). + Execute() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer raw.Body.Close() // to satisfy linter + + if rt.skip && req.GetSkip() { + req, res, err := rt.cl.OAuth2API.AcceptOAuth2LoginRequest(r.Context()). + LoginChallenge(req.Challenge). + AcceptOAuth2LoginRequest(openapi.AcceptOAuth2LoginRequest{Subject: req.Subject}). + Execute() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer res.Body.Close() // to satisfy linter + http.Redirect(w, r, req.RedirectTo, http.StatusFound) + return + } + + pretty, err := prettyJSON(raw.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + _ = tokenUserLogin.Execute(w, struct { + LoginChallenge string + Skip bool + SessionID string + Raw string + }{ + LoginChallenge: req.Challenge, + Skip: req.GetSkip(), + SessionID: req.GetSessionId(), + Raw: pretty, + }) +} + +func (rt *router) loginPOST(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + if err := r.ParseForm(); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + if r.FormValue("revoke-consents") == "on" { + res, err := rt.cl.OAuth2API.RevokeOAuth2ConsentSessions(r.Context()). + Subject(r.FormValue("username")). + All(true). + Execute() + if err != nil { + fmt.Fprintln(rt.cmd.ErrOrStderr(), "Error revoking previous consents:", err) + } else { + fmt.Fprintln(rt.cmd.ErrOrStderr(), "Revoked all previous consents") + } + defer res.Body.Close() // to satisfy linter + } + switch r.FormValue("action") { + case "accept": + + req, res, err := rt.cl.OAuth2API.AcceptOAuth2LoginRequest(r.Context()). + LoginChallenge(r.FormValue("ls")). + AcceptOAuth2LoginRequest(openapi.AcceptOAuth2LoginRequest{ + Subject: r.FormValue("username"), + Remember: pointerx.Ptr(r.FormValue("remember") == "on"), + RememberFor: pointerx.Int64(3600), + Context: map[string]string{ + "context from": "login step", + }, + }).Execute() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer res.Body.Close() // to satisfy linter + http.Redirect(w, r, req.RedirectTo, http.StatusFound) + + case "deny": + req, res, err := rt.cl.OAuth2API.RejectOAuth2LoginRequest(r.Context()).LoginChallenge(r.FormValue("ls")).Execute() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer res.Body.Close() // to satisfy linter + http.Redirect(w, r, req.RedirectTo, http.StatusFound) + + default: + http.Error(w, "Invalid action", http.StatusBadRequest) + } +} + +func (rt *router) consentGET(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + req, raw, err := rt.cl.OAuth2API.GetOAuth2ConsentRequest(r.Context()). + ConsentChallenge(r.URL.Query().Get("consent_challenge")). + Execute() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer raw.Body.Close() // to satisfy linter + + if rt.skip && req.GetSkip() { + req, res, err := rt.cl.OAuth2API.AcceptOAuth2ConsentRequest(r.Context()). + ConsentChallenge(req.Challenge). + AcceptOAuth2ConsentRequest(openapi.AcceptOAuth2ConsentRequest{ + GrantScope: req.GetRequestedScope(), + GrantAccessTokenAudience: req.GetRequestedAccessTokenAudience(), + Remember: pointerx.Ptr(true), + RememberFor: pointerx.Int64(3600), + Session: &openapi.AcceptOAuth2ConsentRequestSession{ + AccessToken: map[string]string{ + "foo": "bar", + }, + IdToken: map[string]string{ + "baz": "bar", + }, + }, + }).Execute() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer res.Body.Close() // to satisfy linter + http.Redirect(w, r, req.RedirectTo, http.StatusFound) + return + } + + pretty, err := prettyJSON(raw.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + _, raw, err = rt.cl.OAuth2API.ListOAuth2ConsentSessions(r.Context()). + Subject(req.GetSubject()). + LoginSessionId(req.GetLoginSessionId()). + Execute() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer raw.Body.Close() // to satisfy linter + prettyPrevConsent, err := prettyJSON(raw.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + _ = tokenUserConsent.Execute(w, struct { + ConsentChallenge string + Audiences []string + Scopes []string + Skip bool + SessionID string + PreviousConsents string + Raw string + }{ + ConsentChallenge: req.Challenge, + Audiences: req.RequestedAccessTokenAudience, + Scopes: req.RequestedScope, + Skip: req.GetSkip(), + SessionID: req.GetLoginSessionId(), + PreviousConsents: prettyPrevConsent, + Raw: pretty, + }) +} + +func (rt *router) consentPOST(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + if err := r.ParseForm(); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + switch r.FormValue("action") { + case "accept": + req, res, err := rt.cl.OAuth2API.AcceptOAuth2ConsentRequest(r.Context()). + ConsentChallenge(r.FormValue("cs")). + AcceptOAuth2ConsentRequest(openapi.AcceptOAuth2ConsentRequest{ + GrantScope: r.Form["scope"], + GrantAccessTokenAudience: r.Form["audience"], + Remember: pointerx.Ptr(r.FormValue("remember") == "on"), + RememberFor: pointerx.Int64(3600), + Session: &openapi.AcceptOAuth2ConsentRequestSession{ + AccessToken: map[string]string{ + "foo": "bar", + }, + IdToken: map[string]string{ + "baz": "bar", + }, + }, + }).Execute() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer res.Body.Close() // to satisfy linter + http.Redirect(w, r, req.RedirectTo, http.StatusFound) + + case "deny": + req, res, err := rt.cl.OAuth2API.RejectOAuth2ConsentRequest(r.Context()). + ConsentChallenge(r.FormValue("cs")). + Execute() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + defer res.Body.Close() // to satisfy linter + http.Redirect(w, r, req.RedirectTo, http.StatusFound) + + default: + http.Error(w, "Invalid action", http.StatusBadRequest) + } +} + +func (rt *router) callback(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + defer rt.onDone() + + if len(r.URL.Query().Get("error")) > 0 { + _, _ = fmt.Fprintf(rt.cmd.ErrOrStderr(), "Got error: %s\n", r.URL.Query().Get("error_description")) + + w.WriteHeader(http.StatusInternalServerError) + _ = tokenUserError.Execute(w, &ed{ + Name: r.URL.Query().Get("error"), + Description: r.URL.Query().Get("error_description"), + Hint: r.URL.Query().Get("error_hint"), + Debug: r.URL.Query().Get("error_debug"), + }) + return + } + + if r.URL.Query().Get("state") != *rt.state { + descr := fmt.Sprintf("States do not match. Expected %q, got %q.", *rt.state, r.URL.Query().Get("state")) + _, _ = fmt.Fprintln(rt.cmd.ErrOrStderr(), descr) + + w.WriteHeader(http.StatusInternalServerError) + _ = tokenUserError.Execute(w, &ed{ + Name: "States do not match", + Description: descr, + }) + return + } + + code := r.URL.Query().Get("code") + ctx := context.WithValue(rt.cmd.Context(), oauth2.HTTPClient, rt.cl) + token, err := rt.conf.Exchange(ctx, code) + if err != nil { + _, _ = fmt.Fprintf(rt.cmd.ErrOrStderr(), "Unable to exchange code for token: %s\n", err) + + w.WriteHeader(http.StatusInternalServerError) + _ = tokenUserError.Execute(w, &ed{ + Name: err.Error(), + }) + return + } + + cmdx.PrintRow(rt.cmd, outputOAuth2Token(*token)) + _ = tokenUserResult.Execute(w, struct { + AccessToken string + RefreshToken string + Expiry string + IDToken string + BackURL string + DisplayBackButton bool + }{ + AccessToken: token.AccessToken, + RefreshToken: token.RefreshToken, + Expiry: token.Expiry.Format(time.RFC1123), + IDToken: fmt.Sprintf("%s", token.Extra("id_token")), + BackURL: rt.serverLocation, + DisplayBackButton: rt.noShutdown, + }) +} + +func (rt *router) callbackPOSTForm(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + if err := r.ParseForm(); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + u := url.URL{ + Path: r.URL.Path, + RawQuery: r.PostForm.Encode(), + } + http.Redirect(w, r, u.String(), http.StatusFound) +} + +type ed struct { + Name string + Description string + Hint string + Debug string +} + +func prettyJSON(r io.Reader) (string, error) { + contentsRaw, err := io.ReadAll(r) + if err != nil { + return "", err + } + var buf bytes.Buffer + if err := json.Indent(&buf, contentsRaw, "", " "); err != nil { + return "", err + } + return buf.String(), nil +} diff --git a/cmd/cmd_perform_client_credentials.go b/cmd/cmd_perform_client_credentials.go index ac645b30532..d2246f64498 100644 --- a/cmd/cmd_perform_client_credentials.go +++ b/cmd/cmd_perform_client_credentials.go @@ -10,7 +10,7 @@ import ( "os" "strings" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/spf13/cobra" "golang.org/x/oauth2" diff --git a/cmd/cmd_perform_client_credentials_test.go b/cmd/cmd_perform_client_credentials_test.go index 6026e352944..4415c06cea2 100644 --- a/cmd/cmd_perform_client_credentials_test.go +++ b/cmd/cmd_perform_client_credentials_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/tidwall/gjson" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" ) @@ -22,7 +22,7 @@ func TestPerformClientCredentialsGrant(t *testing.T) { expected := createClientCredentialsClient(t, reg) t.Run("case=exchanges for access token", func(t *testing.T) { - result := cmdx.ExecNoErr(t, c, "--client-id", expected.ID.String(), "--client-secret", expected.Secret) + result := cmdx.ExecNoErr(t, c, "--client-id", expected.GetID(), "--client-secret", expected.Secret) actual := gjson.Parse(result) assert.Equal(t, "bearer", actual.Get("token_type").String(), result) assert.NotEmpty(t, actual.Get("access_token").String(), result) diff --git a/cmd/cmd_revoke_token.go b/cmd/cmd_revoke_token.go index d637a9bfcf5..7e0e5f8831e 100644 --- a/cmd/cmd_revoke_token.go +++ b/cmd/cmd_revoke_token.go @@ -9,7 +9,7 @@ import ( "os" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" "github.com/ory/x/flagx" @@ -38,7 +38,7 @@ Please provide a Client ID and Client Secret using flags --client-id and --clien } token := args[0] - _, err = client.OAuth2Api.RevokeOAuth2Token( + _, err = client.OAuth2API.RevokeOAuth2Token( context.WithValue(cmd.Context(), hydra.ContextBasicAuth, hydra.BasicAuth{ UserName: clientID, Password: clientSecret, diff --git a/cmd/cmd_revoke_token_test.go b/cmd/cmd_revoke_token_test.go index fec8078386e..abaa2a59995 100644 --- a/cmd/cmd_revoke_token_test.go +++ b/cmd/cmd_revoke_token_test.go @@ -12,7 +12,7 @@ import ( "github.com/tidwall/gjson" "golang.org/x/oauth2/clientcredentials" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" "github.com/ory/x/snapshotx" ) diff --git a/cmd/cmd_update_client.go b/cmd/cmd_update_client.go index 1067b861b1d..6205b21ad71 100644 --- a/cmd/cmd_update_client.go +++ b/cmd/cmd_update_client.go @@ -9,8 +9,8 @@ import ( "github.com/spf13/cobra" - "github.com/ory/hydra/cmd/cli" - "github.com/ory/hydra/cmd/cliclient" + "github.com/ory/hydra/v2/cmd/cli" + "github.com/ory/hydra/v2/cmd/cliclient" "github.com/ory/x/cmdx" "github.com/ory/x/flagx" "github.com/ory/x/pointerx" @@ -42,15 +42,18 @@ To encrypt an auto-generated OAuth2 Client Secret, use flags ` + "`--pgp-key`" + } id := args[0] - cc := clientFromFlags(cmd) + cc, err := clientFromFlags(cmd) + if err != nil { + return err + } - client, _, err := m.OAuth2Api.SetOAuth2Client(context.Background(), id).OAuth2Client(cc).Execute() //nolint:bodyclose + client, _, err := m.OAuth2API.SetOAuth2Client(context.Background(), id).OAuth2Client(cc).Execute() //nolint:bodyclose if err != nil { return cmdx.PrintOpenAPIError(cmd, err) } if client.ClientSecret == nil && len(secret) > 0 { - client.ClientSecret = pointerx.String(secret) + client.ClientSecret = pointerx.Ptr(secret) } if encryptSecret && client.ClientSecret != nil { @@ -60,7 +63,7 @@ To encrypt an auto-generated OAuth2 Client Secret, use flags ` + "`--pgp-key`" + return cmdx.FailSilently(cmd) } - client.ClientSecret = pointerx.String(enc.Base64Encode()) + client.ClientSecret = pointerx.Ptr(enc.Base64Encode()) } cmdx.PrintRow(cmd, (*outputOAuth2Client)(client)) diff --git a/cmd/cmd_update_client_test.go b/cmd/cmd_update_client_test.go index e52638ace73..6cbcb7dfe5f 100644 --- a/cmd/cmd_update_client_test.go +++ b/cmd/cmd_update_client_test.go @@ -4,15 +4,18 @@ package cmd_test import ( + "bytes" "context" "encoding/json" "testing" + "github.com/tidwall/sjson" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/cmdx" "github.com/ory/x/snapshotx" ) @@ -24,24 +27,63 @@ func TestUpdateClient(t *testing.T) { original := createClient(t, reg, nil) t.Run("case=creates successfully", func(t *testing.T) { - actual := gjson.Parse(cmdx.ExecNoErr(t, c, "--grant-type", "implicit", original.ID.String())) - expected, err := reg.ClientManager().GetClient(ctx, actual.Get("client_id").String()) + actual := gjson.Parse(cmdx.ExecNoErr(t, c, "--grant-type", "implicit", original.GetID())) + expected, err := reg.ClientManager().GetClient(ctx, actual.Get("client_id").Str) require.NoError(t, err) - assert.Equal(t, expected.GetID(), actual.Get("client_id").String()) - assert.Equal(t, "implicit", actual.Get("grant_types").Array()[0].String()) + assert.Equal(t, expected.GetID(), actual.Get("client_id").Str) + assert.Equal(t, "implicit", actual.Get("grant_types").Array()[0].Str) snapshotx.SnapshotT(t, json.RawMessage(actual.Raw), snapshotExcludedClientFields...) }) t.Run("case=supports encryption", func(t *testing.T) { actual := gjson.Parse(cmdx.ExecNoErr(t, c, - original.ID.String(), + original.GetID(), "--secret", "some-userset-secret", "--pgp-key", base64EncodedPGPPublicKey(t), )) - assert.NotEmpty(t, actual.Get("client_id").String()) - assert.NotEmpty(t, actual.Get("client_secret").String()) + assert.Equal(t, original.ID, actual.Get("client_id").Str) + assert.NotEmpty(t, actual.Get("client_secret").Str) + assert.NotEqual(t, original.Secret, actual.Get("client_secret").Str) snapshotx.SnapshotT(t, json.RawMessage(actual.Raw), snapshotExcludedClientFields...) }) + + t.Run("case=updates from file", func(t *testing.T) { + original, err := reg.ClientManager().GetConcreteClient(ctx, original.GetID()) + require.NoError(t, err) + + raw, err := json.Marshal(original) + require.NoError(t, err) + + t.Run("file=stdin", func(t *testing.T) { + raw, err = sjson.SetBytes(raw, "client_name", "updated through file stdin") + require.NoError(t, err) + + stdout, stderr, err := cmdx.Exec(t, c, bytes.NewReader(raw), original.GetID(), "--file", "-") + require.NoError(t, err, stderr) + + actual := gjson.Parse(stdout) + assert.Equal(t, original.ID, actual.Get("client_id").Str) + assert.Equal(t, "updated through file stdin", actual.Get("client_name").Str) + + snapshotx.SnapshotT(t, json.RawMessage(actual.Raw), snapshotExcludedClientFields...) + }) + + t.Run("file=from disk", func(t *testing.T) { + raw, err = sjson.SetBytes(raw, "client_name", "updated through file from disk") + require.NoError(t, err) + + fn := writeTempFile(t, json.RawMessage(raw)) + + stdout, stderr, err := cmdx.Exec(t, c, nil, original.GetID(), "--file", fn) + require.NoError(t, err, stderr) + + actual := gjson.Parse(stdout) + assert.Equal(t, original.ID, actual.Get("client_id").Str) + assert.Equal(t, "updated through file from disk", actual.Get("client_name").Str) + + snapshotx.SnapshotT(t, json.RawMessage(actual.Raw), snapshotExcludedClientFields...) + }) + }) } diff --git a/cmd/helper_test.go b/cmd/helper_test.go index ac4e0364815..d19624e0c48 100644 --- a/cmd/helper_test.go +++ b/cmd/helper_test.go @@ -33,5 +33,5 @@ func TestGetPageToken(t *testing.T) { u, _ := url.Parse("https://example.com/foobar") rec := httptest.NewRecorder() tokenpagination.PaginationHeader(rec, u, 100, 3, 10) - assert.Equal(t, `eyJwYWdlIjoiNDAiLCJ2IjoxfQ`, getPageToken(rec.Result()), rec.Result().Header.Get("Link")) + assert.Equal(t, `eyJvZmZzZXQiOiI0MCIsInYiOjJ9`, getPageToken(rec.Result()), rec.Result().Header.Get("Link")) } diff --git a/cmd/janitor.go b/cmd/janitor.go index 31ffd4e7a63..be3d7f9f33d 100644 --- a/cmd/janitor.go +++ b/cmd/janitor.go @@ -6,18 +6,18 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/ory/hydra/driver" + "github.com/ory/hydra/v2/driver" "github.com/ory/x/servicelocatorx" - "github.com/ory/hydra/cmd/cli" + "github.com/ory/hydra/v2/cmd/cli" "github.com/ory/x/configx" ) func NewJanitorCmd(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *cobra.Command { cmd := &cobra.Command{ - Use: "janitor []", + Use: "janitor [[database_url]]", Short: "This command cleans up stale database rows.", - Example: `hydra janitor --keep-if-younger 23h --access-lifespan 1h --refresh-lifespan 40h --consent-request-lifespan 10m `, + Example: `hydra janitor --keep-if-younger 23h --access-lifespan 1h --refresh-lifespan 40h --consent-request-lifespan 10m [database_url]`, Long: `This command cleans up stale database rows. This will select records to delete with a limit and delete records in batch to ensure that no table locking issues arise in big production databases. diff --git a/cmd/migrate_gen.go b/cmd/migrate_gen.go index 05a46fa6c87..d9dbe837a85 100644 --- a/cmd/migrate_gen.go +++ b/cmd/migrate_gen.go @@ -6,7 +6,7 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/ory/hydra/cmd/cli" + "github.com/ory/hydra/v2/cmd/cli" ) func NewMigrateGenCmd() *cobra.Command { diff --git a/cmd/migrate_sql.go b/cmd/migrate_sql.go index 4b03588cf04..50b687d4470 100644 --- a/cmd/migrate_sql.go +++ b/cmd/migrate_sql.go @@ -6,17 +6,19 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/ory/hydra/driver" + "github.com/ory/x/popx" + + "github.com/ory/hydra/v2/cmd/cli" + "github.com/ory/hydra/v2/driver" "github.com/ory/x/configx" "github.com/ory/x/servicelocatorx" - - "github.com/ory/hydra/cmd/cli" ) -func NewMigrateSqlCmd(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *cobra.Command { +func NewMigrateSQLCmd(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *cobra.Command { cmd := &cobra.Command{ - Use: "sql ", - Short: "Create SQL schemas and apply migration plans", + Use: "sql [database_url]", + Deprecated: "Please use `hydra migrate sql up` instead.", + Short: "Perform SQL migrations", Long: `Run this command on a fresh SQL installation and when you upgrade Hydra to a new minor version. For example, upgrading Hydra 0.7.0 to 0.8.0 requires running this command. @@ -25,16 +27,32 @@ This decreases risk of failure and decreases time required. You can read in the database URL using the -e flag, for example: export DSN=... - hydra migrate sql -e + hydra migrate sql up -e ### WARNING ### Before running this command on an existing database, create a back up!`, - RunE: cli.NewHandler(slOpts, dOpts, cOpts).Migration.MigrateSQL, + RunE: cli.NewHandler(slOpts, dOpts, cOpts).Migration.MigrateSQLUp, } - cmd.Flags().BoolP("read-from-env", "e", false, "If set, reads the database connection string from the environment variable DSN or config file key dsn.") cmd.Flags().BoolP("yes", "y", false, "If set all confirmation requests are accepted without user interaction.") + cmd.PersistentFlags().BoolP("read-from-env", "e", false, "If set, reads the database connection string from the environment variable DSN or config file key dsn.") + + cmd.AddCommand(NewMigrateSQLDownCmd(slOpts, dOpts, cOpts)) + cmd.AddCommand(NewMigrateSQLUpCmd(slOpts, dOpts, cOpts)) + cmd.AddCommand(NewMigrateSQLStatusCmd(slOpts, dOpts, cOpts)) return cmd } + +func NewMigrateSQLDownCmd(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *cobra.Command { + return popx.NewMigrateSQLDownCmd("hydra", cli.NewHandler(slOpts, dOpts, cOpts).Migration.MigrateSQLDown) +} + +func NewMigrateSQLStatusCmd(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *cobra.Command { + return popx.NewMigrateSQLStatusCmd("hydra", cli.NewHandler(slOpts, dOpts, cOpts).Migration.MigrateStatus) +} + +func NewMigrateSQLUpCmd(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *cobra.Command { + return popx.NewMigrateSQLUpCmd("hydra", cli.NewHandler(slOpts, dOpts, cOpts).Migration.MigrateSQLUp) +} diff --git a/cmd/migrate_status.go b/cmd/migrate_status.go new file mode 100644 index 00000000000..b1529d9c48c --- /dev/null +++ b/cmd/migrate_status.go @@ -0,0 +1,26 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package cmd + +import ( + "github.com/ory/x/configx" + "github.com/ory/x/popx" + "github.com/ory/x/servicelocatorx" + + "github.com/spf13/cobra" + + "github.com/ory/hydra/v2/cmd/cli" + "github.com/ory/hydra/v2/driver" +) + +func NewMigrateStatusCmd(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier, cOpts []configx.OptionModifier) *cobra.Command { + cmd := popx.RegisterMigrateStatusFlags(&cobra.Command{ + Use: "status", + Deprecated: "Please use `hydra migrate sql status` instead.", + Short: "Get the current migration status", + RunE: cli.NewHandler(slOpts, dOpts, cOpts).Migration.MigrateStatus, + }) + cmd.PersistentFlags().BoolP("read-from-env", "e", false, "If set, reads the database connection string from the environment variable DSN or config file key dsn.") + return cmd +} diff --git a/cmd/output_client.go b/cmd/output_client.go index 1b052c56967..3f060f281df 100644 --- a/cmd/output_client.go +++ b/cmd/output_client.go @@ -19,7 +19,7 @@ type ( } ) -func (_ outputOAuth2Client) Header() []string { +func (outputOAuth2Client) Header() []string { return []string{"CLIENT ID", "CLIENT SECRET", "GRANT TYPES", "RESPONSE TYPES", "SCOPE", "AUDIENCE", "REDIRECT URIS"} } @@ -40,7 +40,7 @@ func (i outputOAuth2Client) Interface() interface{} { return i } -func (_ outputOAuth2ClientCollection) Header() []string { +func (outputOAuth2ClientCollection) Header() []string { return outputOAuth2Client{}.Header() } diff --git a/cmd/output_introspection.go b/cmd/output_introspection.go index e3aa576421d..1f89f016530 100644 --- a/cmd/output_introspection.go +++ b/cmd/output_introspection.go @@ -16,7 +16,7 @@ type ( outputOAuth2TokenIntrospection hydra.IntrospectedOAuth2Token ) -func (_ outputOAuth2TokenIntrospection) Header() []string { +func (outputOAuth2TokenIntrospection) Header() []string { return []string{"ACTIVE", "SUBJECT", "CLIENT ID", "SCOPE", "EXPIRY", "TOKEN USE"} } diff --git a/cmd/output_jwks.go b/cmd/output_jwks.go index 3b42af3b113..207e33a9d1f 100644 --- a/cmd/output_jwks.go +++ b/cmd/output_jwks.go @@ -20,7 +20,7 @@ type ( } ) -func (_ outputJsonWebKey) Header() []string { +func (outputJsonWebKey) Header() []string { return []string{"SET ID", "KEY ID", "ALGORITHM", "USE"} } @@ -38,7 +38,7 @@ func (i outputJsonWebKey) Interface() interface{} { return i } -func (_ outputJSONWebKeyCollection) Header() []string { +func (outputJSONWebKeyCollection) Header() []string { return outputJsonWebKey{}.Header() } diff --git a/cmd/output_token.go b/cmd/output_token.go index c91add12cb5..17da6bf274c 100644 --- a/cmd/output_token.go +++ b/cmd/output_token.go @@ -16,7 +16,7 @@ type ( outputOAuth2Token oauth2.Token ) -func (_ outputOAuth2Token) Header() []string { +func (outputOAuth2Token) Header() []string { return []string{"ACCESS TOKEN", "REFRESH TOKEN", "ID TOKEN", "EXPIRY"} } diff --git a/cmd/root.go b/cmd/root.go index 082e9553877..20832d40546 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -7,9 +7,11 @@ import ( "fmt" "os" + "github.com/pkg/errors" + "github.com/ory/x/cmdx" - "github.com/ory/hydra/driver" + "github.com/ory/hydra/v2/driver" "github.com/ory/x/configx" "github.com/ory/x/servicelocatorx" @@ -72,7 +74,8 @@ func RegisterCommandRecursive(parent *cobra.Command, slOpts []servicelocatorx.Op migrateCmd := NewMigrateCmd() migrateCmd.AddCommand(NewMigrateGenCmd()) - migrateCmd.AddCommand(NewMigrateSqlCmd(slOpts, dOpts, cOpts)) + migrateCmd.AddCommand(NewMigrateSQLCmd(slOpts, dOpts, cOpts)) + migrateCmd.AddCommand(NewMigrateStatusCmd(slOpts, dOpts, cOpts)) serveCmd := NewServeCmd() serveCmd.AddCommand(NewServeAdminCmd(slOpts, dOpts, cOpts)) @@ -98,8 +101,11 @@ func RegisterCommandRecursive(parent *cobra.Command, slOpts []servicelocatorx.Op // Execute adds all child commands to the root command sets flags appropriately. func Execute() { - if err := NewRootCmd(nil, nil, nil).Execute(); err != nil { - fmt.Println(err) - os.Exit(-1) + c := NewRootCmd(nil, nil, nil) + if err := c.Execute(); err != nil { + if !errors.Is(err, cmdx.ErrNoPrintButFail) { + _, _ = fmt.Fprintln(c.ErrOrStderr(), err) + } + os.Exit(1) } } diff --git a/cmd/serve_admin.go b/cmd/serve_admin.go index 28de0576ac7..afbbe53025c 100644 --- a/cmd/serve_admin.go +++ b/cmd/serve_admin.go @@ -6,11 +6,11 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/ory/hydra/driver" + "github.com/ory/hydra/v2/driver" "github.com/ory/x/configx" "github.com/ory/x/servicelocatorx" - "github.com/ory/hydra/cmd/server" + "github.com/ory/hydra/v2/cmd/server" ) // adminCmd represents the admin command diff --git a/cmd/serve_all.go b/cmd/serve_all.go index 229c919d7b3..08cdd412bcf 100644 --- a/cmd/serve_all.go +++ b/cmd/serve_all.go @@ -6,11 +6,11 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/ory/hydra/driver" + "github.com/ory/hydra/v2/driver" "github.com/ory/x/configx" "github.com/ory/x/servicelocatorx" - "github.com/ory/hydra/cmd/server" + "github.com/ory/hydra/v2/cmd/server" ) // allCmd represents the all command diff --git a/cmd/serve_public.go b/cmd/serve_public.go index e09311b16fe..c64dc32a62b 100644 --- a/cmd/serve_public.go +++ b/cmd/serve_public.go @@ -6,11 +6,11 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/ory/hydra/driver" + "github.com/ory/hydra/v2/driver" "github.com/ory/x/configx" "github.com/ory/x/servicelocatorx" - "github.com/ory/hydra/cmd/server" + "github.com/ory/hydra/v2/cmd/server" ) // servePublicCmd represents the public command diff --git a/cmd/server/banner.go b/cmd/server/banner.go index 230420b798c..26721272c9c 100644 --- a/cmd/server/banner.go +++ b/cmd/server/banner.go @@ -8,5 +8,5 @@ func banner(version string) string { Take security seriously and subscribe to the Ory Security Newsletter. Stay on top of new patches and security insights. ->> Subscribe now: http://eepurl.com/di390P <<` +>> Subscribe now: https://www.ory.sh/l/sign-up-newsletter <<` } diff --git a/cmd/server/handler.go b/cmd/server/handler.go index 79d25bab550..97400167738 100644 --- a/cmd/server/handler.go +++ b/cmd/server/handler.go @@ -12,12 +12,15 @@ import ( "sync" "time" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + + "github.com/ory/x/otelx/semconv" + "github.com/ory/x/servicelocatorx" - "github.com/ory/x/corsx" "github.com/ory/x/httprouterx" - analytics "github.com/ory/analytics-go/v4" + "github.com/ory/analytics-go/v5" "github.com/ory/x/configx" "github.com/ory/x/reqlog" @@ -34,19 +37,19 @@ import ( "github.com/ory/x/networkx" "github.com/ory/x/otelx" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/x" prometheus "github.com/ory/x/prometheusx" ) var _ = &consent.Handler{} -func EnhanceMiddleware(ctx context.Context, sl *servicelocatorx.Options, d driver.Registry, n *negroni.Negroni, address string, router *httprouter.Router, enableCORS bool, iface config.ServeInterface) http.Handler { +func EnhanceMiddleware(ctx context.Context, sl *servicelocatorx.Options, d driver.Registry, n *negroni.Negroni, address string, router *httprouter.Router, iface config.ServeInterface) http.Handler { if !networkx.AddressIsUnixSocket(address) { n.UseFunc(x.RejectInsecureRequests(d, d.Config().TLS(ctx, iface))) } @@ -54,16 +57,21 @@ func EnhanceMiddleware(ctx context.Context, sl *servicelocatorx.Options, d drive for _, mw := range sl.HTTPMiddlewares() { n.UseFunc(mw) } + n.UseFunc(func(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) { + cfg, enabled := d.Config().CORS(r.Context(), iface) + if !enabled { + next(w, r) + return + } + cors.New(cfg).ServeHTTP(w, r, next) + }) n.UseHandler(router) - corsx.ContextualizedMiddleware(func(ctx context.Context) (opts cors.Options, enabled bool) { - return d.Config().CORS(ctx, iface) - }) return n } -func isDSNAllowed(ctx context.Context, r driver.Registry) { +func ensureNoMemoryDSN(r driver.Registry) { if r.Config().DSN() == "memory" { r.Logger().Fatalf(`When using "hydra serve admin" or "hydra serve public" the DSN can not be set to "memory".`) } @@ -74,11 +82,11 @@ func RunServeAdmin(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifi ctx := cmd.Context() sl := servicelocatorx.NewOptions(slOpts...) - d, err := driver.New(cmd.Context(), sl, append(dOpts, driver.WithOptions(configx.WithFlags(cmd.Flags())))) + d, err := driver.New(cmd.Context(), sl, append(dOpts, driver.WithOptions(append(cOpts, configx.WithFlags(cmd.Flags()))...))) if err != nil { return err } - isDSNAllowed(ctx, d) + ensureNoMemoryDSN(d) admin, _, adminmw, _ := setup(ctx, d, cmd) d.PrometheusManager().RegisterRouter(admin.Router) @@ -92,7 +100,7 @@ func RunServeAdmin(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifi cmd, &wg, config.AdminInterface, - EnhanceMiddleware(ctx, sl, d, adminmw, d.Config().ListenOn(config.AdminInterface), admin.Router, true, config.AdminInterface), + EnhanceMiddleware(ctx, sl, d, adminmw, d.Config().ListenOn(config.AdminInterface), admin.Router, config.AdminInterface), d.Config().ListenOn(config.AdminInterface), d.Config().SocketPermission(config.AdminInterface), ) @@ -107,11 +115,11 @@ func RunServePublic(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModif ctx := cmd.Context() sl := servicelocatorx.NewOptions(slOpts...) - d, err := driver.New(cmd.Context(), sl, append(dOpts, driver.WithOptions(configx.WithFlags(cmd.Flags())))) + d, err := driver.New(cmd.Context(), sl, append(dOpts, driver.WithOptions(append(cOpts, configx.WithFlags(cmd.Flags()))...))) if err != nil { return err } - isDSNAllowed(ctx, d) + ensureNoMemoryDSN(d) _, public, _, publicmw := setup(ctx, d, cmd) d.PrometheusManager().RegisterRouter(public.Router) @@ -125,7 +133,7 @@ func RunServePublic(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModif cmd, &wg, config.PublicInterface, - EnhanceMiddleware(ctx, sl, d, publicmw, d.Config().ListenOn(config.PublicInterface), public.Router, false, config.PublicInterface), + EnhanceMiddleware(ctx, sl, d, publicmw, d.Config().ListenOn(config.PublicInterface), public.Router, config.PublicInterface), d.Config().ListenOn(config.PublicInterface), d.Config().SocketPermission(config.PublicInterface), ) @@ -140,7 +148,7 @@ func RunServeAll(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier ctx := cmd.Context() sl := servicelocatorx.NewOptions(slOpts...) - d, err := driver.New(cmd.Context(), sl, append(dOpts, driver.WithOptions(configx.WithFlags(cmd.Flags())))) + d, err := driver.New(cmd.Context(), sl, append(dOpts, driver.WithOptions(append(cOpts, configx.WithFlags(cmd.Flags()))...))) if err != nil { return err } @@ -159,7 +167,7 @@ func RunServeAll(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier cmd, &wg, config.PublicInterface, - EnhanceMiddleware(ctx, sl, d, publicmw, d.Config().ListenOn(config.PublicInterface), public.Router, false, config.PublicInterface), + EnhanceMiddleware(ctx, sl, d, publicmw, d.Config().ListenOn(config.PublicInterface), public.Router, config.PublicInterface), d.Config().ListenOn(config.PublicInterface), d.Config().SocketPermission(config.PublicInterface), ) @@ -170,7 +178,7 @@ func RunServeAll(slOpts []servicelocatorx.Option, dOpts []driver.OptionsModifier cmd, &wg, config.AdminInterface, - EnhanceMiddleware(ctx, sl, d, adminmw, d.Config().ListenOn(config.AdminInterface), admin.Router, true, config.AdminInterface), + EnhanceMiddleware(ctx, sl, d, adminmw, d.Config().ListenOn(config.AdminInterface), admin.Router, config.AdminInterface), d.Config().ListenOn(config.AdminInterface), d.Config().SocketPermission(config.AdminInterface), ) @@ -201,9 +209,10 @@ func setup(ctx context.Context, d driver.Registry, cmd *cobra.Command) (admin *h NewMiddlewareFromLogger(d.Logger(), fmt.Sprintf("hydra/admin: %s", d.Config().IssuerURL(ctx).String())) if d.Config().DisableHealthAccessLog(config.AdminInterface) { - adminLogger = adminLogger.ExcludePaths("/admin"+healthx.AliveCheckPath, "/admin"+healthx.ReadyCheckPath) + adminLogger = adminLogger.ExcludePaths(healthx.AliveCheckPath, healthx.ReadyCheckPath, "/admin"+prometheus.MetricsPrometheusPath) } + adminmw.UseFunc(semconv.Middleware) adminmw.Use(adminLogger) adminmw.Use(d.PrometheusManager()) @@ -215,6 +224,7 @@ func setup(ctx context.Context, d driver.Registry, cmd *cobra.Command) (admin *h publicLogger.ExcludePaths(healthx.AliveCheckPath, healthx.ReadyCheckPath) } + publicmw.UseFunc(semconv.Middleware) publicmw.Use(publicLogger) publicmw.Use(d.PrometheusManager()) @@ -223,11 +233,8 @@ func setup(ctx context.Context, d driver.Registry, cmd *cobra.Command) (admin *h d.Logger(), d.Config().Source(ctx), &metricsx.Options{ - Service: "ory-hydra", - ClusterID: metricsx.Hash(fmt.Sprintf("%s|%s", - d.Config().IssuerURL(ctx).String(), - d.Config().DSN(), - )), + Service: "hydra", + DeploymentId: metricsx.Hash(d.Persister().NetworkID(ctx).String()), IsDevelopment: d.Config().DSN() == "memory" || d.Config().IssuerURL(ctx).String() == "" || strings.Contains(d.Config().IssuerURL(ctx).String(), "localhost"), @@ -283,8 +290,8 @@ func setup(ctx context.Context, d driver.Registry, cmd *cobra.Command) (admin *h Endpoint: "https://sqa.ory.sh", GzipCompressionLevel: 6, BatchMaxSize: 500 * 1000, - BatchSize: 250, - Interval: time.Hour * 24, + BatchSize: 1000, + Interval: time.Hour * 6, }, }, ) @@ -310,7 +317,13 @@ func serve( defer wg.Done() if tracer := d.Tracer(cmd.Context()); tracer.IsLoaded() { - handler = otelx.TraceHandler(handler) + handler = otelx.TraceHandler( + handler, + otelhttp.WithTracerProvider(tracer.Provider()), + otelhttp.WithFilter(func(r *http.Request) bool { + return !strings.HasPrefix(r.URL.Path, "/admin/metrics/") + }), + ) } var tlsConfig *tls.Config diff --git a/cmd/server/helper_cert.go b/cmd/server/helper_cert.go index e85f27ea296..6cef67bc362 100644 --- a/cmd/server/helper_cert.go +++ b/cmd/server/helper_cert.go @@ -14,16 +14,16 @@ import ( "github.com/gofrs/uuid" - "gopkg.in/square/go-jose.v2" + "github.com/go-jose/go-jose/v3" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" "github.com/pkg/errors" "github.com/ory/x/tlsx" - "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/jwk" ) const ( diff --git a/cmd/server/helper_cert_test.go b/cmd/server/helper_cert_test.go index c9e2a24fd0d..66b90c7afd3 100644 --- a/cmd/server/helper_cert_test.go +++ b/cmd/server/helper_cert_test.go @@ -13,20 +13,20 @@ import ( "testing" "time" + "github.com/go-jose/go-jose/v3" "github.com/google/uuid" "github.com/sirupsen/logrus/hooks/test" "github.com/stretchr/testify/require" - "gopkg.in/square/go-jose.v2" "github.com/ory/x/configx" "github.com/ory/x/logrusx" "github.com/ory/x/tlsx" - "github.com/ory/hydra/cmd/server" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal/testhelpers" - "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/cmd/server" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal/testhelpers" + "github.com/ory/hydra/v2/jwk" ) func TestGetOrCreateTLSCertificate(t *testing.T) { diff --git a/cmd/version.go b/cmd/version.go index 0caf3a315dd..88c0da2ee0b 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -6,7 +6,7 @@ package cmd import ( "fmt" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver/config" "github.com/spf13/cobra" ) diff --git a/consent/csrf.go b/consent/csrf.go new file mode 100644 index 00000000000..0a21c8e28ab --- /dev/null +++ b/consent/csrf.go @@ -0,0 +1,78 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +//go:build !flagka + +package consent + +import ( + "net/http" + "strings" + "time" + + "github.com/ory/hydra/v2/flow" + + "github.com/gorilla/sessions" + + "github.com/ory/fosite" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/errorsx" + "github.com/ory/x/mapx" +) + +// WARNING - changes in this file need to be mirrored elsewhere. + +func createCsrfSession(w http.ResponseWriter, r *http.Request, conf x.CookieConfigProvider, store sessions.Store, name string, csrfValue string, maxAge time.Duration) error { + // Errors can be ignored here, because we always get a session back. Error typically means that the + // session doesn't exist yet. + session, _ := store.Get(r, name) + + sameSite := conf.CookieSameSiteMode(r.Context()) + if isLegacyCsrfSessionName(name) { + sameSite = 0 + } + + session.Values["csrf"] = csrfValue + session.Options.HttpOnly = true + session.Options.Secure = conf.CookieSecure(r.Context()) + session.Options.SameSite = sameSite + session.Options.Domain = conf.CookieDomain(r.Context()) + session.Options.MaxAge = int(maxAge.Seconds()) + if err := session.Save(r, w); err != nil { + return errorsx.WithStack(err) + } + + if sameSite == http.SameSiteNoneMode && conf.CookieSameSiteLegacyWorkaround(r.Context()) { + return createCsrfSession(w, r, conf, store, legacyCsrfSessionName(name), csrfValue, maxAge) + } + + return nil +} + +func ValidateCsrfSession(r *http.Request, conf x.CookieConfigProvider, store sessions.Store, name, expectedCSRF string, f *flow.Flow) error { + if cookie, err := getCsrfSession(r, store, conf, name); err != nil { + return errorsx.WithStack(fosite.ErrRequestForbidden.WithHint("CSRF session cookie could not be decoded.")) + } else if csrf, err := mapx.GetString(cookie.Values, "csrf"); err != nil { + return errorsx.WithStack(fosite.ErrRequestForbidden.WithHint("No CSRF value available in the session cookie.")) + } else if csrf != expectedCSRF { + return errorsx.WithStack(fosite.ErrRequestForbidden.WithHint("The CSRF value from the token does not match the CSRF value from the data store.")) + } + + return nil +} + +func getCsrfSession(r *http.Request, store sessions.Store, conf x.CookieConfigProvider, name string) (*sessions.Session, error) { + cookie, err := store.Get(r, name) + if !isLegacyCsrfSessionName(name) && conf.CookieSameSiteMode(r.Context()) == http.SameSiteNoneMode && conf.CookieSameSiteLegacyWorkaround(r.Context()) && (err != nil || len(cookie.Values) == 0) { + return store.Get(r, legacyCsrfSessionName(name)) + } + return cookie, err +} + +func legacyCsrfSessionName(name string) string { + return name + "_legacy" +} + +func isLegacyCsrfSessionName(name string) bool { + return strings.HasSuffix(name, "_legacy") +} diff --git a/consent/handler.go b/consent/handler.go index 99078be690d..48167e7380f 100644 --- a/consent/handler.go +++ b/consent/handler.go @@ -4,11 +4,15 @@ package consent import ( + "context" "encoding/json" "net/http" "net/url" "time" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/oauth2/flowctx" + "github.com/ory/hydra/v2/x/events" "github.com/ory/x/pagination/tokenpagination" "github.com/ory/x/httprouterx" @@ -17,8 +21,8 @@ import ( "github.com/pkg/errors" "github.com/ory/fosite" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/x" "github.com/ory/x/errorsx" "github.com/ory/x/sqlxx" "github.com/ory/x/stringsx" @@ -68,6 +72,8 @@ func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin) { // Revoke OAuth 2.0 Consent Session Parameters // // swagger:parameters revokeOAuth2ConsentSessions +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type revokeOAuth2ConsentSessions struct { // OAuth 2.0 Consent Subject // @@ -110,7 +116,7 @@ type revokeOAuth2ConsentSessions struct { // Responses: // 204: emptyResponse // default: errorOAuth2 -func (h *Handler) revokeOAuth2ConsentSessions(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) revokeOAuth2ConsentSessions(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { subject := r.URL.Query().Get("subject") client := r.URL.Query().Get("client") allClients := r.URL.Query().Get("all") == "true" @@ -125,11 +131,13 @@ func (h *Handler) revokeOAuth2ConsentSessions(w http.ResponseWriter, r *http.Req h.r.Writer().WriteError(w, r, err) return } + events.Trace(r.Context(), events.ConsentRevoked, events.WithSubject(subject), events.WithClientID(client)) case allClients: if err := h.r.ConsentManager().RevokeSubjectConsentSession(r.Context(), subject); err != nil && !errors.Is(err, x.ErrNotFound) { h.r.Writer().WriteError(w, r, err) return } + events.Trace(r.Context(), events.ConsentRevoked, events.WithSubject(subject)) default: h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint(`Query parameter both 'client' and 'all' is not defined but one of them should have been.`))) return @@ -141,6 +149,8 @@ func (h *Handler) revokeOAuth2ConsentSessions(w http.ResponseWriter, r *http.Req // List OAuth 2.0 Consent Session Parameters // // swagger:parameters listOAuth2ConsentSessions +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type listOAuth2ConsentSessions struct { tokenpagination.RequestParameters @@ -149,6 +159,7 @@ type listOAuth2ConsentSessions struct { // in: query // required: true Subject string `json:"subject"` + // The login session id to list the consent sessions for. // // in: query @@ -175,7 +186,7 @@ type listOAuth2ConsentSessions struct { // Responses: // 200: oAuth2ConsentSessions // default: errorOAuth2 -func (h *Handler) listOAuth2ConsentSessions(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) listOAuth2ConsentSessions(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { subject := r.URL.Query().Get("subject") if subject == "" { h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint(`Query parameter 'subject' is not defined but should have been.`))) @@ -185,7 +196,7 @@ func (h *Handler) listOAuth2ConsentSessions(w http.ResponseWriter, r *http.Reque page, itemsPerPage := x.ParsePagination(r) - var s []AcceptOAuth2ConsentRequest + var s []flow.AcceptOAuth2ConsentRequest var err error if len(loginSessionId) == 0 { s, err = h.r.ConsentManager().FindSubjectsGrantedConsentRequests(r.Context(), subject, itemsPerPage, itemsPerPage*page) @@ -193,21 +204,21 @@ func (h *Handler) listOAuth2ConsentSessions(w http.ResponseWriter, r *http.Reque s, err = h.r.ConsentManager().FindSubjectsSessionGrantedConsentRequests(r.Context(), subject, loginSessionId, itemsPerPage, itemsPerPage*page) } if errors.Is(err, ErrNoPreviousConsentFound) { - h.r.Writer().Write(w, r, []OAuth2ConsentSession{}) + h.r.Writer().Write(w, r, []flow.OAuth2ConsentSession{}) return } else if err != nil { h.r.Writer().WriteError(w, r, err) return } - var a []OAuth2ConsentSession + var a []flow.OAuth2ConsentSession for _, session := range s { session.ConsentRequest.Client = sanitizeClient(session.ConsentRequest.Client) - a = append(a, OAuth2ConsentSession(session)) + a = append(a, flow.OAuth2ConsentSession(session)) } if len(a) == 0 { - a = []OAuth2ConsentSession{} + a = []flow.OAuth2ConsentSession{} } n, err := h.r.ConsentManager().CountSubjectsGrantedConsentRequests(r.Context(), subject) @@ -223,23 +234,36 @@ func (h *Handler) listOAuth2ConsentSessions(w http.ResponseWriter, r *http.Reque // Revoke OAuth 2.0 Consent Login Sessions Parameters // // swagger:parameters revokeOAuth2LoginSessions +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type revokeOAuth2LoginSessions struct { // OAuth 2.0 Subject // // The subject to revoke authentication sessions for. // // in: query - // required: true Subject string `json:"subject"` + + // Login Session ID + // + // The login session to revoke. + // + // in: query + SessionID string `json:"sid"` } // swagger:route DELETE /admin/oauth2/auth/sessions/login oAuth2 revokeOAuth2LoginSessions // -// # Revokes All OAuth 2.0 Login Sessions of a Subject +// # Revokes OAuth 2.0 Login Sessions by either a Subject or a SessionID // -// This endpoint invalidates a subject's authentication session. After revoking the authentication session, the subject -// has to re-authenticate at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens and -// does not work with OpenID Connect Front- or Back-channel logout. +// This endpoint invalidates authentication sessions. After revoking the authentication session(s), the subject +// has to re-authenticate at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens. +// +// If you send the subject in a query param, all authentication sessions that belong to that subject are revoked. +// No OpenID Connect Front- or Back-channel logout is performed in this case. +// +// Alternatively, you can send a SessionID via `sid` query param, in which case, only the session that is connected +// to that SessionID is revoked. OpenID Connect Back-channel logout is performed in this case. // // Consumes: // - application/json @@ -252,10 +276,22 @@ type revokeOAuth2LoginSessions struct { // Responses: // 204: emptyResponse // default: errorOAuth2 -func (h *Handler) revokeOAuth2LoginSessions(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) revokeOAuth2LoginSessions(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + sid := r.URL.Query().Get("sid") subject := r.URL.Query().Get("subject") - if subject == "" { - h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint(`Query parameter 'subject' is not defined but should have been.`))) + + if sid == "" && subject == "" { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint(`Either 'subject' or 'sid' query parameters need to be defined.`))) + return + } + + if sid != "" { + if err := h.r.ConsentStrategy().HandleHeadlessLogout(r.Context(), w, r, sid); err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + + w.WriteHeader(http.StatusNoContent) return } @@ -270,6 +306,8 @@ func (h *Handler) revokeOAuth2LoginSessions(w http.ResponseWriter, r *http.Reque // Get OAuth 2.0 Login Request // // swagger:parameters getOAuth2LoginRequest +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type getOAuth2LoginRequest struct { // OAuth 2.0 Login Request Challenge // @@ -304,7 +342,7 @@ type getOAuth2LoginRequest struct { // 200: oAuth2LoginRequest // 410: oAuth2RedirectTo // default: errorOAuth2 -func (h *Handler) getOAuth2LoginRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) getOAuth2LoginRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { challenge := stringsx.Coalesce( r.URL.Query().Get("login_challenge"), r.URL.Query().Get("challenge"), @@ -321,12 +359,20 @@ func (h *Handler) getOAuth2LoginRequest(w http.ResponseWriter, r *http.Request, return } if request.WasHandled { - h.r.Writer().WriteCode(w, r, http.StatusGone, &OAuth2RedirectTo{ + h.r.Writer().WriteCode(w, r, http.StatusGone, &flow.OAuth2RedirectTo{ RedirectTo: request.RequestURL, }) return } + if request.RequestedScope == nil { + request.RequestedScope = []string{} + } + + if request.RequestedAudience == nil { + request.RequestedAudience = []string{} + } + request.Client = sanitizeClient(request.Client) h.r.Writer().Write(w, r, request) } @@ -334,6 +380,8 @@ func (h *Handler) getOAuth2LoginRequest(w http.ResponseWriter, r *http.Request, // Accept OAuth 2.0 Login Request // // swagger:parameters acceptOAuth2LoginRequest +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type acceptOAuth2LoginRequest struct { // OAuth 2.0 Login Request Challenge // @@ -342,7 +390,7 @@ type acceptOAuth2LoginRequest struct { Challenge string `json:"login_challenge"` // in: body - Body HandledLoginRequest + Body flow.HandledLoginRequest } // swagger:route PUT /admin/oauth2/auth/requests/login/accept oAuth2 acceptOAuth2LoginRequest @@ -372,7 +420,9 @@ type acceptOAuth2LoginRequest struct { // Responses: // 200: oAuth2RedirectTo // default: errorOAuth2 -func (h *Handler) acceptOAuth2LoginRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) acceptOAuth2LoginRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + ctx := r.Context() + challenge := stringsx.Coalesce( r.URL.Query().Get("login_challenge"), r.URL.Query().Get("challenge"), @@ -382,41 +432,58 @@ func (h *Handler) acceptOAuth2LoginRequest(w http.ResponseWriter, r *http.Reques return } - var p HandledLoginRequest + var handledLoginRequest flow.HandledLoginRequest d := json.NewDecoder(r.Body) d.DisallowUnknownFields() - if err := d.Decode(&p); err != nil { + if err := d.Decode(&handledLoginRequest); err != nil { h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithWrap(err).WithHintf("Unable to decode body because: %s", err))) return } - if p.Subject == "" { + if handledLoginRequest.Subject == "" { h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint("Field 'subject' must not be empty."))) return } - p.ID = challenge - ar, err := h.r.ConsentManager().GetLoginRequest(r.Context(), challenge) + handledLoginRequest.ID = challenge + loginRequest, err := h.r.ConsentManager().GetLoginRequest(ctx, challenge) if err != nil { h.r.Writer().WriteError(w, r, err) return - } else if ar.Subject != "" && p.Subject != ar.Subject { - h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint("Field 'subject' does not match subject from previous authentication."))) + } else if loginRequest.Subject != "" && handledLoginRequest.Subject != loginRequest.Subject { + // The subject that was confirmed by the login screen does not match what we + // remembered in the session cookie. We handle this gracefully by redirecting the + // original authorization request URL, but attaching "prompt=login" to the query. + // This forces the user to log in again. + requestURL, err := url.Parse(loginRequest.RequestURL) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + h.r.Writer().Write(w, r, &flow.OAuth2RedirectTo{ + RedirectTo: urlx.SetQuery(requestURL, url.Values{"prompt": {"login"}}).String(), + }) return } - if ar.Skip { - p.Remember = true // If skip is true remember is also true to allow consecutive calls as the same user! - p.AuthenticatedAt = ar.AuthenticatedAt + if loginRequest.Skip { + handledLoginRequest.Remember = true // If skip is true remember is also true to allow consecutive calls as the same user! + handledLoginRequest.AuthenticatedAt = loginRequest.AuthenticatedAt } else { - p.AuthenticatedAt = sqlxx.NullTime(time.Now().UTC(). + handledLoginRequest.AuthenticatedAt = sqlxx.NullTime(time.Now().UTC(). // Rounding is important to avoid SQL time synchronization issues in e.g. MySQL! Truncate(time.Second)) - ar.AuthenticatedAt = p.AuthenticatedAt + loginRequest.AuthenticatedAt = handledLoginRequest.AuthenticatedAt } - p.RequestedAt = ar.RequestedAt + handledLoginRequest.RequestedAt = loginRequest.RequestedAt - request, err := h.r.ConsentManager().HandleLoginRequest(r.Context(), challenge, &p) + f, err := h.decodeFlowWithClient(ctx, challenge, flowctx.AsLoginChallenge) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + + request, err := h.r.ConsentManager().HandleLoginRequest(ctx, f, challenge, &handledLoginRequest) if err != nil { h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) return @@ -428,14 +495,23 @@ func (h *Handler) acceptOAuth2LoginRequest(w http.ResponseWriter, r *http.Reques return } - h.r.Writer().Write(w, r, &OAuth2RedirectTo{ - RedirectTo: urlx.SetQuery(ru, url.Values{"login_verifier": {request.Verifier}}).String(), + verifier, err := f.ToLoginVerifier(ctx, h.r) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + + events.Trace(ctx, events.LoginAccepted, events.WithClientID(request.Client.GetID()), events.WithSubject(request.Subject)) + h.r.Writer().Write(w, r, &flow.OAuth2RedirectTo{ + RedirectTo: urlx.SetQuery(ru, url.Values{"login_verifier": {verifier}}).String(), }) } // Reject OAuth 2.0 Login Request // // swagger:parameters rejectOAuth2LoginRequest +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type rejectOAuth2LoginRequest struct { // OAuth 2.0 Login Request Challenge // @@ -444,7 +520,7 @@ type rejectOAuth2LoginRequest struct { Challenge string `json:"login_challenge"` // in: body - Body RequestDeniedError + Body flow.RequestDeniedError } // swagger:route PUT /admin/oauth2/auth/requests/login/reject oAuth2 rejectOAuth2LoginRequest @@ -473,7 +549,9 @@ type rejectOAuth2LoginRequest struct { // Responses: // 200: oAuth2RedirectTo // default: errorOAuth2 -func (h *Handler) rejectOAuth2LoginRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) rejectOAuth2LoginRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + ctx := r.Context() + challenge := stringsx.Coalesce( r.URL.Query().Get("login_challenge"), r.URL.Query().Get("challenge"), @@ -483,7 +561,7 @@ func (h *Handler) rejectOAuth2LoginRequest(w http.ResponseWriter, r *http.Reques return } - var p RequestDeniedError + var p flow.RequestDeniedError d := json.NewDecoder(r.Body) d.DisallowUnknownFields() if err := d.Decode(&p); err != nil { @@ -491,15 +569,20 @@ func (h *Handler) rejectOAuth2LoginRequest(w http.ResponseWriter, r *http.Reques return } - p.valid = true - p.SetDefaults(loginRequestDeniedErrorName) - ar, err := h.r.ConsentManager().GetLoginRequest(r.Context(), challenge) + p.Valid = true + p.SetDefaults(flow.LoginRequestDeniedErrorName) + ar, err := h.r.ConsentManager().GetLoginRequest(ctx, challenge) if err != nil { h.r.Writer().WriteError(w, r, err) return } - request, err := h.r.ConsentManager().HandleLoginRequest(r.Context(), challenge, &HandledLoginRequest{ + f, err := h.decodeFlowWithClient(ctx, challenge, flowctx.AsLoginChallenge) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + request, err := h.r.ConsentManager().HandleLoginRequest(ctx, f, challenge, &flow.HandledLoginRequest{ Error: &p, ID: challenge, RequestedAt: ar.RequestedAt, @@ -509,20 +592,30 @@ func (h *Handler) rejectOAuth2LoginRequest(w http.ResponseWriter, r *http.Reques return } + verifier, err := f.ToLoginVerifier(ctx, h.r) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + ru, err := url.Parse(request.RequestURL) if err != nil { h.r.Writer().WriteError(w, r, err) return } - h.r.Writer().Write(w, r, &OAuth2RedirectTo{ - RedirectTo: urlx.SetQuery(ru, url.Values{"login_verifier": {request.Verifier}}).String(), + events.Trace(ctx, events.LoginRejected, events.WithClientID(request.Client.GetID()), events.WithSubject(request.Subject)) + + h.r.Writer().Write(w, r, &flow.OAuth2RedirectTo{ + RedirectTo: urlx.SetQuery(ru, url.Values{"login_verifier": {verifier}}).String(), }) } // Get OAuth 2.0 Consent Request // // swagger:parameters getOAuth2ConsentRequest +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type getOAuth2ConsentRequest struct { // OAuth 2.0 Consent Request Challenge // @@ -558,7 +651,7 @@ type getOAuth2ConsentRequest struct { // 200: oAuth2ConsentRequest // 410: oAuth2RedirectTo // default: errorOAuth2 -func (h *Handler) getOAuth2ConsentRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) getOAuth2ConsentRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { challenge := stringsx.Coalesce( r.URL.Query().Get("consent_challenge"), r.URL.Query().Get("challenge"), @@ -574,7 +667,7 @@ func (h *Handler) getOAuth2ConsentRequest(w http.ResponseWriter, r *http.Request return } if request.WasHandled { - h.r.Writer().WriteCode(w, r, http.StatusGone, &OAuth2RedirectTo{ + h.r.Writer().WriteCode(w, r, http.StatusGone, &flow.OAuth2RedirectTo{ RedirectTo: request.RequestURL, }) return @@ -595,6 +688,8 @@ func (h *Handler) getOAuth2ConsentRequest(w http.ResponseWriter, r *http.Request // Accept OAuth 2.0 Consent Request // // swagger:parameters acceptOAuth2ConsentRequest +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type acceptOAuth2ConsentRequest struct { // OAuth 2.0 Consent Request Challenge // @@ -603,7 +698,7 @@ type acceptOAuth2ConsentRequest struct { Challenge string `json:"consent_challenge"` // in: body - Body AcceptOAuth2ConsentRequest + Body flow.AcceptOAuth2ConsentRequest } // swagger:route PUT /admin/oauth2/auth/requests/consent/accept oAuth2 acceptOAuth2ConsentRequest @@ -638,7 +733,9 @@ type acceptOAuth2ConsentRequest struct { // Responses: // 200: oAuth2RedirectTo // default: errorOAuth2 -func (h *Handler) acceptOAuth2ConsentRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) acceptOAuth2ConsentRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + ctx := r.Context() + challenge := stringsx.Coalesce( r.URL.Query().Get("consent_challenge"), r.URL.Query().Get("challenge"), @@ -648,7 +745,7 @@ func (h *Handler) acceptOAuth2ConsentRequest(w http.ResponseWriter, r *http.Requ return } - var p AcceptOAuth2ConsentRequest + var p flow.AcceptOAuth2ConsentRequest d := json.NewDecoder(r.Body) d.DisallowUnknownFields() if err := d.Decode(&p); err != nil { @@ -656,7 +753,7 @@ func (h *Handler) acceptOAuth2ConsentRequest(w http.ResponseWriter, r *http.Requ return } - cr, err := h.r.ConsentManager().GetConsentRequest(r.Context(), challenge) + cr, err := h.r.ConsentManager().GetConsentRequest(ctx, challenge) if err != nil { h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) return @@ -666,7 +763,12 @@ func (h *Handler) acceptOAuth2ConsentRequest(w http.ResponseWriter, r *http.Requ p.RequestedAt = cr.RequestedAt p.HandledAt = sqlxx.NullTime(time.Now().UTC()) - hr, err := h.r.ConsentManager().HandleConsentRequest(r.Context(), &p) + f, err := h.decodeFlowWithClient(ctx, challenge, flowctx.AsConsentChallenge) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + hr, err := h.r.ConsentManager().HandleConsentRequest(ctx, f, &p) if err != nil { h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) return @@ -680,14 +782,24 @@ func (h *Handler) acceptOAuth2ConsentRequest(w http.ResponseWriter, r *http.Requ return } - h.r.Writer().Write(w, r, &OAuth2RedirectTo{ - RedirectTo: urlx.SetQuery(ru, url.Values{"consent_verifier": {hr.Verifier}}).String(), + verifier, err := f.ToConsentVerifier(ctx, h.r) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + + events.Trace(ctx, events.ConsentAccepted, events.WithClientID(cr.Client.GetID()), events.WithSubject(cr.Subject)) + + h.r.Writer().Write(w, r, &flow.OAuth2RedirectTo{ + RedirectTo: urlx.SetQuery(ru, url.Values{"consent_verifier": {verifier}}).String(), }) } // Reject OAuth 2.0 Consent Request // // swagger:parameters rejectOAuth2ConsentRequest +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type adminRejectOAuth2ConsentRequest struct { // OAuth 2.0 Consent Request Challenge // @@ -696,7 +808,7 @@ type adminRejectOAuth2ConsentRequest struct { Challenge string `json:"consent_challenge"` // in: body - Body RequestDeniedError + Body flow.RequestDeniedError } // swagger:route PUT /admin/oauth2/auth/requests/consent/reject oAuth2 rejectOAuth2ConsentRequest @@ -730,7 +842,9 @@ type adminRejectOAuth2ConsentRequest struct { // Responses: // 200: oAuth2RedirectTo // default: errorOAuth2 -func (h *Handler) rejectOAuth2ConsentRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) rejectOAuth2ConsentRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + ctx := r.Context() + challenge := stringsx.Coalesce( r.URL.Query().Get("consent_challenge"), r.URL.Query().Get("challenge"), @@ -740,7 +854,7 @@ func (h *Handler) rejectOAuth2ConsentRequest(w http.ResponseWriter, r *http.Requ return } - var p RequestDeniedError + var p flow.RequestDeniedError d := json.NewDecoder(r.Body) d.DisallowUnknownFields() if err := d.Decode(&p); err != nil { @@ -748,15 +862,21 @@ func (h *Handler) rejectOAuth2ConsentRequest(w http.ResponseWriter, r *http.Requ return } - p.valid = true - p.SetDefaults(consentRequestDeniedErrorName) - hr, err := h.r.ConsentManager().GetConsentRequest(r.Context(), challenge) + p.Valid = true + p.SetDefaults(flow.ConsentRequestDeniedErrorName) + hr, err := h.r.ConsentManager().GetConsentRequest(ctx, challenge) if err != nil { h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) return } - request, err := h.r.ConsentManager().HandleConsentRequest(r.Context(), &AcceptOAuth2ConsentRequest{ + f, err := h.decodeFlowWithClient(ctx, challenge, flowctx.AsConsentChallenge) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + + request, err := h.r.ConsentManager().HandleConsentRequest(ctx, f, &flow.AcceptOAuth2ConsentRequest{ Error: &p, ID: challenge, RequestedAt: hr.RequestedAt, @@ -773,14 +893,24 @@ func (h *Handler) rejectOAuth2ConsentRequest(w http.ResponseWriter, r *http.Requ return } - h.r.Writer().Write(w, r, &OAuth2RedirectTo{ - RedirectTo: urlx.SetQuery(ru, url.Values{"consent_verifier": {request.Verifier}}).String(), + verifier, err := f.ToConsentVerifier(ctx, h.r) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + + events.Trace(ctx, events.ConsentRejected, events.WithClientID(request.Client.GetID()), events.WithSubject(request.Subject)) + + h.r.Writer().Write(w, r, &flow.OAuth2RedirectTo{ + RedirectTo: urlx.SetQuery(ru, url.Values{"consent_verifier": {verifier}}).String(), }) } // Accept OAuth 2.0 Logout Request // // swagger:parameters acceptOAuth2LogoutRequest +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type acceptOAuth2LogoutRequest struct { // OAuth 2.0 Logout Request Challenge // @@ -805,7 +935,7 @@ type acceptOAuth2LogoutRequest struct { // Responses: // 200: oAuth2RedirectTo // default: errorOAuth2 -func (h *Handler) acceptOAuth2LogoutRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) acceptOAuth2LogoutRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { challenge := stringsx.Coalesce( r.URL.Query().Get("logout_challenge"), r.URL.Query().Get("challenge"), @@ -817,7 +947,7 @@ func (h *Handler) acceptOAuth2LogoutRequest(w http.ResponseWriter, r *http.Reque return } - h.r.Writer().Write(w, r, &OAuth2RedirectTo{ + h.r.Writer().Write(w, r, &flow.OAuth2RedirectTo{ RedirectTo: urlx.SetQuery(urlx.AppendPaths(h.c.PublicURL(r.Context()), "/oauth2/sessions/logout"), url.Values{"logout_verifier": {c.Verifier}}).String(), }) } @@ -825,6 +955,8 @@ func (h *Handler) acceptOAuth2LogoutRequest(w http.ResponseWriter, r *http.Reque // Reject OAuth 2.0 Logout Request // // swagger:parameters rejectOAuth2LogoutRequest +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type rejectOAuth2LogoutRequest struct { // in: query // required: true @@ -848,7 +980,7 @@ type rejectOAuth2LogoutRequest struct { // Responses: // 204: emptyResponse // default: errorOAuth2 -func (h *Handler) rejectOAuth2LogoutRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) rejectOAuth2LogoutRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { challenge := stringsx.Coalesce( r.URL.Query().Get("logout_challenge"), r.URL.Query().Get("challenge"), @@ -865,6 +997,8 @@ func (h *Handler) rejectOAuth2LogoutRequest(w http.ResponseWriter, r *http.Reque // Get OAuth 2.0 Logout Request // // swagger:parameters getOAuth2LogoutRequest +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type getOAuth2LogoutRequest struct { // in: query // required: true @@ -886,7 +1020,7 @@ type getOAuth2LogoutRequest struct { // 200: oAuth2LogoutRequest // 410: oAuth2RedirectTo // default: errorOAuth2 -func (h *Handler) getOAuth2LogoutRequest(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) getOAuth2LogoutRequest(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { challenge := stringsx.Coalesce( r.URL.Query().Get("logout_challenge"), r.URL.Query().Get("challenge"), @@ -904,7 +1038,7 @@ func (h *Handler) getOAuth2LogoutRequest(w http.ResponseWriter, r *http.Request, } if request.WasHandled { - h.r.Writer().WriteCode(w, r, http.StatusGone, &OAuth2RedirectTo{ + h.r.Writer().WriteCode(w, r, http.StatusGone, &flow.OAuth2RedirectTo{ RedirectTo: request.RequestURL, }) return @@ -912,3 +1046,12 @@ func (h *Handler) getOAuth2LogoutRequest(w http.ResponseWriter, r *http.Request, h.r.Writer().Write(w, r, request) } + +func (h *Handler) decodeFlowWithClient(ctx context.Context, challenge string, opts ...flowctx.CodecOption) (*flow.Flow, error) { + f, err := flowctx.Decode[flow.Flow](ctx, h.r.FlowCipher(), challenge, opts...) + if err != nil { + return nil, err + } + + return f, nil +} diff --git a/consent/handler_test.go b/consent/handler_test.go index ca4e10fa596..d5dfe5254ad 100644 --- a/consent/handler_test.go +++ b/consent/handler_test.go @@ -13,20 +13,17 @@ import ( "testing" "time" - "github.com/ory/x/pointerx" - - "github.com/ory/hydra/consent" - "github.com/ory/hydra/x" - "github.com/ory/x/contextx" - "github.com/ory/x/sqlxx" - - "github.com/ory/hydra/internal" - "github.com/stretchr/testify/require" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/client" - . "github.com/ory/hydra/consent" + "github.com/ory/hydra/v2/client" + . "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/contextx" + "github.com/ory/x/pointerx" + "github.com/ory/x/sqlxx" ) func TestGetLogoutRequest(t *testing.T) { @@ -40,6 +37,7 @@ func TestGetLogoutRequest(t *testing.T) { {true, true, http.StatusGone}, } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + ctx := context.Background() key := fmt.Sprint(k) challenge := "challenge" + key requestURL := "http://192.0.2.1" @@ -48,9 +46,9 @@ func TestGetLogoutRequest(t *testing.T) { reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) if tc.exists { - cl := &client.Client{LegacyClientID: "client" + key} - require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cl)) - require.NoError(t, reg.ConsentManager().CreateLogoutRequest(context.TODO(), &LogoutRequest{ + cl := &client.Client{ID: "client" + key} + require.NoError(t, reg.ClientManager().CreateClient(ctx, cl)) + require.NoError(t, reg.ConsentManager().CreateLogoutRequest(context.TODO(), &flow.LogoutRequest{ Client: cl, ID: challenge, WasHandled: tc.handled, @@ -70,11 +68,11 @@ func TestGetLogoutRequest(t *testing.T) { require.EqualValues(t, tc.status, resp.StatusCode) if tc.handled { - var result OAuth2RedirectTo + var result flow.OAuth2RedirectTo require.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) require.Equal(t, requestURL, result.RedirectTo) } else if tc.exists { - var result LogoutRequest + var result flow.LogoutRequest require.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) require.Equal(t, challenge, result.ID) require.Equal(t, requestURL, result.RequestURL) @@ -93,7 +91,8 @@ func TestGetLoginRequest(t *testing.T) { {true, false, http.StatusOK}, {true, true, http.StatusGone}, } { - t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + t.Run(fmt.Sprintf("exists=%v/handled=%v", tc.exists, tc.handled), func(t *testing.T) { + ctx := context.Background() key := fmt.Sprint(k) challenge := "challenge" + key requestURL := "http://192.0.2.1" @@ -102,16 +101,22 @@ func TestGetLoginRequest(t *testing.T) { reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) if tc.exists { - cl := &client.Client{LegacyClientID: "client" + key} + cl := &client.Client{ID: "client" + key} require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cl)) - require.NoError(t, reg.ConsentManager().CreateLoginRequest(context.Background(), &LoginRequest{ - Client: cl, - ID: challenge, - RequestURL: requestURL, - })) + f, err := reg.ConsentManager().CreateLoginRequest(context.Background(), &flow.LoginRequest{ + Client: cl, + ID: challenge, + RequestURL: requestURL, + RequestedAt: time.Now(), + }) + require.NoError(t, err) + challenge, err = f.ToLoginChallenge(ctx, reg) + require.NoError(t, err) if tc.handled { - _, err := reg.ConsentManager().HandleLoginRequest(context.Background(), challenge, &HandledLoginRequest{ID: challenge, WasHandled: true}) + _, err := reg.ConsentManager().HandleLoginRequest(ctx, f, challenge, &flow.HandledLoginRequest{ID: challenge, WasHandled: true}) + require.NoError(t, err) + challenge, err = f.ToLoginChallenge(ctx, reg) require.NoError(t, err) } } @@ -128,11 +133,11 @@ func TestGetLoginRequest(t *testing.T) { require.EqualValues(t, tc.status, resp.StatusCode) if tc.handled { - var result OAuth2RedirectTo + var result flow.OAuth2RedirectTo require.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) require.Equal(t, requestURL, result.RedirectTo) } else if tc.exists { - var result LoginRequest + var result flow.LoginRequest require.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) require.Equal(t, challenge, result.ID) require.Equal(t, requestURL, result.RequestURL) @@ -153,6 +158,7 @@ func TestGetConsentRequest(t *testing.T) { {true, true, http.StatusGone}, } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + ctx := context.Background() key := fmt.Sprint(k) challenge := "challenge" + key requestURL := "http://192.0.2.1" @@ -161,15 +167,25 @@ func TestGetConsentRequest(t *testing.T) { reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) if tc.exists { - cl := &client.Client{LegacyClientID: "client" + key} - require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cl)) - lr := &LoginRequest{ID: "login-" + challenge, Client: cl, RequestURL: requestURL} - require.NoError(t, reg.ConsentManager().CreateLoginRequest(context.Background(), lr)) - _, err := reg.ConsentManager().HandleLoginRequest(context.Background(), lr.ID, &consent.HandledLoginRequest{ - ID: lr.ID, + cl := &client.Client{ID: "client" + key} + require.NoError(t, reg.ClientManager().CreateClient(ctx, cl)) + lr := &flow.LoginRequest{ + ID: "login-" + challenge, + Client: cl, + RequestURL: requestURL, + RequestedAt: time.Now(), + } + f, err := reg.ConsentManager().CreateLoginRequest(ctx, lr) + require.NoError(t, err) + challenge, err = f.ToLoginChallenge(ctx, reg) + require.NoError(t, err) + _, err = reg.ConsentManager().HandleLoginRequest(ctx, f, challenge, &flow.HandledLoginRequest{ + ID: challenge, }) require.NoError(t, err) - require.NoError(t, reg.ConsentManager().CreateConsentRequest(context.Background(), &OAuth2ConsentRequest{ + challenge, err = f.ToConsentChallenge(ctx, reg) + require.NoError(t, err) + require.NoError(t, reg.ConsentManager().CreateConsentRequest(ctx, f, &flow.OAuth2ConsentRequest{ Client: cl, ID: challenge, Verifier: challenge, @@ -178,12 +194,14 @@ func TestGetConsentRequest(t *testing.T) { })) if tc.handled { - _, err := reg.ConsentManager().HandleConsentRequest(context.Background(), &AcceptOAuth2ConsentRequest{ + _, err := reg.ConsentManager().HandleConsentRequest(ctx, f, &flow.AcceptOAuth2ConsentRequest{ ID: challenge, WasHandled: true, HandledAt: sqlxx.NullTime(time.Now()), }) require.NoError(t, err) + challenge, err = f.ToConsentChallenge(ctx, reg) + require.NoError(t, err) } } @@ -200,11 +218,11 @@ func TestGetConsentRequest(t *testing.T) { require.EqualValues(t, tc.status, resp.StatusCode) if tc.handled { - var result OAuth2RedirectTo + var result flow.OAuth2RedirectTo require.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) require.Equal(t, requestURL, result.RedirectTo) } else if tc.exists { - var result OAuth2ConsentRequest + var result flow.OAuth2ConsentRequest require.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) require.Equal(t, challenge, result.ID) require.Equal(t, requestURL, result.RequestURL) @@ -216,19 +234,24 @@ func TestGetConsentRequest(t *testing.T) { func TestGetLoginRequestWithDuplicateAccept(t *testing.T) { t.Run("Test get login request with duplicate accept", func(t *testing.T) { + ctx := context.Background() challenge := "challenge" requestURL := "http://192.0.2.1" conf := internal.NewConfigurationWithDefaults() reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) - cl := &client.Client{LegacyClientID: "client"} - require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cl)) - require.NoError(t, reg.ConsentManager().CreateLoginRequest(context.Background(), &LoginRequest{ - Client: cl, - ID: challenge, - RequestURL: requestURL, - })) + cl := &client.Client{ID: "client"} + require.NoError(t, reg.ClientManager().CreateClient(ctx, cl)) + f, err := reg.ConsentManager().CreateLoginRequest(ctx, &flow.LoginRequest{ + Client: cl, + ID: challenge, + RequestURL: requestURL, + RequestedAt: time.Now(), + }) + require.NoError(t, err) + challenge, err = f.ToLoginChallenge(ctx, reg) + require.NoError(t, err) h := NewHandler(reg, conf) r := x.NewRouterAdmin(conf.AdminURL) @@ -239,7 +262,7 @@ func TestGetLoginRequestWithDuplicateAccept(t *testing.T) { c := &http.Client{} sub := "sub123" - acceptLogin := &hydra.AcceptOAuth2LoginRequest{Remember: pointerx.Bool(true), Subject: sub} + acceptLogin := &hydra.AcceptOAuth2LoginRequest{Remember: pointerx.Ptr(true), Subject: sub} // marshal User to json acceptLoginJson, err := json.Marshal(acceptLogin) @@ -257,7 +280,7 @@ func TestGetLoginRequestWithDuplicateAccept(t *testing.T) { require.NoError(t, err) require.EqualValues(t, http.StatusOK, resp.StatusCode) - var result OAuth2RedirectTo + var result flow.OAuth2RedirectTo require.NoError(t, json.NewDecoder(resp.Body).Decode(&result)) require.NotNil(t, result.RedirectTo) require.Contains(t, result.RedirectTo, "login_verifier") @@ -271,7 +294,7 @@ func TestGetLoginRequestWithDuplicateAccept(t *testing.T) { require.NoError(t, err) require.EqualValues(t, http.StatusOK, resp2.StatusCode) - var result2 OAuth2RedirectTo + var result2 flow.OAuth2RedirectTo require.NoError(t, json.NewDecoder(resp2.Body).Decode(&result2)) require.NotNil(t, result2.RedirectTo) require.Contains(t, result2.RedirectTo, "login_verifier") diff --git a/consent/helper.go b/consent/helper.go index 42ed8963a6b..362f2952284 100644 --- a/consent/helper.go +++ b/consent/helper.go @@ -4,21 +4,9 @@ package consent import ( - "net/http" - "strings" - - "time" - - "github.com/ory/hydra/x" - - "github.com/ory/x/errorsx" - - "github.com/gorilla/sessions" - "github.com/ory/fosite" - "github.com/ory/x/mapx" - - "github.com/ory/hydra/client" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/flow" ) func sanitizeClientFromRequest(ar fosite.AuthorizeRequester) *client.Client { @@ -33,7 +21,7 @@ func sanitizeClient(c *client.Client) *client.Client { return cc } -func matchScopes(scopeStrategy fosite.ScopeStrategy, previousConsent []AcceptOAuth2ConsentRequest, requestedScope []string) *AcceptOAuth2ConsentRequest { +func matchScopes(scopeStrategy fosite.ScopeStrategy, previousConsent []flow.AcceptOAuth2ConsentRequest, requestedScope []string) *flow.AcceptOAuth2ConsentRequest { for _, cs := range previousConsent { var found = true for _, scope := range requestedScope { @@ -50,58 +38,3 @@ func matchScopes(scopeStrategy fosite.ScopeStrategy, previousConsent []AcceptOAu return nil } - -func createCsrfSession(w http.ResponseWriter, r *http.Request, conf x.CookieConfigProvider, store sessions.Store, name string, csrfValue string, maxAge time.Duration) error { - // Errors can be ignored here, because we always get a session back. Error typically means that the - // session doesn't exist yet. - session, _ := store.Get(r, name) - - sameSite := conf.CookieSameSiteMode(r.Context()) - if isLegacyCsrfSessionName(name) { - sameSite = 0 - } - - session.Values["csrf"] = csrfValue - session.Options.HttpOnly = true - session.Options.Secure = conf.CookieSecure(r.Context()) - session.Options.SameSite = sameSite - session.Options.Domain = conf.CookieDomain(r.Context()) - session.Options.MaxAge = int(maxAge.Seconds()) - if err := session.Save(r, w); err != nil { - return errorsx.WithStack(err) - } - - if sameSite == http.SameSiteNoneMode && conf.CookieSameSiteLegacyWorkaround(r.Context()) { - return createCsrfSession(w, r, conf, store, legacyCsrfSessionName(name), csrfValue, maxAge) - } - - return nil -} - -func validateCsrfSession(r *http.Request, conf x.CookieConfigProvider, store sessions.Store, name, expectedCSRF string) error { - if cookie, err := getCsrfSession(r, store, conf, name); err != nil { - return errorsx.WithStack(fosite.ErrRequestForbidden.WithHint("CSRF session cookie could not be decoded.")) - } else if csrf, err := mapx.GetString(cookie.Values, "csrf"); err != nil { - return errorsx.WithStack(fosite.ErrRequestForbidden.WithHint("No CSRF value available in the session cookie.")) - } else if csrf != expectedCSRF { - return errorsx.WithStack(fosite.ErrRequestForbidden.WithHint("The CSRF value from the token does not match the CSRF value from the data store.")) - } - - return nil -} - -func getCsrfSession(r *http.Request, store sessions.Store, conf x.CookieConfigProvider, name string) (*sessions.Session, error) { - cookie, err := store.Get(r, name) - if !isLegacyCsrfSessionName(name) && conf.CookieSameSiteMode(r.Context()) == http.SameSiteNoneMode && conf.CookieSameSiteLegacyWorkaround(r.Context()) && (err != nil || len(cookie.Values) == 0) { - return store.Get(r, legacyCsrfSessionName(name)) - } - return cookie, err -} - -func legacyCsrfSessionName(name string) string { - return name + "_legacy" -} - -func isLegacyCsrfSessionName(name string) bool { - return strings.HasSuffix(name, "_legacy") -} diff --git a/consent/helper_test.go b/consent/helper_test.go index 86fcc15940c..4a347575f3a 100644 --- a/consent/helper_test.go +++ b/consent/helper_test.go @@ -12,14 +12,15 @@ import ( "github.com/golang/mock/gomock" - "github.com/ory/hydra/internal/mock" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/internal/mock" "github.com/gorilla/securecookie" "github.com/gorilla/sessions" "github.com/stretchr/testify/assert" "github.com/ory/fosite" - "github.com/ory/hydra/client" + "github.com/ory/hydra/v2/client" ) func TestSanitizeClient(t *testing.T) { @@ -38,22 +39,22 @@ func TestSanitizeClient(t *testing.T) { func TestMatchScopes(t *testing.T) { for k, tc := range []struct { - granted []AcceptOAuth2ConsentRequest + granted []flow.AcceptOAuth2ConsentRequest requested []string expectChallenge string }{ { - granted: []AcceptOAuth2ConsentRequest{{ID: "1", GrantedScope: []string{"foo", "bar"}}}, + granted: []flow.AcceptOAuth2ConsentRequest{{ID: "1", GrantedScope: []string{"foo", "bar"}}}, requested: []string{"foo", "bar"}, expectChallenge: "1", }, { - granted: []AcceptOAuth2ConsentRequest{{ID: "1", GrantedScope: []string{"foo", "bar"}}}, + granted: []flow.AcceptOAuth2ConsentRequest{{ID: "1", GrantedScope: []string{"foo", "bar"}}}, requested: []string{"foo", "bar", "baz"}, expectChallenge: "", }, { - granted: []AcceptOAuth2ConsentRequest{ + granted: []flow.AcceptOAuth2ConsentRequest{ {ID: "1", GrantedScope: []string{"foo", "bar"}}, {ID: "2", GrantedScope: []string{"foo", "bar"}}, }, @@ -61,7 +62,7 @@ func TestMatchScopes(t *testing.T) { expectChallenge: "1", }, { - granted: []AcceptOAuth2ConsentRequest{ + granted: []flow.AcceptOAuth2ConsentRequest{ {ID: "1", GrantedScope: []string{"foo", "bar"}}, {ID: "2", GrantedScope: []string{"foo", "bar", "baz"}}, }, @@ -69,7 +70,7 @@ func TestMatchScopes(t *testing.T) { expectChallenge: "2", }, { - granted: []AcceptOAuth2ConsentRequest{ + granted: []flow.AcceptOAuth2ConsentRequest{ {ID: "1", GrantedScope: []string{"foo", "bar"}}, {ID: "2", GrantedScope: []string{"foo", "bar", "baz"}}, }, @@ -266,7 +267,7 @@ func TestValidateCsrfSession(t *testing.T) { assert.NoError(t, err, "failed to save cookie %s", c.name) } - err := validateCsrfSession(r, config, store, name, tc.csrfValue) + err := ValidateCsrfSession(r, config, store, name, tc.csrfValue, new(flow.Flow)) if tc.expectError { assert.Error(t, err) } else { diff --git a/consent/janitor_consent_test_helper.go b/consent/janitor_consent_test_helper.go index 6467eb1a63d..645a88a2209 100644 --- a/consent/janitor_consent_test_helper.go +++ b/consent/janitor_consent_test_helper.go @@ -6,23 +6,24 @@ package consent import ( "time" + "github.com/ory/hydra/v2/flow" "github.com/ory/x/sqlxx" ) -func NewHandledLoginRequest(challenge string, hasError bool, requestedAt time.Time, authenticatedAt sqlxx.NullTime) *HandledLoginRequest { - var deniedErr *RequestDeniedError +func NewHandledLoginRequest(challenge string, hasError bool, requestedAt time.Time, authenticatedAt sqlxx.NullTime) *flow.HandledLoginRequest { + var deniedErr *flow.RequestDeniedError if hasError { - deniedErr = &RequestDeniedError{ + deniedErr = &flow.RequestDeniedError{ Name: "consent request denied", Description: "some description", Hint: "some hint", Code: 403, Debug: "some debug", - valid: true, + Valid: true, } } - return &HandledLoginRequest{ + return &flow.HandledLoginRequest{ ID: challenge, Error: deniedErr, WasHandled: true, @@ -31,20 +32,20 @@ func NewHandledLoginRequest(challenge string, hasError bool, requestedAt time.Ti } } -func NewHandledConsentRequest(challenge string, hasError bool, requestedAt time.Time, authenticatedAt sqlxx.NullTime) *AcceptOAuth2ConsentRequest { - var deniedErr *RequestDeniedError +func NewHandledConsentRequest(challenge string, hasError bool, requestedAt time.Time, authenticatedAt sqlxx.NullTime) *flow.AcceptOAuth2ConsentRequest { + var deniedErr *flow.RequestDeniedError if hasError { - deniedErr = &RequestDeniedError{ + deniedErr = &flow.RequestDeniedError{ Name: "consent request denied", Description: "some description", Hint: "some hint", Code: 403, Debug: "some debug", - valid: true, + Valid: true, } } - return &AcceptOAuth2ConsentRequest{ + return &flow.AcceptOAuth2ConsentRequest{ ID: challenge, HandledAt: sqlxx.NullTime(time.Now().Round(time.Second)), Error: deniedErr, diff --git a/consent/manager.go b/consent/manager.go index bc84ddf91c9..fe4b018352e 100644 --- a/consent/manager.go +++ b/consent/manager.go @@ -5,11 +5,11 @@ package consent import ( "context" - "time" "github.com/gofrs/uuid" - "github.com/ory/hydra/client" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/flow" ) type ForcedObfuscatedLoginSession struct { @@ -19,44 +19,50 @@ type ForcedObfuscatedLoginSession struct { NID uuid.UUID `db:"nid"` } -func (_ ForcedObfuscatedLoginSession) TableName() string { +func (ForcedObfuscatedLoginSession) TableName() string { return "hydra_oauth2_obfuscated_authentication_session" } -type Manager interface { - CreateConsentRequest(ctx context.Context, req *OAuth2ConsentRequest) error - GetConsentRequest(ctx context.Context, challenge string) (*OAuth2ConsentRequest, error) - HandleConsentRequest(ctx context.Context, r *AcceptOAuth2ConsentRequest) (*OAuth2ConsentRequest, error) - RevokeSubjectConsentSession(ctx context.Context, user string) error - RevokeSubjectClientConsentSession(ctx context.Context, user, client string) error - - VerifyAndInvalidateConsentRequest(ctx context.Context, verifier string) (*AcceptOAuth2ConsentRequest, error) - FindGrantedAndRememberedConsentRequests(ctx context.Context, client, user string) ([]AcceptOAuth2ConsentRequest, error) - FindSubjectsGrantedConsentRequests(ctx context.Context, user string, limit, offset int) ([]AcceptOAuth2ConsentRequest, error) - FindSubjectsSessionGrantedConsentRequests(ctx context.Context, user, sid string, limit, offset int) ([]AcceptOAuth2ConsentRequest, error) - CountSubjectsGrantedConsentRequests(ctx context.Context, user string) (int, error) - - // Cookie management - GetRememberedLoginSession(ctx context.Context, id string) (*LoginSession, error) - CreateLoginSession(ctx context.Context, session *LoginSession) error - DeleteLoginSession(ctx context.Context, id string) error - RevokeSubjectLoginSession(ctx context.Context, user string) error - ConfirmLoginSession(ctx context.Context, id string, authTime time.Time, subject string, remember bool) error - - CreateLoginRequest(ctx context.Context, req *LoginRequest) error - GetLoginRequest(ctx context.Context, challenge string) (*LoginRequest, error) - HandleLoginRequest(ctx context.Context, challenge string, r *HandledLoginRequest) (*LoginRequest, error) - VerifyAndInvalidateLoginRequest(ctx context.Context, verifier string) (*HandledLoginRequest, error) - - CreateForcedObfuscatedLoginSession(ctx context.Context, session *ForcedObfuscatedLoginSession) error - GetForcedObfuscatedLoginSession(ctx context.Context, client, obfuscated string) (*ForcedObfuscatedLoginSession, error) - - ListUserAuthenticatedClientsWithFrontChannelLogout(ctx context.Context, subject, sid string) ([]client.Client, error) - ListUserAuthenticatedClientsWithBackChannelLogout(ctx context.Context, subject, sid string) ([]client.Client, error) - - CreateLogoutRequest(ctx context.Context, request *LogoutRequest) error - GetLogoutRequest(ctx context.Context, challenge string) (*LogoutRequest, error) - AcceptLogoutRequest(ctx context.Context, challenge string) (*LogoutRequest, error) - RejectLogoutRequest(ctx context.Context, challenge string) error - VerifyAndInvalidateLogoutRequest(ctx context.Context, verifier string) (*LogoutRequest, error) -} +type ( + Manager interface { + CreateConsentRequest(ctx context.Context, f *flow.Flow, req *flow.OAuth2ConsentRequest) error + GetConsentRequest(ctx context.Context, challenge string) (*flow.OAuth2ConsentRequest, error) + HandleConsentRequest(ctx context.Context, f *flow.Flow, r *flow.AcceptOAuth2ConsentRequest) (*flow.OAuth2ConsentRequest, error) + RevokeSubjectConsentSession(ctx context.Context, user string) error + RevokeSubjectClientConsentSession(ctx context.Context, user, client string) error + + VerifyAndInvalidateConsentRequest(ctx context.Context, verifier string) (*flow.AcceptOAuth2ConsentRequest, error) + FindGrantedAndRememberedConsentRequests(ctx context.Context, client, user string) ([]flow.AcceptOAuth2ConsentRequest, error) + FindSubjectsGrantedConsentRequests(ctx context.Context, user string, limit, offset int) ([]flow.AcceptOAuth2ConsentRequest, error) + FindSubjectsSessionGrantedConsentRequests(ctx context.Context, user, sid string, limit, offset int) ([]flow.AcceptOAuth2ConsentRequest, error) + CountSubjectsGrantedConsentRequests(ctx context.Context, user string) (int, error) + + // Cookie management + GetRememberedLoginSession(ctx context.Context, loginSessionFromCookie *flow.LoginSession, id string) (*flow.LoginSession, error) + CreateLoginSession(ctx context.Context, session *flow.LoginSession) error + DeleteLoginSession(ctx context.Context, id string) (deletedSession *flow.LoginSession, err error) + RevokeSubjectLoginSession(ctx context.Context, user string) error + ConfirmLoginSession(ctx context.Context, loginSession *flow.LoginSession) error + + CreateLoginRequest(ctx context.Context, req *flow.LoginRequest) (*flow.Flow, error) + GetLoginRequest(ctx context.Context, challenge string) (*flow.LoginRequest, error) + HandleLoginRequest(ctx context.Context, f *flow.Flow, challenge string, r *flow.HandledLoginRequest) (*flow.LoginRequest, error) + VerifyAndInvalidateLoginRequest(ctx context.Context, verifier string) (*flow.HandledLoginRequest, error) + + CreateForcedObfuscatedLoginSession(ctx context.Context, session *ForcedObfuscatedLoginSession) error + GetForcedObfuscatedLoginSession(ctx context.Context, client, obfuscated string) (*ForcedObfuscatedLoginSession, error) + + ListUserAuthenticatedClientsWithFrontChannelLogout(ctx context.Context, subject, sid string) ([]client.Client, error) + ListUserAuthenticatedClientsWithBackChannelLogout(ctx context.Context, subject, sid string) ([]client.Client, error) + + CreateLogoutRequest(ctx context.Context, request *flow.LogoutRequest) error + GetLogoutRequest(ctx context.Context, challenge string) (*flow.LogoutRequest, error) + AcceptLogoutRequest(ctx context.Context, challenge string) (*flow.LogoutRequest, error) + RejectLogoutRequest(ctx context.Context, challenge string) error + VerifyAndInvalidateLogoutRequest(ctx context.Context, verifier string) (*flow.LogoutRequest, error) + } + + ManagerProvider interface { + ConsentManager() Manager + } +) diff --git a/consent/registry.go b/consent/registry.go index aa5fae8b758..59e626efaad 100644 --- a/consent/registry.go +++ b/consent/registry.go @@ -7,8 +7,10 @@ import ( "context" "github.com/ory/fosite/handler/openid" - "github.com/ory/hydra/client" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/internal/kratos" + "github.com/ory/hydra/v2/x" ) type InternalRegistry interface { @@ -16,9 +18,11 @@ type InternalRegistry interface { x.RegistryCookieStore x.RegistryLogger x.HTTPClientProvider + kratos.Provider Registry client.Registry + FlowCipher() *aead.XChaCha20Poly1305 OAuth2Storage() x.FositeStorer OpenIDConnectRequestValidator() *openid.OpenIDConnectRequestValidator } diff --git a/consent/sdk_test.go b/consent/sdk_test.go index ffcfb74fd8a..f749428d5d8 100644 --- a/consent/sdk_test.go +++ b/consent/sdk_test.go @@ -6,21 +6,25 @@ package consent_test import ( "context" "fmt" + "net/http" "net/http/httptest" "testing" "time" + "github.com/ory/hydra/v2/consent/test" + hydra "github.com/ory/hydra-client-go/v2" + . "github.com/ory/hydra/v2/flow" "github.com/ory/x/httprouterx" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - . "github.com/ory/hydra/consent" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/x" + . "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" ) @@ -36,6 +40,10 @@ func TestSDK(t *testing.T) { conf.MustSet(ctx, config.KeyAccessTokenLifespan, time.Minute) reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) + consentChallenge := func(f *Flow) string { return x.Must(f.ToConsentChallenge(ctx, reg)) } + consentVerifier := func(f *Flow) string { return x.Must(f.ToConsentVerifier(ctx, reg)) } + loginChallenge := func(f *Flow) string { return x.Must(f.ToLoginChallenge(ctx, reg)) } + router := x.NewRouterPublic() h := NewHandler(reg, conf) @@ -52,10 +60,8 @@ func TestSDK(t *testing.T) { Subject: "subject1", })) - ar1, _ := MockAuthRequest("ar-1", false, network) - ar2, _ := MockAuthRequest("ar-2", false, network) - require.NoError(t, reg.ClientManager().CreateClient(context.Background(), ar1.Client)) - require.NoError(t, reg.ClientManager().CreateClient(context.Background(), ar2.Client)) + ar1, _, _ := test.MockAuthRequest("1", false, network) + ar2, _, _ := test.MockAuthRequest("2", false, network) require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ ID: ar1.SessionID.String(), Subject: ar1.Subject, @@ -64,116 +70,160 @@ func TestSDK(t *testing.T) { ID: ar2.SessionID.String(), Subject: ar2.Subject, })) - require.NoError(t, m.CreateLoginRequest(context.Background(), ar1)) - require.NoError(t, m.CreateLoginRequest(context.Background(), ar2)) + _, err := m.CreateLoginRequest(context.Background(), ar1) + require.NoError(t, err) + _, err = m.CreateLoginRequest(context.Background(), ar2) + require.NoError(t, err) - cr1, hcr1 := MockConsentRequest("1", false, 0, false, false, false, "fk-login-challenge", network) - cr2, hcr2 := MockConsentRequest("2", false, 0, false, false, false, "fk-login-challenge", network) - cr3, hcr3 := MockConsentRequest("3", true, 3600, false, false, false, "fk-login-challenge", network) - cr4, hcr4 := MockConsentRequest("4", true, 3600, false, false, false, "fk-login-challenge", network) + cr1, hcr1, _ := test.MockConsentRequest("1", false, 0, false, false, false, "fk-login-challenge", network) + cr2, hcr2, _ := test.MockConsentRequest("2", false, 0, false, false, false, "fk-login-challenge", network) + cr3, hcr3, _ := test.MockConsentRequest("3", true, 3600, false, false, false, "fk-login-challenge", network) + cr4, hcr4, _ := test.MockConsentRequest("4", true, 3600, false, false, false, "fk-login-challenge", network) require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cr1.Client)) require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cr2.Client)) require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cr3.Client)) require.NoError(t, reg.ClientManager().CreateClient(context.Background(), cr4.Client)) - require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr1.LoginChallenge.String(), Subject: cr1.Subject, Client: cr1.Client, Verifier: cr1.ID})) - require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr2.LoginChallenge.String(), Subject: cr2.Subject, Client: cr2.Client, Verifier: cr2.ID})) - require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ID: cr3.LoginSessionID.String()})) - require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr3.LoginChallenge.String(), Subject: cr3.Subject, Client: cr3.Client, Verifier: cr3.ID, RequestedAt: hcr3.RequestedAt, SessionID: cr3.LoginSessionID})) - require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ID: cr4.LoginSessionID.String()})) - require.NoError(t, m.CreateLoginRequest(context.Background(), &LoginRequest{ID: cr4.LoginChallenge.String(), Client: cr4.Client, Verifier: cr4.ID, SessionID: cr4.LoginSessionID})) - require.NoError(t, m.CreateConsentRequest(context.Background(), cr1)) - require.NoError(t, m.CreateConsentRequest(context.Background(), cr2)) - require.NoError(t, m.CreateConsentRequest(context.Background(), cr3)) - require.NoError(t, m.CreateConsentRequest(context.Background(), cr4)) - _, err := m.HandleConsentRequest(context.Background(), hcr1) + + cr1Flow, err := m.CreateLoginRequest(context.Background(), &LoginRequest{ + ID: cr1.LoginChallenge.String(), + Subject: cr1.Subject, + Client: cr1.Client, + Verifier: cr1.ID, + RequestedAt: time.Now(), + }) + require.NoError(t, err) + cr1Flow.LoginSkip = ar1.Skip + + cr2Flow, err := m.CreateLoginRequest(context.Background(), &LoginRequest{ + ID: cr2.LoginChallenge.String(), + Subject: cr2.Subject, + Client: cr2.Client, + Verifier: cr2.ID, + RequestedAt: time.Now(), + }) require.NoError(t, err) - _, err = m.HandleConsentRequest(context.Background(), hcr2) + cr2Flow.LoginSkip = ar2.Skip + + loginSession3 := &LoginSession{ID: cr3.LoginSessionID.String()} + require.NoError(t, m.CreateLoginSession(context.Background(), loginSession3)) + require.NoError(t, m.ConfirmLoginSession(context.Background(), loginSession3)) + cr3Flow, err := m.CreateLoginRequest(context.Background(), &LoginRequest{ + ID: cr3.LoginChallenge.String(), + Subject: cr3.Subject, + Client: cr3.Client, + Verifier: cr3.ID, + RequestedAt: hcr3.RequestedAt, + SessionID: cr3.LoginSessionID, + }) require.NoError(t, err) - _, err = m.HandleConsentRequest(context.Background(), hcr3) + + loginSession4 := &LoginSession{ID: cr4.LoginSessionID.String()} + require.NoError(t, m.CreateLoginSession(context.Background(), loginSession4)) + require.NoError(t, m.ConfirmLoginSession(context.Background(), loginSession4)) + cr4Flow, err := m.CreateLoginRequest(context.Background(), &LoginRequest{ + ID: cr4.LoginChallenge.String(), + Client: cr4.Client, + Verifier: cr4.ID, + SessionID: cr4.LoginSessionID, + }) + require.NoError(t, err) + + require.NoError(t, m.CreateConsentRequest(context.Background(), cr1Flow, cr1)) + require.NoError(t, m.CreateConsentRequest(context.Background(), cr2Flow, cr2)) + require.NoError(t, m.CreateConsentRequest(context.Background(), cr3Flow, cr3)) + require.NoError(t, m.CreateConsentRequest(context.Background(), cr4Flow, cr4)) + _, err = m.HandleConsentRequest(context.Background(), cr1Flow, hcr1) require.NoError(t, err) - _, err = m.HandleConsentRequest(context.Background(), hcr4) + _, err = m.HandleConsentRequest(context.Background(), cr2Flow, hcr2) + require.NoError(t, err) + _, err = m.HandleConsentRequest(context.Background(), cr3Flow, hcr3) + require.NoError(t, err) + _, err = m.HandleConsentRequest(context.Background(), cr4Flow, hcr4) require.NoError(t, err) - lur1 := MockLogoutRequest("testsdk-1", true, network) + _, err = m.VerifyAndInvalidateConsentRequest(context.Background(), consentVerifier(cr3Flow)) + require.NoError(t, err) + _, err = m.VerifyAndInvalidateConsentRequest(context.Background(), consentVerifier(cr4Flow)) + require.NoError(t, err) + + lur1 := test.MockLogoutRequest("testsdk-1", true, network) require.NoError(t, reg.ClientManager().CreateClient(context.Background(), lur1.Client)) require.NoError(t, m.CreateLogoutRequest(context.Background(), lur1)) - lur2 := MockLogoutRequest("testsdk-2", false, network) + lur2 := test.MockLogoutRequest("testsdk-2", false, network) require.NoError(t, m.CreateLogoutRequest(context.Background(), lur2)) - crGot, _, err := sdk.OAuth2Api.GetOAuth2ConsentRequest(ctx).ConsentChallenge(makeID("challenge", network, "1")).Execute() - require.NoError(t, err) + cr1.ID = consentChallenge(cr1Flow) + crGot := execute[hydra.OAuth2ConsentRequest](t, sdk.OAuth2API.GetOAuth2ConsentRequest(ctx).ConsentChallenge(cr1.ID)) compareSDKConsentRequest(t, cr1, *crGot) - crGot, _, err = sdk.OAuth2Api.GetOAuth2ConsentRequest(ctx).ConsentChallenge(makeID("challenge", network, "2")).Execute() - require.NoError(t, err) + cr2.ID = consentChallenge(cr2Flow) + crGot = execute[hydra.OAuth2ConsentRequest](t, sdk.OAuth2API.GetOAuth2ConsentRequest(ctx).ConsentChallenge(cr2.ID)) compareSDKConsentRequest(t, cr2, *crGot) - arGot, _, err := sdk.OAuth2Api.GetOAuth2LoginRequest(ctx).LoginChallenge(makeID("challenge", network, "ar-1")).Execute() - require.NoError(t, err) + ar1.ID = loginChallenge(cr1Flow) + arGot := execute[hydra.OAuth2LoginRequest](t, sdk.OAuth2API.GetOAuth2LoginRequest(ctx).LoginChallenge(ar1.ID)) compareSDKLoginRequest(t, ar1, *arGot) - arGot, _, err = sdk.OAuth2Api.GetOAuth2LoginRequest(ctx).LoginChallenge(makeID("challenge", network, "ar-2")).Execute() + ar2.ID = loginChallenge(cr2Flow) + arGot = execute[hydra.OAuth2LoginRequest](t, sdk.OAuth2API.GetOAuth2LoginRequest(ctx).LoginChallenge(ar2.ID)) require.NoError(t, err) compareSDKLoginRequest(t, ar2, *arGot) - _, err = sdk.OAuth2Api.RevokeOAuth2LoginSessions(ctx).Subject("subject1").Execute() + _, err = sdk.OAuth2API.RevokeOAuth2LoginSessions(ctx).Subject("subject1").Execute() require.NoError(t, err) - _, err = sdk.OAuth2Api.RevokeOAuth2ConsentSessions(ctx).Subject("subject1").Execute() + _, err = sdk.OAuth2API.RevokeOAuth2ConsentSessions(ctx).Subject("subject1").Execute() require.Error(t, err) - _, err = sdk.OAuth2Api.RevokeOAuth2ConsentSessions(ctx).Subject(cr4.Subject).Client(cr4.Client.GetID()).Execute() + _, err = sdk.OAuth2API.RevokeOAuth2ConsentSessions(ctx).Subject(cr4.Subject).Client(cr4.Client.GetID()).Execute() require.NoError(t, err) - _, err = sdk.OAuth2Api.RevokeOAuth2ConsentSessions(ctx).Subject("subject1").All(true).Execute() + _, err = sdk.OAuth2API.RevokeOAuth2ConsentSessions(ctx).Subject("subject1").All(true).Execute() require.NoError(t, err) - _, _, err = sdk.OAuth2Api.GetOAuth2ConsentRequest(ctx).ConsentChallenge(makeID("challenge", network, "1")).Execute() + _, _, err = sdk.OAuth2API.GetOAuth2ConsentRequest(ctx).ConsentChallenge(makeID("challenge", network, "1")).Execute() require.Error(t, err) - crGot, _, err = sdk.OAuth2Api.GetOAuth2ConsentRequest(ctx).ConsentChallenge(makeID("challenge", network, "2")).Execute() + cr2.ID = consentChallenge(cr2Flow) + crGot, _, err = sdk.OAuth2API.GetOAuth2ConsentRequest(ctx).ConsentChallenge(cr2.ID).Execute() require.NoError(t, err) compareSDKConsentRequest(t, cr2, *crGot) - _, err = sdk.OAuth2Api.RevokeOAuth2ConsentSessions(ctx).Subject("subject2").Client("fk-client-2").Execute() + _, err = sdk.OAuth2API.RevokeOAuth2ConsentSessions(ctx).Subject("subject2").Client("fk-client-2").Execute() require.NoError(t, err) - _, _, err = sdk.OAuth2Api.GetOAuth2ConsentRequest(ctx).ConsentChallenge(makeID("challenge", network, "2")).Execute() + _, _, err = sdk.OAuth2API.GetOAuth2ConsentRequest(ctx).ConsentChallenge(makeID("challenge", network, "2")).Execute() require.Error(t, err) - csGot, _, err := sdk.OAuth2Api.ListOAuth2ConsentSessions(ctx).Subject("subject3").Execute() + csGot, _, err := sdk.OAuth2API.ListOAuth2ConsentSessions(ctx).Subject("subject3").Execute() require.NoError(t, err) assert.Equal(t, 1, len(csGot)) - cs := csGot[0] - assert.Equal(t, makeID("challenge", network, "3"), cs.ConsentRequest.Challenge) - csGot, _, err = sdk.OAuth2Api.ListOAuth2ConsentSessions(ctx).Subject("subject2").Execute() + csGot, _, err = sdk.OAuth2API.ListOAuth2ConsentSessions(ctx).Subject("subject2").Execute() require.NoError(t, err) assert.Equal(t, 0, len(csGot)) - csGot, _, err = sdk.OAuth2Api.ListOAuth2ConsentSessions(ctx).Subject("subject3").LoginSessionId("fk-login-session-t1-3").Execute() + csGot, _, err = sdk.OAuth2API.ListOAuth2ConsentSessions(ctx).Subject("subject3").LoginSessionId("fk-login-session-t1-3").Execute() require.NoError(t, err) assert.Equal(t, 1, len(csGot)) - cs = csGot[0] - assert.Equal(t, makeID("challenge", network, "3"), cs.ConsentRequest.Challenge) - csGot, _, err = sdk.OAuth2Api.ListOAuth2ConsentSessions(ctx).Subject("subject3").LoginSessionId("fk-login-session-t1-X").Execute() + csGot, _, err = sdk.OAuth2API.ListOAuth2ConsentSessions(ctx).Subject("subject3").LoginSessionId("fk-login-session-t1-X").Execute() require.NoError(t, err) assert.Equal(t, 0, len(csGot)) - luGot, _, err := sdk.OAuth2Api.GetOAuth2LogoutRequest(ctx).LogoutChallenge(makeID("challenge", network, "testsdk-1")).Execute() + luGot, _, err := sdk.OAuth2API.GetOAuth2LogoutRequest(ctx).LogoutChallenge(makeID("challenge", network, "testsdk-1")).Execute() require.NoError(t, err) compareSDKLogoutRequest(t, lur1, luGot) - luaGot, _, err := sdk.OAuth2Api.AcceptOAuth2LogoutRequest(ctx).LogoutChallenge(makeID("challenge", network, "testsdk-1")).Execute() + luaGot, _, err := sdk.OAuth2API.AcceptOAuth2LogoutRequest(ctx).LogoutChallenge(makeID("challenge", network, "testsdk-1")).Execute() require.NoError(t, err) assert.EqualValues(t, "https://www.ory.sh/oauth2/sessions/logout?logout_verifier="+makeID("verifier", network, "testsdk-1"), luaGot.RedirectTo) - _, err = sdk.OAuth2Api.RejectOAuth2LogoutRequest(ctx).LogoutChallenge(lur2.ID).Execute() + _, err = sdk.OAuth2API.RejectOAuth2LogoutRequest(ctx).LogoutChallenge(lur2.ID).Execute() require.NoError(t, err) - _, _, err = sdk.OAuth2Api.GetOAuth2LogoutRequest(ctx).LogoutChallenge(lur2.ID).Execute() + _, _, err = sdk.OAuth2API.GetOAuth2LogoutRequest(ctx).LogoutChallenge(lur2.ID).Execute() require.Error(t, err) } @@ -198,3 +248,15 @@ func compareSDKLogoutRequest(t *testing.T, expected *LogoutRequest, got *hydra.O assert.EqualValues(t, expected.RequestURL, *got.RequestUrl) assert.EqualValues(t, expected.RPInitiated, *got.RpInitiated) } + +type executer[T any] interface { + Execute() (*T, *http.Response, error) +} + +func execute[T any](t *testing.T, e executer[T]) *T { + got, res, err := e.Execute() + require.NoError(t, err) + require.NoError(t, res.Body.Close()) + + return got +} diff --git a/consent/strategy.go b/consent/strategy.go index 3ae24d0172a..08e8788c756 100644 --- a/consent/strategy.go +++ b/consent/strategy.go @@ -8,12 +8,19 @@ import ( "net/http" "github.com/ory/fosite" + "github.com/ory/hydra/v2/flow" ) var _ Strategy = new(DefaultStrategy) type Strategy interface { - HandleOAuth2AuthorizationRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, req fosite.AuthorizeRequester) (*AcceptOAuth2ConsentRequest, error) - HandleOpenIDConnectLogout(ctx context.Context, w http.ResponseWriter, r *http.Request) (*LogoutResult, error) + HandleOAuth2AuthorizationRequest( + ctx context.Context, + w http.ResponseWriter, + r *http.Request, + req fosite.AuthorizeRequester, + ) (*flow.AcceptOAuth2ConsentRequest, *flow.Flow, error) + HandleOpenIDConnectLogout(ctx context.Context, w http.ResponseWriter, r *http.Request) (*flow.LogoutResult, error) + HandleHeadlessLogout(ctx context.Context, w http.ResponseWriter, r *http.Request, sid string) error ObfuscateSubjectIdentifier(ctx context.Context, cl fosite.Client, subject, forcedIdentifier string) (string, error) } diff --git a/consent/strategy_default.go b/consent/strategy_default.go index ecbeccb76e9..8acf7f7c2fa 100644 --- a/consent/strategy_default.go +++ b/consent/strategy_default.go @@ -5,40 +5,39 @@ package consent import ( "context" + stderrs "errors" "fmt" + "io" "net/http" "net/url" "strconv" "strings" "time" - "github.com/twmb/murmur3" - - "github.com/ory/hydra/driver/config" - - "github.com/ory/x/errorsx" - - "github.com/ory/x/sqlcon" - "github.com/gorilla/sessions" + "github.com/hashicorp/go-retryablehttp" "github.com/pborman/uuid" "github.com/pkg/errors" "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel/trace" - jwtgo "github.com/ory/fosite/token/jwt" - - "github.com/ory/x/sqlxx" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/oauth2/flowctx" "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/token/jwt" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/errorsx" "github.com/ory/x/mapx" + "github.com/ory/x/otelx" + "github.com/ory/x/sqlcon" + "github.com/ory/x/sqlxx" "github.com/ory/x/stringslice" "github.com/ory/x/stringsx" "github.com/ory/x/urlx" - - "github.com/ory/hydra/client" - "github.com/ory/hydra/x" ) const ( @@ -60,10 +59,10 @@ func NewStrategy( } } -var ErrAbortOAuth2Request = errors.New("the OAuth 2.0 Authorization request must be aborted") -var ErrNoPreviousConsentFound = errors.New("no previous OAuth 2.0 Consent could be found for this access request") -var ErrNoAuthenticationSessionFound = errors.New("no previous login session was found") -var ErrHintDoesNotMatchAuthentication = errors.New("subject from hint does not match subject from session") +var ErrAbortOAuth2Request = stderrs.New("the OAuth 2.0 Authorization request must be aborted") +var ErrNoPreviousConsentFound = stderrs.New("no previous OAuth 2.0 Consent could be found for this access request") +var ErrNoAuthenticationSessionFound = stderrs.New("no previous login session was found") +var ErrHintDoesNotMatchAuthentication = stderrs.New("subject from hint does not match subject from session") func (s *DefaultStrategy) matchesValueFromSession(ctx context.Context, c fosite.Client, hintSubject string, sessionSubject string) error { obfuscatedUserID, err := s.ObfuscateSubjectIdentifier(ctx, c, sessionSubject, "") @@ -87,7 +86,7 @@ func (s *DefaultStrategy) matchesValueFromSession(ctx context.Context, c fosite. return nil } -func (s *DefaultStrategy) authenticationSession(ctx context.Context, w http.ResponseWriter, r *http.Request) (*LoginSession, error) { +func (s *DefaultStrategy) authenticationSession(ctx context.Context, _ http.ResponseWriter, r *http.Request) (*flow.LoginSession, error) { store, err := s.r.CookieStore(ctx) if err != nil { return nil, err @@ -110,7 +109,7 @@ func (s *DefaultStrategy) authenticationSession(ctx context.Context, w http.Resp return nil, errorsx.WithStack(ErrNoAuthenticationSessionFound) } - session, err := s.r.ConsentManager().GetRememberedLoginSession(r.Context(), sessionID) + session, err := s.r.ConsentManager().GetRememberedLoginSession(r.Context(), nil, sessionID) if errors.Is(err, x.ErrNotFound) { s.r.Logger().WithRequest(r).WithError(err). Debug("User logout skipped because cookie exists and session value exist but are not remembered any more.") @@ -122,7 +121,10 @@ func (s *DefaultStrategy) authenticationSession(ctx context.Context, w http.Resp return session, nil } -func (s *DefaultStrategy) requestAuthentication(ctx context.Context, w http.ResponseWriter, r *http.Request, ar fosite.AuthorizeRequester) error { +func (s *DefaultStrategy) requestAuthentication(ctx context.Context, w http.ResponseWriter, r *http.Request, ar fosite.AuthorizeRequester) (err error) { + ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("").Start(ctx, "DefaultStrategy.requestAuthentication") + defer otelx.End(span, &err) + prompt := stringsx.Splitx(ar.GetRequestForm().Get("prompt"), " ") if stringslice.Has(prompt, "login") { return s.forwardAuthenticationRequest(ctx, w, r, ar, "", time.Time{}, nil) @@ -168,9 +170,9 @@ func (s *DefaultStrategy) requestAuthentication(ctx context.Context, w http.Resp return s.forwardAuthenticationRequest(ctx, w, r, ar, session.Subject, time.Time(session.AuthenticatedAt), session) } -func (s *DefaultStrategy) getIDTokenHintClaims(ctx context.Context, idTokenHint string) (jwtgo.MapClaims, error) { +func (s *DefaultStrategy) getIDTokenHintClaims(ctx context.Context, idTokenHint string) (jwt.MapClaims, error) { token, err := s.r.OpenIDJWTStrategy().Decode(ctx, idTokenHint) - if ve := new(jwtgo.ValidationError); errors.As(err, &ve) && ve.Errors == jwtgo.ValidationErrorExpired { + if ve := new(jwt.ValidationError); errors.As(err, &ve) && ve.Errors == jwt.ValidationErrorExpired { // Expired is ok } else if err != nil { return nil, errorsx.WithStack(fosite.ErrInvalidRequest.WithHint(err.Error())) @@ -192,7 +194,7 @@ func (s *DefaultStrategy) getSubjectFromIDTokenHint(ctx context.Context, idToken return sub, nil } -func (s *DefaultStrategy) forwardAuthenticationRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, ar fosite.AuthorizeRequester, subject string, authenticatedAt time.Time, session *LoginSession) error { +func (s *DefaultStrategy) forwardAuthenticationRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, ar fosite.AuthorizeRequester, subject string, authenticatedAt time.Time, session *flow.LoginSession) error { if (subject != "" && authenticatedAt.IsZero()) || (subject == "" && !authenticatedAt.IsZero()) { return errorsx.WithStack(fosite.ErrServerError.WithHint("Consent strategy returned a non-empty subject with an empty auth date, or an empty subject with a non-empty auth date.")) } @@ -202,7 +204,7 @@ func (s *DefaultStrategy) forwardAuthenticationRequest(ctx context.Context, w ht skip = true } - // Let'id validate that prompt is actually not "none" if we can't skip authentication + // Let's validate that prompt is actually not "none" if we can't skip authentication prompt := stringsx.Splitx(ar.GetRequestForm().Get("prompt"), " ") if stringslice.Has(prompt, "none") && !skip { return errorsx.WithStack(fosite.ErrLoginRequired.WithHint(`Prompt 'none' was requested, but no existing login session was found.`)) @@ -217,7 +219,7 @@ func (s *DefaultStrategy) forwardAuthenticationRequest(ctx context.Context, w ht iu := s.c.OAuth2AuthURL(ctx) iu.RawQuery = r.URL.RawQuery - var idTokenHintClaims jwtgo.MapClaims + var idTokenHintClaims jwt.MapClaims if idTokenHint := ar.GetRequestForm().Get("id_token_hint"); len(idTokenHint) > 0 { claims, err := s.getIDTokenHintClaims(r.Context(), idTokenHint) if err != nil { @@ -230,39 +232,36 @@ func (s *DefaultStrategy) forwardAuthenticationRequest(ctx context.Context, w ht sessionID := uuid.New() if session != nil { sessionID = session.ID - } else { - // Create a stub session so that we can later update it. - if err := s.r.ConsentManager().CreateLoginSession(r.Context(), &LoginSession{ID: sessionID}); err != nil { - return err - } } // Set the session cl := sanitizeClientFromRequest(ar) - if err := s.r.ConsentManager().CreateLoginRequest( - r.Context(), - &LoginRequest{ - ID: challenge, - Verifier: verifier, - CSRF: csrf, - Skip: skip, - RequestedScope: []string(ar.GetRequestedScopes()), - RequestedAudience: []string(ar.GetRequestedAudience()), - Subject: subject, - Client: cl, - RequestURL: iu.String(), - AuthenticatedAt: sqlxx.NullTime(authenticatedAt), - RequestedAt: time.Now().Truncate(time.Second).UTC(), - SessionID: sqlxx.NullString(sessionID), - OpenIDConnectContext: &OAuth2ConsentRequestOpenIDConnectContext{ - IDTokenHintClaims: idTokenHintClaims, - ACRValues: stringsx.Splitx(ar.GetRequestForm().Get("acr_values"), " "), - UILocales: stringsx.Splitx(ar.GetRequestForm().Get("ui_locales"), " "), - Display: ar.GetRequestForm().Get("display"), - LoginHint: ar.GetRequestForm().Get("login_hint"), - }, + loginRequest := &flow.LoginRequest{ + ID: challenge, + Verifier: verifier, + CSRF: csrf, + Skip: skip, + RequestedScope: []string(ar.GetRequestedScopes()), + RequestedAudience: []string(ar.GetRequestedAudience()), + Subject: subject, + Client: cl, + RequestURL: iu.String(), + AuthenticatedAt: sqlxx.NullTime(authenticatedAt), + RequestedAt: time.Now().Truncate(time.Second).UTC(), + SessionID: sqlxx.NullString(sessionID), + OpenIDConnectContext: &flow.OAuth2ConsentRequestOpenIDConnectContext{ + IDTokenHintClaims: idTokenHintClaims, + ACRValues: stringsx.Splitx(ar.GetRequestForm().Get("acr_values"), " "), + UILocales: stringsx.Splitx(ar.GetRequestForm().Get("ui_locales"), " "), + Display: ar.GetRequestForm().Get("display"), + LoginHint: ar.GetRequestForm().Get("login_hint"), }, - ); err != nil { + } + f, err := s.r.ConsentManager().CreateLoginRequest( + ctx, + loginRequest, + ) + if err != nil { return errorsx.WithStack(err) } @@ -271,12 +270,24 @@ func (s *DefaultStrategy) forwardAuthenticationRequest(ctx context.Context, w ht return err } - clientSpecificCookieNameLoginCSRF := fmt.Sprintf("%s_%d", s.r.Config().CookieNameLoginCSRF(ctx), murmur3.Sum32(cl.ID.Bytes())) + clientSpecificCookieNameLoginCSRF := fmt.Sprintf("%s_%s", s.r.Config().CookieNameLoginCSRF(ctx), cl.CookieSuffix()) if err := createCsrfSession(w, r, s.r.Config(), store, clientSpecificCookieNameLoginCSRF, csrf, s.c.ConsentRequestMaxAge(ctx)); err != nil { return errorsx.WithStack(err) } - http.Redirect(w, r, urlx.SetQuery(s.c.LoginURL(ctx), url.Values{"login_challenge": {challenge}}).String(), http.StatusFound) + encodedFlow, err := f.ToLoginChallenge(ctx, s.r) + if err != nil { + return err + } + + var baseURL *url.URL + if stringslice.Has(prompt, "registration") { + baseURL = s.c.RegistrationURL(ctx) + } else { + baseURL = s.c.LoginURL(ctx) + } + + http.Redirect(w, r, urlx.SetQuery(baseURL, url.Values{"login_challenge": {encodedFlow}}).String(), http.StatusFound) // generate the verifier return errorsx.WithStack(ErrAbortOAuth2Request) @@ -297,7 +308,9 @@ func (s *DefaultStrategy) revokeAuthenticationSession(ctx context.Context, w htt return nil } - return s.r.ConsentManager().DeleteLoginSession(r.Context(), sid) + _, err = s.r.ConsentManager().DeleteLoginSession(r.Context(), sid) + + return err } func (s *DefaultStrategy) revokeAuthenticationCookie(w http.ResponseWriter, r *http.Request, ss sessions.Store) (string, error) { @@ -307,7 +320,7 @@ func (s *DefaultStrategy) revokeAuthenticationCookie(w http.ResponseWriter, r *h cookie.Values[CookieAuthenticationSIDName] = "" cookie.Options.HttpOnly = true - cookie.Options.Path = "/" + cookie.Options.Path = s.c.SessionCookiePath(ctx) cookie.Options.SameSite = s.c.CookieSameSiteMode(ctx) cookie.Options.Secure = s.c.CookieSecure(ctx) cookie.Options.Domain = s.c.CookieDomain(ctx) @@ -320,8 +333,22 @@ func (s *DefaultStrategy) revokeAuthenticationCookie(w http.ResponseWriter, r *h return sid, nil } -func (s *DefaultStrategy) verifyAuthentication(w http.ResponseWriter, r *http.Request, req fosite.AuthorizeRequester, verifier string) (*HandledLoginRequest, error) { - ctx := r.Context() +func (s *DefaultStrategy) verifyAuthentication( + ctx context.Context, + w http.ResponseWriter, + r *http.Request, + req fosite.AuthorizeRequester, + verifier string, +) (_ *flow.Flow, err error) { + ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("").Start(ctx, "DefaultStrategy.verifyAuthentication") + defer otelx.End(span, &err) + + // We decode the flow from the cookie again because VerifyAndInvalidateLoginRequest does not return the flow + f, err := flowctx.Decode[flow.Flow](ctx, s.r.FlowCipher(), verifier, flowctx.AsLoginVerifier) + if err != nil { + return nil, errorsx.WithStack(fosite.ErrAccessDenied.WithHint("The login verifier is invalid.")) + } + session, err := s.r.ConsentManager().VerifyAndInvalidateLoginRequest(ctx, verifier) if errors.Is(err, sqlcon.ErrNoRows) { return nil, errorsx.WithStack(fosite.ErrAccessDenied.WithHint("The login verifier has already been used, has not been granted, or is invalid.")) @@ -330,8 +357,8 @@ func (s *DefaultStrategy) verifyAuthentication(w http.ResponseWriter, r *http.Re } if session.HasError() { - session.Error.SetDefaults(loginRequestDeniedErrorName) - return nil, errorsx.WithStack(session.Error.toRFCError()) + session.Error.SetDefaults(flow.LoginRequestDeniedErrorName) + return nil, errorsx.WithStack(session.Error.ToRFCError()) } if session.RequestedAt.Add(s.c.ConsentRequestMaxAge(ctx)).Before(time.Now()) { @@ -343,8 +370,8 @@ func (s *DefaultStrategy) verifyAuthentication(w http.ResponseWriter, r *http.Re return nil, err } - clientSpecificCookieNameLoginCSRF := fmt.Sprintf("%s_%d", s.r.Config().CookieNameLoginCSRF(ctx), murmur3.Sum32(session.LoginRequest.Client.ID.Bytes())) - if err := validateCsrfSession(r, s.r.Config(), store, clientSpecificCookieNameLoginCSRF, session.LoginRequest.CSRF); err != nil { + clientSpecificCookieNameLoginCSRF := fmt.Sprintf("%s_%s", s.r.Config().CookieNameLoginCSRF(ctx), session.LoginRequest.Client.CookieSuffix()) + if err := ValidateCsrfSession(r, s.r.Config(), store, clientSpecificCookieNameLoginCSRF, session.LoginRequest.CSRF, f); err != nil { return nil, err } @@ -417,10 +444,21 @@ func (s *DefaultStrategy) verifyAuthentication(w http.ResponseWriter, r *http.Re if !session.LoginRequest.Skip { if time.Time(session.AuthenticatedAt).IsZero() { - return nil, errorsx.WithStack(fosite.ErrServerError.WithHint("Expected the handled login request to contain a valid authenticated_at value but it was zero. This is a bug which should be reported to https://github.com/ory/hydra.")) + return nil, errorsx.WithStack(fosite.ErrServerError.WithHint( + "Expected the handled login request to contain a valid authenticated_at value but it was zero. " + + "This is a bug which should be reported to https://github.com/ory/hydra.")) } - if err := s.r.ConsentManager().ConfirmLoginSession(r.Context(), sessionID, time.Time(session.AuthenticatedAt), session.Subject, session.Remember); err != nil { + if err := s.r.ConsentManager().ConfirmLoginSession(ctx, &flow.LoginSession{ + ID: sessionID, + AuthenticatedAt: session.AuthenticatedAt, + Subject: session.Subject, + IdentityProviderSessionID: sqlxx.NullString(session.IdentityProviderSessionID), + Remember: session.Remember, + }); err != nil { + if errors.Is(err, sqlcon.ErrUniqueViolation) { + return nil, errorsx.WithStack(fosite.ErrAccessDenied.WithHint("The login verifier has already been used.")) + } return nil, err } } @@ -433,11 +471,11 @@ func (s *DefaultStrategy) verifyAuthentication(w http.ResponseWriter, r *http.Re } } - if !session.Remember || session.LoginRequest.Skip { + if !session.Remember || session.LoginRequest.Skip && !session.ExtendSessionLifespan { // If the user doesn't want to remember the session, we do not store a cookie. // If login was skipped, it means an authentication cookie was present and // we don't want to touch it (in order to preserve its original expiry date) - return session, nil + return f, nil } // Not a skipped login and the user asked to remember its session, store a cookie @@ -447,7 +485,7 @@ func (s *DefaultStrategy) verifyAuthentication(w http.ResponseWriter, r *http.Re cookie.Options.MaxAge = session.RememberFor } cookie.Options.HttpOnly = true - cookie.Options.Path = "/" + cookie.Options.Path = s.c.SessionCookiePath(ctx) cookie.Options.SameSite = s.c.CookieSameSiteMode(ctx) cookie.Options.Secure = s.c.CookieSecure(ctx) if err := cookie.Save(r, w); err != nil { @@ -461,13 +499,23 @@ func (s *DefaultStrategy) verifyAuthentication(w http.ResponseWriter, r *http.Re "cookie_same_site": s.c.CookieSameSiteMode(ctx), "cookie_secure": s.c.CookieSecure(ctx), }).Debug("Authentication session cookie was set.") - return session, nil + + return f, nil } -func (s *DefaultStrategy) requestConsent(ctx context.Context, w http.ResponseWriter, r *http.Request, ar fosite.AuthorizeRequester, authenticationSession *HandledLoginRequest) error { +func (s *DefaultStrategy) requestConsent( + ctx context.Context, + w http.ResponseWriter, + r *http.Request, + ar fosite.AuthorizeRequester, + f *flow.Flow, +) (err error) { + ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("").Start(ctx, "DefaultStrategy.requestConsent") + defer otelx.End(span, &err) + prompt := stringsx.Splitx(ar.GetRequestForm().Get("prompt"), " ") if stringslice.Has(prompt, "consent") { - return s.forwardConsentRequest(ctx, w, r, ar, authenticationSession, nil) + return s.forwardConsentRequest(ctx, w, r, ar, f, nil) } // https://tools.ietf.org/html/rfc6749 @@ -491,7 +539,7 @@ func (s *DefaultStrategy) requestConsent(ctx context.Context, w http.ResponseWri // This is tracked as issue: https://github.com/ory/hydra/issues/866 // This is also tracked as upstream issue: https://github.com/openid-certification/oidctest/issues/97 if !(ar.GetRedirectURI().Scheme == "https" || (fosite.IsLocalhost(ar.GetRedirectURI()) && ar.GetRedirectURI().Scheme == "http")) { - return s.forwardConsentRequest(ctx, w, r, ar, authenticationSession, nil) + return s.forwardConsentRequest(ctx, w, r, ar, f, nil) } } @@ -502,23 +550,31 @@ func (s *DefaultStrategy) requestConsent(ctx context.Context, w http.ResponseWri // return s.forwardConsentRequest(w, r, ar, authenticationSession, nil) // } - consentSessions, err := s.r.ConsentManager().FindGrantedAndRememberedConsentRequests(r.Context(), ar.GetClient().GetID(), authenticationSession.Subject) + consentSessions, err := s.r.ConsentManager().FindGrantedAndRememberedConsentRequests(ctx, ar.GetClient().GetID(), f.Subject) if errors.Is(err, ErrNoPreviousConsentFound) { - return s.forwardConsentRequest(ctx, w, r, ar, authenticationSession, nil) + return s.forwardConsentRequest(ctx, w, r, ar, f, nil) } else if err != nil { return err } if found := matchScopes(s.r.Config().GetScopeStrategy(ctx), consentSessions, ar.GetRequestedScopes()); found != nil { - return s.forwardConsentRequest(ctx, w, r, ar, authenticationSession, found) + return s.forwardConsentRequest(ctx, w, r, ar, f, found) } - return s.forwardConsentRequest(ctx, w, r, ar, authenticationSession, nil) + return s.forwardConsentRequest(ctx, w, r, ar, f, nil) } -func (s *DefaultStrategy) forwardConsentRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, ar fosite.AuthorizeRequester, as *HandledLoginRequest, cs *AcceptOAuth2ConsentRequest) error { +func (s *DefaultStrategy) forwardConsentRequest( + ctx context.Context, + w http.ResponseWriter, + r *http.Request, + ar fosite.AuthorizeRequester, + f *flow.Flow, + previousConsent *flow.AcceptOAuth2ConsentRequest, +) error { + as := f.GetHandledLoginRequest() skip := false - if cs != nil { + if previousConsent != nil { skip = true } @@ -533,45 +589,54 @@ func (s *DefaultStrategy) forwardConsentRequest(ctx context.Context, w http.Resp csrf := strings.Replace(uuid.New(), "-", "", -1) cl := sanitizeClientFromRequest(ar) - if err := s.r.ConsentManager().CreateConsentRequest( - r.Context(), - &OAuth2ConsentRequest{ - ID: challenge, - ACR: as.ACR, - AMR: as.AMR, - Verifier: verifier, - CSRF: csrf, - Skip: skip, - RequestedScope: []string(ar.GetRequestedScopes()), - RequestedAudience: []string(ar.GetRequestedAudience()), - Subject: as.Subject, - Client: cl, - RequestURL: as.LoginRequest.RequestURL, - AuthenticatedAt: as.AuthenticatedAt, - RequestedAt: as.RequestedAt, - ForceSubjectIdentifier: as.ForceSubjectIdentifier, - OpenIDConnectContext: as.LoginRequest.OpenIDConnectContext, - LoginSessionID: as.LoginRequest.SessionID, - LoginChallenge: sqlxx.NullString(as.LoginRequest.ID), - Context: as.Context, - }, - ); err != nil { + + consentRequest := &flow.OAuth2ConsentRequest{ + ID: challenge, + ACR: as.ACR, + AMR: as.AMR, + Verifier: verifier, + CSRF: csrf, + Skip: skip, + RequestedScope: []string(ar.GetRequestedScopes()), + RequestedAudience: []string(ar.GetRequestedAudience()), + Subject: as.Subject, + Client: cl, + RequestURL: as.LoginRequest.RequestURL, + AuthenticatedAt: as.AuthenticatedAt, + RequestedAt: as.RequestedAt, + ForceSubjectIdentifier: as.ForceSubjectIdentifier, + OpenIDConnectContext: as.LoginRequest.OpenIDConnectContext, + LoginSessionID: as.LoginRequest.SessionID, + LoginChallenge: sqlxx.NullString(as.LoginRequest.ID), + Context: as.Context, + } + err := s.r.ConsentManager().CreateConsentRequest(ctx, f, consentRequest) + if err != nil { return errorsx.WithStack(err) } + consentChallenge, err := f.ToConsentChallenge(ctx, s.r) + if err != nil { + return err + } + store, err := s.r.CookieStore(ctx) if err != nil { return err } - clientSpecificCookieNameConsentCSRF := fmt.Sprintf("%s_%d", s.r.Config().CookieNameConsentCSRF(ctx), murmur3.Sum32(cl.ID.Bytes())) + if f.Client.GetID() != cl.GetID() { + return errorsx.WithStack(fosite.ErrInvalidClient.WithHint("The flow client id does not match the authorize request client id.")) + } + + clientSpecificCookieNameConsentCSRF := fmt.Sprintf("%s_%s", s.r.Config().CookieNameConsentCSRF(ctx), cl.CookieSuffix()) if err := createCsrfSession(w, r, s.r.Config(), store, clientSpecificCookieNameConsentCSRF, csrf, s.c.ConsentRequestMaxAge(ctx)); err != nil { return errorsx.WithStack(err) } http.Redirect( w, r, - urlx.SetQuery(s.c.ConsentURL(ctx), url.Values{"consent_challenge": {challenge}}).String(), + urlx.SetQuery(s.c.ConsentURL(ctx), url.Values{"consent_challenge": {consentChallenge}}).String(), http.StatusFound, ) @@ -579,39 +644,53 @@ func (s *DefaultStrategy) forwardConsentRequest(ctx context.Context, w http.Resp return errorsx.WithStack(ErrAbortOAuth2Request) } -func (s *DefaultStrategy) verifyConsent(ctx context.Context, w http.ResponseWriter, r *http.Request, req fosite.AuthorizeRequester, verifier string) (*AcceptOAuth2ConsentRequest, error) { - session, err := s.r.ConsentManager().VerifyAndInvalidateConsentRequest(r.Context(), verifier) - if errors.Is(err, sqlcon.ErrNoRows) { - return nil, errorsx.WithStack(fosite.ErrAccessDenied.WithHint("The consent verifier has already been used, has not been granted, or is invalid.")) +func (s *DefaultStrategy) verifyConsent(ctx context.Context, _ http.ResponseWriter, r *http.Request, verifier string) (_ *flow.AcceptOAuth2ConsentRequest, _ *flow.Flow, err error) { + ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("").Start(ctx, "DefaultStrategy.verifyConsent") + defer otelx.End(span, &err) + + // We decode the flow here once again because VerifyAndInvalidateConsentRequest does not return the flow + f, err := flowctx.Decode[flow.Flow](ctx, s.r.FlowCipher(), verifier, flowctx.AsConsentVerifier) + if err != nil { + return nil, nil, errorsx.WithStack(fosite.ErrAccessDenied.WithHint("The consent verifier has already been used, has not been granted, or is invalid.")) + } + if f.Client.GetID() != r.URL.Query().Get("client_id") { + return nil, nil, errorsx.WithStack(fosite.ErrInvalidClient.WithHint("The flow client id does not match the authorize request client id.")) + } + + session, err := s.r.ConsentManager().VerifyAndInvalidateConsentRequest(ctx, verifier) + if errors.Is(err, sqlcon.ErrUniqueViolation) { + return nil, nil, errorsx.WithStack(fosite.ErrAccessDenied.WithHint("The consent verifier has already been used.")) + } else if errors.Is(err, sqlcon.ErrNoRows) { + return nil, nil, errorsx.WithStack(fosite.ErrAccessDenied.WithHint("The consent verifier has already been used, has not been granted, or is invalid.")) } else if err != nil { - return nil, err + return nil, nil, err } if session.RequestedAt.Add(s.c.ConsentRequestMaxAge(ctx)).Before(time.Now()) { - return nil, errorsx.WithStack(fosite.ErrRequestUnauthorized.WithHint("The consent request has expired, please try again.")) + return nil, nil, errorsx.WithStack(fosite.ErrRequestUnauthorized.WithHint("The consent request has expired, please try again.")) } if session.HasError() { - session.Error.SetDefaults(consentRequestDeniedErrorName) - return nil, errorsx.WithStack(session.Error.toRFCError()) + session.Error.SetDefaults(flow.ConsentRequestDeniedErrorName) + return nil, nil, errorsx.WithStack(session.Error.ToRFCError()) } if time.Time(session.ConsentRequest.AuthenticatedAt).IsZero() { - return nil, errorsx.WithStack(fosite.ErrServerError.WithHint("The authenticatedAt value was not set.")) + return nil, nil, errorsx.WithStack(fosite.ErrServerError.WithHint("The authenticatedAt value was not set.")) } store, err := s.r.CookieStore(ctx) if err != nil { - return nil, err + return nil, nil, err } - clientSpecificCookieNameConsentCSRF := fmt.Sprintf("%s_%d", s.r.Config().CookieNameConsentCSRF(ctx), murmur3.Sum32(session.ConsentRequest.Client.ID.Bytes())) - if err := validateCsrfSession(r, s.r.Config(), store, clientSpecificCookieNameConsentCSRF, session.ConsentRequest.CSRF); err != nil { - return nil, err + clientSpecificCookieNameConsentCSRF := fmt.Sprintf("%s_%s", s.r.Config().CookieNameConsentCSRF(ctx), session.ConsentRequest.Client.CookieSuffix()) + if err := ValidateCsrfSession(r, s.r.Config(), store, clientSpecificCookieNameConsentCSRF, session.ConsentRequest.CSRF, f); err != nil { + return nil, nil, err } if session.Session == nil { - session.Session = NewConsentRequestSessionData() + session.Session = flow.NewConsentRequestSessionData() } if session.Session.AccessToken == nil { @@ -623,7 +702,7 @@ func (s *DefaultStrategy) verifyConsent(ctx context.Context, w http.ResponseWrit } session.AuthenticatedAt = session.ConsentRequest.AuthenticatedAt - return session, nil + return session, f, nil } func (s *DefaultStrategy) generateFrontChannelLogoutURLs(ctx context.Context, subject, sid string) ([]string, error) { @@ -648,7 +727,8 @@ func (s *DefaultStrategy) generateFrontChannelLogoutURLs(ctx context.Context, su return urls, nil } -func (s *DefaultStrategy) executeBackChannelLogout(ctx context.Context, r *http.Request, subject, sid string) error { +func (s *DefaultStrategy) executeBackChannelLogout(r *http.Request, subject, sid string) error { + ctx := r.Context() clients, err := s.r.ConsentManager().ListUserAuthenticatedClientsWithBackChannelLogout(ctx, subject, sid) if err != nil { return err @@ -674,9 +754,9 @@ func (s *DefaultStrategy) executeBackChannelLogout(ctx context.Context, r *http. // s.r.ConsentManager().GetForcedObfuscatedLoginSession(context.Background(), subject, ) // sub := s.obfuscateSubjectIdentifier(c, subject, ) - t, _, err := s.r.OpenIDJWTStrategy().Generate(ctx, jwtgo.MapClaims{ + t, _, err := s.r.OpenIDJWTStrategy().Generate(ctx, jwt.MapClaims{ "iss": s.c.IssuerURL(ctx).String(), - "aud": []string{c.LegacyClientID}, + "aud": []string{c.ID}, "iat": time.Now().UTC().Unix(), "jti": uuid.New(), "events": map[string]struct{}{"http://schemas.openid.net/event/backchannel-logout": {}}, @@ -691,20 +771,30 @@ func (s *DefaultStrategy) executeBackChannelLogout(ctx context.Context, r *http. tasks = append(tasks, task{url: c.BackChannelLogoutURI, clientID: c.GetID(), token: t}) } - var execute = func(t task) { + span := trace.SpanFromContext(ctx) + cl := s.r.HTTPClient(ctx) + execute := func(t task) { log := s.r.Logger().WithRequest(r). WithField("client_id", t.clientID). WithField("backchannel_logout_url", t.url) - res, err := s.r.HTTPClient(ctx).PostForm(t.url, url.Values{"logout_token": {t.token}}) + body := url.Values{"logout_token": {t.token}}.Encode() + req, err := retryablehttp.NewRequestWithContext(trace.ContextWithSpan(context.Background(), span), "POST", t.url, []byte(body)) + if err != nil { + log.WithError(err).Error("Unable to construct OpenID Connect Back-Channel Logout Request") + return + } + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + res, err := cl.Do(req) if err != nil { log.WithError(err).Error("Unable to execute OpenID Connect Back-Channel Logout Request") return } defer res.Body.Close() + res.Body = io.NopCloser(io.LimitReader(res.Body, 1<<20 /* 1 MB */)) // in case we ever start to read this response - if res.StatusCode != http.StatusOK { - log.WithError(errors.Errorf("expected HTTP status code %d but got %d", http.StatusOK, res.StatusCode)). + if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusNoContent { + log.WithError(errors.Errorf("expected HTTP status code %d or %d but got %d", http.StatusOK, http.StatusNoContent, res.StatusCode)). Error("Unable to execute OpenID Connect Back-Channel Logout Request") return } else { @@ -719,7 +809,7 @@ func (s *DefaultStrategy) executeBackChannelLogout(ctx context.Context, r *http. return nil } -func (s *DefaultStrategy) issueLogoutVerifier(ctx context.Context, w http.ResponseWriter, r *http.Request) (*LogoutResult, error) { +func (s *DefaultStrategy) issueLogoutVerifier(ctx context.Context, w http.ResponseWriter, r *http.Request) (*flow.LogoutResult, error) { // There are two types of log out flows: // // - RP initiated logout @@ -766,12 +856,14 @@ func (s *DefaultStrategy) issueLogoutVerifier(ctx context.Context, w http.Respon } challenge := uuid.New() - if err := s.r.ConsentManager().CreateLogoutRequest(r.Context(), &LogoutRequest{ + if err := s.r.ConsentManager().CreateLogoutRequest(r.Context(), &flow.LogoutRequest{ RequestURL: r.URL.String(), ID: challenge, Subject: session.Subject, SessionID: session.ID, Verifier: uuid.New(), + RequestedAt: sqlxx.NullTime(time.Now().UTC().Round(time.Second)), + ExpiresAt: sqlxx.NullTime(time.Now().UTC().Round(time.Second).Add(s.c.ConsentRequestMaxAge(ctx))), RPInitiated: false, // PostLogoutRedirectURI is set to the value from config.Provider().LogoutRedirectURL() @@ -877,7 +969,7 @@ func (s *DefaultStrategy) issueLogoutVerifier(ctx context.Context, w http.Respon // We do not really want to verify if the user (from id token hint) has a session here because it doesn't really matter. // Instead, we'll check this when we're actually revoking the cookie! - session, err := s.r.ConsentManager().GetRememberedLoginSession(r.Context(), hintSid) + session, err := s.r.ConsentManager().GetRememberedLoginSession(r.Context(), nil, hintSid) if errors.Is(err, x.ErrNotFound) { // Such a session does not exist - maybe it has already been revoked? In any case, we can't do much except // leaning back and redirecting back. @@ -888,7 +980,7 @@ func (s *DefaultStrategy) issueLogoutVerifier(ctx context.Context, w http.Respon } challenge := uuid.New() - if err := s.r.ConsentManager().CreateLogoutRequest(r.Context(), &LogoutRequest{ + if err := s.r.ConsentManager().CreateLogoutRequest(r.Context(), &flow.LogoutRequest{ RequestURL: r.URL.String(), ID: challenge, SessionID: hintSid, @@ -907,7 +999,33 @@ func (s *DefaultStrategy) issueLogoutVerifier(ctx context.Context, w http.Respon return nil, errorsx.WithStack(ErrAbortOAuth2Request) } -func (s *DefaultStrategy) completeLogout(ctx context.Context, w http.ResponseWriter, r *http.Request) (*LogoutResult, error) { +func (s *DefaultStrategy) performBackChannelLogoutAndDeleteSession(r *http.Request, subject string, sid string) error { + ctx := r.Context() + if err := s.executeBackChannelLogout(r, subject, sid); err != nil { + return err + } + + // We delete the session after back channel log out has worked as the session is otherwise removed + // from the store which will break the query for finding all the channels. + // + // executeBackChannelLogout only fails on system errors so not on URL errors, so this should be fine + // even if an upstream URL fails! + if session, err := s.r.ConsentManager().DeleteLoginSession(ctx, sid); errors.Is(err, sqlcon.ErrNoRows) { + // This is ok (session probably already revoked), do nothing! + } else if err != nil { + return err + } else { + innerErr := s.r.Kratos().DisableSession(ctx, session.IdentityProviderSessionID.String()) + if innerErr != nil { + s.r.Logger().WithError(innerErr).WithField("sid", sid).Error("Unable to revoke session in ORY Kratos.") + } + // We don't return the error here because we don't want to break the logout flow if Kratos is down. + } + + return nil +} + +func (s *DefaultStrategy) completeLogout(ctx context.Context, w http.ResponseWriter, r *http.Request) (*flow.LogoutResult, error) { verifier := r.URL.Query().Get("logout_verifier") lr, err := s.r.ConsentManager().VerifyAndInvalidateLogoutRequest(r.Context(), verifier) @@ -956,18 +1074,7 @@ func (s *DefaultStrategy) completeLogout(ctx context.Context, w http.ResponseWri return nil, err } - if err := s.executeBackChannelLogout(r.Context(), r, lr.Subject, lr.SessionID); err != nil { - return nil, err - } - - // We delete the session after back channel log out has worked as the session is otherwise removed - // from the store which will break the query for finding all the channels. - // - // executeBackChannelLogout only fails on system errors so not on URL errors, so this should be fine - // even if an upstream URL fails! - if err := s.r.ConsentManager().DeleteLoginSession(r.Context(), lr.SessionID); errors.Is(err, sqlcon.ErrNoRows) { - // This is ok (session probably already revoked), do nothing! - } else if err != nil { + if err := s.performBackChannelLogoutAndDeleteSession(r, lr.Subject, lr.SessionID); err != nil { return nil, err } @@ -976,13 +1083,13 @@ func (s *DefaultStrategy) completeLogout(ctx context.Context, w http.ResponseWri WithField("subject", lr.Subject). Info("User logout completed!") - return &LogoutResult{ + return &flow.LogoutResult{ RedirectTo: lr.PostLogoutRedirectURI, FrontChannelLogoutURLs: urls, }, nil } -func (s *DefaultStrategy) HandleOpenIDConnectLogout(ctx context.Context, w http.ResponseWriter, r *http.Request) (*LogoutResult, error) { +func (s *DefaultStrategy) HandleOpenIDConnectLogout(ctx context.Context, w http.ResponseWriter, r *http.Request) (*flow.LogoutResult, error) { verifier := r.URL.Query().Get("logout_verifier") if verifier == "" { return s.issueLogoutVerifier(ctx, w, r) @@ -991,28 +1098,61 @@ func (s *DefaultStrategy) HandleOpenIDConnectLogout(ctx context.Context, w http. return s.completeLogout(ctx, w, r) } -func (s *DefaultStrategy) HandleOAuth2AuthorizationRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, req fosite.AuthorizeRequester) (*AcceptOAuth2ConsentRequest, error) { - authenticationVerifier := strings.TrimSpace(req.GetRequestForm().Get("login_verifier")) +func (s *DefaultStrategy) HandleHeadlessLogout(ctx context.Context, _ http.ResponseWriter, r *http.Request, sid string) error { + loginSession, lsErr := s.r.ConsentManager().GetRememberedLoginSession(ctx, nil, sid) + + if errors.Is(lsErr, x.ErrNotFound) { + // This is ok (session probably already revoked), do nothing! + // Not triggering the back-channel logout because subject is not available + // See https://github.com/ory/hydra/pull/3450#discussion_r1127798485 + return nil + } else if lsErr != nil { + return lsErr + } + + if err := s.performBackChannelLogoutAndDeleteSession(r, loginSession.Subject, sid); err != nil { + return err + } + + s.r.AuditLogger(). + WithRequest(r). + WithField("subject", loginSession.Subject). + WithField("sid", sid). + Info("User logout completed via headless flow!") + + return nil +} + +func (s *DefaultStrategy) HandleOAuth2AuthorizationRequest( + ctx context.Context, + w http.ResponseWriter, + r *http.Request, + req fosite.AuthorizeRequester, +) (_ *flow.AcceptOAuth2ConsentRequest, _ *flow.Flow, err error) { + ctx, span := trace.SpanFromContext(ctx).TracerProvider().Tracer("").Start(ctx, "DefaultStrategy.HandleOAuth2AuthorizationRequest") + defer otelx.End(span, &err) + + loginVerifier := strings.TrimSpace(req.GetRequestForm().Get("login_verifier")) consentVerifier := strings.TrimSpace(req.GetRequestForm().Get("consent_verifier")) - if authenticationVerifier == "" && consentVerifier == "" { + if loginVerifier == "" && consentVerifier == "" { // ok, we need to process this request and redirect to auth endpoint - return nil, s.requestAuthentication(ctx, w, r, req) - } else if authenticationVerifier != "" { - authSession, err := s.verifyAuthentication(w, r, req, authenticationVerifier) + return nil, nil, s.requestAuthentication(ctx, w, r, req) + } else if loginVerifier != "" { + f, err := s.verifyAuthentication(ctx, w, r, req, loginVerifier) if err != nil { - return nil, err + return nil, nil, err } // ok, we need to process this request and redirect to auth endpoint - return nil, s.requestConsent(ctx, w, r, req, authSession) + return nil, f, s.requestConsent(ctx, w, r, req, f) } - consentSession, err := s.verifyConsent(ctx, w, r, req, consentVerifier) + consentSession, f, err := s.verifyConsent(ctx, w, r, consentVerifier) if err != nil { - return nil, err + return nil, nil, err } - return consentSession, nil + return consentSession, f, nil } func (s *DefaultStrategy) ObfuscateSubjectIdentifier(ctx context.Context, cl fosite.Client, subject, forcedIdentifier string) (string, error) { diff --git a/consent/strategy_default_test.go b/consent/strategy_default_test.go index 18475064b3d..e1746d4bf0c 100644 --- a/consent/strategy_default_test.go +++ b/consent/strategy_default_test.go @@ -8,36 +8,30 @@ import ( "net/http" "net/http/cookiejar" "net/http/httptest" - "testing" - - hydra "github.com/ory/hydra-client-go/v2" - - "github.com/stretchr/testify/require" - - jwtgo "github.com/ory/fosite/token/jwt" - - "github.com/ory/fosite/token/jwt" - "github.com/ory/x/urlx" - "net/url" + "testing" "github.com/google/uuid" + "github.com/stretchr/testify/require" "github.com/tidwall/gjson" - "github.com/ory/hydra/client" - . "github.com/ory/hydra/consent" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/internal/testhelpers" + "github.com/ory/fosite/token/jwt" + hydra "github.com/ory/hydra-client-go/v2" + "github.com/ory/hydra/v2/client" + . "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/internal/testhelpers" "github.com/ory/x/ioutilx" + "github.com/ory/x/urlx" ) func checkAndAcceptLoginHandler(t *testing.T, apiClient *hydra.APIClient, subject string, cb func(*testing.T, *hydra.OAuth2LoginRequest, error) hydra.AcceptOAuth2LoginRequest) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - res, _, err := apiClient.OAuth2Api.GetOAuth2LoginRequest(context.Background()).LoginChallenge(r.URL.Query().Get("login_challenge")).Execute() + res, _, err := apiClient.OAuth2API.GetOAuth2LoginRequest(context.Background()).LoginChallenge(r.URL.Query().Get("login_challenge")).Execute() payload := cb(t, res, err) payload.Subject = subject - v, _, err := apiClient.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()). + v, _, err := apiClient.OAuth2API.AcceptOAuth2LoginRequest(context.Background()). LoginChallenge(r.URL.Query().Get("login_challenge")). AcceptOAuth2LoginRequest(payload). Execute() @@ -49,10 +43,10 @@ func checkAndAcceptLoginHandler(t *testing.T, apiClient *hydra.APIClient, subjec func checkAndAcceptConsentHandler(t *testing.T, apiClient *hydra.APIClient, cb func(*testing.T, *hydra.OAuth2ConsentRequest, error) hydra.AcceptOAuth2ConsentRequest) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - res, _, err := apiClient.OAuth2Api.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() + res, _, err := apiClient.OAuth2API.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() payload := cb(t, res, err) - v, _, err := apiClient.OAuth2Api.AcceptOAuth2ConsentRequest(context.Background()). + v, _, err := apiClient.OAuth2API.AcceptOAuth2ConsentRequest(context.Background()). ConsentChallenge(r.URL.Query().Get("consent_challenge")). AcceptOAuth2ConsentRequest(payload). Execute() @@ -82,7 +76,7 @@ func createClient(t *testing.T, reg driver.Registry, c *client.Client) *client.C secret := uuid.New().String() c.Secret = secret c.Scope = "openid offline" - c.LegacyClientID = uuid.New().String() + c.ID = uuid.New().String() require.NoError(t, reg.ClientManager().CreateClient(context.Background(), c)) c.Secret = secret return c @@ -108,7 +102,7 @@ func newAuthCookieJar(t *testing.T, reg driver.Registry, u, sessionID string) ht return cj } -func genIDToken(t *testing.T, reg driver.Registry, c jwtgo.MapClaims) string { +func genIDToken(t *testing.T, reg driver.Registry, c jwt.MapClaims) string { r, _, err := reg.OpenIDJWTStrategy().Generate(context.Background(), c, jwt.NewHeaders()) require.NoError(t, err) return r @@ -116,18 +110,18 @@ func genIDToken(t *testing.T, reg driver.Registry, c jwtgo.MapClaims) string { func checkAndDuplicateAcceptLoginHandler(t *testing.T, apiClient *hydra.APIClient, subject string, cb func(*testing.T, *hydra.OAuth2LoginRequest, error) hydra.AcceptOAuth2LoginRequest) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - res, _, err := apiClient.OAuth2Api.GetOAuth2LoginRequest(context.Background()).LoginChallenge(r.URL.Query().Get("login_challenge")).Execute() + res, _, err := apiClient.OAuth2API.GetOAuth2LoginRequest(context.Background()).LoginChallenge(r.URL.Query().Get("login_challenge")).Execute() payload := cb(t, res, err) payload.Subject = subject - v, _, err := apiClient.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()). + v, _, err := apiClient.OAuth2API.AcceptOAuth2LoginRequest(context.Background()). LoginChallenge(r.URL.Query().Get("login_challenge")). AcceptOAuth2LoginRequest(payload). Execute() require.NoError(t, err) require.NotEmpty(t, v.RedirectTo) - v2, _, err := apiClient.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()). + v2, _, err := apiClient.OAuth2API.AcceptOAuth2LoginRequest(context.Background()). LoginChallenge(r.URL.Query().Get("login_challenge")). AcceptOAuth2LoginRequest(payload). Execute() @@ -139,22 +133,22 @@ func checkAndDuplicateAcceptLoginHandler(t *testing.T, apiClient *hydra.APIClien func checkAndDuplicateAcceptConsentHandler(t *testing.T, apiClient *hydra.APIClient, cb func(*testing.T, *hydra.OAuth2ConsentRequest, error) hydra.AcceptOAuth2ConsentRequest) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - res, _, err := apiClient.OAuth2Api.GetOAuth2ConsentRequest(context.Background()). + res, _, err := apiClient.OAuth2API.GetOAuth2ConsentRequest(context.Background()). ConsentChallenge(r.URL.Query().Get("consent_challenge")). Execute() payload := cb(t, res, err) - v, _, err := apiClient.OAuth2Api.AcceptOAuth2ConsentRequest(context.Background()). + v, _, err := apiClient.OAuth2API.AcceptOAuth2ConsentRequest(context.Background()). ConsentChallenge(r.URL.Query().Get("consent_challenge")). AcceptOAuth2ConsentRequest(payload). Execute() require.NoError(t, err) require.NotEmpty(t, v.RedirectTo) - res2, _, err := apiClient.OAuth2Api.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() + res2, _, err := apiClient.OAuth2API.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() payload2 := cb(t, res2, err) - v2, _, err := apiClient.OAuth2Api.AcceptOAuth2ConsentRequest(context.Background()). + v2, _, err := apiClient.OAuth2API.AcceptOAuth2ConsentRequest(context.Background()). ConsentChallenge(r.URL.Query().Get("consent_challenge")). AcceptOAuth2ConsentRequest(payload2). Execute() diff --git a/consent/strategy_logout_test.go b/consent/strategy_logout_test.go index fb98b4727aa..6432a3e13a0 100644 --- a/consent/strategy_logout_test.go +++ b/consent/strategy_logout_test.go @@ -16,6 +16,7 @@ import ( "testing" "time" + "github.com/ory/hydra/v2/internal/kratos" "github.com/ory/x/pointerx" "github.com/stretchr/testify/assert" @@ -25,20 +26,23 @@ import ( jwtgo "github.com/ory/fosite/token/jwt" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/client" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/internal/testhelpers" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/internal/testhelpers" "github.com/ory/x/contextx" "github.com/ory/x/ioutilx" ) func TestLogoutFlows(t *testing.T) { ctx := context.Background() + fakeKratos := kratos.NewFake() reg := internal.NewMockedRegistry(t, &contextx.Default{}) reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") reg.Config().MustSet(ctx, config.KeyConsentRequestMaxAge, time.Hour) + reg.WithKratos(fakeKratos) + defaultRedirectedMessage := "redirected to default server" postLogoutCallback := func(w http.ResponseWriter, r *http.Request) { _ = r.ParseForm() @@ -99,6 +103,29 @@ func TestLogoutFlows(t *testing.T) { return string(ioutilx.MustReadAll(resp.Body)), resp } + makeHeadlessLogoutRequest := func(t *testing.T, hc *http.Client, values url.Values) (body string, resp *http.Response) { + var err error + req, err := http.NewRequest(http.MethodDelete, adminTS.URL+"/admin/oauth2/auth/sessions/login?"+values.Encode(), nil) + require.NoError(t, err) + + resp, err = hc.Do(req) + + require.NoError(t, err) + defer resp.Body.Close() + return string(ioutilx.MustReadAll(resp.Body)), resp + } + + logoutViaHeadlessAndExpectNoContent := func(t *testing.T, browser *http.Client, values url.Values) { + _, res := makeHeadlessLogoutRequest(t, browser, values) + assert.EqualValues(t, http.StatusNoContent, res.StatusCode) + } + + logoutViaHeadlessAndExpectError := func(t *testing.T, browser *http.Client, values url.Values, expectedErrorMessage string) { + body, res := makeHeadlessLogoutRequest(t, browser, values) + assert.EqualValues(t, http.StatusBadRequest, res.StatusCode) + assert.Contains(t, body, expectedErrorMessage) + } + logoutAndExpectErrorPage := func(t *testing.T, browser *http.Client, method string, values url.Values, expectedErrorMessage string) { body, res := makeLogoutRequest(t, browser, method, values) assert.EqualValues(t, http.StatusInternalServerError, res.StatusCode) @@ -131,18 +158,20 @@ func TestLogoutFlows(t *testing.T) { return &wg } - checkAndAcceptLogout := func(t *testing.T, wg *sync.WaitGroup, cb func(*testing.T, *hydra.OAuth2LogoutRequest, error)) { + setupCheckAndAcceptLogoutHandler := func(t *testing.T, wg *sync.WaitGroup, cb func(*testing.T, *hydra.OAuth2LogoutRequest, error)) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if wg != nil { defer wg.Done() } - res, _, err := adminApi.OAuth2Api.GetOAuth2LogoutRequest(ctx).LogoutChallenge(r.URL.Query().Get("logout_challenge")).Execute() + res, _, err := adminApi.OAuth2API.GetOAuth2LogoutRequest(ctx).LogoutChallenge(r.URL.Query().Get("logout_challenge")).Execute() if cb != nil { cb(t, res, err) + } else { + require.NoError(t, err) } - v, _, err := adminApi.OAuth2Api.AcceptOAuth2LogoutRequest(ctx).LogoutChallenge(r.URL.Query().Get("logout_challenge")).Execute() + v, _, err := adminApi.OAuth2API.AcceptOAuth2LogoutRequest(ctx).LogoutChallenge(r.URL.Query().Get("logout_challenge")).Execute() require.NoError(t, err) require.NotEmpty(t, v.RedirectTo) http.Redirect(w, r, v.RedirectTo, http.StatusFound) @@ -153,27 +182,36 @@ func TestLogoutFlows(t *testing.T) { reg.Config().MustSet(ctx, config.KeyLogoutURL, server.URL) } - acceptLoginAsAndWatchSid := func(t *testing.T, subject string, sid chan string) { + acceptLoginAsAndWatchSidForConsumers := func(t *testing.T, subject string, sid chan string, remember bool, numSidConsumers int) { testhelpers.NewLoginConsentUI(t, reg.Config(), checkAndAcceptLoginHandler(t, adminApi, subject, func(t *testing.T, res *hydra.OAuth2LoginRequest, err error) hydra.AcceptOAuth2LoginRequest { require.NoError(t, err) //res.Payload.SessionID - return hydra.AcceptOAuth2LoginRequest{Remember: pointerx.Bool(true)} + return hydra.AcceptOAuth2LoginRequest{ + Remember: pointerx.Ptr(true), + IdentityProviderSessionId: pointerx.Ptr(kratos.FakeSessionID), + } }), checkAndAcceptConsentHandler(t, adminApi, func(t *testing.T, res *hydra.OAuth2ConsentRequest, err error) hydra.AcceptOAuth2ConsentRequest { require.NoError(t, err) if sid != nil { go func() { - sid <- *res.LoginSessionId + for i := 0; i < numSidConsumers; i++ { + sid <- *res.LoginSessionId + } }() } - return hydra.AcceptOAuth2ConsentRequest{Remember: pointerx.Bool(true)} + return hydra.AcceptOAuth2ConsentRequest{Remember: pointerx.Bool(remember)} })) } + acceptLoginAsAndWatchSid := func(t *testing.T, subject string, sid chan string) { + acceptLoginAsAndWatchSidForConsumers(t, subject, sid, true, 1) + } + acceptLoginAs := func(t *testing.T, subject string) { - acceptLoginAsAndWatchSid(t, subject, nil) + acceptLoginAsAndWatchSidForConsumers(t, subject, nil, true, 0) } subject := "aeneas-rekkas" @@ -207,7 +245,7 @@ func TestLogoutFlows(t *testing.T) { acceptLoginAs(t, subject) wg := newWg(2) - checkAndAcceptLogout(t, wg, func(t *testing.T, res *hydra.OAuth2LogoutRequest, err error) { + setupCheckAndAcceptLogoutHandler(t, wg, func(t *testing.T, res *hydra.OAuth2LogoutRequest, err error) { require.NoError(t, err) assert.EqualValues(t, subject, *res.Subject) assert.NotEmpty(t, subject, res.Sid) @@ -227,7 +265,7 @@ func TestLogoutFlows(t *testing.T) { // run once to invalidate session wg := newWg(1) - checkAndAcceptLogout(t, wg, nil) + setupCheckAndAcceptLogoutHandler(t, wg, nil) logoutAndExpectPostLogoutPage(t, browser, http.MethodGet, url.Values{}, defaultRedirectedMessage) t.Run("method=get", testExpectPostLogoutPage(browser, http.MethodGet, url.Values{}, defaultRedirectedMessage)) @@ -236,12 +274,59 @@ func TestLogoutFlows(t *testing.T) { wg.Wait() // we want to ensure that logout ui was called exactly once }) + t.Run("case=should handle double-submit of the logout challenge gracefully", func(t *testing.T) { + acceptLoginAs(t, subject) + browser := createBrowserWithSession(t, createSampleClient(t)) + + var logoutReq *hydra.OAuth2LogoutRequest + setupCheckAndAcceptLogoutHandler(t, nil, func(t *testing.T, req *hydra.OAuth2LogoutRequest, err error) { + require.NoError(t, err) + logoutReq = req + }) + + // run once to log out + logoutAndExpectPostLogoutPage(t, browser, http.MethodGet, url.Values{}, defaultRedirectedMessage) + + // run again to ensure that the logout challenge is invalid + _, _, err := adminApi.OAuth2API.GetOAuth2LogoutRequest(ctx).LogoutChallenge(logoutReq.GetChallenge()).Execute() + assert.Error(t, err) + + v, _, err := adminApi.OAuth2API.AcceptOAuth2LogoutRequest(ctx).LogoutChallenge(logoutReq.GetChallenge()).Execute() + require.NoError(t, err) + require.NotEmpty(t, v.RedirectTo) + + res, err := browser.Get(v.RedirectTo) + require.NoError(t, err) + assert.Equal(t, 200, res.StatusCode) + }) + + t.Run("case=should handle an invalid logout challenge", func(t *testing.T) { + _, res, err := adminApi.OAuth2API.GetOAuth2LogoutRequest(ctx).LogoutChallenge("some-invalid-challenge").Execute() + assert.Error(t, err) + assert.Equal(t, http.StatusNotFound, res.StatusCode) + + _, res, err = adminApi.OAuth2API.AcceptOAuth2LogoutRequest(ctx).LogoutChallenge("some-invalid-challenge").Execute() + assert.Error(t, err) + assert.Equal(t, http.StatusNotFound, res.StatusCode) + + res, err = adminApi.OAuth2API.RejectOAuth2LogoutRequest(ctx).LogoutChallenge("some-invalid-challenge").Execute() + assert.Error(t, err) + assert.Equal(t, http.StatusNotFound, res.StatusCode) + }) + + t.Run("case=should handle an invalid logout verifier", func(t *testing.T) { + setupCheckAndAcceptLogoutHandler(t, nil, nil) + logoutAndExpectErrorPage(t, http.DefaultClient, http.MethodGet, url.Values{ + "logout_verifier": {"an-invalid-verifier"}, + }, "Description: Unable to locate the requested resource") + }) + t.Run("case=should execute backchannel logout if issued without rp-involvement", func(t *testing.T) { sid := make(chan string) acceptLoginAsAndWatchSid(t, subject, sid) logoutWg := newWg(2) - checkAndAcceptLogout(t, logoutWg, nil) + setupCheckAndAcceptLogoutHandler(t, logoutWg, nil) backChannelWG := newWg(2) c := createClientWithBackchannelLogout(t, backChannelWG, func(t *testing.T, logoutToken gjson.Result) { @@ -263,7 +348,7 @@ func TestLogoutFlows(t *testing.T) { t.Run("case=should fail several flows when id_token_hint is invalid", func(t *testing.T) { t.Run("case=should error when rp-flow without valid id token", func(t *testing.T) { acceptLoginAs(t, "aeneas-rekkas") - checkAndAcceptLogout(t, nil, nil) + setupCheckAndAcceptLogoutHandler(t, nil, nil) expectedMessage := "compact JWS format must have three parts" browser := createBrowserWithSession(t, createSampleClient(t)) @@ -309,7 +394,7 @@ func TestLogoutFlows(t *testing.T) { browser := createBrowserWithSession(t, c) wg := newWg(1) - checkAndAcceptLogout(t, wg, nil) + setupCheckAndAcceptLogoutHandler(t, wg, nil) tc.claims["sub"] = subject tc.claims["sid"] = <-sid tc.claims["aud"] = c.GetID() @@ -354,7 +439,7 @@ func TestLogoutFlows(t *testing.T) { sid := make(chan string) acceptLoginAsAndWatchSid(t, subject, sid) - checkAndAcceptLogout(t, nil, nil) + setupCheckAndAcceptLogoutHandler(t, nil, nil) browser := createBrowserWithSession(t, c) sendClaims := jwtgo.MapClaims{ @@ -399,9 +484,9 @@ func TestLogoutFlows(t *testing.T) { t.Run("case=should pass rp-inititated flow without any action because SID is unknown", func(t *testing.T) { c := createSampleClient(t) - acceptLoginAsAndWatchSid(t, subject, nil) + acceptLoginAs(t, subject) - checkAndAcceptLogout(t, nil, func(t *testing.T, res *hydra.OAuth2LogoutRequest, err error) { + setupCheckAndAcceptLogoutHandler(t, nil, func(t *testing.T, res *hydra.OAuth2LogoutRequest, err error) { t.Fatalf("Logout should not have been called") }) browser := createBrowserWithSession(t, c) @@ -425,7 +510,7 @@ func TestLogoutFlows(t *testing.T) { sid := make(chan string) acceptLoginAsAndWatchSid(t, subject, sid) - checkAndAcceptLogout(t, nil, nil) + setupCheckAndAcceptLogoutHandler(t, nil, nil) browser := createBrowserWithSession(t, c) body, res := makeLogoutRequest(t, browser, "GET", url.Values{ @@ -447,12 +532,13 @@ func TestLogoutFlows(t *testing.T) { }) t.Run("case=should return to default post logout because session was revoked in browser context", func(t *testing.T) { + fakeKratos.Reset() c := createSampleClient(t) sid := make(chan string) acceptLoginAsAndWatchSid(t, subject, sid) wg := newWg(2) - checkAndAcceptLogout(t, wg, nil) + setupCheckAndAcceptLogoutHandler(t, wg, nil) browser := createBrowserWithSession(t, c) // Use another browser (without session cookie) to make the logout request: @@ -476,11 +562,11 @@ func TestLogoutFlows(t *testing.T) { defer wg.Done() require.NoError(t, err) assert.False(t, res.Skip) - return hydra.AcceptOAuth2LoginRequest{Remember: pointerx.Bool(true)} + return hydra.AcceptOAuth2LoginRequest{Remember: pointerx.Ptr(true)} }), checkAndAcceptConsentHandler(t, adminApi, func(t *testing.T, res *hydra.OAuth2ConsentRequest, err error) hydra.AcceptOAuth2ConsentRequest { require.NoError(t, err) - return hydra.AcceptOAuth2ConsentRequest{Remember: pointerx.Bool(true)} + return hydra.AcceptOAuth2ConsentRequest{Remember: pointerx.Ptr(true)} })) // Make an oauth 2 request to trigger the login check. @@ -489,5 +575,52 @@ func TestLogoutFlows(t *testing.T) { assert.NotEmpty(t, res.Request.URL.Query().Get("code")) wg.Wait() + + assert.True(t, fakeKratos.DisableSessionWasCalled) + assert.Equal(t, fakeKratos.LastDisabledSession, kratos.FakeSessionID) + }) + + t.Run("case=should execute backchannel logout in headless flow with sid", func(t *testing.T) { + fakeKratos.Reset() + numSidConsumers := 2 + sid := make(chan string, numSidConsumers) + acceptLoginAsAndWatchSidForConsumers(t, subject, sid, true, numSidConsumers) + + backChannelWG := newWg(1) + c := createClientWithBackchannelLogout(t, backChannelWG, func(t *testing.T, logoutToken gjson.Result) { + assert.EqualValues(t, <-sid, logoutToken.Get("sid").String(), logoutToken.Raw) + assert.Empty(t, logoutToken.Get("sub").String(), logoutToken.Raw) // The sub claim should be empty because it doesn't work with forced obfuscation and thus we can't easily recover it. + assert.Empty(t, logoutToken.Get("nonce").String(), logoutToken.Raw) + }) + + logoutViaHeadlessAndExpectNoContent(t, createBrowserWithSession(t, c), url.Values{"sid": {<-sid}}) + + backChannelWG.Wait() // we want to ensure that all back channels have been called! + assert.True(t, fakeKratos.DisableSessionWasCalled) + assert.Equal(t, fakeKratos.LastDisabledSession, kratos.FakeSessionID) + }) + + t.Run("case=should logout in headless flow with non-existing sid", func(t *testing.T) { + fakeKratos.Reset() + logoutViaHeadlessAndExpectNoContent(t, browserWithoutSession, url.Values{"sid": {"non-existing-sid"}}) + assert.False(t, fakeKratos.DisableSessionWasCalled) + }) + + t.Run("case=should logout in headless flow with session that has remember=false", func(t *testing.T) { + fakeKratos.Reset() + sid := make(chan string) + acceptLoginAsAndWatchSidForConsumers(t, subject, sid, false, 1) + + c := createSampleClient(t) + + logoutViaHeadlessAndExpectNoContent(t, createBrowserWithSession(t, c), url.Values{"sid": {<-sid}}) + assert.True(t, fakeKratos.DisableSessionWasCalled) + assert.Equal(t, fakeKratos.LastDisabledSession, kratos.FakeSessionID) + }) + + t.Run("case=should fail headless logout because neither sid nor subject were provided", func(t *testing.T) { + fakeKratos.Reset() + logoutViaHeadlessAndExpectError(t, browserWithoutSession, url.Values{}, `Either 'subject' or 'sid' query parameters need to be defined.`) + assert.False(t, fakeKratos.DisableSessionWasCalled) }) } diff --git a/consent/strategy_oauth_test.go b/consent/strategy_oauth_test.go index e032e2e451c..370a3378074 100644 --- a/consent/strategy_oauth_test.go +++ b/consent/strategy_oauth_test.go @@ -10,14 +10,13 @@ import ( "encoding/json" "fmt" "net/http" + "net/http/cookiejar" "net/url" + "regexp" "testing" "time" - "github.com/ory/x/ioutilx" - - "github.com/twmb/murmur3" - + "golang.org/x/exp/slices" "golang.org/x/oauth2" "github.com/ory/x/pointerx" @@ -28,7 +27,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/ory/hydra/internal/testhelpers" + "github.com/ory/hydra/v2/internal/testhelpers" "github.com/ory/x/contextx" "github.com/ory/fosite" @@ -36,9 +35,9 @@ import ( "github.com/ory/x/uuidx" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/client" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" ) func TestStrategyLoginConsentNext(t *testing.T) { @@ -113,8 +112,12 @@ func TestStrategyLoginConsentNext(t *testing.T) { t.Run("case=should fail because a login verifier was given that doesn't exist in the store", func(t *testing.T) { testhelpers.NewLoginConsentUI(t, reg.Config(), testhelpers.HTTPServerNoExpectedCallHandler(t), testhelpers.HTTPServerNoExpectedCallHandler(t)) c := createDefaultClient(t) + hc := testhelpers.NewEmptyJarClient(t) - makeRequestAndExpectError(t, nil, c, url.Values{"login_verifier": {"does-not-exist"}}, "The login verifier has already been used, has not been granted, or is invalid.") + makeRequestAndExpectError( + t, hc, c, url.Values{"login_verifier": {"does-not-exist"}}, + "The resource owner or authorization server denied the request. The login verifier is invalid", + ) }) t.Run("case=should fail because a non-existing consent verifier was given", func(t *testing.T) { @@ -123,7 +126,12 @@ func TestStrategyLoginConsentNext(t *testing.T) { // - This should fail because a consent verifier was given but no login verifier testhelpers.NewLoginConsentUI(t, reg.Config(), testhelpers.HTTPServerNoExpectedCallHandler(t), testhelpers.HTTPServerNoExpectedCallHandler(t)) c := createDefaultClient(t) - makeRequestAndExpectError(t, nil, c, url.Values{"consent_verifier": {"does-not-exist"}}, "The consent verifier has already been used, has not been granted, or is invalid.") + hc := testhelpers.NewEmptyJarClient(t) + + makeRequestAndExpectError( + t, hc, c, url.Values{"consent_verifier": {"does-not-exist"}}, + "The consent verifier has already been used, has not been granted, or is invalid.", + ) }) t.Run("case=should fail because the request was redirected but the login endpoint doesn't do anything (like redirecting back)", func(t *testing.T) { @@ -147,7 +155,7 @@ func TestStrategyLoginConsentNext(t *testing.T) { t.Run("case=should fail because the request was redirected but the login endpoint rejected the request", func(t *testing.T) { testhelpers.NewLoginConsentUI(t, reg.Config(), func(w http.ResponseWriter, r *http.Request) { - vr, _, err := adminClient.OAuth2Api.RejectOAuth2LoginRequest(context.Background()). + vr, _, err := adminClient.OAuth2API.RejectOAuth2LoginRequest(context.Background()). LoginChallenge(r.URL.Query().Get("login_challenge")). RejectOAuth2Request(hydra.RejectOAuth2Request{ Error: pointerx.String(fosite.ErrInteractionRequired.ErrorField), @@ -169,6 +177,7 @@ func TestStrategyLoginConsentNext(t *testing.T) { testhelpers.HTTPServerNoExpectedCallHandler(t)) hc := new(http.Client) + hc.Jar = DropCookieJar(regexp.MustCompile("ory_hydra_.*_csrf_.*")) makeRequestAndExpectError(t, hc, c, url.Values{}, "No CSRF value available in the session cookie.") }) @@ -177,7 +186,7 @@ func TestStrategyLoginConsentNext(t *testing.T) { testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, "aeneas-rekkas", nil), func(w http.ResponseWriter, r *http.Request) { - vr, _, err := adminClient.OAuth2Api.RejectOAuth2ConsentRequest(context.Background()). + vr, _, err := adminClient.OAuth2API.RejectOAuth2ConsentRequest(context.Background()). ConsentChallenge(r.URL.Query().Get("consent_challenge")). RejectOAuth2Request(hydra.RejectOAuth2Request{ Error: pointerx.String(fosite.ErrInteractionRequired.ErrorField), @@ -191,6 +200,76 @@ func TestStrategyLoginConsentNext(t *testing.T) { makeRequestAndExpectError(t, nil, c, url.Values{}, "expect-reject-consent") }) + t.Run("suite=double-submit", func(t *testing.T) { + ctx := context.Background() + c := createDefaultClient(t) + hc := testhelpers.NewEmptyJarClient(t) + var loginChallenge, consentChallenge string + + testhelpers.NewLoginConsentUI(t, reg.Config(), + func(w http.ResponseWriter, r *http.Request) { + res, _, err := adminClient.OAuth2API.GetOAuth2LoginRequest(ctx). + LoginChallenge(r.URL.Query().Get("login_challenge")). + Execute() + require.NoError(t, err) + loginChallenge = res.Challenge + + v, _, err := adminClient.OAuth2API.AcceptOAuth2LoginRequest(ctx). + LoginChallenge(loginChallenge). + AcceptOAuth2LoginRequest(hydra.AcceptOAuth2LoginRequest{Subject: "aeneas-rekkas"}). + Execute() + require.NoError(t, err) + require.NotEmpty(t, v.RedirectTo) + http.Redirect(w, r, v.RedirectTo, http.StatusFound) + }, + func(w http.ResponseWriter, r *http.Request) { + res, _, err := adminClient.OAuth2API.GetOAuth2ConsentRequest(ctx). + ConsentChallenge(r.URL.Query().Get("consent_challenge")). + Execute() + require.NoError(t, err) + consentChallenge = res.Challenge + + v, _, err := adminClient.OAuth2API.AcceptOAuth2ConsentRequest(ctx). + ConsentChallenge(consentChallenge). + AcceptOAuth2ConsentRequest(hydra.AcceptOAuth2ConsentRequest{}). + Execute() + require.NoError(t, err) + require.NotEmpty(t, v.RedirectTo) + http.Redirect(w, r, v.RedirectTo, http.StatusFound) + }) + + makeRequestAndExpectCode(t, hc, c, url.Values{}) + + t.Run("case=double-submit login verifier", func(t *testing.T) { + v, _, err := adminClient.OAuth2API.AcceptOAuth2LoginRequest(ctx). + LoginChallenge(loginChallenge). + AcceptOAuth2LoginRequest(hydra.AcceptOAuth2LoginRequest{Subject: "aeneas-rekkas"}). + Execute() + require.NoError(t, err) + res, err := hc.Get(v.RedirectTo) + require.NoError(t, err) + q := res.Request.URL.Query() + assert.Equal(t, + "The resource owner or authorization server denied the request. The consent verifier has already been used.", + q.Get("error_description"), q) + }) + + t.Run("case=double-submit consent verifier", func(t *testing.T) { + v, _, err := adminClient.OAuth2API.AcceptOAuth2ConsentRequest(ctx). + ConsentChallenge(consentChallenge). + AcceptOAuth2ConsentRequest(hydra.AcceptOAuth2ConsentRequest{}). + Execute() + require.NoError(t, err) + res, err := hc.Get(v.RedirectTo) + require.NoError(t, err) + q := res.Request.URL.Query() + assert.Equal(t, + "The resource owner or authorization server denied the request. The consent verifier has already been used.", + q.Get("error_description"), q) + }) + + }) + t.Run("case=should pass and set acr values properly", func(t *testing.T) { c := createDefaultClient(t) testhelpers.NewLoginConsentUI(t, reg.Config(), @@ -210,6 +289,7 @@ func TestStrategyLoginConsentNext(t *testing.T) { subject := "aeneas-rekkas" c := createDefaultClient(t) + now := 1723546027 // Unix timestamps must round-trip through Hydra without converting to floats or similar testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, subject, &hydra.AcceptOAuth2LoginRequest{ Remember: pointerx.Bool(true), @@ -218,8 +298,14 @@ func TestStrategyLoginConsentNext(t *testing.T) { Remember: pointerx.Bool(true), GrantScope: []string{"openid"}, Session: &hydra.AcceptOAuth2ConsentRequestSession{ - AccessToken: map[string]interface{}{"foo": "bar"}, - IdToken: map[string]interface{}{"bar": "baz"}, + AccessToken: map[string]interface{}{ + "foo": "bar", + "ts1": now, + }, + IdToken: map[string]interface{}{ + "bar": "baz", + "ts2": now, + }, }, })) @@ -235,12 +321,14 @@ func TestStrategyLoginConsentNext(t *testing.T) { require.NoError(t, err) claims := testhelpers.IntrospectToken(t, conf, token.AccessToken, adminTS) - assert.Equal(t, "bar", claims.Get("ext.foo").String(), "%s", claims.Raw) + assert.Equalf(t, `"bar"`, claims.Get("ext.foo").Raw, "%s", claims.Raw) // Raw rather than .Int() or .Value() to verify the exact JSON payload + assert.Equalf(t, "1723546027", claims.Get("ext.ts1").Raw, "%s", claims.Raw) // must round-trip as integer idClaims := testhelpers.DecodeIDToken(t, token) - assert.Equal(t, "baz", idClaims.Get("bar").String(), "%s", idClaims.Raw) + assert.Equalf(t, `"baz"`, idClaims.Get("bar").Raw, "%s", idClaims.Raw) // Raw rather than .Int() or .Value() to verify the exact JSON payload + assert.Equalf(t, "1723546027", idClaims.Get("ts2").Raw, "%s", idClaims.Raw) // must round-trip as integer sid = idClaims.Get("sid").String() - assert.NotNil(t, sid) + assert.NotEmpty(t, sid) } t.Run("perform first flow", run) @@ -255,21 +343,28 @@ func TestStrategyLoginConsentNext(t *testing.T) { assert.Empty(t, pointerx.StringR(res.Client.ClientSecret)) return hydra.AcceptOAuth2LoginRequest{ Subject: subject, - Context: map[string]interface{}{"foo": "bar"}, + Context: map[string]interface{}{"xyz": "abc"}, } }), - checkAndAcceptConsentHandler(t, adminClient, func(t *testing.T, res *hydra.OAuth2ConsentRequest, err error) hydra.AcceptOAuth2ConsentRequest { + checkAndAcceptConsentHandler(t, adminClient, func(t *testing.T, req *hydra.OAuth2ConsentRequest, err error) hydra.AcceptOAuth2ConsentRequest { require.NoError(t, err) - assert.True(t, *res.Skip) - assert.Equal(t, sid, *res.LoginSessionId) - assert.Equal(t, subject, *res.Subject) - assert.Empty(t, pointerx.StringR(res.Client.ClientSecret)) + assert.True(t, *req.Skip) + assert.Equal(t, sid, *req.LoginSessionId) + assert.Equal(t, subject, *req.Subject) + assert.Empty(t, pointerx.StringR(req.Client.ClientSecret)) + assert.Equal(t, map[string]interface{}{"xyz": "abc"}, req.Context) return hydra.AcceptOAuth2ConsentRequest{ Remember: pointerx.Bool(true), GrantScope: []string{"openid"}, Session: &hydra.AcceptOAuth2ConsentRequestSession{ - AccessToken: map[string]interface{}{"foo": "bar"}, - IdToken: map[string]interface{}{"bar": "baz"}, + AccessToken: map[string]interface{}{ + "foo": "bar", + "ts1": now, + }, + IdToken: map[string]interface{}{ + "bar": "baz", + "ts2": now, + }, }, } })) @@ -332,37 +427,201 @@ func TestStrategyLoginConsentNext(t *testing.T) { loginChallengeRedirect, err := oauthRes.Location() require.NoError(t, err) defer oauthRes.Body.Close() - setCookieHeader := oauthRes.Header.Get("set-cookie") - assert.NotNil(t, setCookieHeader) - - t.Run("login cookie client specific suffix is set", func(t *testing.T) { - assert.Regexp(t, fmt.Sprintf("ory_hydra_login_csrf_dev_%d=.*", murmur3.Sum32(c.ID.Bytes())), setCookieHeader) - }) - t.Run("login cookie max age is set", func(t *testing.T) { - assert.Regexp(t, fmt.Sprintf("ory_hydra_login_csrf_dev_%d=.*Max-Age=%.0f;.*", murmur3.Sum32(c.ID.Bytes()), consentRequestMaxAge), setCookieHeader) + foundLoginCookie := slices.ContainsFunc(oauthRes.Header.Values("set-cookie"), func(sc string) bool { + ok, err := regexp.MatchString(fmt.Sprintf("ory_hydra_login_csrf_dev_%s=.*Max-Age=%.0f;.*", c.CookieSuffix(), consentRequestMaxAge), sc) + require.NoError(t, err) + return ok }) + require.True(t, foundLoginCookie, "client-specific login cookie with max age set") loginChallengeRes, err := hc.Get(loginChallengeRedirect.String()) require.NoError(t, err) defer loginChallengeRes.Body.Close() loginVerifierRedirect, err := loginChallengeRes.Location() + require.NoError(t, err) loginVerifierRes, err := hc.Get(loginVerifierRedirect.String()) require.NoError(t, err) defer loginVerifierRes.Body.Close() - setCookieHeader = loginVerifierRes.Header.Values("set-cookie")[1] - assert.NotNil(t, setCookieHeader) - t.Run("consent cookie client specific suffix set", func(t *testing.T) { - assert.Regexp(t, fmt.Sprintf("ory_hydra_consent_csrf_dev_%d=.*", murmur3.Sum32(c.ID.Bytes())), setCookieHeader) + foundConsentCookie := slices.ContainsFunc(loginVerifierRes.Header.Values("set-cookie"), func(sc string) bool { + ok, err := regexp.MatchString(fmt.Sprintf("ory_hydra_consent_csrf_dev_%s=.*Max-Age=%.0f;.*", c.CookieSuffix(), consentRequestMaxAge), sc) + require.NoError(t, err) + return ok + }) + require.True(t, foundConsentCookie, "client-specific consent cookie with max age set") + }) + + t.Run("case=should pass if both login and consent are granted and check remember flows with refresh session cookie", func(t *testing.T) { + + subject := "subject-1" + c := createDefaultClient(t) + testhelpers.NewLoginConsentUI(t, reg.Config(), + acceptLoginHandler(t, subject, &hydra.AcceptOAuth2LoginRequest{ + Remember: pointerx.Bool(true), + }), + acceptConsentHandler(t, &hydra.AcceptOAuth2ConsentRequest{ + Remember: pointerx.Bool(true), + GrantScope: []string{"openid"}, + Session: &hydra.AcceptOAuth2ConsentRequestSession{ + AccessToken: map[string]interface{}{"foo": "bar"}, + IdToken: map[string]interface{}{"bar": "baz"}, + }, + })) + + hc := testhelpers.NewEmptyJarClient(t) + + followUpHandler := func(extendSessionLifespan bool) { + rememberFor := int64(12345) + testhelpers.NewLoginConsentUI(t, reg.Config(), + checkAndAcceptLoginHandler(t, adminClient, subject, func(t *testing.T, res *hydra.OAuth2LoginRequest, err error) hydra.AcceptOAuth2LoginRequest { + require.NoError(t, err) + assert.True(t, res.Skip) + assert.Equal(t, subject, res.Subject) + assert.Empty(t, res.Client.ClientSecret) + return hydra.AcceptOAuth2LoginRequest{ + Subject: subject, + Remember: pointerx.Bool(true), + RememberFor: pointerx.Int64(rememberFor), + ExtendSessionLifespan: pointerx.Bool(extendSessionLifespan), + Context: map[string]interface{}{"foo": "bar"}, + } + }), + checkAndAcceptConsentHandler(t, adminClient, func(t *testing.T, res *hydra.OAuth2ConsentRequest, err error) hydra.AcceptOAuth2ConsentRequest { + require.NoError(t, err) + assert.True(t, *res.Skip) + assert.Equal(t, subject, res.Subject) + assert.Empty(t, res.Client.ClientSecret) + return hydra.AcceptOAuth2ConsentRequest{ + Remember: pointerx.Bool(true), + GrantScope: []string{"openid"}, + Session: &hydra.AcceptOAuth2ConsentRequestSession{ + AccessToken: map[string]interface{}{"foo": "bar"}, + IdToken: map[string]interface{}{"bar": "baz"}, + }, + } + })) + + hc := &http.Client{ + Jar: hc.Jar, + Transport: &http.Transport{}, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + + _, oauthRes := makeOAuth2Request(t, reg, hc, c, url.Values{"redirect_uri": {c.RedirectURIs[0]}, "scope": {"openid"}}) + assert.EqualValues(t, http.StatusFound, oauthRes.StatusCode) + loginChallengeRedirect, err := oauthRes.Location() + require.NoError(t, err) + defer oauthRes.Body.Close() + + loginChallengeRes, err := hc.Get(loginChallengeRedirect.String()) + require.NoError(t, err) + defer loginChallengeRes.Body.Close() + loginVerifierRedirect, err := loginChallengeRes.Location() + require.NoError(t, err) + + loginVerifierRes, err := hc.Get(loginVerifierRedirect.String()) + require.NoError(t, err) + defer loginVerifierRes.Body.Close() + + setCookieHeader := loginVerifierRes.Header.Get("set-cookie") + assert.NotNil(t, setCookieHeader) + if extendSessionLifespan { + assert.Regexp(t, fmt.Sprintf("ory_hydra_session_dev=.*; Path=/; Expires=.*Max-Age=%d; HttpOnly; SameSite=Lax", rememberFor), setCookieHeader) + } else { + assert.NotContains(t, setCookieHeader, "ory_hydra_session_dev") + } + } + + t.Run("perform first flow", func(t *testing.T) { + makeRequestAndExpectCode(t, hc, c, url.Values{"redirect_uri": {c.RedirectURIs[0]}, + "scope": {"openid"}}) + }) + + t.Run("perform follow up flow with extend_session_lifespan=false", func(t *testing.T) { + followUpHandler(false) }) - t.Run("consent cookie max age is set", func(t *testing.T) { - assert.Regexp(t, fmt.Sprintf("ory_hydra_consent_csrf_dev_%d=.*Max-Age=%.0f;.*", murmur3.Sum32(c.ID.Bytes()), consentRequestMaxAge), setCookieHeader) + t.Run("perform follow up flow with extend_session_lifespan=true", func(t *testing.T) { + followUpHandler(true) }) }) + t.Run("case=should set session cookie with correct configuration", func(t *testing.T) { + cookiePath := "/foo" + reg.Config().MustSet(ctx, config.KeyCookieSessionPath, cookiePath) + defer reg.Config().MustSet(ctx, config.KeyCookieSessionPath, "/") + + subject := "subject-1" + c := createDefaultClient(t) + testhelpers.NewLoginConsentUI(t, reg.Config(), + acceptLoginHandler(t, subject, &hydra.AcceptOAuth2LoginRequest{ + Remember: pointerx.Bool(true), + }), + acceptConsentHandler(t, &hydra.AcceptOAuth2ConsentRequest{ + Remember: pointerx.Bool(true), + GrantScope: []string{"openid"}, + Session: &hydra.AcceptOAuth2ConsentRequestSession{ + AccessToken: map[string]interface{}{"foo": "bar"}, + IdToken: map[string]interface{}{"bar": "baz"}, + }, + })) + testhelpers.NewLoginConsentUI(t, reg.Config(), + checkAndAcceptLoginHandler(t, adminClient, subject, func(t *testing.T, res *hydra.OAuth2LoginRequest, err error) hydra.AcceptOAuth2LoginRequest { + require.NoError(t, err) + assert.Empty(t, res.Subject) + assert.Empty(t, pointerx.StringR(res.Client.ClientSecret)) + return hydra.AcceptOAuth2LoginRequest{ + Subject: subject, + Context: map[string]interface{}{"foo": "bar"}, + } + }), + checkAndAcceptConsentHandler(t, adminClient, func(t *testing.T, res *hydra.OAuth2ConsentRequest, err error) hydra.AcceptOAuth2ConsentRequest { + require.NoError(t, err) + assert.Equal(t, subject, *res.Subject) + assert.Empty(t, pointerx.StringR(res.Client.ClientSecret)) + return hydra.AcceptOAuth2ConsentRequest{ + Remember: pointerx.Bool(true), + GrantScope: []string{"openid"}, + Session: &hydra.AcceptOAuth2ConsentRequestSession{ + AccessToken: map[string]interface{}{"foo": "bar"}, + IdToken: map[string]interface{}{"bar": "baz"}, + }, + } + })) + hc := &http.Client{ + Jar: testhelpers.NewEmptyCookieJar(t), + Transport: &http.Transport{}, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + + _, oauthRes := makeOAuth2Request(t, reg, hc, c, url.Values{"redirect_uri": {c.RedirectURIs[0]}, "scope": {"openid"}}) + assert.EqualValues(t, http.StatusFound, oauthRes.StatusCode) + loginChallengeRedirect, err := oauthRes.Location() + require.NoError(t, err) + defer oauthRes.Body.Close() + + loginChallengeRes, err := hc.Get(loginChallengeRedirect.String()) + require.NoError(t, err) + defer loginChallengeRes.Body.Close() + + loginVerifierRedirect, err := loginChallengeRes.Location() + require.NoError(t, err) + loginVerifierRes, err := hc.Get(loginVerifierRedirect.String()) + require.NoError(t, err) + defer loginVerifierRes.Body.Close() + + setCookieHeader := loginVerifierRes.Header.Get("set-cookie") + assert.NotNil(t, setCookieHeader) + + assert.Regexp(t, fmt.Sprintf("ory_hydra_session_dev=.*; Path=%s; Expires=.*; Max-Age=0; HttpOnly; SameSite=Lax", cookiePath), setCookieHeader) + }) + t.Run("case=should pass and check if login context is set properly", func(t *testing.T) { // This should pass because login was remembered and session id should be set and session context should also work subject := "aeneas-rekkas" @@ -396,7 +655,7 @@ func TestStrategyLoginConsentNext(t *testing.T) { // - This should fail because prompt=none, client is public, and redirection scheme is not HTTPS but a custom scheme // - This should pass because prompt=none, client is public, redirection scheme is HTTP and host is localhost - c := &client.Client{LegacyClientID: uuidx.NewV4().String(), TokenEndpointAuthMethod: "none", + c := &client.Client{ID: uuidx.NewV4().String(), TokenEndpointAuthMethod: "none", RedirectURIs: []string{ testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler), "custom://redirection-scheme/path", @@ -411,9 +670,8 @@ func TestStrategyLoginConsentNext(t *testing.T) { hc := testhelpers.NewEmptyJarClient(t) - t.Run("set up initial session", func(t *testing.T) { - makeRequestAndExpectCode(t, hc, c, url.Values{"redirect_uri": {c.RedirectURIs[0]}}) - }) + // set up initial session + makeRequestAndExpectCode(t, hc, c, url.Values{"redirect_uri": {c.RedirectURIs[0]}}) // By not waiting here we ensure that there are no race conditions when it comes to authenticated_at and // requested_at time comparisons: @@ -457,7 +715,7 @@ func TestStrategyLoginConsentNext(t *testing.T) { }) }) - t.Run("case=should fail at login screen because subject in login challenge does not match subject from previous session", func(t *testing.T) { + t.Run("case=should retry the authorization with prompt=login if subject in login challenge does not match subject from previous session", func(t *testing.T) { // Previously: This should fail at login screen because subject from accept does not match subject from session c := createDefaultClient(t) testhelpers.NewLoginConsentUI(t, reg.Config(), @@ -470,13 +728,15 @@ func TestStrategyLoginConsentNext(t *testing.T) { testhelpers.NewLoginConsentUI(t, reg.Config(), func(w http.ResponseWriter, r *http.Request) { - _, res, err := adminClient.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()). + res, _, err := adminClient.OAuth2API.AcceptOAuth2LoginRequest(context.Background()). LoginChallenge(r.URL.Query().Get("login_challenge")). AcceptOAuth2LoginRequest(hydra.AcceptOAuth2LoginRequest{ Subject: "not-aeneas-rekkas", }).Execute() - require.Error(t, err) - assert.Contains(t, string(ioutilx.MustReadAll(res.Body)), "Field 'subject' does not match subject from previous authentication") + require.NoError(t, err) + redirectURL, err := url.Parse(res.RedirectTo) + require.NoError(t, err) + assert.Equal(t, "login", redirectURL.Query().Get("prompt")) w.WriteHeader(http.StatusBadRequest) }, testhelpers.HTTPServerNoExpectedCallHandler(t)) @@ -563,7 +823,7 @@ func TestStrategyLoginConsentNext(t *testing.T) { makeRequestAndExpectCode(t, hc, c, url.Values{}) // Make request with additional scope and prompt none, which fails - makeRequestAndExpectError(t, hc, c, url.Values{"prompt": {"none"}, "scope": {"openid"}}, + makeRequestAndExpectError(t, hc, c, url.Values{"prompt": {"none"}, "scope": {"openid"}, "redirect_uri": {c.RedirectURIs[0]}}, "Prompt 'none' was requested, but no previous consent was found") }) @@ -670,11 +930,11 @@ func TestStrategyLoginConsentNext(t *testing.T) { }{ { d: "check all the sub claims", - values: url.Values{"scope": {"openid"}}, + values: url.Values{"scope": {"openid"}, "redirect_uri": {c.RedirectURIs[0]}}, }, { d: "works with id_token_hint", - values: url.Values{"scope": {"openid"}, "id_token_hint": {testhelpers.NewIDToken(t, reg, hash)}}, + values: url.Values{"scope": {"openid"}, "redirect_uri": {c.RedirectURIs[0]}, "id_token_hint": {testhelpers.NewIDToken(t, reg, hash)}}, }, } { t.Run("case="+tc.d, func(t *testing.T) { @@ -714,7 +974,7 @@ func TestStrategyLoginConsentNext(t *testing.T) { }), acceptConsentHandler(t, &hydra.AcceptOAuth2ConsentRequest{GrantScope: []string{"openid"}})) - code := makeRequestAndExpectCode(t, nil, c, url.Values{}) + code := makeRequestAndExpectCode(t, nil, c, url.Values{"redirect_uri": {c.RedirectURIs[0]}}) conf := oauth2Config(t, c) token, err := conf.Exchange(context.Background(), code) @@ -848,3 +1108,31 @@ func TestStrategyLoginConsentNext(t *testing.T) { makeRequestAndExpectCode(t, hc, c, url.Values{"redirect_uri": {c.RedirectURIs[0]}}) }) } + +func DropCookieJar(drop *regexp.Regexp) http.CookieJar { + jar, _ := cookiejar.New(nil) + return &dropCSRFCookieJar{ + jar: jar, + drop: drop, + } +} + +type dropCSRFCookieJar struct { + jar *cookiejar.Jar + drop *regexp.Regexp +} + +var _ http.CookieJar = (*dropCSRFCookieJar)(nil) + +func (d *dropCSRFCookieJar) SetCookies(u *url.URL, cookies []*http.Cookie) { + for _, c := range cookies { + if d.drop.MatchString(c.Name) { + continue + } + d.jar.SetCookies(u, []*http.Cookie{c}) + } +} + +func (d *dropCSRFCookieJar) Cookies(u *url.URL) []*http.Cookie { + return d.jar.Cookies(u) +} diff --git a/consent/subject_identifier_algorithm.go b/consent/subject_identifier_algorithm.go index 343ab7d458e..67adaac8891 100644 --- a/consent/subject_identifier_algorithm.go +++ b/consent/subject_identifier_algorithm.go @@ -3,7 +3,7 @@ package consent -import "github.com/ory/hydra/client" +import "github.com/ory/hydra/v2/client" type SubjectIdentifierAlgorithm interface { // Obfuscate derives a pairwise subject identifier from the given string. diff --git a/consent/subject_identifier_algorithm_pairwise.go b/consent/subject_identifier_algorithm_pairwise.go index b27f7690bb2..ff14095652a 100644 --- a/consent/subject_identifier_algorithm_pairwise.go +++ b/consent/subject_identifier_algorithm_pairwise.go @@ -11,7 +11,7 @@ import ( "github.com/ory/x/errorsx" "github.com/ory/fosite" - "github.com/ory/hydra/client" + "github.com/ory/hydra/v2/client" ) type SubjectIdentifierAlgorithmPairwise struct { diff --git a/consent/subject_identifier_algorithm_public.go b/consent/subject_identifier_algorithm_public.go index a73062f3d64..e3e159b5c0f 100644 --- a/consent/subject_identifier_algorithm_public.go +++ b/consent/subject_identifier_algorithm_public.go @@ -3,7 +3,7 @@ package consent -import "github.com/ory/hydra/client" +import "github.com/ory/hydra/v2/client" type SubjectIdentifierAlgorithmPublic struct{} diff --git a/consent/manager_test_helpers.go b/consent/test/manager_test_helpers.go similarity index 58% rename from consent/manager_test_helpers.go rename to consent/test/manager_test_helpers.go index 0a2133c461f..a5b141f5359 100644 --- a/consent/manager_test_helpers.go +++ b/consent/test/manager_test_helpers.go @@ -1,7 +1,7 @@ // Copyright © 2022 Ory Corp // SPDX-License-Identifier: Apache-2.0 -package consent +package test import ( "context" @@ -10,7 +10,14 @@ import ( "testing" "time" + "github.com/ory/fosite/handler/openid" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/oauth2" + + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/flow" "github.com/ory/x/assertx" + "github.com/ory/x/contextx" gofrsuuid "github.com/gofrs/uuid" "github.com/google/uuid" @@ -21,23 +28,23 @@ import ( "github.com/ory/fosite" - "github.com/ory/hydra/client" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/x" ) -func MockConsentRequest(key string, remember bool, rememberFor int, hasError bool, skip bool, authAt bool, loginChallengeBase string, network string) (c *OAuth2ConsentRequest, h *AcceptOAuth2ConsentRequest) { - c = &OAuth2ConsentRequest{ +func MockConsentRequest(key string, remember bool, rememberFor int, hasError bool, skip bool, authAt bool, loginChallengeBase string, network string) (c *flow.OAuth2ConsentRequest, h *flow.AcceptOAuth2ConsentRequest, f *flow.Flow) { + c = &flow.OAuth2ConsentRequest{ ID: makeID("challenge", network, key), RequestedScope: []string{"scopea" + key, "scopeb" + key}, RequestedAudience: []string{"auda" + key, "audb" + key}, Skip: skip, Subject: "subject" + key, - OpenIDConnectContext: &OAuth2ConsentRequestOpenIDConnectContext{ + OpenIDConnectContext: &flow.OAuth2ConsentRequestOpenIDConnectContext{ ACRValues: []string{"1" + key, "2" + key}, UILocales: []string{"fr" + key, "de" + key}, Display: "popup" + key, }, - Client: &client.Client{LegacyClientID: "fk-client-" + key}, + Client: &client.Client{ID: "fk-client-" + key}, RequestURL: "https://request-url/path" + key, LoginChallenge: sqlxx.NullString(makeID(loginChallengeBase, network, key)), LoginSessionID: sqlxx.NullString(makeID("fk-login-session", network, key)), @@ -46,19 +53,37 @@ func MockConsentRequest(key string, remember bool, rememberFor int, hasError boo CSRF: "csrf" + key, ACR: "1", AuthenticatedAt: sqlxx.NullTime(time.Now().UTC().Add(-time.Hour)), - RequestedAt: time.Now().UTC().Add(-time.Hour), + RequestedAt: time.Now().UTC(), Context: sqlxx.JSONRawMessage(`{"foo": "bar` + key + `"}`), } - var err *RequestDeniedError + f = &flow.Flow{ + ID: c.LoginChallenge.String(), + LoginVerifier: makeID("login-verifier", network, key), + SessionID: c.LoginSessionID, + Client: c.Client, + State: flow.FlowStateConsentInitialized, + ConsentChallengeID: sqlxx.NullString(c.ID), + ConsentSkip: c.Skip, + ConsentVerifier: sqlxx.NullString(c.Verifier), + ConsentCSRF: sqlxx.NullString(c.CSRF), + OpenIDConnectContext: c.OpenIDConnectContext, + Subject: c.Subject, + RequestedScope: c.RequestedScope, + RequestedAudience: c.RequestedAudience, + RequestURL: c.RequestURL, + RequestedAt: c.RequestedAt, + } + + var err *flow.RequestDeniedError if hasError { - err = &RequestDeniedError{ + err = &flow.RequestDeniedError{ Name: "error_name" + key, Description: "error_description" + key, Hint: "error_hint,omitempty" + key, Code: 100, Debug: "error_debug,omitempty" + key, - valid: true, + Valid: true, } } @@ -67,7 +92,7 @@ func MockConsentRequest(key string, remember bool, rememberFor int, hasError boo authenticatedAt = sqlxx.NullTime(time.Now().UTC().Add(-time.Minute)) } - h = &AcceptOAuth2ConsentRequest{ + h = &flow.AcceptOAuth2ConsentRequest{ ConsentRequest: c, RememberFor: rememberFor, Remember: remember, @@ -81,17 +106,17 @@ func MockConsentRequest(key string, remember bool, rememberFor int, hasError boo // WasUsed: true, } - return c, h + return c, h, f } -func MockLogoutRequest(key string, withClient bool, network string) (c *LogoutRequest) { +func MockLogoutRequest(key string, withClient bool, network string) (c *flow.LogoutRequest) { var cl *client.Client if withClient { cl = &client.Client{ - LegacyClientID: "fk-client-" + key, + ID: "fk-client-" + key, } } - return &LogoutRequest{ + return &flow.LogoutRequest{ Subject: "subject" + key, ID: makeID("challenge", network, key), Verifier: makeID("verifier", network, key), @@ -105,15 +130,15 @@ func MockLogoutRequest(key string, withClient bool, network string) (c *LogoutRe } } -func MockAuthRequest(key string, authAt bool, network string) (c *LoginRequest, h *HandledLoginRequest) { - c = &LoginRequest{ - OpenIDConnectContext: &OAuth2ConsentRequestOpenIDConnectContext{ +func MockAuthRequest(key string, authAt bool, network string) (c *flow.LoginRequest, h *flow.HandledLoginRequest, f *flow.Flow) { + c = &flow.LoginRequest{ + OpenIDConnectContext: &flow.OAuth2ConsentRequestOpenIDConnectContext{ ACRValues: []string{"1" + key, "2" + key}, UILocales: []string{"fr" + key, "de" + key}, Display: "popup" + key, }, RequestedAt: time.Now().UTC().Add(-time.Minute), - Client: &client.Client{LegacyClientID: "fk-client-" + key}, + Client: &client.Client{ID: "fk-client-" + key}, Subject: "subject" + key, RequestURL: "https://request-url/path" + key, Skip: true, @@ -124,13 +149,15 @@ func MockAuthRequest(key string, authAt bool, network string) (c *LoginRequest, SessionID: sqlxx.NullString(makeID("fk-login-session", network, key)), } - var err = &RequestDeniedError{ + f = flow.NewFlow(c) + + var err = &flow.RequestDeniedError{ Name: "error_name" + key, Description: "error_description" + key, Hint: "error_hint,omitempty" + key, Code: 100, Debug: "error_debug,omitempty" + key, - valid: true, + Valid: true, } var authenticatedAt time.Time @@ -138,7 +165,7 @@ func MockAuthRequest(key string, authAt bool, network string) (c *LoginRequest, authenticatedAt = time.Now().UTC().Add(-time.Minute) } - h = &HandledLoginRequest{ + h = &flow.HandledLoginRequest{ LoginRequest: c, RememberFor: 120, Remember: true, @@ -152,23 +179,23 @@ func MockAuthRequest(key string, authAt bool, network string) (c *LoginRequest, WasHandled: false, } - return c, h + return c, h, f } -func SaneMockHandleConsentRequest(t *testing.T, m Manager, c *OAuth2ConsentRequest, authAt time.Time, rememberFor int, remember bool, hasError bool) *AcceptOAuth2ConsentRequest { - var rde *RequestDeniedError +func SaneMockHandleConsentRequest(t *testing.T, m consent.Manager, f *flow.Flow, c *flow.OAuth2ConsentRequest, authAt time.Time, rememberFor int, remember bool, hasError bool) *flow.AcceptOAuth2ConsentRequest { + var rde *flow.RequestDeniedError if hasError { - rde = &RequestDeniedError{ + rde = &flow.RequestDeniedError{ Name: "error_name", Description: "error_description", Hint: "error_hint", Code: 100, Debug: "error_debug", - valid: true, + Valid: true, } } - h := &AcceptOAuth2ConsentRequest{ + h := &flow.AcceptOAuth2ConsentRequest{ ConsentRequest: c, RememberFor: rememberFor, Remember: remember, @@ -182,27 +209,28 @@ func SaneMockHandleConsentRequest(t *testing.T, m Manager, c *OAuth2ConsentReque HandledAt: sqlxx.NullTime(time.Now().UTC().Add(-time.Minute)), } - _, err := m.HandleConsentRequest(context.Background(), h) + _, err := m.HandleConsentRequest(context.Background(), f, h) require.NoError(t, err) + return h } // SaneMockConsentRequest does the same thing as MockConsentRequest but uses less insanity and implicit dependencies. -func SaneMockConsentRequest(t *testing.T, m Manager, ar *LoginRequest, skip bool) (c *OAuth2ConsentRequest) { - c = &OAuth2ConsentRequest{ +func SaneMockConsentRequest(t *testing.T, m consent.Manager, f *flow.Flow, skip bool) (c *flow.OAuth2ConsentRequest) { + c = &flow.OAuth2ConsentRequest{ RequestedScope: []string{"scopea", "scopeb"}, RequestedAudience: []string{"auda", "audb"}, Skip: skip, - Subject: ar.Subject, - OpenIDConnectContext: &OAuth2ConsentRequestOpenIDConnectContext{ + Subject: f.Subject, + OpenIDConnectContext: &flow.OAuth2ConsentRequestOpenIDConnectContext{ ACRValues: []string{"1", "2"}, UILocales: []string{"fr", "de"}, Display: "popup", }, - Client: ar.Client, + Client: f.Client, RequestURL: "https://request-url/path", - LoginChallenge: sqlxx.NullString(ar.ID), - LoginSessionID: ar.SessionID, + LoginChallenge: sqlxx.NullString(f.ID), + LoginSessionID: f.SessionID, ForceSubjectIdentifier: "forced-subject", ACR: "1", AuthenticatedAt: sqlxx.NullTime(time.Now().UTC().Add(-time.Hour)), @@ -214,14 +242,15 @@ func SaneMockConsentRequest(t *testing.T, m Manager, ar *LoginRequest, skip bool CSRF: uuid.New().String(), } - require.NoError(t, m.CreateConsentRequest(context.Background(), c)) + require.NoError(t, m.CreateConsentRequest(context.Background(), f, c)) + return c } // SaneMockAuthRequest does the same thing as MockAuthRequest but uses less insanity and implicit dependencies. -func SaneMockAuthRequest(t *testing.T, m Manager, ls *LoginSession, cl *client.Client) (c *LoginRequest) { - c = &LoginRequest{ - OpenIDConnectContext: &OAuth2ConsentRequestOpenIDConnectContext{ +func SaneMockAuthRequest(t *testing.T, m consent.Manager, ls *flow.LoginSession, cl *client.Client) (c *flow.LoginRequest) { + c = &flow.LoginRequest{ + OpenIDConnectContext: &flow.OAuth2ConsentRequestOpenIDConnectContext{ ACRValues: []string{"1", "2"}, UILocales: []string{"fr", "de"}, Display: "popup", @@ -238,7 +267,8 @@ func SaneMockAuthRequest(t *testing.T, m Manager, ls *LoginSession, cl *client.C ID: uuid.New().String(), Verifier: uuid.New().String(), } - require.NoError(t, m.CreateLoginRequest(context.Background(), c)) + _, err := m.CreateLoginRequest(context.Background(), c) + require.NoError(t, err) return c } @@ -246,20 +276,23 @@ func makeID(base string, network string, key string) string { return fmt.Sprintf("%s-%s-%s", base, network, key) } -func TestHelperNID(t1ClientManager client.Manager, t1ValidNID Manager, t2InvalidNID Manager) func(t *testing.T) { - testClient := client.Client{LegacyClientID: fmt.Sprintf("2022-03-11-client-nid-test-1")} - testLS := LoginSession{ +func TestHelperNID(r interface { + client.ManagerProvider + FlowCipher() *aead.XChaCha20Poly1305 +}, t1ValidNID consent.Manager, t2InvalidNID consent.Manager) func(t *testing.T) { + testClient := client.Client{ID: "2022-03-11-client-nid-test-1"} + testLS := flow.LoginSession{ ID: "2022-03-11-ls-nid-test-1", Subject: "2022-03-11-test-1-sub", } - testLR := LoginRequest{ + testLR := flow.LoginRequest{ ID: "2022-03-11-lr-nid-test-1", Subject: "2022-03-11-test-1-sub", Verifier: "2022-03-11-test-1-ver", RequestedAt: time.Now(), - Client: &client.Client{LegacyClientID: fmt.Sprintf("2022-03-11-client-nid-test-1")}, + Client: &client.Client{ID: "2022-03-11-client-nid-test-1"}, } - testHLR := HandledLoginRequest{ + testHLR := flow.HandledLoginRequest{ LoginRequest: &testLR, RememberFor: 120, Remember: true, @@ -274,100 +307,131 @@ func TestHelperNID(t1ClientManager client.Manager, t1ValidNID Manager, t2Invalid } return func(t *testing.T) { - require.NoError(t, t1ClientManager.CreateClient(context.Background(), &testClient)) - require.Error(t, t2InvalidNID.CreateLoginSession(context.Background(), &testLS)) - require.NoError(t, t1ValidNID.CreateLoginSession(context.Background(), &testLS)) - require.Error(t, t2InvalidNID.CreateLoginRequest(context.Background(), &testLR)) - require.NoError(t, t1ValidNID.CreateLoginRequest(context.Background(), &testLR)) - _, err := t2InvalidNID.GetLoginRequest(context.Background(), testLR.ID) + ctx := context.Background() + require.NoError(t, r.ClientManager().CreateClient(ctx, &testClient)) + require.Error(t, t2InvalidNID.CreateLoginSession(ctx, &testLS)) + require.NoError(t, t1ValidNID.CreateLoginSession(ctx, &testLS)) + + _, err := t2InvalidNID.CreateLoginRequest(ctx, &testLR) + require.Error(t, err) + f, err := t1ValidNID.CreateLoginRequest(ctx, &testLR) + require.NoError(t, err) + + testLR.ID = x.Must(f.ToLoginChallenge(ctx, r)) + _, err = t2InvalidNID.GetLoginRequest(ctx, testLR.ID) + require.Error(t, err) + _, err = t1ValidNID.GetLoginRequest(ctx, testLR.ID) + require.NoError(t, err) + _, err = t2InvalidNID.HandleLoginRequest(ctx, f, testLR.ID, &testHLR) require.Error(t, err) - _, err = t1ValidNID.GetLoginRequest(context.Background(), testLR.ID) + _, err = t1ValidNID.HandleLoginRequest(ctx, f, testLR.ID, &testHLR) require.NoError(t, err) - _, err = t2InvalidNID.HandleLoginRequest(context.Background(), testLR.ID, &testHLR) + require.Error(t, t2InvalidNID.ConfirmLoginSession(ctx, &testLS)) + require.NoError(t, t1ValidNID.ConfirmLoginSession(ctx, &testLS)) + ls, err := t2InvalidNID.DeleteLoginSession(ctx, testLS.ID) require.Error(t, err) - _, err = t1ValidNID.HandleLoginRequest(context.Background(), testLR.ID, &testHLR) + assert.Nil(t, ls) + ls, err = t1ValidNID.DeleteLoginSession(ctx, testLS.ID) require.NoError(t, err) - require.NoError(t, t2InvalidNID.ConfirmLoginSession(context.Background(), testLS.ID, time.Now(), testLS.Subject, true)) - require.NoError(t, t1ValidNID.ConfirmLoginSession(context.Background(), testLS.ID, time.Now(), testLS.Subject, true)) - require.Error(t, t2InvalidNID.DeleteLoginSession(context.Background(), testLS.ID)) - require.NoError(t, t1ValidNID.DeleteLoginSession(context.Background(), testLS.ID)) + assert.Equal(t, testLS.ID, ls.ID) } } -func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.FositeStorer, network string, parallel bool) func(t *testing.T) { - lr := make(map[string]*LoginRequest) +type Deps interface { + FlowCipher() *aead.XChaCha20Poly1305 + contextx.Provider +} + +func ManagerTests(deps Deps, m consent.Manager, clientManager client.Manager, fositeManager x.FositeStorer, network string, parallel bool) func(t *testing.T) { + lr := make(map[string]*flow.LoginRequest) return func(t *testing.T) { if parallel { t.Parallel() } + ctx := context.Background() t.Run("case=init-fks", func(t *testing.T) { for _, k := range []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "rv1", "rv2"} { - require.NoError(t, clientManager.CreateClient(context.Background(), &client.Client{LegacyClientID: fmt.Sprintf("fk-client-%s", k)})) + require.NoError(t, clientManager.CreateClient(ctx, &client.Client{ID: fmt.Sprintf("fk-client-%s", k)})) - require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ + loginSession := &flow.LoginSession{ ID: makeID("fk-login-session", network, k), AuthenticatedAt: sqlxx.NullTime(time.Now().Round(time.Second).UTC()), Subject: fmt.Sprintf("subject-%s", k), - })) + } + require.NoError(t, m.CreateLoginSession(ctx, loginSession)) + require.NoError(t, m.ConfirmLoginSession(ctx, loginSession)) - lr[k] = &LoginRequest{ + lr[k] = &flow.LoginRequest{ ID: makeID("fk-login-challenge", network, k), Subject: fmt.Sprintf("subject%s", k), SessionID: sqlxx.NullString(makeID("fk-login-session", network, k)), Verifier: makeID("fk-login-verifier", network, k), - Client: &client.Client{LegacyClientID: fmt.Sprintf("fk-client-%s", k)}, + Client: &client.Client{ID: fmt.Sprintf("fk-client-%s", k)}, AuthenticatedAt: sqlxx.NullTime(time.Now()), RequestedAt: time.Now(), } - require.NoError(t, m.CreateLoginRequest(context.Background(), lr[k])) + _, err := m.CreateLoginRequest(ctx, lr[k]) + require.NoError(t, err) } }) t.Run("case=auth-session", func(t *testing.T) { for _, tc := range []struct { - s LoginSession + s flow.LoginSession }{ { - s: LoginSession{ + s: flow.LoginSession{ ID: makeID("session", network, "1"), AuthenticatedAt: sqlxx.NullTime(time.Now().Round(time.Second).Add(-time.Minute).UTC()), Subject: "subject1", }, }, { - s: LoginSession{ + s: flow.LoginSession{ ID: makeID("session", network, "2"), AuthenticatedAt: sqlxx.NullTime(time.Now().Round(time.Minute).Add(-time.Minute).UTC()), Subject: "subject2", }, }, } { + tc := tc t.Run("case=create-get-"+tc.s.ID, func(t *testing.T) { - _, err := m.GetRememberedLoginSession(context.Background(), tc.s.ID) + _, err := m.GetRememberedLoginSession(ctx, &tc.s, tc.s.ID) require.EqualError(t, err, x.ErrNotFound.Error(), "%#v", err) - err = m.CreateLoginSession(context.Background(), &tc.s) + err = m.CreateLoginSession(ctx, &tc.s) require.NoError(t, err) - _, err = m.GetRememberedLoginSession(context.Background(), tc.s.ID) + _, err = m.GetRememberedLoginSession(ctx, &tc.s, tc.s.ID) require.EqualError(t, err, x.ErrNotFound.Error()) updatedAuth := time.Time(tc.s.AuthenticatedAt).Add(time.Second) - require.NoError(t, m.ConfirmLoginSession(context.Background(), tc.s.ID, updatedAuth, tc.s.Subject, true)) - - got, err := m.GetRememberedLoginSession(context.Background(), tc.s.ID) + tc.s.AuthenticatedAt = sqlxx.NullTime(updatedAuth) + require.NoError(t, m.ConfirmLoginSession(ctx, &flow.LoginSession{ + ID: tc.s.ID, + AuthenticatedAt: sqlxx.NullTime(updatedAuth), + Subject: tc.s.Subject, + Remember: true, + })) + + got, err := m.GetRememberedLoginSession(ctx, nil, tc.s.ID) require.NoError(t, err) assert.EqualValues(t, tc.s.ID, got.ID) - assert.Equal(t, updatedAuth.Unix(), time.Time(got.AuthenticatedAt).Unix()) // this was updated from confirm... + assert.Equal(t, tc.s.AuthenticatedAt, got.AuthenticatedAt) // this was updated from confirm... assert.EqualValues(t, tc.s.Subject, got.Subject) - time.Sleep(time.Second) // Make sure AuthAt does not equal... - updatedAuth2 := time.Now().Truncate(time.Second).UTC() - require.NoError(t, m.ConfirmLoginSession(context.Background(), tc.s.ID, updatedAuth2, "some-other-subject", true)) + // Make sure AuthAt does not equal... + updatedAuth2 := updatedAuth.Add(1 * time.Second).UTC() + require.NoError(t, m.ConfirmLoginSession(ctx, &flow.LoginSession{ + ID: tc.s.ID, + AuthenticatedAt: sqlxx.NullTime(updatedAuth2), + Subject: "some-other-subject", + Remember: true, + })) - got2, err := m.GetRememberedLoginSession(context.Background(), tc.s.ID) + got2, err := m.GetRememberedLoginSession(ctx, nil, tc.s.ID) require.NoError(t, err) assert.EqualValues(t, tc.s.ID, got2.ID) assert.Equal(t, updatedAuth2.Unix(), time.Time(got2.AuthenticatedAt).Unix()) // this was updated from confirm... @@ -385,10 +449,11 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit }, } { t.Run("case=delete-get-"+tc.id, func(t *testing.T) { - err := m.DeleteLoginSession(context.Background(), tc.id) + ls, err := m.DeleteLoginSession(ctx, tc.id) require.NoError(t, err) + assert.EqualValues(t, tc.id, ls.ID) - _, err = m.GetRememberedLoginSession(context.Background(), tc.id) + _, err = m.GetRememberedLoginSession(ctx, nil, tc.id) require.Error(t, err) }) } @@ -408,34 +473,36 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit {"7", true}, } { t.Run("key="+tc.key, func(t *testing.T) { - c, h := MockAuthRequest(tc.key, tc.authAt, network) - _ = clientManager.CreateClient(context.Background(), c.Client) // Ignore errors that are caused by duplication + c, h, f := MockAuthRequest(tc.key, tc.authAt, network) + _ = clientManager.CreateClient(ctx, c.Client) // Ignore errors that are caused by duplication + loginChallenge := x.Must(f.ToLoginChallenge(ctx, deps)) - _, err := m.GetLoginRequest(context.Background(), makeID("challenge", network, tc.key)) + _, err := m.GetLoginRequest(ctx, loginChallenge) require.Error(t, err) - require.NoError(t, m.CreateLoginRequest(context.Background(), c)) + f, err = m.CreateLoginRequest(ctx, c) + require.NoError(t, err) + + loginChallenge = x.Must(f.ToLoginChallenge(ctx, deps)) - got1, err := m.GetLoginRequest(context.Background(), makeID("challenge", network, tc.key)) + got1, err := m.GetLoginRequest(ctx, loginChallenge) require.NoError(t, err) assert.False(t, got1.WasHandled) compareAuthenticationRequest(t, c, got1) - got1, err = m.HandleLoginRequest(context.Background(), makeID("challenge", network, tc.key), h) + got1, err = m.HandleLoginRequest(ctx, f, loginChallenge, h) require.NoError(t, err) compareAuthenticationRequest(t, c, got1) - got2, err := m.VerifyAndInvalidateLoginRequest(context.Background(), makeID("verifier", network, tc.key)) + loginVerifier := x.Must(f.ToLoginVerifier(ctx, deps)) + + got2, err := m.VerifyAndInvalidateLoginRequest(ctx, loginVerifier) require.NoError(t, err) compareAuthenticationRequest(t, c, got2.LoginRequest) - assert.Equal(t, c.ID, got2.ID) - - _, err = m.VerifyAndInvalidateLoginRequest(context.Background(), makeID("verifier", network, tc.key)) - require.Error(t, err) - got1, err = m.GetLoginRequest(context.Background(), makeID("challenge", network, tc.key)) + loginChallenge = x.Must(f.ToLoginChallenge(ctx, deps)) + got1, err = m.GetLoginRequest(ctx, loginChallenge) require.NoError(t, err) - assert.True(t, got1.WasHandled) }) } }) @@ -458,53 +525,54 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit {"7", false, 0, false, false, false}, } { t.Run("key="+tc.key, func(t *testing.T) { - c, h := MockConsentRequest(tc.key, tc.remember, tc.rememberFor, tc.hasError, tc.skip, tc.authAt, "challenge", network) - _ = clientManager.CreateClient(context.Background(), c.Client) // Ignore errors that are caused by duplication + consentRequest, h, f := MockConsentRequest(tc.key, tc.remember, tc.rememberFor, tc.hasError, tc.skip, tc.authAt, "challenge", network) + _ = clientManager.CreateClient(ctx, consentRequest.Client) // Ignore errors that are caused by duplication + f.NID = deps.Contextualizer().Network(context.Background(), gofrsuuid.Nil) consentChallenge := makeID("challenge", network, tc.key) - _, err := m.GetConsentRequest(context.Background(), consentChallenge) + _, err := m.GetConsentRequest(ctx, consentChallenge) require.Error(t, err) - require.NoError(t, m.CreateConsentRequest(context.Background(), c)) + consentChallenge = x.Must(f.ToConsentChallenge(ctx, deps)) + consentRequest.ID = consentChallenge - got1, err := m.GetConsentRequest(context.Background(), consentChallenge) + err = m.CreateConsentRequest(ctx, f, consentRequest) require.NoError(t, err) - compareConsentRequest(t, c, got1) + + got1, err := m.GetConsentRequest(ctx, consentChallenge) + require.NoError(t, err) + compareConsentRequest(t, consentRequest, got1) assert.False(t, got1.WasHandled) - got1, err = m.HandleConsentRequest(context.Background(), h) + got1, err = m.HandleConsentRequest(ctx, f, h) require.NoError(t, err) assertx.TimeDifferenceLess(t, time.Now(), time.Time(h.HandledAt), 5) - compareConsentRequest(t, c, got1) + compareConsentRequest(t, consentRequest, got1) h.GrantedAudience = sqlxx.StringSliceJSONFormat{"new-audience"} - _, err = m.HandleConsentRequest(context.Background(), h) + _, err = m.HandleConsentRequest(ctx, f, h) require.NoError(t, err) - got2, err := m.VerifyAndInvalidateConsentRequest(context.Background(), makeID("verifier", network, tc.key)) + consentVerifier := x.Must(f.ToConsentVerifier(ctx, deps)) + + got2, err := m.VerifyAndInvalidateConsentRequest(ctx, consentVerifier) require.NoError(t, err) - compareConsentRequest(t, c, got2.ConsentRequest) - assert.Equal(t, c.ID, got2.ID) + consentRequest.ID = got2.ID + compareConsentRequest(t, consentRequest, got2.ConsentRequest) + assert.Equal(t, consentRequest.ID, got2.ID) assert.Equal(t, h.GrantedAudience, got2.GrantedAudience) - // Trying to update this again should return an error because the consent request was used. - h.GrantedAudience = sqlxx.StringSliceJSONFormat{"new-audience", "new-audience-2"} - _, err = m.HandleConsentRequest(context.Background(), h) - require.Error(t, err) + t.Run("sub=detect double-submit for consent verifier", func(t *testing.T) { + _, err := m.VerifyAndInvalidateConsentRequest(ctx, consentVerifier) + require.Error(t, err) + }) if tc.hasError { assert.True(t, got2.HasError()) } assert.Equal(t, tc.remember, got2.Remember) assert.Equal(t, tc.rememberFor, got2.RememberFor) - - _, err = m.VerifyAndInvalidateConsentRequest(context.Background(), makeID("verifier", network, tc.key)) - require.Error(t, err) - - got1, err = m.GetConsentRequest(context.Background(), consentChallenge) - require.NoError(t, err) - assert.True(t, got1.WasHandled) }) } @@ -515,7 +583,7 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit }{ {"1", "1", 1}, {"2", "2", 0}, - {"3", "3", 0}, + // {"3", "3", 0}, // Some consent is given in some other test case. Yay global fixtues :) {"4", "4", 0}, {"1", "2", 0}, {"2", "1", 0}, @@ -523,9 +591,10 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit {"6", "6", 0}, } { t.Run("key="+tc.keyC+"-"+tc.keyS, func(t *testing.T) { - rs, err := m.FindGrantedAndRememberedConsentRequests(context.Background(), "fk-client-"+tc.keyC, "subject"+tc.keyS) + rs, err := m.FindGrantedAndRememberedConsentRequests(ctx, "fk-client-"+tc.keyC, "subject"+tc.keyS) if tc.expectedLength == 0 { - assert.EqualError(t, err, ErrNoPreviousConsentFound.Error()) + assert.Nil(t, rs) + assert.EqualError(t, err, consent.ErrNoPreviousConsentFound.Error()) } else { require.NoError(t, err) assert.Len(t, rs, tc.expectedLength) @@ -535,19 +604,19 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit }) t.Run("case=revoke-auth-request", func(t *testing.T) { - require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ + require.NoError(t, m.CreateLoginSession(ctx, &flow.LoginSession{ ID: makeID("rev-session", network, "-1"), AuthenticatedAt: sqlxx.NullTime(time.Now()), Subject: "subject-1", })) - require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ + require.NoError(t, m.CreateLoginSession(ctx, &flow.LoginSession{ ID: makeID("rev-session", network, "-2"), AuthenticatedAt: sqlxx.NullTime(time.Now()), Subject: "subject-2", })) - require.NoError(t, m.CreateLoginSession(context.Background(), &LoginSession{ + require.NoError(t, m.CreateLoginSession(ctx, &flow.LoginSession{ ID: makeID("rev-session", network, "-3"), AuthenticatedAt: sqlxx.NullTime(time.Now()), Subject: "subject-1", @@ -567,11 +636,11 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit }, } { t.Run(fmt.Sprintf("case=%d/subject=%s", i, tc.subject), func(t *testing.T) { - require.NoError(t, m.RevokeSubjectLoginSession(context.Background(), tc.subject)) + require.NoError(t, m.RevokeSubjectLoginSession(ctx, tc.subject)) for _, id := range tc.ids { t.Run(fmt.Sprintf("id=%s", id), func(t *testing.T) { - _, err := m.GetRememberedLoginSession(context.Background(), id) + _, err := m.GetRememberedLoginSession(ctx, nil, id) assert.EqualError(t, err, x.ErrNotFound.Error()) }) } @@ -582,24 +651,50 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit challengerv1 := makeID("challenge", network, "rv1") challengerv2 := makeID("challenge", network, "rv2") t.Run("case=revoke-used-consent-request", func(t *testing.T) { - cr1, hcr1 := MockConsentRequest("rv1", false, 0, false, false, false, "fk-login-challenge", network) - cr2, hcr2 := MockConsentRequest("rv2", false, 0, false, false, false, "fk-login-challenge", network) + + cr1, hcr1, f1 := MockConsentRequest("rv1", false, 0, false, false, false, "fk-login-challenge", network) + cr2, hcr2, f2 := MockConsentRequest("rv2", false, 0, false, false, false, "fk-login-challenge", network) + f1.NID = deps.Contextualizer().Network(context.Background(), gofrsuuid.Nil) + f2.NID = deps.Contextualizer().Network(context.Background(), gofrsuuid.Nil) // Ignore duplication errors - _ = clientManager.CreateClient(context.Background(), cr1.Client) - _ = clientManager.CreateClient(context.Background(), cr2.Client) + _ = clientManager.CreateClient(ctx, cr1.Client) + _ = clientManager.CreateClient(ctx, cr2.Client) - require.NoError(t, m.CreateConsentRequest(context.Background(), cr1)) - require.NoError(t, m.CreateConsentRequest(context.Background(), cr2)) - _, err := m.HandleConsentRequest(context.Background(), hcr1) + err := m.CreateConsentRequest(ctx, f1, cr1) + require.NoError(t, err) + err = m.CreateConsentRequest(ctx, f2, cr2) require.NoError(t, err) - _, err = m.HandleConsentRequest(context.Background(), hcr2) + _, err = m.HandleConsentRequest(ctx, f1, hcr1) + require.NoError(t, err) + _, err = m.HandleConsentRequest(ctx, f2, hcr2) require.NoError(t, err) - require.NoError(t, fositeManager.CreateAccessTokenSession(context.Background(), makeID("", network, "trva1"), &fosite.Request{Client: cr1.Client, ID: challengerv1, RequestedAt: time.Now()})) - require.NoError(t, fositeManager.CreateRefreshTokenSession(context.Background(), makeID("", network, "rrva1"), &fosite.Request{Client: cr1.Client, ID: challengerv1, RequestedAt: time.Now()})) - require.NoError(t, fositeManager.CreateAccessTokenSession(context.Background(), makeID("", network, "trva2"), &fosite.Request{Client: cr2.Client, ID: challengerv2, RequestedAt: time.Now()})) - require.NoError(t, fositeManager.CreateRefreshTokenSession(context.Background(), makeID("", network, "rrva2"), &fosite.Request{Client: cr2.Client, ID: challengerv2, RequestedAt: time.Now()})) + crr1, err := m.VerifyAndInvalidateConsentRequest(ctx, x.Must(f1.ToConsentVerifier(ctx, deps))) + require.NoError(t, err) + crr2, err := m.VerifyAndInvalidateConsentRequest(ctx, x.Must(f2.ToConsentVerifier(ctx, deps))) + require.NoError(t, err) + + require.NoError(t, fositeManager.CreateAccessTokenSession( + ctx, + makeID("", network, "trva1"), + &fosite.Request{Client: cr1.Client, ID: crr1.ID, RequestedAt: time.Now(), Session: &oauth2.Session{DefaultSession: openid.NewDefaultSession()}}, + )) + require.NoError(t, fositeManager.CreateRefreshTokenSession( + ctx, + makeID("", network, "rrva1"), + &fosite.Request{Client: cr1.Client, ID: crr1.ID, RequestedAt: time.Now(), Session: &oauth2.Session{DefaultSession: openid.NewDefaultSession()}}, + )) + require.NoError(t, fositeManager.CreateAccessTokenSession( + ctx, + makeID("", network, "trva2"), + &fosite.Request{Client: cr2.Client, ID: crr2.ID, RequestedAt: time.Now(), Session: &oauth2.Session{DefaultSession: openid.NewDefaultSession()}}, + )) + require.NoError(t, fositeManager.CreateRefreshTokenSession( + ctx, + makeID("", network, "rrva2"), + &fosite.Request{Client: cr2.Client, ID: crr2.ID, RequestedAt: time.Now(), Session: &oauth2.Session{DefaultSession: openid.NewDefaultSession()}}, + )) for i, tc := range []struct { subject string @@ -609,64 +704,74 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit ids []string }{ { - at: makeID("", network, "trva1"), rt: makeID("", network, "rrva1"), + at: makeID("", network, "trva1"), + rt: makeID("", network, "rrva1"), subject: "subjectrv1", client: "", ids: []string{challengerv1}, }, { - at: makeID("", network, "trva2"), rt: makeID("", network, "rrva2"), + at: makeID("", network, "trva2"), + rt: makeID("", network, "rrva2"), subject: "subjectrv2", client: "fk-client-rv2", ids: []string{challengerv2}, }, } { t.Run(fmt.Sprintf("case=%d/subject=%s", i, tc.subject), func(t *testing.T) { - _, err := fositeManager.GetAccessTokenSession(context.Background(), tc.at, nil) + _, err := fositeManager.GetAccessTokenSession(ctx, tc.at, nil) assert.NoError(t, err) - _, err = fositeManager.GetRefreshTokenSession(context.Background(), tc.rt, nil) + _, err = fositeManager.GetRefreshTokenSession(ctx, tc.rt, nil) assert.NoError(t, err) if tc.client == "" { - require.NoError(t, m.RevokeSubjectConsentSession(context.Background(), tc.subject)) + require.NoError(t, m.RevokeSubjectConsentSession(ctx, tc.subject)) } else { - require.NoError(t, m.RevokeSubjectClientConsentSession(context.Background(), tc.subject, tc.client)) + require.NoError(t, m.RevokeSubjectClientConsentSession(ctx, tc.subject, tc.client)) } for _, id := range tc.ids { t.Run(fmt.Sprintf("id=%s", id), func(t *testing.T) { - _, err := m.GetConsentRequest(context.Background(), id) + _, err := m.GetConsentRequest(ctx, id) assert.True(t, errors.Is(err, x.ErrNotFound)) }) } - r, err := fositeManager.GetAccessTokenSession(context.Background(), tc.at, nil) + r, err := fositeManager.GetAccessTokenSession(ctx, tc.at, nil) assert.Error(t, err, "%+v", r) - r, err = fositeManager.GetRefreshTokenSession(context.Background(), tc.rt, nil) + r, err = fositeManager.GetRefreshTokenSession(ctx, tc.rt, nil) assert.Error(t, err, "%+v", r) }) } - require.EqualError(t, m.RevokeSubjectConsentSession(context.Background(), "i-do-not-exist"), x.ErrNotFound.Error()) - require.EqualError(t, m.RevokeSubjectClientConsentSession(context.Background(), "i-do-not-exist", "i-do-not-exist"), x.ErrNotFound.Error()) + require.NoError(t, m.RevokeSubjectConsentSession(ctx, "i-do-not-exist")) + require.NoError(t, m.RevokeSubjectClientConsentSession(ctx, "i-do-not-exist", "i-do-not-exist")) }) t.Run("case=list-used-consent-requests", func(t *testing.T) { - require.NoError(t, m.CreateLoginRequest(context.Background(), lr["rv1"])) - require.NoError(t, m.CreateLoginRequest(context.Background(), lr["rv2"])) + f1, err := m.CreateLoginRequest(ctx, lr["rv1"]) + require.NoError(t, err) + f2, err := m.CreateLoginRequest(ctx, lr["rv2"]) + require.NoError(t, err) - cr1, hcr1 := MockConsentRequest("rv1", true, 0, false, false, false, "fk-login-challenge", network) - cr2, hcr2 := MockConsentRequest("rv2", false, 0, false, false, false, "fk-login-challenge", network) + cr1, hcr1, _ := MockConsentRequest("rv1", true, 0, false, false, false, "fk-login-challenge", network) + cr2, hcr2, _ := MockConsentRequest("rv2", false, 0, false, false, false, "fk-login-challenge", network) // Ignore duplicate errors - _ = clientManager.CreateClient(context.Background(), cr1.Client) - _ = clientManager.CreateClient(context.Background(), cr2.Client) + _ = clientManager.CreateClient(ctx, cr1.Client) + _ = clientManager.CreateClient(ctx, cr2.Client) - require.NoError(t, m.CreateConsentRequest(context.Background(), cr1)) - require.NoError(t, m.CreateConsentRequest(context.Background(), cr2)) - _, err := m.HandleConsentRequest(context.Background(), hcr1) + err = m.CreateConsentRequest(ctx, f1, cr1) + require.NoError(t, err) + err = m.CreateConsentRequest(ctx, f2, cr2) + require.NoError(t, err) + _, err = m.HandleConsentRequest(ctx, f1, hcr1) + require.NoError(t, err) + _, err = m.HandleConsentRequest(ctx, f2, hcr2) require.NoError(t, err) - _, err = m.HandleConsentRequest(context.Background(), hcr2) + handledConsentRequest1, err := m.VerifyAndInvalidateConsentRequest(ctx, x.Must(f1.ToConsentVerifier(ctx, deps))) + require.NoError(t, err) + handledConsentRequest2, err := m.VerifyAndInvalidateConsentRequest(ctx, x.Must(f2.ToConsentVerifier(ctx, deps))) require.NoError(t, err) for i, tc := range []struct { @@ -678,13 +783,13 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit { subject: cr1.Subject, sid: makeID("fk-login-session", network, "rv1"), - challenges: []string{challengerv1}, + challenges: []string{handledConsentRequest1.ID}, clients: []string{"fk-client-rv1"}, }, { subject: cr2.Subject, sid: makeID("fk-login-session", network, "rv2"), - challenges: []string{challengerv2}, + challenges: []string{handledConsentRequest2.ID}, clients: []string{"fk-client-rv2"}, }, { @@ -695,11 +800,11 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit }, } { t.Run(fmt.Sprintf("case=%d/subject=%s/session=%s", i, tc.subject, tc.sid), func(t *testing.T) { - consents, err := m.FindSubjectsSessionGrantedConsentRequests(context.Background(), tc.subject, tc.sid, 100, 0) + consents, err := m.FindSubjectsSessionGrantedConsentRequests(ctx, tc.subject, tc.sid, 100, 0) assert.Equal(t, len(tc.challenges), len(consents)) if len(tc.challenges) == 0 { - assert.EqualError(t, err, ErrNoPreviousConsentFound.Error()) + assert.EqualError(t, err, consent.ErrNoPreviousConsentFound.Error()) } else { require.NoError(t, err) for _, consent := range consents { @@ -708,7 +813,7 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit } } - n, err := m.CountSubjectsGrantedConsentRequests(context.Background(), tc.subject) + n, err := m.CountSubjectsGrantedConsentRequests(ctx, tc.subject) require.NoError(t, err) assert.Equal(t, n, len(tc.challenges)) @@ -722,12 +827,12 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit }{ { subject: "subjectrv1", - challenges: []string{challengerv1}, + challenges: []string{handledConsentRequest1.ID}, clients: []string{"fk-client-rv1"}, }, { subject: "subjectrv2", - challenges: []string{challengerv2}, + challenges: []string{handledConsentRequest2.ID}, clients: []string{"fk-client-rv2"}, }, { @@ -737,11 +842,11 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit }, } { t.Run(fmt.Sprintf("case=%d/subject=%s", i, tc.subject), func(t *testing.T) { - consents, err := m.FindSubjectsGrantedConsentRequests(context.Background(), tc.subject, 100, 0) + consents, err := m.FindSubjectsGrantedConsentRequests(ctx, tc.subject, 100, 0) assert.Equal(t, len(tc.challenges), len(consents)) if len(tc.challenges) == 0 { - assert.EqualError(t, err, ErrNoPreviousConsentFound.Error()) + assert.EqualError(t, err, consent.ErrNoPreviousConsentFound.Error()) } else { require.NoError(t, err) for _, consent := range consents { @@ -750,7 +855,7 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit } } - n, err := m.CountSubjectsGrantedConsentRequests(context.Background(), tc.subject) + n, err := m.CountSubjectsGrantedConsentRequests(ctx, tc.subject) require.NoError(t, err) assert.Equal(t, n, len(tc.challenges)) @@ -758,36 +863,36 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit } t.Run("case=obfuscated", func(t *testing.T) { - _, err := m.GetForcedObfuscatedLoginSession(context.Background(), "fk-client-1", "obfuscated-1") + _, err := m.GetForcedObfuscatedLoginSession(ctx, "fk-client-1", "obfuscated-1") require.True(t, errors.Is(err, x.ErrNotFound)) - expect := &ForcedObfuscatedLoginSession{ + expect := &consent.ForcedObfuscatedLoginSession{ ClientID: "fk-client-1", Subject: "subject-1", SubjectObfuscated: "obfuscated-1", } - require.NoError(t, m.CreateForcedObfuscatedLoginSession(context.Background(), expect)) + require.NoError(t, m.CreateForcedObfuscatedLoginSession(ctx, expect)) - got, err := m.GetForcedObfuscatedLoginSession(context.Background(), "fk-client-1", "obfuscated-1") + got, err := m.GetForcedObfuscatedLoginSession(ctx, "fk-client-1", "obfuscated-1") require.NoError(t, err) require.NotEqual(t, got.NID, gofrsuuid.Nil) got.NID = gofrsuuid.Nil assert.EqualValues(t, expect, got) - expect = &ForcedObfuscatedLoginSession{ + expect = &consent.ForcedObfuscatedLoginSession{ ClientID: "fk-client-1", Subject: "subject-1", SubjectObfuscated: "obfuscated-2", } - require.NoError(t, m.CreateForcedObfuscatedLoginSession(context.Background(), expect)) + require.NoError(t, m.CreateForcedObfuscatedLoginSession(ctx, expect)) - got, err = m.GetForcedObfuscatedLoginSession(context.Background(), "fk-client-1", "obfuscated-2") + got, err = m.GetForcedObfuscatedLoginSession(ctx, "fk-client-1", "obfuscated-2") require.NotEqual(t, got.NID, gofrsuuid.Nil) got.NID = gofrsuuid.Nil require.NoError(t, err) assert.EqualValues(t, expect, got) - _, err = m.GetForcedObfuscatedLoginSession(context.Background(), "fk-client-1", "obfuscated-1") + _, err = m.GetForcedObfuscatedLoginSession(ctx, "fk-client-1", "obfuscated-1") require.True(t, errors.Is(err, x.ErrNotFound)) }) @@ -800,21 +905,23 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit subjects[k] = fmt.Sprintf("subject-ListUserAuthenticatedClientsWithFrontAndBackChannelLogout-%d", k) } - sessions := make([]LoginSession, len(subjects)*1) + sessions := make([]flow.LoginSession, len(subjects)*1) frontChannels := map[string][]client.Client{} backChannels := map[string][]client.Client{} for k := range sessions { id := uuid.New().String() subject := subjects[k%len(subjects)] t.Run(fmt.Sprintf("create/session=%s/subject=%s", id, subject), func(t *testing.T) { - ls := &LoginSession{ + ls := &flow.LoginSession{ ID: id, AuthenticatedAt: sqlxx.NullTime(time.Now()), Subject: subject, } - require.NoError(t, m.CreateLoginSession(context.Background(), ls)) + require.NoError(t, m.CreateLoginSession(ctx, ls)) + ls.Remember = true + require.NoError(t, m.ConfirmLoginSession(ctx, ls)) - cl := &client.Client{LegacyClientID: uuid.New().String()} + cl := &client.Client{ID: uuid.New().String()} switch k % 4 { case 0: cl.FrontChannelLogoutURI = "http://some-url.com/" @@ -828,11 +935,15 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit frontChannels[id] = append(frontChannels[id], *cl) backChannels[id] = append(backChannels[id], *cl) } - require.NoError(t, clientManager.CreateClient(context.Background(), cl)) + require.NoError(t, clientManager.CreateClient(ctx, cl)) ar := SaneMockAuthRequest(t, m, ls, cl) - cr := SaneMockConsentRequest(t, m, ar, false) - _ = SaneMockHandleConsentRequest(t, m, cr, time.Time{}, 0, false, false) + f := flow.NewFlow(ar) + f.NID = deps.Contextualizer().Network(ctx, gofrsuuid.Nil) + cr := SaneMockConsentRequest(t, m, f, false) + _ = SaneMockHandleConsentRequest(t, m, f, cr, time.Time{}, 0, false, false) + _, err = m.VerifyAndInvalidateConsentRequest(ctx, x.Must(f.ToConsentVerifier(ctx, deps))) + require.NoError(t, err) sessions[k] = *ls }) @@ -862,13 +973,13 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit } t.Run(fmt.Sprintf("method=ListUserAuthenticatedClientsWithFrontChannelLogout/session=%s/subject=%s", ls.ID, ls.Subject), func(t *testing.T) { - actual, err := m.ListUserAuthenticatedClientsWithFrontChannelLogout(context.Background(), ls.Subject, ls.ID) + actual, err := m.ListUserAuthenticatedClientsWithFrontChannelLogout(ctx, ls.Subject, ls.ID) require.NoError(t, err) check(t, frontChannels, actual) }) t.Run(fmt.Sprintf("method=ListUserAuthenticatedClientsWithBackChannelLogout/session=%s", ls.ID), func(t *testing.T) { - actual, err := m.ListUserAuthenticatedClientsWithBackChannelLogout(context.Background(), ls.Subject, ls.ID) + actual, err := m.ListUserAuthenticatedClientsWithBackChannelLogout(ctx, ls.Subject, ls.ID) require.NoError(t, err) check(t, backChannels, actual) }) @@ -893,42 +1004,42 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit verifier := makeID("verifier", network, tc.key) c := MockLogoutRequest(tc.key, tc.withClient, network) if tc.withClient { - require.NoError(t, clientManager.CreateClient(context.Background(), c.Client)) // Ignore errors that are caused by duplication + require.NoError(t, clientManager.CreateClient(ctx, c.Client)) // Ignore errors that are caused by duplication } - _, err := m.GetLogoutRequest(context.Background(), challenge) + _, err := m.GetLogoutRequest(ctx, challenge) require.Error(t, err) - require.NoError(t, m.CreateLogoutRequest(context.Background(), c)) + require.NoError(t, m.CreateLogoutRequest(ctx, c)) - got2, err := m.GetLogoutRequest(context.Background(), challenge) + got2, err := m.GetLogoutRequest(ctx, challenge) require.NoError(t, err) assert.False(t, got2.WasHandled) assert.False(t, got2.Accepted) compareLogoutRequest(t, c, got2) if k%2 == 0 { - got2, err = m.AcceptLogoutRequest(context.Background(), challenge) + got2, err = m.AcceptLogoutRequest(ctx, challenge) require.NoError(t, err) assert.True(t, got2.Accepted) compareLogoutRequest(t, c, got2) - got3, err := m.VerifyAndInvalidateLogoutRequest(context.Background(), verifier) + got3, err := m.VerifyAndInvalidateLogoutRequest(ctx, verifier) require.NoError(t, err) assert.True(t, got3.Accepted) assert.True(t, got3.WasHandled) compareLogoutRequest(t, c, got3) - _, err = m.VerifyAndInvalidateLogoutRequest(context.Background(), verifier) - require.Error(t, err) + _, err = m.VerifyAndInvalidateLogoutRequest(ctx, verifier) + require.NoError(t, err) - got2, err = m.GetLogoutRequest(context.Background(), challenge) + got2, err = m.GetLogoutRequest(ctx, challenge) require.NoError(t, err) compareLogoutRequest(t, got3, got2) assert.True(t, got2.WasHandled) } else { - require.NoError(t, m.RejectLogoutRequest(context.Background(), challenge)) - _, err = m.GetLogoutRequest(context.Background(), challenge) + require.NoError(t, m.RejectLogoutRequest(ctx, challenge)) + _, err = m.GetLogoutRequest(ctx, challenge) require.Error(t, err) } }) @@ -937,20 +1048,20 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit }) t.Run("case=foreign key regression", func(t *testing.T) { - cl := &client.Client{LegacyClientID: uuid.New().String()} - require.NoError(t, clientManager.CreateClient(context.Background(), cl)) + cl := &client.Client{ID: uuid.New().String()} + require.NoError(t, clientManager.CreateClient(ctx, cl)) subject := uuid.New().String() - s := LoginSession{ + s := flow.LoginSession{ ID: uuid.New().String(), AuthenticatedAt: sqlxx.NullTime(time.Now().Round(time.Minute).Add(-time.Minute).UTC()), Subject: subject, } - err := m.CreateLoginSession(context.Background(), &s) - require.NoError(t, err) + require.NoError(t, m.CreateLoginSession(ctx, &s)) + require.NoError(t, m.ConfirmLoginSession(ctx, &s)) - lr := &LoginRequest{ + lr := &flow.LoginRequest{ ID: uuid.New().String(), Subject: uuid.New().String(), Verifier: uuid.New().String(), @@ -960,36 +1071,39 @@ func ManagerTests(m Manager, clientManager client.Manager, fositeManager x.Fosit SessionID: sqlxx.NullString(s.ID), } - require.NoError(t, m.CreateLoginRequest(context.Background(), lr)) - expected := &OAuth2ConsentRequest{ - ID: uuid.New().String(), + f, err := m.CreateLoginRequest(ctx, lr) + require.NoError(t, err) + expected := &flow.OAuth2ConsentRequest{ + ID: x.Must(f.ToConsentChallenge(ctx, deps)), Skip: true, Subject: subject, OpenIDConnectContext: nil, Client: cl, - ClientID: cl.LegacyClientID, + ClientID: cl.ID, RequestURL: "", LoginChallenge: sqlxx.NullString(lr.ID), LoginSessionID: sqlxx.NullString(s.ID), Verifier: uuid.New().String(), CSRF: uuid.New().String(), } - require.NoError(t, m.CreateConsentRequest(context.Background(), expected)) + err = m.CreateConsentRequest(ctx, f, expected) + require.NoError(t, err) - result, err := m.GetConsentRequest(context.Background(), expected.ID) + result, err := m.GetConsentRequest(ctx, expected.ID) require.NoError(t, err) assert.EqualValues(t, expected.ID, result.ID) - require.NoError(t, m.DeleteLoginSession(context.Background(), s.ID)) + _, err = m.DeleteLoginSession(ctx, s.ID) + require.NoError(t, err) - result, err = m.GetConsentRequest(context.Background(), expected.ID) + result, err = m.GetConsentRequest(ctx, expected.ID) require.NoError(t, err) assert.EqualValues(t, expected.ID, result.ID) }) } } -func compareLogoutRequest(t *testing.T, a, b *LogoutRequest) { +func compareLogoutRequest(t *testing.T, a, b *flow.LogoutRequest) { require.True(t, (a.Client != nil && b.Client != nil) || (a.Client == nil && b.Client == nil)) if a.Client != nil { assert.EqualValues(t, a.Client.GetID(), b.Client.GetID()) @@ -1004,9 +1118,8 @@ func compareLogoutRequest(t *testing.T, a, b *LogoutRequest) { assert.EqualValues(t, a.SessionID, b.SessionID) } -func compareAuthenticationRequest(t *testing.T, a, b *LoginRequest) { +func compareAuthenticationRequest(t *testing.T, a, b *flow.LoginRequest) { assert.EqualValues(t, a.Client.GetID(), b.Client.GetID()) - assert.EqualValues(t, a.ID, b.ID) assert.EqualValues(t, *a.OpenIDConnectContext, *b.OpenIDConnectContext) assert.EqualValues(t, a.Subject, b.Subject) assert.EqualValues(t, a.RequestedScope, b.RequestedScope) @@ -1017,7 +1130,7 @@ func compareAuthenticationRequest(t *testing.T, a, b *LoginRequest) { assert.EqualValues(t, a.SessionID, b.SessionID) } -func compareConsentRequest(t *testing.T, a, b *OAuth2ConsentRequest) { +func compareConsentRequest(t *testing.T, a, b *flow.OAuth2ConsentRequest) { assert.EqualValues(t, a.Client.GetID(), b.Client.GetID()) assert.EqualValues(t, a.ID, b.ID) assert.EqualValues(t, *a.OpenIDConnectContext, *b.OpenIDConnectContext) diff --git a/consent/types_test.go b/consent/types_test.go deleted file mode 100644 index 6366404d9e9..00000000000 --- a/consent/types_test.go +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package consent - -import ( - "fmt" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/ory/fosite" -) - -func TestToRFCError(t *testing.T) { - for k, tc := range []struct { - input *RequestDeniedError - expect *fosite.RFC6749Error - }{ - { - input: &RequestDeniedError{ - Name: "not empty", - valid: true, - }, - expect: &fosite.RFC6749Error{ - ErrorField: "not empty", - DescriptionField: "", - CodeField: fosite.ErrInvalidRequest.CodeField, - DebugField: "", - }, - }, - { - input: &RequestDeniedError{ - Name: "", - Description: "not empty", - valid: true, - }, - expect: &fosite.RFC6749Error{ - ErrorField: "request_denied", - DescriptionField: "not empty", - CodeField: fosite.ErrInvalidRequest.CodeField, - DebugField: "", - }, - }, - { - input: &RequestDeniedError{valid: true}, - expect: &fosite.RFC6749Error{ - ErrorField: "request_denied", - DescriptionField: "", - HintField: "", - CodeField: fosite.ErrInvalidRequest.CodeField, - DebugField: "", - }, - }, - } { - t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { - require.EqualValues(t, tc.input.toRFCError(), tc.expect) - }) - } -} - -func TestRequestDeniedError(t *testing.T) { - var e *RequestDeniedError - v, err := e.Value() - require.NoError(t, err) - assert.EqualValues(t, "{}", fmt.Sprintf("%v", v)) -} diff --git a/contrib/quickstart/gitlab/config/gitlab.rb b/contrib/quickstart/gitlab/config/gitlab.rb index 9540469d3bd..6cd8c378e34 100644 --- a/contrib/quickstart/gitlab/config/gitlab.rb +++ b/contrib/quickstart/gitlab/config/gitlab.rb @@ -70,7 +70,7 @@ ### Request duration ###! Tells the rails application how long it has to complete a request ###! This value needs to be lower than the worker timeout set in unicorn/puma. -###! By default, we'll allow 95% of the the worker timeout +###! By default, we'll allow 95% of the worker timeout # gitlab_rails['max_request_duration_seconds'] = 57 ### Email Settings diff --git a/cypress/integration/oauth2/authorize_code.js b/cypress/integration/oauth2/authorize_code.js index e204adc72ae..a6d81fe4480 100644 --- a/cypress/integration/oauth2/authorize_code.js +++ b/cypress/integration/oauth2/authorize_code.js @@ -3,91 +3,120 @@ import { prng } from "../../helpers" +const accessTokenStrategies = ["opaque", "jwt"] + describe("The OAuth 2.0 Authorization Code Grant", function () { - const nc = () => ({ - client_secret: prng(), - scope: "offline_access openid", - subject_type: "public", - token_endpoint_auth_method: "client_secret_basic", - redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = (extradata) => ({ + client_secret: prng(), + scope: "offline_access openid", + subject_type: "public", + token_endpoint_auth_method: "client_secret_basic", + redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, + ...extradata, + }) - it("should return an Access, Refresh, and ID Token when scope offline_access and openid are granted", function () { - const client = nc() - cy.authCodeFlow(client, { - consent: { scope: ["offline_access", "openid"] }, - }) + it("should return an Access, Refresh, and ID Token when scope offline_access and openid are granted", function () { + const client = nc() + cy.authCodeFlow(client, { + consent: { scope: ["offline_access", "openid"] }, + }) + + cy.get("body") + .invoke("text") + .then((content) => { + const { + result, + token: { access_token, id_token, refresh_token }, + } = JSON.parse(content) - cy.get("body") - .invoke("text") - .then((content) => { - const { - result, - token: { access_token, id_token, refresh_token }, - } = JSON.parse(content) - - expect(result).to.equal("success") - expect(access_token).to.not.be.empty - expect(id_token).to.not.be.empty - expect(refresh_token).to.not.be.empty + expect(result).to.equal("success") + expect(access_token).to.not.be.empty + expect(id_token).to.not.be.empty + expect(refresh_token).to.not.be.empty + }) }) - }) - it("should return an Access and Refresh Token when scope offline_access is granted", function () { - const client = nc() - cy.authCodeFlow(client, { consent: { scope: ["offline_access"] } }) - - cy.get("body") - .invoke("text") - .then((content) => { - const { - result, - token: { access_token, id_token, refresh_token }, - } = JSON.parse(content) - - expect(result).to.equal("success") - expect(access_token).to.not.be.empty - expect(id_token).to.be.undefined - expect(refresh_token).to.not.be.empty + it("should return an Access and Refresh Token when scope offline_access is granted", function () { + const client = nc() + cy.authCodeFlow(client, { consent: { scope: ["offline_access"] } }) + + cy.get("body") + .invoke("text") + .then((content) => { + const { + result, + token: { access_token, id_token, refresh_token }, + } = JSON.parse(content) + + expect(result).to.equal("success") + expect(access_token).to.not.be.empty + expect(id_token).to.be.undefined + expect(refresh_token).to.not.be.empty + }) }) - }) - it("should return an Access and ID Token when scope offline_access is granted", function () { - const client = nc() - cy.authCodeFlow(client, { consent: { scope: ["openid"] } }) - - cy.get("body") - .invoke("text") - .then((content) => { - const { - result, - token: { access_token, id_token, refresh_token }, - } = JSON.parse(content) - - expect(result).to.equal("success") - expect(access_token).to.not.be.empty - expect(id_token).to.not.be.empty - expect(refresh_token).to.be.undefined + it("should return an Access and ID Token when scope offline_access is granted", function () { + const client = nc() + cy.authCodeFlow(client, { consent: { scope: ["openid"] } }) + + cy.get("body") + .invoke("text") + .then((content) => { + const { + result, + token: { access_token, id_token, refresh_token }, + } = JSON.parse(content) + + expect(result).to.equal("success") + expect(access_token).to.not.be.empty + expect(id_token).to.not.be.empty + expect(refresh_token).to.be.undefined + }) }) - }) - it("should return an Access Token when no scope is granted", function () { - const client = nc() - cy.authCodeFlow(client, { consent: { scope: [] } }) - - cy.get("body") - .invoke("text") - .then((content) => { - const { - result, - token: { access_token, id_token, refresh_token }, - } = JSON.parse(content) - - expect(result).to.equal("success") - expect(access_token).to.not.be.empty - expect(id_token).to.be.undefined - expect(refresh_token).to.be.undefined + it("should return an Access Token when no scope is granted", function () { + const client = nc() + cy.authCodeFlow(client, { consent: { scope: [] } }) + + cy.get("body") + .invoke("text") + .then((content) => { + const { + result, + token: { access_token, id_token, refresh_token }, + } = JSON.parse(content) + + expect(result).to.equal("success") + expect(access_token).to.not.be.empty + expect(id_token).to.be.undefined + expect(refresh_token).to.be.undefined + }) }) + + it("should skip consent if the client is confgured thus", function () { + const client = nc({ skip_consent: true }) + cy.authCodeFlow(client, { + consent: { scope: ["offline_access", "openid"], skip: true }, + }) + + cy.get("body") + .invoke("text") + .then((content) => { + const { + result, + token: { access_token, id_token, refresh_token }, + } = JSON.parse(content) + + expect(result).to.equal("success") + expect(access_token).to.not.be.empty + expect(id_token).to.not.be.empty + expect(refresh_token).to.not.be.empty + }) + }) + }) }) }) diff --git a/cypress/integration/oauth2/authorize_error.js b/cypress/integration/oauth2/authorize_error.js index c537aa920dd..517e9d11e80 100644 --- a/cypress/integration/oauth2/authorize_error.js +++ b/cypress/integration/oauth2/authorize_error.js @@ -4,173 +4,180 @@ import { createClient, prng } from "../../helpers" import qs from "querystring" +const accessTokenStrategies = ["opaque", "jwt"] + describe("OAuth 2.0 Authorization Endpoint Error Handling", () => { - describe("rejecting login and consent requests", () => { - const nc = () => ({ - client_secret: prng(), - scope: "offline_access openid", - subject_type: "public", - token_endpoint_auth_method: "client_secret_basic", - redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + describe("rejecting login and consent requests", () => { + const nc = () => ({ + client_secret: prng(), + scope: "offline_access openid", + subject_type: "public", + token_endpoint_auth_method: "client_secret_basic", + redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, + }) - it("should return an error when rejecting login", function () { - const client = nc() - cy.authCodeFlow(client, { - login: { accept: false }, - consent: { skip: true }, - createClient: true, - }) + it("should return an error when rejecting login", function () { + const client = nc() + cy.authCodeFlow(client, { + login: { accept: false }, + consent: { skip: true }, + createClient: true, + }) + + cy.get("body") + .invoke("text") + .then((content) => { + const { + result, + error_description, + token: { access_token, id_token, refresh_token } = {}, + } = JSON.parse(content) + + expect(result).to.equal("error") + expect(error_description).to.equal( + "The resource owner denied the request", + ) + expect(access_token).to.be.undefined + expect(id_token).to.be.undefined + expect(refresh_token).to.be.undefined + }) + }) - cy.get("body") - .invoke("text") - .then((content) => { - const { - result, - error_description, - token: { access_token, id_token, refresh_token } = {}, - } = JSON.parse(content) - - expect(result).to.equal("error") - expect(error_description).to.equal( - "The resource owner denied the request", - ) - expect(access_token).to.be.undefined - expect(id_token).to.be.undefined - expect(refresh_token).to.be.undefined + it("should return an error when rejecting consent", function () { + const client = nc() + cy.authCodeFlow(client, { + consent: { accept: false }, + createClient: true, + }) + + cy.get("body") + .invoke("text") + .then((content) => { + const { + result, + error_description, + token: { access_token, id_token, refresh_token } = {}, + } = JSON.parse(content) + + expect(result).to.equal("error") + expect(error_description).to.equal( + "The resource owner denied the request", + ) + expect(access_token).to.be.undefined + expect(id_token).to.be.undefined + expect(refresh_token).to.be.undefined + }) }) - }) + }) - it("should return an error when rejecting consent", function () { - const client = nc() - cy.authCodeFlow(client, { - consent: { accept: false }, - createClient: true, + it("should return an error when an OAuth 2.0 Client ID is used that does not exist", () => { + cy.visit( + `${Cypress.env( + "client_url", + )}/oauth2/code?client_id=i-do-not-exist&client_secret=i-am-not-correct}`, + { failOnStatusCode: false }, + ) + + cy.location().should(({ search, port }) => { + const query = qs.parse(search.substr(1)) + expect(query.error).to.equal("invalid_client") + + // Should show Ory Hydra's Error URL because a redirect URL could not be determined + expect(port).to.equal(Cypress.env("public_port")) + }) }) - cy.get("body") - .invoke("text") - .then((content) => { - const { - result, - error_description, - token: { access_token, id_token, refresh_token } = {}, - } = JSON.parse(content) - - expect(result).to.equal("error") - expect(error_description).to.equal( - "The resource owner denied the request", + it("should return an error when an OAuth 2.0 Client requests a scope that is not allowed to be requested", () => { + createClient({ + client_secret: prng(), + scope: "foo", + redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], + grant_types: ["authorization_code"], + }).then((c) => { + cy.visit( + `${Cypress.env("client_url")}/oauth2/code?client_id=${ + c.client_id + }&client_secret=${c.client_secret}&scope=bar`, + { failOnStatusCode: false }, ) - expect(access_token).to.be.undefined - expect(id_token).to.be.undefined - expect(refresh_token).to.be.undefined - }) - }) - }) - it("should return an error when an OAuth 2.0 Client ID is used that does not exist", () => { - cy.visit( - `${Cypress.env( - "client_url", - )}/oauth2/code?client_id=i-do-not-exist&client_secret=i-am-not-correct}`, - { failOnStatusCode: false }, - ) + cy.location().should(({ search, port }) => { + const query = qs.parse(search.substr(1)) + expect(query.error).to.equal("invalid_scope") - cy.location().should(({ search, port }) => { - const query = qs.parse(search.substr(1)) - expect(query.error).to.equal("invalid_client") + // This is a client error so we expect the client app to show the error + expect(port).to.equal(Cypress.env("client_port")) + }) + }) + }) - // Should show Ory Hydra's Error URL because a redirect URL could not be determined - expect(port).to.equal(Cypress.env("public_port")) - }) - }) + it("should return an error when an OAuth 2.0 Client requests a response type it is not allowed to call", () => { + createClient({ + client_secret: prng(), + redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], + response_types: ["token"], // disallows Authorization Code Grant + }).then((c) => { + cy.visit( + `${Cypress.env("client_url")}/oauth2/code?client_id=${ + c.client_id + }&client_secret=${c.client_secret}`, + { failOnStatusCode: false }, + ) - it("should return an error when an OAuth 2.0 Client requests a scope that is not allowed to be requested", () => { - createClient({ - client_secret: prng(), - scope: "foo", - redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], - grant_types: ["authorization_code"], - }).then((c) => { - cy.visit( - `${Cypress.env("client_url")}/oauth2/code?client_id=${ - c.client_id - }&client_secret=${c.client_secret}&scope=bar`, - { failOnStatusCode: false }, - ) - - cy.location().should(({ search, port }) => { - const query = qs.parse(search.substr(1)) - expect(query.error).to.equal("invalid_scope") - - // This is a client error so we expect the client app to show the error - expect(port).to.equal(Cypress.env("client_port")) + cy.get("body").should("contain", "unsupported_response_type") + }) }) - }) - }) - it("should return an error when an OAuth 2.0 Client requests a response type it is not allowed to call", () => { - createClient({ - client_secret: prng(), - redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], - response_types: ["token"], // disallows Authorization Code Grant - }).then((c) => { - cy.visit( - `${Cypress.env("client_url")}/oauth2/code?client_id=${ - c.client_id - }&client_secret=${c.client_secret}`, - { failOnStatusCode: false }, - ) - - cy.get("body").should("contain", "unsupported_response_type") - }) - }) + it("should return an error when an OAuth 2.0 Client requests a grant type it is not allowed to call", () => { + createClient({ + client_secret: prng(), + redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], + grant_types: ["client_credentials"], + }).then((c) => { + cy.visit( + `${Cypress.env("client_url")}/oauth2/code?client_id=${ + c.client_id + }&client_secret=${c.client_secret}&scope=`, + { failOnStatusCode: false }, + ) - it("should return an error when an OAuth 2.0 Client requests a grant type it is not allowed to call", () => { - createClient({ - client_secret: prng(), - redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], - grant_types: ["client_credentials"], - }).then((c) => { - cy.visit( - `${Cypress.env("client_url")}/oauth2/code?client_id=${ - c.client_id - }&client_secret=${c.client_secret}&scope=`, - { failOnStatusCode: false }, - ) - - cy.get("#email").type("foo@bar.com", { delay: 1 }) - cy.get("#password").type("foobar", { delay: 1 }) - cy.get("#accept").click() - cy.get("#accept").click() - - cy.get("body").should("contain", "unauthorized_client") - }) + cy.get("#email").type("foo@bar.com", { delay: 1 }) + cy.get("#password").type("foobar", { delay: 1 }) + cy.get("#accept").click() + cy.get("#accept").click() + + cy.get("body").should("contain", "unauthorized_client") + }) - it("should return an error when an OAuth 2.0 Client requests a redirect_uri that is not preregistered", () => { - const c = { - client_secret: prng(), - redirect_uris: ["http://some-other-domain/not-callback"], - grant_types: ["client_credentials"], - } - createClient(c) - - cy.visit( - `${Cypress.env("client_url")}/oauth2/code?client_id=${ - c.client_id - }&client_secret=${c.client_secret}&scope=`, - { failOnStatusCode: false }, - ) - - cy.location().should(({ search, port }) => { - const query = qs.parse(search.substr(1)) - console.log(query) - expect(query.error).to.equal("invalid_request") - expect(query.error_description).to.contain("redirect_uri") - - // Should show Ory Hydra's Error URL because a redirect URL could not be determined - expect(port).to.equal(Cypress.env("public_port")) + it("should return an error when an OAuth 2.0 Client requests a redirect_uri that is not preregistered", () => { + const c = { + client_secret: prng(), + redirect_uris: ["http://some-other-domain/not-callback"], + grant_types: ["client_credentials"], + } + createClient(c) + + cy.visit( + `${Cypress.env("client_url")}/oauth2/code?client_id=${ + c.client_id + }&client_secret=${c.client_secret}&scope=`, + { failOnStatusCode: false }, + ) + + cy.location().should(({ search, port }) => { + const query = qs.parse(search.substr(1)) + console.log(query) + expect(query.error).to.equal("invalid_request") + expect(query.error_description).to.contain("redirect_uri") + + // Should show Ory Hydra's Error URL because a redirect URL could not be determined + expect(port).to.equal(Cypress.env("public_port")) + }) + }) }) }) }) diff --git a/cypress/integration/oauth2/client_creds.js b/cypress/integration/oauth2/client_creds.js index a1419e8b1bd..04f31bf9c23 100644 --- a/cypress/integration/oauth2/client_creds.js +++ b/cypress/integration/oauth2/client_creds.js @@ -3,33 +3,40 @@ import { createClient, prng } from "../../helpers" +const accessTokenStrategies = ["opaque", "jwt"] + describe("The OAuth 2.0 Authorization Code Grant", function () { - const nc = () => ({ - client_secret: prng(), - scope: "foo openid offline_access", - grant_types: ["client_credentials"], - }) + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = () => ({ + client_secret: prng(), + scope: "foo openid offline_access", + grant_types: ["client_credentials"], + access_token_strategy: accessTokenStrategy, + }) - it("should return an Access Token but not Refresh or ID Token for client_credentials flow", function () { - createClient(nc()).then((client) => { - cy.request( - `${Cypress.env("client_url")}/oauth2/cc?client_id=${ - client.client_id - }&client_secret=${client.client_secret}&scope=${client.scope}`, - { failOnStatusCode: false }, - ) - .its("body") - .then((body) => { - const { - result, - token: { access_token, id_token, refresh_token } = {}, - } = body + it("should return an Access Token but not Refresh or ID Token for client_credentials flow", function () { + createClient(nc()).then((client) => { + cy.request( + `${Cypress.env("client_url")}/oauth2/cc?client_id=${ + client.client_id + }&client_secret=${client.client_secret}&scope=${client.scope}`, + { failOnStatusCode: false }, + ) + .its("body") + .then((body) => { + const { + result, + token: { access_token, id_token, refresh_token } = {}, + } = body - expect(result).to.equal("success") - expect(access_token).to.not.be.empty - expect(id_token).to.be.undefined - expect(refresh_token).to.be.undefined + expect(result).to.equal("success") + expect(access_token).to.not.be.empty + expect(id_token).to.be.undefined + expect(refresh_token).to.be.undefined + }) }) + }) }) }) }) diff --git a/cypress/integration/oauth2/consent.js b/cypress/integration/oauth2/consent.js index 5e9829312d2..4d2614a3be1 100644 --- a/cypress/integration/oauth2/consent.js +++ b/cypress/integration/oauth2/consent.js @@ -3,89 +3,99 @@ import { createClient, prng } from "../../helpers" -describe("OAuth 2.0 End-User Authorization", () => { - const nc = () => ({ - client_secret: prng(), - scope: "offline_access", - redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) - - const hasConsent = (client, body) => { - let found = false - body.forEach( - ({ - consent_request: { - client: { client_id }, - }, - }) => { - if (client_id === client.client_id) { - found = true - } - }, - ) - return found - } +const accessTokenStrategies = ["opaque", "jwt"] - it("should check if end user authorization exists", () => { - createClient(nc()).then((client) => { - cy.authCodeFlow(client, { - consent: { - scope: ["offline_access"], - remember: true, - }, - createClient: false, +describe("OAuth 2.0 End-User Authorization", () => { + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = () => ({ + client_secret: prng(), + scope: "offline_access", + redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, }) - console.log("got ", { client }) + const hasConsent = (client, body) => { + let found = false + body.forEach( + ({ + consent_request: { + client: { client_id }, + }, + }) => { + if (client_id === client.client_id) { + found = true + } + }, + ) + return found + } - cy.request( - Cypress.env("admin_url") + - "/oauth2/auth/sessions/consent?subject=foo@bar.com", - ) - .its("body") - .then((body) => { - expect(body.length).to.be.greaterThan(0) - console.log({ body, client }) - expect(hasConsent(client, body)).to.be.true - body.forEach((consent) => { - expect( - consent.handled_at.match( - /^[2-9]\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, - ), - ).not.to.be.empty + it("should check if end user authorization exists", () => { + createClient(nc()).then((client) => { + cy.authCodeFlow(client, { + consent: { + scope: ["offline_access"], + remember: true, + }, + createClient: false, }) - }) - cy.request( - "DELETE", - Cypress.env("admin_url") + - "/oauth2/auth/sessions/consent?subject=foo@bar.com&all=true", - ) + console.log("got ", { client }) - cy.request( - Cypress.env("admin_url") + - "/oauth2/auth/sessions/consent?subject=foo@bar.com", - ) - .its("body") - .then((body) => { - expect(body.length).to.eq(0) - expect(hasConsent(client, body)).to.be.false - }) + cy.request( + Cypress.env("admin_url") + + "/oauth2/auth/sessions/consent?subject=foo@bar.com", + ) + .its("body") + .then((body) => { + expect(body.length).to.be.greaterThan(0) + console.log({ + body, + client, + }) + expect(hasConsent(client, body)).to.be.true + body.forEach((consent) => { + expect( + consent.handled_at.match( + /^[2-9]\d{3}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/, + ), + ).not.to.be.empty + }) + }) - cy.request(`${Cypress.env("client_url")}/oauth2/introspect/at`) - .its("body") - .then((body) => { - expect(body.result).to.equal("success") - expect(body.body.active).to.be.false - }) + cy.request( + "DELETE", + Cypress.env("admin_url") + + "/oauth2/auth/sessions/consent?subject=foo@bar.com&all=true", + ) + + cy.request( + Cypress.env("admin_url") + + "/oauth2/auth/sessions/consent?subject=foo@bar.com", + ) + .its("body") + .then((body) => { + expect(body.length).to.eq(0) + expect(hasConsent(client, body)).to.be.false + }) - cy.request(`${Cypress.env("client_url")}/oauth2/introspect/rt`) - .its("body") - .then((body) => { - expect(body.result).to.equal("success") - expect(body.body.active).to.be.false + cy.request(`${Cypress.env("client_url")}/oauth2/introspect/at`) + .its("body") + .then((body) => { + expect(body.result).to.equal("success") + expect(body.body.active).to.be.false + }) + + cy.request(`${Cypress.env("client_url")}/oauth2/introspect/rt`) + .its("body") + .then((body) => { + expect(body.result).to.equal("success") + expect(body.body.active).to.be.false + }) }) + }) }) }) }) diff --git a/cypress/integration/oauth2/grant_jwtbearer.js b/cypress/integration/oauth2/grant_jwtbearer.js index ccb2aac87aa..3ca08d3b4db 100644 --- a/cypress/integration/oauth2/grant_jwtbearer.js +++ b/cypress/integration/oauth2/grant_jwtbearer.js @@ -58,491 +58,512 @@ const initTestKeyPairs = async () => { invalidtestPrivatePem = invalidPrivatePem } -describe("The OAuth 2.0 JWT Bearer (RFC 7523) Grant", function () { - beforeEach(() => { - deleteGrants() - deleteClients() - }) - - before(() => { - return cy.wrap(initTestKeyPairs()) - }) - - const tokenUrl = `${Cypress.env("public_url")}/oauth2/token` - - const nc = () => ({ - client_secret: prng(), - scope: "foo openid offline_access", - grant_types: ["urn:ietf:params:oauth:grant-type:jwt-bearer"], - token_endpoint_auth_method: "client_secret_post", - response_types: ["token"], - }) - - const gr = (subject) => ({ - issuer: prng(), - subject: subject, - allow_any_subject: subject === "", - scope: ["foo", "openid", "offline_access"], - jwk: testPublicJwk, - expires_at: dayjs() - .utc() - .add(1, "year") - .set("millisecond", 0) - .toISOString(), - }) - - const jwtAssertion = (grant, override) => { - const assert = { - jti: prng(), - iss: grant.issuer, - sub: grant.subject, - aud: tokenUrl, - exp: dayjs().utc().add(2, "minute").set("millisecond", 0).unix(), - iat: dayjs().utc().subtract(2, "minute").set("millisecond", 0).unix(), - } - return { ...assert, ...override } - } - - it("should return an Access Token when given client credentials and a signed JWT assertion", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - const assertion = jwt.sign(jwtAssertion(grant), testPrivatePem, { - algorithm: "RS256", +const accessTokenStrategies = ["opaque", "jwt"] + +accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + describe("The OAuth 2.0 JWT Bearer (RFC 7523) Grant", function () { + beforeEach(() => { + deleteGrants() + deleteClients() }) - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, + before(() => { + return cy.wrap(initTestKeyPairs()) }) - .its("body") - .then((body) => { - const { access_token, expires_in, scope, token_type } = body - - expect(access_token).to.not.be.empty - expect(expires_in).to.not.be.undefined - expect(scope).to.not.be.empty - expect(token_type).to.not.be.empty - }) - }) - }) - it("should return an Error (400) when not given client credentials", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) + const tokenUrl = `${Cypress.env("public_url")}/oauth2/token` - const assertion = jwt.sign(jwtAssertion(grant), testPrivatePem, { - algorithm: "RS256", + const nc = () => ({ + client_secret: prng(), + scope: "foo openid offline_access", + grant_types: ["urn:ietf:params:oauth:grant-type:jwt-bearer"], + token_endpoint_auth_method: "client_secret_post", + response_types: ["token"], + access_token_strategy: accessTokenStrategy, }) - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - }, - failOnStatusCode: false, + const gr = (subject) => ({ + issuer: prng(), + subject: subject, + allow_any_subject: subject === "", + scope: ["foo", "openid", "offline_access"], + jwk: testPublicJwk, + expires_at: dayjs() + .utc() + .add(1, "year") + .set("millisecond", 0) + .toISOString(), }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) - }) - }) - }) - it("should return an Error (400) when given client credentials and a JWT assertion without a jti", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - var ja = jwtAssertion(grant) - delete ja["jti"] - const assertion = jwt.sign(ja, testPrivatePem, { algorithm: "RS256" }) - - // first token request should work fine - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - failOnStatusCode: false, - }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) + const jwtAssertion = (grant, override) => { + const assert = { + jti: prng(), + iss: grant.issuer, + sub: grant.subject, + aud: tokenUrl, + exp: dayjs().utc().add(2, "minute").set("millisecond", 0).unix(), + iat: dayjs().utc().subtract(2, "minute").set("millisecond", 0).unix(), + } + return { ...assert, ...override } + } + + it("should return an Access Token when given client credentials and a signed JWT assertion", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const assertion = jwt.sign(jwtAssertion(grant), testPrivatePem, { + algorithm: "RS256", + }) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + }) + .its("body") + .then((body) => { + const { access_token, expires_in, scope, token_type } = body + + expect(access_token).to.not.be.empty + expect(expires_in).to.not.be.undefined + expect(scope).to.not.be.empty + expect(token_type).to.not.be.empty + }) }) - }) - }) - - it("should return an Error (400) when given client credentials and a JWT assertion with a duplicated jti", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - const jwt1 = jwtAssertion(grant) - const assertion1 = jwt.sign(jwt1, testPrivatePem, { algorithm: "RS256" }) - - // first token request should work fine - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion1, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, }) - .its("body") - .then((body) => { - const { access_token, expires_in, scope, token_type } = body - - expect(access_token).to.not.be.empty - expect(expires_in).to.not.be.undefined - expect(scope).to.not.be.empty - expect(token_type).to.not.be.empty - }) - const assertion2 = jwt.sign( - jwtAssertion(grant, { jti: jwt1["jti"] }), - testPrivatePem, - { algorithm: "RS256" }, - ) - - // the second should fail - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion2, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - failOnStatusCode: false, - }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) + it("should return an Error (400) when not given client credentials", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const assertion = jwt.sign(jwtAssertion(grant), testPrivatePem, { + algorithm: "RS256", + }) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) }) - }) - }) - - it("should return an Error (400) when given client credentials and a JWT assertion without an iat", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - var ja = jwtAssertion(grant) - delete ja["iat"] - const assertion = jwt.sign(ja, testPrivatePem, { - algorithm: "RS256", - noTimestamp: true, }) - // first token request should work fine - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - failOnStatusCode: false, - }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) + it("should return an Error (400) when given client credentials and a JWT assertion without a jti", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + var ja = jwtAssertion(grant) + delete ja["jti"] + const assertion = jwt.sign(ja, testPrivatePem, { algorithm: "RS256" }) + + // first token request should work fine + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) }) - }) - }) - - it("should return an Error (400) when given client credentials and a JWT assertion with an invalid signature", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - const assertion = jwt.sign(jwtAssertion(grant), invalidtestPrivatePem, { - algorithm: "RS256", }) - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - failOnStatusCode: false, - }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) + it("should return an Error (400) when given client credentials and a JWT assertion with a duplicated jti", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const jwt1 = jwtAssertion(grant) + const assertion1 = jwt.sign(jwt1, testPrivatePem, { + algorithm: "RS256", + }) + + // first token request should work fine + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion1, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + }) + .its("body") + .then((body) => { + const { access_token, expires_in, scope, token_type } = body + + expect(access_token).to.not.be.empty + expect(expires_in).to.not.be.undefined + expect(scope).to.not.be.empty + expect(token_type).to.not.be.empty + }) + + const assertion2 = jwt.sign( + jwtAssertion(grant, { jti: jwt1["jti"] }), + testPrivatePem, + { algorithm: "RS256" }, + ) + + // the second should fail + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion2, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) }) - }) - }) - - it("should return an Error (400) when given client credentials and a JWT assertion with an invalid subject", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - const assertion = jwt.sign( - jwtAssertion(grant, { sub: "invalid_subject" }), - testPrivatePem, - { algorithm: "RS256" }, - ) - - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - failOnStatusCode: false, }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) - }) - }) - }) - it("should return an Access Token when given client credentials and a JWT assertion with any subject", function () { - createClient(nc()).then((client) => { - const grant = gr("") // allow any subject - createGrant(grant) - - const assertion = jwt.sign( - jwtAssertion(grant, { sub: "any-subject-is-valid" }), - testPrivatePem, - { - algorithm: "RS256", - }, - ) - - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - }) - .its("body") - .then((body) => { - const { access_token, expires_in, scope, token_type } = body - - expect(access_token).to.not.be.empty - expect(expires_in).to.not.be.undefined - expect(scope).to.not.be.empty - expect(token_type).to.not.be.empty + it("should return an Error (400) when given client credentials and a JWT assertion without an iat", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + var ja = jwtAssertion(grant) + delete ja["iat"] + const assertion = jwt.sign(ja, testPrivatePem, { + algorithm: "RS256", + noTimestamp: true, + }) + + // first token request should work fine + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) }) - }) - }) - - it("should return an Error (400) when given client credentials and a JWT assertion with an invalid issuer", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - const assertion = jwt.sign( - jwtAssertion(grant, { iss: "invalid_issuer" }), - testPrivatePem, - { algorithm: "RS256" }, - ) - - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - failOnStatusCode: false, }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) - }) - }) - }) - it("should return an Error (400) when given client credentials and a JWT assertion with an invalid audience", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - const assertion = jwt.sign( - jwtAssertion(grant, { aud: "invalid_audience" }), - testPrivatePem, - { algorithm: "RS256" }, - ) - - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - failOnStatusCode: false, + it("should return an Error (400) when given client credentials and a JWT assertion with an invalid signature", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const assertion = jwt.sign( + jwtAssertion(grant), + invalidtestPrivatePem, + { + algorithm: "RS256", + }, + ) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) + }) }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) + + it("should return an Error (400) when given client credentials and a JWT assertion with an invalid subject", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const assertion = jwt.sign( + jwtAssertion(grant, { sub: "invalid_subject" }), + testPrivatePem, + { algorithm: "RS256" }, + ) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) }) - }) - }) + }) - it("should return an Error (400) when given client credentials and a JWT assertion with an expired date", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - const assertion = jwt.sign( - jwtAssertion(grant, { - exp: dayjs().utc().subtract(1, "minute").set("millisecond", 0).unix(), - }), - testPrivatePem, - { algorithm: "RS256" }, - ) - - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - failOnStatusCode: false, + it("should return an Access Token when given client credentials and a JWT assertion with any subject", function () { + createClient(nc()).then((client) => { + const grant = gr("") // allow any subject + createGrant(grant) + + const assertion = jwt.sign( + jwtAssertion(grant, { sub: "any-subject-is-valid" }), + testPrivatePem, + { + algorithm: "RS256", + }, + ) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + }) + .its("body") + .then((body) => { + const { access_token, expires_in, scope, token_type } = body + + expect(access_token).to.not.be.empty + expect(expires_in).to.not.be.undefined + expect(scope).to.not.be.empty + expect(token_type).to.not.be.empty + }) + }) }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) + + it("should return an Error (400) when given client credentials and a JWT assertion with an invalid issuer", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const assertion = jwt.sign( + jwtAssertion(grant, { iss: "invalid_issuer" }), + testPrivatePem, + { algorithm: "RS256" }, + ) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) }) - }) - }) + }) - it("should return an Error (400) when given client credentials and a JWT assertion with a nbf that is still not valid", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - const assertion = jwt.sign( - jwtAssertion(grant, { - nbf: dayjs().utc().add(1, "minute").set("millisecond", 0).unix(), - }), - testPrivatePem, - { algorithm: "RS256" }, - ) - - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, - failOnStatusCode: false, + it("should return an Error (400) when given client credentials and a JWT assertion with an invalid audience", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const assertion = jwt.sign( + jwtAssertion(grant, { aud: "invalid_audience" }), + testPrivatePem, + { algorithm: "RS256" }, + ) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) + }) }) - .its("status") - .then((status) => { - expect(status).to.be.equal(400) + + it("should return an Error (400) when given client credentials and a JWT assertion with an expired date", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const assertion = jwt.sign( + jwtAssertion(grant, { + exp: dayjs() + .utc() + .subtract(1, "minute") + .set("millisecond", 0) + .unix(), + }), + testPrivatePem, + { algorithm: "RS256" }, + ) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) }) - }) - }) + }) - it("should return an Access Token when given client credentials and a JWT assertion with a nbf that is valid", function () { - createClient(nc()).then((client) => { - const grant = gr(prng()) - createGrant(grant) - - const assertion = jwt.sign( - jwtAssertion(grant, { - nbf: dayjs().utc().subtract(1, "minute").set("millisecond", 0).unix(), - }), - testPrivatePem, - { algorithm: "RS256" }, - ) - - cy.request({ - method: "POST", - url: tokenUrl, - form: true, - body: { - grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", - assertion: assertion, - scope: client.scope, - client_secret: client.client_secret, - client_id: client.client_id, - }, + it("should return an Error (400) when given client credentials and a JWT assertion with a nbf that is still not valid", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const assertion = jwt.sign( + jwtAssertion(grant, { + nbf: dayjs().utc().add(1, "minute").set("millisecond", 0).unix(), + }), + testPrivatePem, + { algorithm: "RS256" }, + ) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + failOnStatusCode: false, + }) + .its("status") + .then((status) => { + expect(status).to.be.equal(400) + }) + }) }) - .its("body") - .then((body) => { - const { access_token, expires_in, scope, token_type } = body - - expect(access_token).to.not.be.empty - expect(expires_in).to.not.be.undefined - expect(scope).to.not.be.empty - expect(token_type).to.not.be.empty + + it("should return an Access Token when given client credentials and a JWT assertion with a nbf that is valid", function () { + createClient(nc()).then((client) => { + const grant = gr(prng()) + createGrant(grant) + + const assertion = jwt.sign( + jwtAssertion(grant, { + nbf: dayjs() + .utc() + .subtract(1, "minute") + .set("millisecond", 0) + .unix(), + }), + testPrivatePem, + { algorithm: "RS256" }, + ) + + cy.request({ + method: "POST", + url: tokenUrl, + form: true, + body: { + grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer", + assertion: assertion, + scope: client.scope, + client_secret: client.client_secret, + client_id: client.client_id, + }, + }) + .its("body") + .then((body) => { + const { access_token, expires_in, scope, token_type } = body + + expect(access_token).to.not.be.empty + expect(expires_in).to.not.be.undefined + expect(scope).to.not.be.empty + expect(token_type).to.not.be.empty + }) }) + }) }) }) }) diff --git a/cypress/integration/oauth2/introspect.js b/cypress/integration/oauth2/introspect.js index 655b7fb4cfc..c2dfd5feb1c 100644 --- a/cypress/integration/oauth2/introspect.js +++ b/cypress/integration/oauth2/introspect.js @@ -3,59 +3,72 @@ import { prng } from "../../helpers" +const accessTokenStrategies = ["opaque", "jwt"] + describe("OpenID Connect Token Introspection", () => { - const nc = () => ({ - client_secret: prng(), - scope: "offline_access", - redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = () => ({ + client_secret: prng(), + scope: "offline_access", + redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, + }) - it("should introspect access token", function () { - const client = nc() - cy.authCodeFlow(client, { - consent: { scope: ["offline_access"], createClient: true }, - }) + it("should introspect access token", function () { + const client = nc() + cy.authCodeFlow(client, { + consent: { + scope: ["offline_access"], + createClient: true, + }, + }) - cy.get("body") - .invoke("text") - .then((content) => { - const { result } = JSON.parse(content) - expect(result).to.equal("success") - }) + cy.get("body") + .invoke("text") + .then((content) => { + const { result } = JSON.parse(content) + expect(result).to.equal("success") + }) - cy.request(`${Cypress.env("client_url")}/oauth2/introspect/at`) - .its("body") - .then((body) => { - expect(body.result).to.equal("success") - expect(body.body.active).to.be.true - expect(body.body.sub).to.be.equal("foo@bar.com") - expect(body.body.token_type).to.be.equal("Bearer") - expect(body.body.token_use).to.be.equal("access_token") + cy.request(`${Cypress.env("client_url")}/oauth2/introspect/at`) + .its("body") + .then((body) => { + expect(body.result).to.equal("success") + expect(body.body.active).to.be.true + expect(body.body.sub).to.be.equal("foo@bar.com") + expect(body.body.token_type).to.be.equal("Bearer") + expect(body.body.token_use).to.be.equal("access_token") + }) }) - }) - it("should introspect refresh token", function () { - const client = nc() - cy.authCodeFlow(client, { - consent: { scope: ["offline_access"], createClient: true }, - }) + it("should introspect refresh token", function () { + const client = nc() + cy.authCodeFlow(client, { + consent: { + scope: ["offline_access"], + createClient: true, + }, + }) - cy.get("body") - .invoke("text") - .then((content) => { - const { result } = JSON.parse(content) - expect(result).to.equal("success") - }) + cy.get("body") + .invoke("text") + .then((content) => { + const { result } = JSON.parse(content) + expect(result).to.equal("success") + }) - cy.request(`${Cypress.env("client_url")}/oauth2/introspect/rt`) - .its("body") - .then((body) => { - expect(body.result).to.equal("success") - expect(body.body.active).to.be.true - expect(body.body.sub).to.be.equal("foo@bar.com") - expect(body.body.token_type).to.be.equal("Bearer") - expect(body.body.token_use).to.be.equal("refresh_token") + cy.request(`${Cypress.env("client_url")}/oauth2/introspect/rt`) + .its("body") + .then((body) => { + expect(body.result).to.equal("success") + expect(body.body.active).to.be.true + expect(body.body.sub).to.be.equal("foo@bar.com") + expect(body.body.token_type).to.be.equal("Bearer") + expect(body.body.token_use).to.be.equal("refresh_token") + }) }) + }) }) }) diff --git a/cypress/integration/oauth2/jwt.js b/cypress/integration/oauth2/jwt.js index 5054cfee0f2..8b9d0fe78f8 100644 --- a/cypress/integration/oauth2/jwt.js +++ b/cypress/integration/oauth2/jwt.js @@ -3,51 +3,59 @@ import { createClient, prng } from "../../helpers" -describe("OAuth 2.0 JSON Web Token Access Tokens", () => { - before(function () { - // this must be a function otherwise this.skip() fails because the context is wrong - if ( - Cypress.env("jwt_enabled") !== "true" && - !Boolean(Cypress.env("jwt_enabled")) - ) { - this.skip() - } - }) +const accessTokenStrategies = ["opaque", "jwt"] - const nc = () => ({ - client_secret: prng(), - scope: "offline_access", - redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) +describe("OAuth 2.0 JSON Web Token Access Tokens", () => { + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + before(function () { + // this must be a function otherwise this.skip() fails because the context is wrong + if ( + accessTokenStrategy === "opaque" || + (Cypress.env("jwt_enabled") !== "true" && + !Boolean(Cypress.env("jwt_enabled"))) + ) { + this.skip() + } + }) - it("should return an Access Token in JWT format and validate it and a Refresh Token in opaque format", () => { - createClient(nc()).then((client) => { - cy.authCodeFlow(client, { - consent: { scope: ["offline_access"], createClient: true }, - createClient: false, + const nc = () => ({ + client_secret: prng(), + scope: "offline_access", + redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, }) - cy.request(`${Cypress.env("client_url")}/oauth2/refresh`) - .its("body") - .then((body) => { - const { result, token } = body - expect(result).to.equal("success") + it("should return an Access Token in JWT format and validate it and a Refresh Token in opaque format", () => { + createClient(nc()).then((client) => { + cy.authCodeFlow(client, { + consent: { scope: ["offline_access"], createClient: true }, + createClient: false, + }) - expect(token.access_token).to.not.be.empty - expect(token.refresh_token).to.not.be.empty - expect(token.access_token.split(".").length).to.equal(3) - expect(token.refresh_token.split(".").length).to.equal(2) - }) + cy.request(`${Cypress.env("client_url")}/oauth2/refresh`) + .its("body") + .then((body) => { + const { result, token } = body + expect(result).to.equal("success") - cy.request(`${Cypress.env("client_url")}/oauth2/validate-jwt`) - .its("body") - .then((body) => { - console.log(body) - expect(body.sub).to.eq("foo@bar.com") - expect(body.client_id).to.eq(client.client_id) - expect(body.jti).to.not.be.empty + expect(token.access_token).to.not.be.empty + expect(token.refresh_token).to.not.be.empty + expect(token.access_token.split(".").length).to.equal(3) + expect(token.refresh_token.split(".").length).to.equal(2) + }) + + cy.request(`${Cypress.env("client_url")}/oauth2/validate-jwt`) + .its("body") + .then((body) => { + console.log(body) + expect(body.sub).to.eq("foo@bar.com") + expect(body.client_id).to.eq(client.client_id) + expect(body.jti).to.not.be.empty + }) }) + }) }) }) }) diff --git a/cypress/integration/oauth2/refresh_token.js b/cypress/integration/oauth2/refresh_token.js index a3b1c6282bf..fbbbf36e80b 100644 --- a/cypress/integration/oauth2/refresh_token.js +++ b/cypress/integration/oauth2/refresh_token.js @@ -3,89 +3,102 @@ import { createClient, prng } from "../../helpers" +const accessTokenStrategies = ["opaque", "jwt"] + describe("The OAuth 2.0 Refresh Token Grant", function () { - const nc = () => ({ - client_secret: prng(), - scope: "offline_access openid", - redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = () => ({ + client_secret: prng(), + scope: "offline_access openid", + redirect_uris: [`${Cypress.env("client_url")}/oauth2/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, + }) - it("should return an Access and Refresh Token and refresh the Access Token", function () { - const client = nc() - cy.authCodeFlow(client, { - consent: { scope: ["offline_access"], createClient: true }, - }) + it("should return an Access and Refresh Token and refresh the Access Token", function () { + const client = nc() + cy.authCodeFlow(client, { + consent: { + scope: ["offline_access"], + createClient: true, + }, + }) - cy.request(`${Cypress.env("client_url")}/oauth2/refresh`) - .its("body") - .then((body) => { - const { result, token } = body - expect(result).to.equal("success") - expect(token.access_token).to.not.be.empty - expect(token.refresh_token).to.not.be.empty + cy.request(`${Cypress.env("client_url")}/oauth2/refresh`) + .its("body") + .then((body) => { + const { result, token } = body + expect(result).to.equal("success") + expect(token.access_token).to.not.be.empty + expect(token.refresh_token).to.not.be.empty + }) }) - }) - it("should return an Access, ID, and Refresh Token and refresh the Access Token and ID Token", function () { - const client = nc() - cy.authCodeFlow(client, { - consent: { scope: ["offline_access", "openid"], createClient: true }, - }) + it("should return an Access, ID, and Refresh Token and refresh the Access Token and ID Token", function () { + const client = nc() + cy.authCodeFlow(client, { + consent: { + scope: ["offline_access", "openid"], + createClient: true, + }, + }) - cy.request(`${Cypress.env("client_url")}/oauth2/refresh`) - .its("body") - .then((body) => { - const { result, token } = body - expect(result).to.equal("success") - expect(token.access_token).to.not.be.empty - expect(token.id_token).to.not.be.empty - expect(token.refresh_token).to.not.be.empty + cy.request(`${Cypress.env("client_url")}/oauth2/refresh`) + .its("body") + .then((body) => { + const { result, token } = body + expect(result).to.equal("success") + expect(token.access_token).to.not.be.empty + expect(token.id_token).to.not.be.empty + expect(token.refresh_token).to.not.be.empty + }) }) - }) - it("should revoke Refresh Token on reuse", function () { - const referrer = `${Cypress.env("client_url")}/empty` - cy.visit(referrer, { - failOnStatusCode: false, - }) + it("should revoke Refresh Token on reuse", function () { + const referrer = `${Cypress.env("client_url")}/empty` + cy.visit(referrer, { + failOnStatusCode: false, + }) - createClient({ - scope: "offline_access", - redirect_uris: [referrer], - grant_types: ["authorization_code", "refresh_token"], - response_types: ["code"], - token_endpoint_auth_method: "none", - }).then((client) => { - cy.authCodeFlowBrowser(client, { - consent: { scope: ["offline_access"] }, - createClient: false, - }).then((originalResponse) => { - expect(originalResponse.status).to.eq(200) - expect(originalResponse.body.refresh_token).to.not.be.empty + createClient({ + scope: "offline_access", + redirect_uris: [referrer], + grant_types: ["authorization_code", "refresh_token"], + response_types: ["code"], + token_endpoint_auth_method: "none", + }).then((client) => { + cy.authCodeFlowBrowser(client, { + consent: { scope: ["offline_access"] }, + createClient: false, + }).then((originalResponse) => { + expect(originalResponse.status).to.eq(200) + expect(originalResponse.body.refresh_token).to.not.be.empty - const originalToken = originalResponse.body.refresh_token + const originalToken = originalResponse.body.refresh_token - cy.refreshTokenBrowser(client, originalToken).then( - (refreshedResponse) => { - expect(refreshedResponse.status).to.eq(200) - expect(refreshedResponse.body.refresh_token).to.not.be.empty + cy.refreshTokenBrowser(client, originalToken).then( + (refreshedResponse) => { + expect(refreshedResponse.status).to.eq(200) + expect(refreshedResponse.body.refresh_token).to.not.be.empty - const refreshedToken = refreshedResponse.body.refresh_token + const refreshedToken = refreshedResponse.body.refresh_token - return cy - .refreshTokenBrowser(client, originalToken) - .then((response) => { - expect(response.status).to.eq(401) - expect(response.body.error).to.eq("token_inactive") - }) - .then(() => cy.refreshTokenBrowser(client, refreshedToken)) - .then((response) => { - expect(response.status).to.eq(401) - expect(response.body.error).to.eq("token_inactive") - }) - }, - ) + return cy + .refreshTokenBrowser(client, originalToken) + .then((response) => { + expect(response.status).to.eq(401) + expect(response.body.error).to.eq("token_inactive") + }) + .then(() => cy.refreshTokenBrowser(client, refreshedToken)) + .then((response) => { + expect(response.status).to.eq(401) + expect(response.body.error).to.eq("token_inactive") + }) + }, + ) + }) + }) }) }) }) diff --git a/cypress/integration/openid/authorize_code.js b/cypress/integration/openid/authorize_code.js index 96d2a594578..7449249ca56 100644 --- a/cypress/integration/openid/authorize_code.js +++ b/cypress/integration/openid/authorize_code.js @@ -3,36 +3,43 @@ import { prng } from "../../helpers" +const accessTokenStrategies = ["opaque", "jwt"] + describe("OpenID Connect Authorize Code Grant", () => { - const nc = () => ({ - client_secret: prng(), - scope: "openid", - subject_type: "public", - token_endpoint_auth_method: "client_secret_basic", - redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = () => ({ + client_secret: prng(), + scope: "openid", + subject_type: "public", + token_endpoint_auth_method: "client_secret_basic", + redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, + }) - it("should return an access, refresh, and ID token", function () { - const client = nc() - cy.authCodeFlow(client, { consent: { scope: ["openid"] } }, "openid") + it("should return an access, refresh, and ID token", function () { + const client = nc() + cy.authCodeFlow(client, { consent: { scope: ["openid"] } }, "openid") - cy.get("body") - .invoke("text") - .then((content) => { - const { - result, - token: { access_token, id_token, refresh_token }, - claims: { sub, sid }, - } = JSON.parse(content) + cy.get("body") + .invoke("text") + .then((content) => { + const { + result, + token: { access_token, id_token, refresh_token }, + claims: { sub, sid }, + } = JSON.parse(content) - expect(result).to.equal("success") - expect(access_token).to.not.be.empty - expect(id_token).to.not.be.empty - expect(refresh_token).to.be.undefined + expect(result).to.equal("success") + expect(access_token).to.not.be.empty + expect(id_token).to.not.be.empty + expect(refresh_token).to.be.undefined - expect(sub).to.eq("foo@bar.com") - expect(sid).to.not.be.empty + expect(sub).to.eq("foo@bar.com") + expect(sid).to.not.be.empty + }) }) + }) }) }) diff --git a/cypress/integration/openid/logout.js b/cypress/integration/openid/logout.js index 4495198d109..1de78c3917d 100644 --- a/cypress/integration/openid/logout.js +++ b/cypress/integration/openid/logout.js @@ -3,207 +3,236 @@ import { deleteClients, prng } from "../../helpers" -const nc = () => ({ - client_secret: prng(), - scope: "openid", - subject_type: "public", - redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], - grant_types: ["authorization_code"], -}) - -describe("OpenID Connect Logout", () => { - before(() => { - cy.clearCookies({ domain: null }) - }) - - after(() => { - deleteClients() - }) - - describe("logout without id_token_hint", () => { - beforeEach(() => { - Cypress.Cookies.preserveOnce( - "oauth2_authentication_session", - "oauth2_authentication_session_insecure", - "connect.sid", - ) - }) - - before(() => { - deleteClients() +const accessTokenStrategies = ["opaque", "jwt"] + +accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = () => ({ + client_secret: prng(), + scope: "openid", + subject_type: "public", + redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], + grant_types: ["authorization_code"], + access_token_strategy: accessTokenStrategy, }) - const client = { - ...nc(), - backchannel_logout_uri: `${Cypress.env( - "client_url", - )}/openid/session/end/bc`, - } - - it("should log in and remember login without id_token_hint", function () { - cy.authCodeFlow( - client, - { - login: { remember: true }, - consent: { scope: ["openid"], remember: true }, - }, - "openid", - ) - - cy.request(`${Cypress.env("client_url")}/openid/session/check`) - .its("body") - .then(({ has_session }) => { - expect(has_session).to.be.true - }) - }) - - it("should show the logout page and complete logout without id_token_hint", () => { - // cy.request(`${Cypress.env('client_url')}/openid/session/check`) - // .its('body') - // .then(({ has_session }) => { - // expect(has_session).to.be.true; - // }); - - cy.visit(`${Cypress.env("client_url")}/openid/session/end?simple=1`, { - failOnStatusCode: false, + describe("OpenID Connect Logout", () => { + before(() => { + cy.clearCookies({ domain: null }) }) - cy.get("#accept").click() - - cy.get("h1").should("contain", "Your log out request however succeeded.") - }) - - it("should show the login screen again because we logged out", () => { - cy.authCodeFlow( - client, - { - login: { remember: false }, // login should have skip false because we removed the session.mak - consent: { scope: ["openid"], remember: false, skip: true }, - createClient: false, - }, - "openid", - ) - }) - }) - - // The Back-Channel test should run before the front-channel test because otherwise both tests need a long time to finish. - describe.only("Back-Channel", () => { - beforeEach(() => { - Cypress.Cookies.preserveOnce( - "oauth2_authentication_session", - "oauth2_authentication_session_insecure", - "connect.sid", - ) - }) + after(() => { + deleteClients() + }) - before(() => { - deleteClients() - }) + describe("logout without id_token_hint", () => { + beforeEach(() => { + Cypress.Cookies.preserveOnce( + "oauth2_authentication_session", + "oauth2_authentication_session_insecure", + "connect.sid", + ) + }) - const client = { - ...nc(), - backchannel_logout_uri: `${Cypress.env( - "client_url", - )}/openid/session/end/bc`, - } - - it("should log in and remember login with back-channel", function () { - cy.authCodeFlow( - client, - { - login: { remember: true }, - consent: { scope: ["openid"], remember: true }, - }, - "openid", - ) - - cy.request(`${Cypress.env("client_url")}/openid/session/check`) - .its("body") - .then(({ has_session }) => { - expect(has_session).to.be.true + before(() => { + deleteClients() }) - }) - it("should show the logout page and complete logout with back-channel", () => { - cy.request(`${Cypress.env("client_url")}/openid/session/check`) - .its("body") - .then(({ has_session }) => { - expect(has_session).to.be.true + const client = { + ...nc(), + backchannel_logout_uri: `${Cypress.env( + "client_url", + )}/openid/session/end/bc`, + } + + it("should log in and remember login without id_token_hint", function () { + cy.authCodeFlow( + client, + { + login: { remember: true }, + consent: { + scope: ["openid"], + remember: true, + }, + }, + "openid", + ) + + cy.request(`${Cypress.env("client_url")}/openid/session/check`) + .its("body") + .then(({ has_session }) => { + expect(has_session).to.be.true + }) }) - cy.visit(`${Cypress.env("client_url")}/openid/session/end`, { - failOnStatusCode: false, - }) + it("should show the logout page and complete logout without id_token_hint", () => { + // cy.request(`${Cypress.env('client_url')}/openid/session/check`) + // .its('body') + // .then(({ has_session }) => { + // expect(has_session).to.be.true; + // }); - cy.get("#accept").click() + cy.visit(`${Cypress.env("client_url")}/openid/session/end?simple=1`, { + failOnStatusCode: false, + }) - cy.get("h1").should("contain", "Your log out request however succeeded.") + cy.get("#accept").click() - cy.request(`${Cypress.env("client_url")}/openid/session/check`) - .its("body") - .then(({ has_session }) => { - expect(has_session).to.be.false + cy.get("h1").should( + "contain", + "Your log out request however succeeded.", + ) }) - }) - }) - describe("Front-Channel", () => { - beforeEach(() => { - Cypress.Cookies.preserveOnce( - "oauth2_authentication_session", - "oauth2_authentication_session_insecure", - "connect.sid", - ) - }) + it("should show the login screen again because we logged out", () => { + cy.authCodeFlow( + client, + { + login: { remember: false }, // login should have skip false because we removed the session.mak + consent: { + scope: ["openid"], + remember: false, + skip: true, + }, + createClient: false, + }, + "openid", + ) + }) + }) - before(() => { - deleteClients() - }) + // The Back-Channel test should run before the front-channel test because otherwise both tests need a long time to finish. + describe.only("Back-Channel", () => { + beforeEach(() => { + Cypress.Cookies.preserveOnce( + "oauth2_authentication_session", + "oauth2_authentication_session_insecure", + "connect.sid", + ) + }) - const client = { - ...nc(), - frontchannel_logout_uri: `${Cypress.env( - "client_url", - )}/openid/session/end/fc`, - } - - it("should log in and remember login with front-channel", () => { - cy.authCodeFlow( - client, - { - login: { remember: true }, - consent: { scope: ["openid"], remember: true }, - }, - "openid", - ) - - cy.request(`${Cypress.env("client_url")}/openid/session/check`) - .its("body") - .then(({ has_session }) => { - expect(has_session).to.be.true + before(() => { + deleteClients() }) - }) - it("should show the logout page and complete logout with front-channel", () => { - cy.request(`${Cypress.env("client_url")}/openid/session/check`) - .its("body") - .then(({ has_session }) => { - expect(has_session).to.be.true + const client = { + ...nc(), + backchannel_logout_uri: `${Cypress.env( + "client_url", + )}/openid/session/end/bc`, + } + + it("should log in and remember login with back-channel", function () { + cy.authCodeFlow( + client, + { + login: { remember: true }, + consent: { + scope: ["openid"], + remember: true, + }, + }, + "openid", + ) + + cy.request(`${Cypress.env("client_url")}/openid/session/check`) + .its("body") + .then(({ has_session }) => { + expect(has_session).to.be.true + }) }) - cy.visit(`${Cypress.env("client_url")}/openid/session/end`, { - failOnStatusCode: false, + it("should show the logout page and complete logout with back-channel", () => { + cy.request(`${Cypress.env("client_url")}/openid/session/check`) + .its("body") + .then(({ has_session }) => { + expect(has_session).to.be.true + }) + + cy.visit(`${Cypress.env("client_url")}/openid/session/end`, { + failOnStatusCode: false, + }) + + cy.get("#accept").click() + + cy.get("h1").should( + "contain", + "Your log out request however succeeded.", + ) + + cy.request(`${Cypress.env("client_url")}/openid/session/check`) + .its("body") + .then(({ has_session }) => { + expect(has_session).to.be.false + }) + }) }) - cy.get("#accept").click() + describe("Front-Channel", () => { + beforeEach(() => { + Cypress.Cookies.preserveOnce( + "oauth2_authentication_session", + "oauth2_authentication_session_insecure", + "connect.sid", + ) + }) - cy.get("h1").should("contain", "Your log out request however succeeded.") + before(() => { + deleteClients() + }) + + const client = { + ...nc(), + frontchannel_logout_uri: `${Cypress.env( + "client_url", + )}/openid/session/end/fc`, + } + + it("should log in and remember login with front-channel", () => { + cy.authCodeFlow( + client, + { + login: { remember: true }, + consent: { + scope: ["openid"], + remember: true, + }, + }, + "openid", + ) + + cy.request(`${Cypress.env("client_url")}/openid/session/check`) + .its("body") + .then(({ has_session }) => { + expect(has_session).to.be.true + }) + }) - cy.request(`${Cypress.env("client_url")}/openid/session/check`) - .its("body") - .then(({ has_session }) => { - expect(has_session).to.be.false + it("should show the logout page and complete logout with front-channel", () => { + cy.request(`${Cypress.env("client_url")}/openid/session/check`) + .its("body") + .then(({ has_session }) => { + expect(has_session).to.be.true + }) + + cy.visit(`${Cypress.env("client_url")}/openid/session/end`, { + failOnStatusCode: false, + }) + + cy.get("#accept").click() + + cy.get("h1").should( + "contain", + "Your log out request however succeeded.", + ) + + cy.request(`${Cypress.env("client_url")}/openid/session/check`) + .its("body") + .then(({ has_session }) => { + expect(has_session).to.be.false + }) }) + }) }) }) }) diff --git a/cypress/integration/openid/prompt.js b/cypress/integration/openid/prompt.js index 111784c982e..7953734894b 100644 --- a/cypress/integration/openid/prompt.js +++ b/cypress/integration/openid/prompt.js @@ -4,107 +4,125 @@ import { createClient, prng } from "../../helpers" import qs from "querystring" +const accessTokenStrategies = ["opaque", "jwt"] + describe("OpenID Connect Prompt", () => { - const nc = () => ({ - client_secret: prng(), - scope: "openid", - redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = () => ({ + client_secret: prng(), + scope: "openid", + redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, + }) - it("should fail prompt=none when no session exists", function () { - createClient(nc()).then((client) => { - cy.visit( - `${Cypress.env("client_url")}/openid/code?client_id=${ - client.client_id - }&client_secret=${client.client_secret}&prompt=none`, - { failOnStatusCode: false }, - ) + it("should fail prompt=none when no session exists", function () { + createClient(nc()).then((client) => { + cy.visit( + `${Cypress.env("client_url")}/openid/code?client_id=${ + client.client_id + }&client_secret=${client.client_secret}&prompt=none`, + { failOnStatusCode: false }, + ) - cy.location().should(({ search, port }) => { - const query = qs.parse(search.substr(1)) - expect(query.error).to.equal("login_required") - expect(port).to.equal(Cypress.env("client_port")) + cy.location().should(({ search, port }) => { + const query = qs.parse(search.substr(1)) + expect(query.error).to.equal("login_required") + expect(port).to.equal(Cypress.env("client_port")) + }) + }) }) - }) - }) - it("should pass with prompt=none if both login and consent were remembered", function () { - createClient(nc()).then((client) => { - cy.authCodeFlow( - client, - { - login: { remember: true }, - consent: { scope: ["openid"], remember: true }, - createClient: false, - }, - "openid", - ) + it("should pass with prompt=none if both login and consent were remembered", function () { + createClient(nc()).then((client) => { + cy.authCodeFlow( + client, + { + login: { remember: true }, + consent: { + scope: ["openid"], + remember: true, + }, + createClient: false, + }, + "openid", + ) - cy.request( - `${Cypress.env("client_url")}/openid/code?client_id=${ - client.client_id - }&client_secret=${client.client_secret}&scope=openid`, - ) - .its("body") - .then((body) => { - const { - result, - token: { access_token }, - } = body - expect(result).to.equal("success") - expect(access_token).to.not.be.empty + cy.request( + `${Cypress.env("client_url")}/openid/code?client_id=${ + client.client_id + }&client_secret=${client.client_secret}&scope=openid`, + ) + .its("body") + .then((body) => { + const { + result, + token: { access_token }, + } = body + expect(result).to.equal("success") + expect(access_token).to.not.be.empty + }) }) - }) - }) + }) - it("should require login with prompt=login even when session exists", function () { - createClient(nc()).then((client) => { - cy.authCodeFlow( - client, - { - login: { remember: true }, - consent: { scope: ["openid"], remember: true }, - createClient: false, - }, - "openid", - ) + it("should require login with prompt=login even when session exists", function () { + createClient(nc()).then((client) => { + cy.authCodeFlow( + client, + { + login: { remember: true }, + consent: { + scope: ["openid"], + remember: true, + }, + createClient: false, + }, + "openid", + ) - cy.request( - `${Cypress.env("client_url")}/openid/code?client_id=${ - client.client_id - }&client_secret=${client.client_secret}&scope=openid&prompt=login`, - ) - .its("body") - .then((body) => { - expect(body).to.contain("Please log in") + cy.request( + `${Cypress.env("client_url")}/openid/code?client_id=${ + client.client_id + }&client_secret=${client.client_secret}&scope=openid&prompt=login`, + ) + .its("body") + .then((body) => { + expect(body).to.contain("Please log in") + }) }) - }) - }) + }) - it("should require consent with prompt=consent even when session exists", function () { - createClient(nc()).then((client) => { - cy.authCodeFlow( - client, - { - login: { remember: true }, - consent: { scope: ["openid"], remember: true }, - createClient: false, - }, - "openid", - ) + it("should require consent with prompt=consent even when session exists", function () { + createClient(nc()).then((client) => { + cy.authCodeFlow( + client, + { + login: { remember: true }, + consent: { + scope: ["openid"], + remember: true, + }, + createClient: false, + }, + "openid", + ) - cy.request( - `${Cypress.env("client_url")}/openid/code?client_id=${ - client.client_id - }&client_secret=${client.client_secret}&scope=openid&prompt=consent`, - ) - .its("body") - .then((body) => { - expect(body).to.contain( - "An application requests access to your data!", + cy.request( + `${Cypress.env("client_url")}/openid/code?client_id=${ + client.client_id + }&client_secret=${ + client.client_secret + }&scope=openid&prompt=consent`, ) + .its("body") + .then((body) => { + expect(body).to.contain( + "An application requests access to your data!", + ) + }) }) + }) }) }) }) diff --git a/cypress/integration/openid/revoke.js b/cypress/integration/openid/revoke.js index 08c6bf29a1c..3793d3e089d 100644 --- a/cypress/integration/openid/revoke.js +++ b/cypress/integration/openid/revoke.js @@ -3,73 +3,80 @@ import { prng } from "../../helpers" +const accessTokenStrategies = ["opaque", "jwt"] + describe("OpenID Connect Token Revokation", () => { - const nc = () => ({ - client_secret: prng(), - scope: "openid offline_access", - redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = () => ({ + client_secret: prng(), + scope: "openid offline_access", + redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, + }) - it("should be able to revoke the access token", function () { - const client = nc() - cy.authCodeFlow( - client, - { consent: { scope: ["openid", "offline_access"] } }, - "openid", - ) + it("should be able to revoke the access token", function () { + const client = nc() + cy.authCodeFlow( + client, + { consent: { scope: ["openid", "offline_access"] } }, + "openid", + ) - cy.get("body") - .invoke("text") - .then((content) => { - const { result } = JSON.parse(content) - expect(result).to.equal("success") - }) + cy.get("body") + .invoke("text") + .then((content) => { + const { result } = JSON.parse(content) + expect(result).to.equal("success") + }) - cy.request(`${Cypress.env("client_url")}/openid/revoke/at`) - .its("body") - .then((response) => { - expect(response.result).to.equal("success") - }) + cy.request(`${Cypress.env("client_url")}/openid/revoke/at`) + .its("body") + .then((response) => { + expect(response.result).to.equal("success") + }) - cy.request(`${Cypress.env("client_url")}/openid/userinfo`, { - failOnStatusCode: false, - }) - .its("body") - .then((response) => { - expect(response.error).to.contain("request_unauthorized") + cy.request(`${Cypress.env("client_url")}/openid/userinfo`, { + failOnStatusCode: false, + }) + .its("body") + .then((response) => { + expect(response.error).to.contain("request_unauthorized") + }) }) - }) - it("should be able to revoke the refresh token", function () { - const client = nc() - cy.authCodeFlow( - client, - { consent: { scope: ["openid", "offline_access"] } }, - "openid", - ) + it("should be able to revoke the refresh token", function () { + const client = nc() + cy.authCodeFlow( + client, + { consent: { scope: ["openid", "offline_access"] } }, + "openid", + ) - cy.get("body") - .invoke("text") - .then((content) => { - const { result } = JSON.parse(content) - expect(result).to.equal("success") - }) + cy.get("body") + .invoke("text") + .then((content) => { + const { result } = JSON.parse(content) + expect(result).to.equal("success") + }) - cy.request(`${Cypress.env("client_url")}/openid/revoke/rt`, { - failOnStatusCode: false, - }) - .its("body") - .then((response) => { - expect(response.result).to.equal("success") - }) + cy.request(`${Cypress.env("client_url")}/openid/revoke/rt`, { + failOnStatusCode: false, + }) + .its("body") + .then((response) => { + expect(response.result).to.equal("success") + }) - cy.request(`${Cypress.env("client_url")}/openid/userinfo`, { - failOnStatusCode: false, - }) - .its("body") - .then((response) => { - expect(response.error).to.contain("request_unauthorized") + cy.request(`${Cypress.env("client_url")}/openid/userinfo`, { + failOnStatusCode: false, + }) + .its("body") + .then((response) => { + expect(response.error).to.contain("request_unauthorized") + }) }) + }) }) }) diff --git a/cypress/integration/openid/userinfo.js b/cypress/integration/openid/userinfo.js index 7df40c65772..079f4fba846 100644 --- a/cypress/integration/openid/userinfo.js +++ b/cypress/integration/openid/userinfo.js @@ -3,30 +3,37 @@ import { prng } from "../../helpers" +const accessTokenStrategies = ["opaque", "jwt"] + describe("OpenID Connect Userinfo", () => { - const nc = () => ({ - client_secret: prng(), - scope: "openid", - redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], - grant_types: ["authorization_code", "refresh_token"], - }) + accessTokenStrategies.forEach((accessTokenStrategy) => { + describe("access_token_strategy=" + accessTokenStrategy, function () { + const nc = () => ({ + client_secret: prng(), + scope: "openid", + redirect_uris: [`${Cypress.env("client_url")}/openid/callback`], + grant_types: ["authorization_code", "refresh_token"], + access_token_strategy: accessTokenStrategy, + }) - it("should return a proper userinfo response", function () { - const client = nc() - cy.authCodeFlow(client, { consent: { scope: ["openid"] } }, "openid") + it("should return a proper userinfo response", function () { + const client = nc() + cy.authCodeFlow(client, { consent: { scope: ["openid"] } }, "openid") - cy.get("body") - .invoke("text") - .then((content) => { - const { result } = JSON.parse(content) - expect(result).to.equal("success") - }) + cy.get("body") + .invoke("text") + .then((content) => { + const { result } = JSON.parse(content) + expect(result).to.equal("success") + }) - cy.request(`${Cypress.env("client_url")}/openid/userinfo`) - .its("body") - .then(({ aud, sub } = {}) => { - expect(sub).to.eq("foo@bar.com") - expect(aud).to.not.be.empty + cy.request(`${Cypress.env("client_url")}/openid/userinfo`) + .its("body") + .then(({ aud, sub } = {}) => { + expect(sub).to.eq("foo@bar.com") + expect(aud).to.not.be.empty + }) }) + }) }) }) diff --git a/docs/flow-cache-design-doc.md b/docs/flow-cache-design-doc.md new file mode 100644 index 00000000000..22916348936 --- /dev/null +++ b/docs/flow-cache-design-doc.md @@ -0,0 +1,167 @@ +# Flow Cache Design Doc + +## Overview + +This design doc outlines the proposed solution for caching the flow object in +the OAuth2 exchange between the Client, Ory Hydra, and the Consent and Login +UIs. The flow object contains the state of the authorization request. + +## Problem Statement + +Currently, the flow object is stored in the database on the Ory Hydra server. +This approach has several drawbacks: + +- Each step of the OAuth2 flow (initialization, consent, login, etc.) requires a + database query to retrieve the flow object, and another to update it. +- Each part of the exchanges supplies different values (login challenge, consent + challenge, etc.) to identify the flow object. This means the database table + has multiple indices that slow down insertions. + +## Proposed Solution + +The proposed solution is to store the flow object in client cookies and URLs. +This way, the flow object is written only once when the flow is completed and +the final authorization code is generated. + +### Requirements + +- The flow object must be stored in client cookies and URLs. +- The flow object must be secure and protect against unauthorized access. +- The flow object must be persistent, so that the flow can be resumed if the + user navigates away from the page or closes the browser. +- The flow object must be scalable and able to handle a large number of + concurrent requests. + +### Architecture + +The proposed architecture for the flow cache is as follows: + +- Store the flow object in an AEAD encrypted cookie. +- Pass a partial flow around in the URL. +- Use a secure connection to protect against unauthorized access. + +```mermaid +sequenceDiagram + actor Client + participant Hydra + participant LoginUI as Login UI + participant ConsentUI as Consent UI + % participant Callback + + autonumber + + Client->>+Hydra: GET /oauth2/auth?client_id=CLIENT_ID&response_type=code&scope=SCOPES&state=STATE + Hydra->>-Client: Redirect to
http://login.local/?login_challenge=LOGIN_CHALLENGE + + Client->>+LoginUI: GET /?login_challenge=LOGIN_CHALLENGE + LoginUI->>Hydra: GET /admin/oauth2/auth/requests/login + Hydra->>LoginUI: oAuth2LoginRequest + alt accept login + LoginUI->>Hydra: PUT /admin/oauth2/auth/requests/login/accept + else reject login + LoginUI->>Hydra: PUT /admin/oauth2/auth/requests/login/reject + end + Hydra->>LoginUI: oAuth2RedirectTo + LoginUI->>-Client: Redirect to
http://hydra.local/oauth2/auth?client_id=CLIENT_ID&login_verifier=LOGIN_VERIFIER&response_type=code&scope=SCOPES&state=STATE + + Client->>+Hydra: GET /oauth2/auth?client_id=CLIENT_ID&login_verifier=LOGIN_VERIFIER&response_type=code&scope=SCOPES&state=STATE + Hydra->>-Client: Redirect to
http://consent.local/?consent_challenge=CONSENT_CHALLENGE + + Client->>+ConsentUI: GET /?consent_challenge=CONSENT_CHALLENGE + ConsentUI->>Hydra: GET /admin/oauth2/auth/requests/consent + Hydra->>ConsentUI: oAuth2ConsentRequest + alt accept login + ConsentUI->>Hydra: PUT /admin/oauth2/auth/requests/consent/accept + else reject login + ConsentUI->>Hydra: PUT /admin/oauth2/auth/requests/consent/reject + end + Hydra->>ConsentUI: oAuth2RedirectTo + ConsentUI->>-Client: Redirect to
http://hydra.local/oauth2/auth?client_id=CLIENT_ID&consent_verifier=CONSENT_VERIFIER&response_type=code&scope=SCOPES&state=STATE + + Client->>+Hydra: GET /oauth2/auth?client_id=CLIENT_ID&consent_verifier=CONSENT_VERIFIER&response_type=code&scope=SCOPES&state=STATE + Hydra->>-Client: Redirect to
http://callback.local/callback?code=AUTH_CODE&scope=SCOPES&state=STATE + Note over Hydra,Client: next, exchange code for token. + + + % Client->>+Callback: GET /callback?code=AUTH_CODE&scope=SCOPES&state=STATE + % Callback->>-Client: Return Authorization Code +``` + +Step 2: + +- Set the whole flow as an AEAD encrypted cookie on the client +- The cookie is keyed by the `state`, so that multiple flows can run in parallel + from one cookie jar +- Set the `LOGIN_CHALLENGE` to the AEAD-encrypted flow + +Step 5: + +- Decrypt the flow from the `LOGIN_CHALLENGE`, return the `oAuth2LoginRequest` + +Step 8: + +- Encode the flow into the redirect URL in `oAuth2RedirectTo` as the + `LOGIN_VERIFIER` + +Step 11 + +- Check that the login challenge in the `LOGIN_VERIFIER` matches the challenge + in the flow cookie. +- Update the flow based on the request from the `LOGIN_VERIFIER` +- Update the cookie +- Set the `CONSENT_CHALLENGE` to the AEAD-encrypted flow + +Step 14: + +- Decrypt the flow from the `CONSENT_CHALLENGE` + +Step 17: + +- Encode the flow into the redirect URL in `oAuth2RedirectTo` as the + `CONSENT_VERIFIER` + +Step 20 + +- Check that the consent challenge in the `CONSENT_VERIFIER` matches the + challenge in the flow cookie. +- Update the flow based on the request from the `CONSENT_VERIFIER` +- Update the cookie +- Write the flow to the database +- Continue the flow as currently implemented (generate the authentication code, + return the code, etc.) + +### Client HTTP requests + +For reference, these HTTP requests are issued by the client: + +``` +GET http://hydra.local/oauth2/auth?client_id=CLIENT_ID&nonce=NONCE&response_type=code&scope=SCOPES&state=STATE +Redirect to http://login.local/?login_challenge=LOGIN_CHALLENGE +GET http://login.local/?login_challenge=LOGIN_CHALLENGE +Redirect to http://hydra.local/oauth2/auth?client_id=CLIENT_ID&login_verifier=LOGIN_VERIFIER&nonce=NONCE&response_type=code&scope=SCOPES&state=STATE +GET http://hydra.local/oauth2/auth?client_id=CLIENT_ID&login_verifier=LOGIN_VERIFIER&nonce=NONCE&response_type=code&scope=SCOPES&state=STATE +Redirect to http://consent.local/?consent_challenge=CONSENT_CHALLENGE +GET http://consent.local/?consent_challenge=CONSENT_CHALLENGE +Redirect to http://hydra.local/oauth2/auth?client_id=CLIENT_ID&consent_verifier=CONSENT_VERIFIER&nonce=NONCE&response_type=code&scope=SCOPES&state=STATE +GET http://hydra.local/oauth2/auth?client_id=CLIENT_ID&consent_verifier=CONSENT_VERIFIER&nonce=NONCE&response_type=code&scope=SCOPES&state=STATE +Redirect to http://callback.local/callback?code=AUTH_CODE&scope=SCOPES&state=STATE +GET http://callback.local/callback?code=AUTH_CODE&scope=SCOPES&state=STATE +``` + +### Implementation + +The implementation of the flow cache will involve the following steps: + +1. Modify the Ory Hydra server to store the flow object in an AEAD encrypted + cookie. +2. Modify the Consent and Login UIs to include the flow object in the URL. +3. Use HTTPS to protect against unauthorized access. + +## Conclusion + +The proposed solution for caching the flow object in the OAuth2 exchange between +the Client, Ory Hydra, and the Consent and Login UIs is to store the flow object +in client cookies and URLs. This approach eliminates the need for a distributed +cache and provides a scalable and secure solution. The flow object will be +stored in an AEAD encrypted cookie and passed around in the URL. HTTPS will be +used to protect against unauthorized access. diff --git a/driver/config/provider.go b/driver/config/provider.go index 5e7252d6e66..52b9ee45a3f 100644 --- a/driver/config/provider.go +++ b/driver/config/provider.go @@ -6,25 +6,28 @@ package config import ( "context" "fmt" + "math" "net/http" "net/url" "strings" "time" + "github.com/pkg/errors" + "github.com/ory/x/hasherx" "github.com/gofrs/uuid" "github.com/ory/x/otelx" - "github.com/ory/hydra/spec" + "github.com/ory/hydra/v2/spec" "github.com/ory/x/dbal" "github.com/ory/x/configx" "github.com/ory/x/logrusx" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" "github.com/ory/x/stringslice" "github.com/ory/x/urlx" @@ -42,6 +45,7 @@ const ( KeyOAuth2ClientRegistrationURL = "webfinger.oidc_discovery.client_registration_url" KeyOAuth2TokenURL = "webfinger.oidc_discovery.token_url" // #nosec G101 KeyOAuth2AuthURL = "webfinger.oidc_discovery.auth_url" + KeyVerifiableCredentialsURL = "webfinger.oidc_discovery.verifiable_credentials_url" // #nosec G101 KeyJWKSURL = "webfinger.oidc_discovery.jwks_url" KeyOIDCDiscoverySupportedClaims = "webfinger.oidc_discovery.supported_claims" KeyOIDCDiscoverySupportedScope = "webfinger.oidc_discovery.supported_scope" @@ -49,7 +53,8 @@ const ( KeySubjectTypesSupported = "oidc.subject_identifiers.supported_types" KeyDefaultClientScope = "oidc.dynamic_client_registration.default_scope" KeyDSN = "dsn" - ViperKeyClientHTTPNoPrivateIPRanges = "clients.http.disallow_private_ip_ranges" + KeyClientHTTPNoPrivateIPRanges = "clients.http.disallow_private_ip_ranges" + KeyClientHTTPPrivateIPExceptionURLs = "clients.http.private_ip_exception_urls" KeyHasherAlgorithm = "oauth2.hashers.algorithm" KeyBCryptCost = "oauth2.hashers.bcrypt.cost" KeyPBKDF2Iterations = "oauth2.hashers.pbkdf2.iterations" @@ -61,9 +66,11 @@ const ( KeyCookieLoginCSRFName = "serve.cookies.names.login_csrf" KeyCookieConsentCSRFName = "serve.cookies.names.consent_csrf" KeyCookieSessionName = "serve.cookies.names.session" + KeyCookieSessionPath = "serve.cookies.paths.session" KeyConsentRequestMaxAge = "ttl.login_consent_request" KeyAccessTokenLifespan = "ttl.access_token" // #nosec G101 KeyRefreshTokenLifespan = "ttl.refresh_token" // #nosec G101 + KeyVerifiableCredentialsNonceLifespan = "ttl.vc_nonce" // #nosec G101 KeyIDTokenLifespan = "ttl.id_token" // #nosec G101 KeyAuthCodeLifespan = "ttl.auth_code" KeyScopeStrategy = "strategies.scope" @@ -71,13 +78,18 @@ const ( KeyGetSystemSecret = "secrets.system" KeyLogoutRedirectURL = "urls.post_logout_redirect" KeyLoginURL = "urls.login" + KeyRegistrationURL = "urls.registration" KeyLogoutURL = "urls.logout" KeyConsentURL = "urls.consent" KeyErrorURL = "urls.error" KeyPublicURL = "urls.self.public" KeyAdminURL = "urls.self.admin" KeyIssuerURL = "urls.self.issuer" + KeyIdentityProviderAdminURL = "urls.identity_provider.url" + KeyIdentityProviderPublicURL = "urls.identity_provider.publicUrl" + KeyIdentityProviderHeaders = "urls.identity_provider.headers" KeyAccessTokenStrategy = "strategies.access_token" + KeyJWTScopeClaimStrategy = "strategies.jwt.scope_claim" KeyDBIgnoreUnknownTableColumns = "db.ignore_unknown_table_columns" KeySubjectIdentifierAlgorithmSalt = "oidc.subject_identifiers.pairwise.salt" KeyPublicAllowDynamicRegistration = "oidc.dynamic_client_registration.enabled" @@ -89,22 +101,25 @@ const ( KeyExposeOAuth2Debug = "oauth2.expose_internal_errors" KeyExcludeNotBeforeClaim = "oauth2.exclude_not_before_claim" KeyAllowedTopLevelClaims = "oauth2.allowed_top_level_claims" + KeyMirrorTopLevelClaims = "oauth2.mirror_top_level_claims" + KeyRefreshTokenRotationGracePeriod = "oauth2.grant.refresh_token.rotation_grace_period" // #nosec G101 KeyOAuth2GrantJWTIDOptional = "oauth2.grant.jwt.jti_optional" KeyOAuth2GrantJWTIssuedDateOptional = "oauth2.grant.jwt.iat_optional" KeyOAuth2GrantJWTMaxDuration = "oauth2.grant.jwt.max_ttl" - KeyRefreshTokenHookURL = "oauth2.refresh_token_hook" // #nosec G101 + KeyRefreshTokenHook = "oauth2.refresh_token_hook" // #nosec G101 + KeyTokenHook = "oauth2.token_hook" // #nosec G101 KeyDevelopmentMode = "dev" ) const DSNMemory = "memory" -var _ hasherx.PBKDF2Configurator = (*DefaultProvider)(nil) -var _ hasherx.BCryptConfigurator = (*DefaultProvider)(nil) +var ( + _ hasherx.PBKDF2Configurator = (*DefaultProvider)(nil) + _ hasherx.BCryptConfigurator = (*DefaultProvider)(nil) +) type DefaultProvider struct { - generatedSecret []byte - l *logrusx.Logger - + l *logrusx.Logger p *configx.Provider c contextx.Contextualizer } @@ -121,15 +136,34 @@ func (p *DefaultProvider) GetHasherAlgorithm(ctx context.Context) x.HashAlgorith } func (p *DefaultProvider) HasherBcryptConfig(ctx context.Context) *hasherx.BCryptConfig { + var cost uint32 + costInt := int64(p.GetBCryptCost(ctx)) + if costInt < 0 { + cost = 10 + } else if costInt > math.MaxUint32 { + cost = math.MaxUint32 + } else { + cost = uint32(costInt) + } return &hasherx.BCryptConfig{ - Cost: uint32(p.GetBCryptCost(ctx)), + Cost: cost, } } func (p *DefaultProvider) HasherPBKDF2Config(ctx context.Context) *hasherx.PBKDF2Config { + var iters uint32 + itersInt := p.getProvider(ctx).Int64(KeyPBKDF2Iterations) + if itersInt < 1 { + iters = 1 + } else if int64(itersInt) > math.MaxUint32 { + iters = math.MaxUint32 + } else { + iters = uint32(itersInt) + } + return &hasherx.PBKDF2Config{ Algorithm: "sha256", - Iterations: uint32(p.getProvider(ctx).Int(KeyPBKDF2Iterations)), + Iterations: iters, SaltLength: 16, KeyLength: 32, } @@ -188,27 +222,27 @@ func (p *DefaultProvider) IsDevelopmentMode(ctx context.Context) bool { } func (p *DefaultProvider) WellKnownKeys(ctx context.Context, include ...string) []string { - if p.AccessTokenStrategy(ctx) == AccessTokenJWTStrategy { - include = append(include, x.OAuth2JWTKeyName) - } - - include = append(include, x.OpenIDConnectKeyName) + include = append(include, x.OAuth2JWTKeyName, x.OpenIDConnectKeyName) return stringslice.Unique(append(p.getProvider(ctx).Strings(KeyWellKnownKeys), include...)) } -func (p *DefaultProvider) IsUsingJWTAsAccessTokens(ctx context.Context) bool { - return p.AccessTokenStrategy(ctx) != "opaque" +func (p *DefaultProvider) ClientHTTPNoPrivateIPRanges() bool { + return p.getProvider(contextx.RootContext).Bool(KeyClientHTTPNoPrivateIPRanges) } -func (p *DefaultProvider) ClientHTTPNoPrivateIPRanges() bool { - return p.getProvider(contextx.RootContext).Bool(ViperKeyClientHTTPNoPrivateIPRanges) +func (p *DefaultProvider) ClientHTTPPrivateIPExceptionURLs() []string { + return p.getProvider(contextx.RootContext).Strings(KeyClientHTTPPrivateIPExceptionURLs) } func (p *DefaultProvider) AllowedTopLevelClaims(ctx context.Context) []string { return stringslice.Unique(p.getProvider(ctx).Strings(KeyAllowedTopLevelClaims)) } -func (p *DefaultProvider) SubjectTypesSupported(ctx context.Context) []string { +func (p *DefaultProvider) MirrorTopLevelClaims(ctx context.Context) bool { + return p.getProvider(ctx).BoolF(KeyMirrorTopLevelClaims, true) +} + +func (p *DefaultProvider) SubjectTypesSupported(ctx context.Context, additionalSources ...AccessTokenStrategySource) []string { types := stringslice.Filter( p.getProvider(ctx).StringsF(KeySubjectTypesSupported, []string{"public"}), func(s string) bool { @@ -221,7 +255,7 @@ func (p *DefaultProvider) SubjectTypesSupported(ctx context.Context) []string { } if stringslice.Has(types, "pairwise") { - if p.AccessTokenStrategy(ctx) == AccessTokenJWTStrategy { + if p.AccessTokenStrategy(ctx, additionalSources...) == AccessTokenJWTStrategy { p.l.Warn(`The pairwise subject identifier algorithm is not supported by the JWT OAuth 2.0 Access Token Strategy and is thus being disabled. Please remove "pairwise" from oidc.subject_identifiers.supported_types" (e.g. oidc.subject_identifiers.supported_types=public) or set strategies.access_token to "opaque".`) types = stringslice.Filter( types, @@ -285,7 +319,8 @@ func (p *DefaultProvider) CookieSameSiteMode(ctx context.Context) http.SameSite case "strict": return http.SameSiteStrictMode case "none": - if p.IsDevelopmentMode(ctx) { + if p.IssuerURL(ctx).Scheme != "https" { + // SameSite=None can only be set for HTTPS issuers. return http.SameSiteLaxMode } return http.SameSiteNoneMode @@ -362,6 +397,10 @@ func (p *DefaultProvider) LoginURL(ctx context.Context) *url.URL { return urlRoot(p.getProvider(ctx).URIF(KeyLoginURL, p.publicFallbackURL(ctx, "oauth2/fallbacks/login"))) } +func (p *DefaultProvider) RegistrationURL(ctx context.Context) *url.URL { + return urlRoot(p.getProvider(ctx).URIF(KeyRegistrationURL, p.LoginURL(ctx))) +} + func (p *DefaultProvider) LogoutURL(ctx context.Context) *url.URL { return urlRoot(p.getProvider(ctx).RequestURIF(KeyLogoutURL, p.publicFallbackURL(ctx, "oauth2/fallbacks/logout"))) } @@ -392,6 +431,33 @@ func (p *DefaultProvider) IssuerURL(ctx context.Context) *url.URL { ) } +func (p *DefaultProvider) KratosAdminURL(ctx context.Context) (*url.URL, bool) { + u := p.getProvider(ctx).RequestURIF(KeyIdentityProviderAdminURL, nil) + + return u, u != nil +} +func (p *DefaultProvider) KratosPublicURL(ctx context.Context) (*url.URL, bool) { + u := p.getProvider(ctx).RequestURIF(KeyIdentityProviderPublicURL, nil) + + return u, u != nil +} + +func (p *DefaultProvider) KratosRequestHeader(ctx context.Context) http.Header { + hh := map[string]string{} + if err := p.getProvider(ctx).Unmarshal(KeyIdentityProviderHeaders, &hh); err != nil { + p.l.WithError(errors.WithStack(err)). + Errorf("Configuration value from key %s could not be decoded.", KeyIdentityProviderHeaders) + return nil + } + + h := make(http.Header) + for k, v := range hh { + h.Set(k, v) + } + + return h +} + func (p *DefaultProvider) OAuth2ClientRegistrationURL(ctx context.Context) *url.URL { return p.getProvider(ctx).RequestURIF(KeyOAuth2ClientRegistrationURL, new(url.URL)) } @@ -408,7 +474,23 @@ func (p *DefaultProvider) JWKSURL(ctx context.Context) *url.URL { return p.getProvider(ctx).RequestURIF(KeyJWKSURL, urlx.AppendPaths(p.IssuerURL(ctx), "/.well-known/jwks.json")) } -func (p *DefaultProvider) AccessTokenStrategy(ctx context.Context) AccessTokenStrategyType { +func (p *DefaultProvider) CredentialsEndpointURL(ctx context.Context) *url.URL { + return p.getProvider(ctx).RequestURIF(KeyVerifiableCredentialsURL, urlx.AppendPaths(p.PublicURL(ctx), "/credentials")) +} + +type AccessTokenStrategySource interface { + GetAccessTokenStrategy() AccessTokenStrategyType +} + +func (p *DefaultProvider) AccessTokenStrategy(ctx context.Context, additionalSources ...AccessTokenStrategySource) AccessTokenStrategyType { + for _, src := range additionalSources { + if src == nil { + continue + } + if strategy := src.GetAccessTokenStrategy(); strategy != "" { + return strategy + } + } s, err := ToAccessTokenStrategyType(p.getProvider(ctx).String(KeyAccessTokenStrategy)) if err != nil { p.l.WithError(err).Warn("Key `strategies.access_token` contains an invalid value, falling back to `opaque` strategy.") @@ -418,12 +500,57 @@ func (p *DefaultProvider) AccessTokenStrategy(ctx context.Context) AccessTokenSt return s } -func (p *DefaultProvider) TokenRefreshHookURL(ctx context.Context) *url.URL { - if len(p.getProvider(ctx).String(KeyRefreshTokenHookURL)) == 0 { +type ( + Auth struct { + Type string `json:"type"` + Config AuthConfig `json:"config"` + } + AuthConfig struct { + In string `json:"in"` + Name string `json:"name"` + Value string `json:"value"` + } + HookConfig struct { + URL string `json:"url"` + Auth *Auth `json:"auth"` + } +) + +func (p *DefaultProvider) getHookConfig(ctx context.Context, key string) *HookConfig { + if hookURL := p.getProvider(ctx).RequestURIF(key, nil); hookURL != nil { + return &HookConfig{ + URL: hookURL.String(), + } + } + + var hookConfig *HookConfig + if err := p.getProvider(ctx).Unmarshal(key, &hookConfig); err != nil { + p.l.WithError(errors.WithStack(err)). + Errorf("Configuration value from key %s could not be decoded.", key) + return nil + } + if hookConfig == nil { + return nil + } + + // validate URL by parsing it + u, err := url.ParseRequestURI(hookConfig.URL) + if err != nil { + p.l.WithError(errors.WithStack(err)). + Errorf("Configuration value from key %s could not be decoded.", key) return nil } + hookConfig.URL = u.String() + + return hookConfig +} - return p.getProvider(ctx).RequestURIF(KeyRefreshTokenHookURL, nil) +func (p *DefaultProvider) TokenHookConfig(ctx context.Context) *HookConfig { + return p.getHookConfig(ctx, KeyTokenHook) +} + +func (p *DefaultProvider) TokenRefreshHookConfig(ctx context.Context) *HookConfig { + return p.getHookConfig(ctx, KeyRefreshTokenHook) } func (p *DefaultProvider) DbIgnoreUnknownTableColumns() bool { @@ -519,6 +646,10 @@ func (p *DefaultProvider) CookieDomain(ctx context.Context) string { return p.getProvider(ctx).String(KeyCookieDomain) } +func (p *DefaultProvider) SessionCookiePath(ctx context.Context) string { + return p.getProvider(ctx).StringF(KeyCookieSessionPath, "/") +} + func (p *DefaultProvider) CookieNameLoginCSRF(ctx context.Context) string { return p.cookieSuffix(ctx, KeyCookieLoginCSRFName) } @@ -539,3 +670,11 @@ func (p *DefaultProvider) cookieSuffix(ctx context.Context, key string) string { return p.getProvider(ctx).String(key) + suffix } + +func (p *DefaultProvider) RefreshTokenRotationGracePeriod(ctx context.Context) time.Duration { + gracePeriod := p.getProvider(ctx).DurationF(KeyRefreshTokenRotationGracePeriod, 0) + if gracePeriod > time.Hour { + return time.Hour + } + return gracePeriod +} diff --git a/driver/config/provider_fosite.go b/driver/config/provider_fosite.go index 07c43042edd..fa4d0a9be02 100644 --- a/driver/config/provider_fosite.go +++ b/driver/config/provider_fosite.go @@ -11,7 +11,8 @@ import ( "github.com/pkg/errors" "github.com/ory/fosite" - "github.com/ory/hydra/x" + "github.com/ory/fosite/token/jwt" + "github.com/ory/hydra/v2/x" ) var _ fosite.GlobalSecretProvider = (*DefaultProvider)(nil) @@ -68,6 +69,12 @@ func (p *DefaultProvider) GetRefreshTokenLifespan(ctx context.Context) time.Dura return p.getProvider(ctx).DurationF(KeyRefreshTokenLifespan, time.Hour*720) } +var _ fosite.VerifiableCredentialsNonceLifespanProvider = (*DefaultProvider)(nil) + +func (p *DefaultProvider) GetVerifiableCredentialsNonceLifespan(ctx context.Context) time.Duration { + return p.getProvider(ctx).DurationF(KeyVerifiableCredentialsNonceLifespan, time.Hour) +} + var _ fosite.IDTokenLifespanProvider = (*DefaultProvider)(nil) func (p *DefaultProvider) GetIDTokenLifespan(ctx context.Context) time.Duration { @@ -89,6 +96,21 @@ func (p *DefaultProvider) GetScopeStrategy(ctx context.Context) fosite.ScopeStra return fosite.ExactScopeStrategy } +var _ fosite.JWTScopeFieldProvider = (*DefaultProvider)(nil) + +func (p *DefaultProvider) GetJWTScopeField(ctx context.Context) jwt.JWTScopeFieldEnum { + switch strings.ToLower(p.getProvider(ctx).String(KeyJWTScopeClaimStrategy)) { + case "string": + return jwt.JWTScopeFieldString + case "both": + return jwt.JWTScopeFieldBoth + case "list": + return jwt.JWTScopeFieldList + default: + return jwt.JWTScopeFieldUnset + } +} + func (p *DefaultProvider) GetUseLegacyErrorFormat(context.Context) bool { return false } diff --git a/driver/config/provider_test.go b/driver/config/provider_test.go index fbe8cb2fc62..168ca81d69f 100644 --- a/driver/config/provider_test.go +++ b/driver/config/provider_test.go @@ -5,15 +5,16 @@ package config import ( "context" + "encoding/json" "fmt" "io" "net/http" - "net/url" "os" "strings" "testing" "time" + "github.com/ory/fosite/token/jwt" "github.com/ory/x/configx" "github.com/ory/x/otelx" @@ -25,7 +26,7 @@ import ( "github.com/ory/x/logrusx" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" ) func newProvider() *DefaultProvider { @@ -206,11 +207,20 @@ func TestProviderCookieSameSiteMode(t *testing.T) { p.MustSet(ctx, KeyCookieSameSiteMode, "none") assert.Equal(t, http.SameSiteNoneMode, p.CookieSameSiteMode(ctx)) + p.MustSet(ctx, KeyCookieSameSiteMode, "lax") + assert.Equal(t, http.SameSiteLaxMode, p.CookieSameSiteMode(ctx)) + + p.MustSet(ctx, KeyCookieSameSiteMode, "strict") + assert.Equal(t, http.SameSiteStrictMode, p.CookieSameSiteMode(ctx)) + p = MustNew(context.Background(), l, configx.SkipValidation()) p.MustSet(ctx, "dev", true) assert.Equal(t, http.SameSiteLaxMode, p.CookieSameSiteMode(ctx)) p.MustSet(ctx, KeyCookieSameSiteMode, "none") assert.Equal(t, http.SameSiteLaxMode, p.CookieSameSiteMode(ctx)) + + p.MustSet(ctx, KeyIssuerURL, "https://example.com") + assert.Equal(t, http.SameSiteNoneMode, p.CookieSameSiteMode(ctx)) } func TestViperProviderValidates(t *testing.T) { @@ -267,7 +277,7 @@ func TestViperProviderValidates(t *testing.T) { assert.Contains(t, c.DSN(), "sqlite://") // webfinger - assert.Equal(t, []string{"hydra.openid.id-token"}, c.WellKnownKeys(ctx)) + assert.Equal(t, []string{"hydra.openid.id-token", "hydra.jwt.access-token"}, c.WellKnownKeys(ctx)) assert.Equal(t, urlx.ParseOrPanic("https://example.com"), c.OAuth2ClientRegistrationURL(ctx)) assert.Equal(t, urlx.ParseOrPanic("https://example.com/jwks.json"), c.JWKSURL(ctx)) assert.Equal(t, urlx.ParseOrPanic("https://example.com/auth"), c.OAuth2AuthURL(ctx)) @@ -281,6 +291,13 @@ func TestViperProviderValidates(t *testing.T) { assert.Equal(t, "random_salt", c.SubjectIdentifierAlgorithmSalt(ctx)) assert.Equal(t, []string{"whatever"}, c.DefaultClientScope(ctx)) + // refresh + assert.Equal(t, time.Duration(0), c.RefreshTokenRotationGracePeriod(ctx)) + require.NoError(t, c.Set(ctx, KeyRefreshTokenRotationGracePeriod, "1s")) + assert.Equal(t, time.Second, c.RefreshTokenRotationGracePeriod(ctx)) + require.NoError(t, c.Set(ctx, KeyRefreshTokenRotationGracePeriod, "2h")) + assert.Equal(t, time.Hour, c.RefreshTokenRotationGracePeriod(ctx)) + // urls assert.Equal(t, urlx.ParseOrPanic("https://issuer"), c.IssuerURL(ctx)) assert.Equal(t, urlx.ParseOrPanic("https://public/"), c.PublicURL(ctx)) @@ -296,6 +313,7 @@ func TestViperProviderValidates(t *testing.T) { assert.False(t, c.GetScopeStrategy(ctx)([]string{"openid.*"}, "openid.email"), "should us fosite.ExactScopeStrategy") assert.Equal(t, AccessTokenDefaultStrategy, c.AccessTokenStrategy(ctx)) assert.Equal(t, false, c.GrantAllClientCredentialsScopesPerDefault(ctx)) + assert.Equal(t, jwt.JWTScopeFieldList, c.GetJWTScopeField(ctx)) // ttl assert.Equal(t, 2*time.Hour, c.ConsentRequestMaxAge(ctx)) @@ -330,12 +348,20 @@ func TestViperProviderValidates(t *testing.T) { Jaeger: otelx.JaegerConfig{ LocalAgentAddress: "127.0.0.1:6831", Sampling: otelx.JaegerSampling{ - ServerURL: "http://sampling", + ServerURL: "http://sampling", + TraceIdRatio: 1, }, }, Zipkin: otelx.ZipkinConfig{ ServerURL: "http://zipkin/api/v2/spans", }, + OTLP: otelx.OTLPConfig{ + ServerURL: "localhost:4318", + Insecure: true, + Sampling: otelx.OTLPSampling{ + SamplingRatio: 1.0, + }, + }, }, }, c.Tracing()) } @@ -406,17 +432,44 @@ func TestCookieSecure(t *testing.T) { assert.True(t, c.CookieSecure(ctx)) } -func TestTokenRefreshHookURL(t *testing.T) { +func TestHookConfigs(t *testing.T) { ctx := context.Background() l := logrusx.New("", "") l.Logrus().SetOutput(io.Discard) c := MustNew(context.Background(), l, configx.SkipValidation()) - assert.EqualValues(t, (*url.URL)(nil), c.TokenRefreshHookURL(ctx)) - c.MustSet(ctx, KeyRefreshTokenHookURL, "") - assert.EqualValues(t, (*url.URL)(nil), c.TokenRefreshHookURL(ctx)) - c.MustSet(ctx, KeyRefreshTokenHookURL, "http://localhost:8080/oauth/token_refresh") - assert.EqualValues(t, "http://localhost:8080/oauth/token_refresh", c.TokenRefreshHookURL(ctx).String()) + for key, getFunc := range map[string]func(context.Context) *HookConfig{ + KeyRefreshTokenHook: c.TokenRefreshHookConfig, + KeyTokenHook: c.TokenHookConfig, + } { + assert.Nil(t, getFunc(ctx)) + c.MustSet(ctx, key, "") + assert.Nil(t, getFunc(ctx)) + c.MustSet(ctx, key, "http://localhost:8080/hook") + hc := getFunc(ctx) + require.NotNil(t, hc) + assert.EqualValues(t, "http://localhost:8080/hook", hc.URL) + + c.MustSet(ctx, key, ` +{ + "url": "http://localhost:8080/hook2", + "auth": { + "type": "api_key", + "config": { + "in": "header", + "name": "my-header", + "value": "my-value" + } + } +}`) + hc = getFunc(ctx) + require.NotNil(t, hc) + assert.EqualValues(t, "http://localhost:8080/hook2", hc.URL) + assert.EqualValues(t, "api_key", hc.Auth.Type) + rawConfig, err := json.Marshal(hc.Auth.Config) + require.NoError(t, err) + assert.JSONEq(t, `{"in":"header","name":"my-header","value":"my-value"}`, string(rawConfig)) + } } func TestJWTBearer(t *testing.T) { @@ -425,25 +478,41 @@ func TestJWTBearer(t *testing.T) { p := MustNew(context.Background(), l) ctx := context.Background() - //p.MustSet(ctx, KeyOAuth2GrantJWTClientAuthOptional, false) + // p.MustSet(ctx, KeyOAuth2GrantJWTClientAuthOptional, false) p.MustSet(ctx, KeyOAuth2GrantJWTMaxDuration, "1h") p.MustSet(ctx, KeyOAuth2GrantJWTIssuedDateOptional, false) p.MustSet(ctx, KeyOAuth2GrantJWTIDOptional, false) - //assert.Equal(t, false, p.GetGrantTypeJWTBearerCanSkipClientAuth(ctx)) + // assert.Equal(t, false, p.GetGrantTypeJWTBearerCanSkipClientAuth(ctx)) assert.Equal(t, 1.0, p.GetJWTMaxDuration(ctx).Hours()) assert.Equal(t, false, p.GetGrantTypeJWTBearerIssuedDateOptional(ctx)) assert.Equal(t, false, p.GetGrantTypeJWTBearerIDOptional(ctx)) p2 := MustNew(context.Background(), l) - //p2.MustSet(ctx, KeyOAuth2GrantJWTClientAuthOptional, true) + // p2.MustSet(ctx, KeyOAuth2GrantJWTClientAuthOptional, true) p2.MustSet(ctx, KeyOAuth2GrantJWTMaxDuration, "24h") p2.MustSet(ctx, KeyOAuth2GrantJWTIssuedDateOptional, true) p2.MustSet(ctx, KeyOAuth2GrantJWTIDOptional, true) - //assert.Equal(t, true, p2.GetGrantTypeJWTBearerCanSkipClientAuth(ctx)) + // assert.Equal(t, true, p2.GetGrantTypeJWTBearerCanSkipClientAuth(ctx)) assert.Equal(t, 24.0, p2.GetJWTMaxDuration(ctx).Hours()) assert.Equal(t, true, p2.GetGrantTypeJWTBearerIssuedDateOptional(ctx)) assert.Equal(t, true, p2.GetGrantTypeJWTBearerIDOptional(ctx)) } + +func TestJWTScopeClaimStrategy(t *testing.T) { + l := logrusx.New("", "") + l.Logrus().SetOutput(io.Discard) + p := MustNew(context.Background(), l) + + ctx := context.Background() + + assert.Equal(t, jwt.JWTScopeFieldList, p.GetJWTScopeField(ctx)) + p.MustSet(ctx, KeyJWTScopeClaimStrategy, "list") + assert.Equal(t, jwt.JWTScopeFieldList, p.GetJWTScopeField(ctx)) + p.MustSet(ctx, KeyJWTScopeClaimStrategy, "string") + assert.Equal(t, jwt.JWTScopeFieldString, p.GetJWTScopeField(ctx)) + p.MustSet(ctx, KeyJWTScopeClaimStrategy, "both") + assert.Equal(t, jwt.JWTScopeFieldBoth, p.GetJWTScopeField(ctx)) +} diff --git a/driver/config/serve.go b/driver/config/serve.go index f37dcde41eb..21932e3078f 100644 --- a/driver/config/serve.go +++ b/driver/config/serve.go @@ -6,7 +6,8 @@ package config import ( "context" "fmt" - "os" + "io/fs" + "math" "strings" "github.com/ory/x/contextx" @@ -63,10 +64,22 @@ func (p *DefaultProvider) ListenOn(iface ServeInterface) string { } func (p *DefaultProvider) SocketPermission(iface ServeInterface) *configx.UnixPermission { + modeInt := int64(0o755) + if p.getProvider(contextx.RootContext).Exists(iface.Key(KeySuffixSocketMode)) { + modeInt = int64(p.getProvider(contextx.RootContext).Int(iface.Key(KeySuffixSocketMode))) + } + mode := fs.FileMode(0) + if modeInt < 0 { + mode = 0 + } else if modeInt > math.MaxUint32 { + mode = 0777 + } else { + mode = fs.FileMode(modeInt) + } return &configx.UnixPermission{ Owner: p.getProvider(contextx.RootContext).String(iface.Key(KeySuffixSocketOwner)), Group: p.getProvider(contextx.RootContext).String(iface.Key(KeySuffixSocketGroup)), - Mode: os.FileMode(p.getProvider(contextx.RootContext).IntF(iface.Key(KeySuffixSocketMode), 0755)), + Mode: mode, } } diff --git a/driver/config/types_test.go b/driver/config/types_test.go index e7fe500f91e..39523fde6ea 100644 --- a/driver/config/types_test.go +++ b/driver/config/types_test.go @@ -19,6 +19,6 @@ func TestToAccessTokenStrategyType(t *testing.T) { require.NoError(t, err) assert.Equal(t, AccessTokenJWTStrategy, actual) - actual, err = ToAccessTokenStrategyType("invalid") + _, err = ToAccessTokenStrategyType("invalid") require.Error(t, err) } diff --git a/driver/di.go b/driver/di.go new file mode 100644 index 00000000000..584bf76c043 --- /dev/null +++ b/driver/di.go @@ -0,0 +1,70 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package driver + +import ( + "github.com/pkg/errors" + "go.opentelemetry.io/otel/trace" + + "github.com/ory/fosite" + "github.com/ory/fosite/handler/oauth2" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/fositex" + "github.com/ory/hydra/v2/hsm" + "github.com/ory/hydra/v2/internal/kratos" + "github.com/ory/x/contextx" + "github.com/ory/x/logrusx" +) + +// WritableRegistry is a deprecated interface that should not be used anymore. +// +// Deprecate this at some point. +type WritableRegistry interface { + // WithBuildInfo(v, h, d string) Registry + + WithConfig(c *config.DefaultProvider) Registry + WithContextualizer(ctxer contextx.Contextualizer) Registry + WithLogger(l *logrusx.Logger) Registry + WithTracer(t trace.Tracer) Registry + WithTracerWrapper(TracerWrapper) Registry + WithKratos(k kratos.Client) Registry + WithExtraFositeFactories(f []fositex.Factory) Registry + ExtraFositeFactories() []fositex.Factory + WithOAuth2Provider(f fosite.OAuth2Provider) + WithConsentStrategy(c consent.Strategy) + WithHsmContext(h hsm.Context) +} + +type RegistryModifier func(r Registry) error + +func WithRegistryModifiers(f ...RegistryModifier) OptionsModifier { + return func(o *Options) { + o.registryModifiers = f + } +} + +func RegistryWithHMACSHAStrategy(s func(r Registry) oauth2.CoreStrategy) RegistryModifier { + return func(r Registry) error { + switch rt := r.(type) { + case *RegistrySQL: + rt.hmacs = s(r) + default: + return errors.Errorf("unable to set HMAC strategy on registry of type %T", r) + } + return nil + } +} + +func RegistryWithHsmContext(h hsm.Context) RegistryModifier { + return func(r Registry) error { + switch rt := r.(type) { + case *RegistrySQL: + rt.hsm = h + default: + return errors.Errorf("unable to set HMAC strategy on registry of type %T", r) + } + return nil + } +} diff --git a/driver/factory.go b/driver/factory.go index 8f7a09928a6..c7b5d30c3f4 100644 --- a/driver/factory.go +++ b/driver/factory.go @@ -5,45 +5,59 @@ package driver import ( "context" + "io/fs" - "github.com/ory/x/servicelocatorx" + "github.com/pkg/errors" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/fositex" "github.com/ory/x/configx" - "github.com/ory/x/logrusx" - - "github.com/ory/hydra/driver/config" - "github.com/ory/x/contextx" + "github.com/ory/x/otelx" + "github.com/ory/x/popx" + "github.com/ory/x/servicelocatorx" ) -type options struct { - forcedValues map[string]interface{} - preload bool - validate bool - opts []configx.OptionModifier - config *config.DefaultProvider - // The first default refers to determining the NID at startup; the second default referes to the fact that the Contextualizer may dynamically change the NID. - skipNetworkInit bool -} +type ( + Options struct { + preload bool + validate bool + opts []configx.OptionModifier + config *config.DefaultProvider + // The first default refers to determining the NID at startup; the second default referes to the fact that the Contextualizer may dynamically change the NID. + skipNetworkInit bool + tracerWrapper TracerWrapper + extraMigrations []fs.FS + goMigrations []popx.Migration + fositexFactories []fositex.Factory + registryModifiers []RegistryModifier + inspect func(Registry) error + } + OptionsModifier func(*Options) + + TracerWrapper func(*otelx.Tracer) *otelx.Tracer +) -func newOptions() *options { - return &options{ +func NewOptions(opts []OptionsModifier) *Options { + o := &Options{ validate: true, preload: true, opts: []configx.OptionModifier{}, } + for _, f := range opts { + f(o) + } + return o } -func WithConfig(config *config.DefaultProvider) func(o *options) { - return func(o *options) { +func WithConfig(config *config.DefaultProvider) OptionsModifier { + return func(o *Options) { o.config = config } } -type OptionsModifier func(*options) - func WithOptions(opts ...configx.OptionModifier) OptionsModifier { - return func(o *options) { + return func(o *Options) { o.opts = append(o.opts, opts...) } } @@ -52,29 +66,58 @@ func WithOptions(opts ...configx.OptionModifier) OptionsModifier { // // This does not affect schema validation! func DisableValidation() OptionsModifier { - return func(o *options) { + return func(o *Options) { o.validate = false } } // DisablePreloading will not preload the config. func DisablePreloading() OptionsModifier { - return func(o *options) { + return func(o *Options) { o.preload = false } } func SkipNetworkInit() OptionsModifier { - return func(o *options) { + return func(o *Options) { o.skipNetworkInit = true } } -func New(ctx context.Context, sl *servicelocatorx.Options, opts []OptionsModifier) (Registry, error) { - o := newOptions() - for _, f := range opts { - f(o) +// WithTracerWrapper sets a function that wraps the tracer. +func WithTracerWrapper(wrapper TracerWrapper) OptionsModifier { + return func(o *Options) { + o.tracerWrapper = wrapper + } +} + +// WithExtraMigrations specifies additional database migration. +func WithExtraMigrations(m ...fs.FS) OptionsModifier { + return func(o *Options) { + o.extraMigrations = append(o.extraMigrations, m...) + } +} + +func WithGoMigrations(m ...popx.Migration) OptionsModifier { + return func(o *Options) { + o.goMigrations = append(o.goMigrations, m...) + } +} + +func WithExtraFositeFactories(f ...fositex.Factory) OptionsModifier { + return func(o *Options) { + o.fositexFactories = append(o.fositexFactories, f...) + } +} + +func Inspect(f func(Registry) error) OptionsModifier { + return func(o *Options) { + o.inspect = f } +} + +func New(ctx context.Context, sl *servicelocatorx.Options, opts []OptionsModifier) (Registry, error) { + o := NewOptions(opts) l := sl.Logger() if l == nil { @@ -98,13 +141,25 @@ func New(ctx context.Context, sl *servicelocatorx.Options, opts []OptionsModifie } } - r, err := NewRegistryFromDSN(ctx, c, l, o.skipNetworkInit, false, ctxter) + r, err := NewRegistryWithoutInit(c, l) if err != nil { l.WithError(err).Error("Unable to create service registry.") return nil, err } - if err = r.Init(ctx, o.skipNetworkInit, false, &contextx.Default{}); err != nil { + if o.tracerWrapper != nil { + r.WithTracerWrapper(o.tracerWrapper) + } + + r.WithExtraFositeFactories(o.fositexFactories) + + for _, f := range o.registryModifiers { + if err := f(r); err != nil { + return nil, err + } + } + + if err = r.Init(ctx, o.skipNetworkInit, false, ctxter, o.extraMigrations, o.goMigrations); err != nil { l.WithError(err).Error("Unable to initialize service registry.") return nil, err } @@ -114,6 +169,11 @@ func New(ctx context.Context, sl *servicelocatorx.Options, opts []OptionsModifie CallRegistry(ctx, r) } - c.Source(ctx).SetTracer(ctx, r.Tracer(ctx)) + if o.inspect != nil { + if err := o.inspect(r); err != nil { + return nil, errors.WithStack(err) + } + } + return r, nil } diff --git a/driver/registry.go b/driver/registry.go index f12dc429f0d..954d77a5ad4 100644 --- a/driver/registry.go +++ b/driver/registry.go @@ -5,50 +5,49 @@ package driver import ( "context" + "io/fs" + "net/http" - "github.com/ory/x/httprouterx" + enigma "github.com/ory/fosite/token/hmac" + "github.com/ory/x/popx" - "github.com/ory/hydra/hsm" + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/internal/kratos" "github.com/ory/x/contextx" + "github.com/ory/x/httprouterx" - "github.com/ory/hydra/oauth2/trust" - - "github.com/pkg/errors" - - "github.com/ory/x/errorsx" + "github.com/ory/hydra/v2/oauth2/trust" "github.com/ory/fosite" foauth2 "github.com/ory/fosite/handler/oauth2" "github.com/ory/x/logrusx" - "github.com/ory/hydra/persistence" + "github.com/ory/hydra/v2/persistence" prometheus "github.com/ory/x/prometheusx" "github.com/ory/x/dbal" "github.com/ory/x/healthx" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/x" ) type Registry interface { dbal.Driver + WritableRegistry - Init(ctx context.Context, skipNetworkInit bool, migrate bool, ctxer contextx.Contextualizer) error + Init(ctx context.Context, skipNetworkInit bool, migrate bool, ctxer contextx.Contextualizer, extraMigrations []fs.FS, goMigrations []popx.Migration) error - WithBuildInfo(v, h, d string) Registry - WithConfig(c *config.DefaultProvider) Registry - WithContextualizer(ctxer contextx.Contextualizer) Registry - WithLogger(l *logrusx.Logger) Registry x.HTTPClientProvider GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy + contextx.Provider config.Provider persistence.Provider x.RegistryLogger @@ -61,6 +60,9 @@ type Registry interface { oauth2.Registry PrometheusManager() *prometheus.MetricsManager x.TracingProvider + FlowCipher() *aead.XChaCha20Poly1305 + + kratos.Provider RegisterRoutes(ctx context.Context, admin *httprouterx.RouterAdmin, public *httprouterx.RouterPublic) ClientHandler() *client.Handler @@ -68,11 +70,10 @@ type Registry interface { ConsentHandler() *consent.Handler OAuth2Handler() *oauth2.Handler HealthHandler() *healthx.Handler + OAuth2EnigmaStrategy() *enigma.HMACStrategy + OAuth2AwareMiddleware() func(h http.Handler) http.Handler - OAuth2HMACStrategy() *foauth2.HMACSHAStrategy - WithOAuth2Provider(f fosite.OAuth2Provider) - WithConsentStrategy(c consent.Strategy) - WithHsmContext(h hsm.Context) + OAuth2HMACStrategy() foauth2.CoreStrategy } func NewRegistryFromDSN(ctx context.Context, c *config.DefaultProvider, l *logrusx.Logger, skipNetworkInit bool, migrate bool, ctxer contextx.Contextualizer) (Registry, error) { @@ -80,22 +81,26 @@ func NewRegistryFromDSN(ctx context.Context, c *config.DefaultProvider, l *logru if err != nil { return nil, err } - if err := registry.Init(ctx, skipNetworkInit, migrate, ctxer); err != nil { + + if err := registry.Init(ctx, skipNetworkInit, migrate, ctxer, nil, nil); err != nil { return nil, err } + return registry, nil } func NewRegistryWithoutInit(c *config.DefaultProvider, l *logrusx.Logger) (Registry, error) { - driver, err := dbal.GetDriverFor(c.DSN()) - if err != nil { - return nil, errorsx.WithStack(err) - } - registry, ok := driver.(Registry) - if !ok { - return nil, errors.Errorf("driver of type %T does not implement interface Registry", driver) + registry := NewRegistrySQL( + c, l, config.Version, config.Commit, config.Date, + ) + + if !registry.CanHandle(c.DSN()) { + if dbal.IsSQLite(c.DSN()) { + return nil, dbal.ErrSQLiteSupportMissing + } + + return nil, dbal.ErrNoResponsibleDriverFound } - registry = registry.WithLogger(l).WithConfig(c).WithBuildInfo(config.Version, config.Commit, config.Date) return registry, nil } @@ -109,6 +114,7 @@ func CallRegistry(ctx context.Context, r Registry) { r.SubjectIdentifierAlgorithm(ctx) r.KeyManager() r.KeyCipher() + r.FlowCipher() r.OAuth2Storage() r.OAuth2Provider() r.AudienceStrategy() diff --git a/driver/registry_base.go b/driver/registry_base.go deleted file mode 100644 index 8a81a8fa4b1..00000000000 --- a/driver/registry_base.go +++ /dev/null @@ -1,547 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package driver - -import ( - "context" - "crypto/sha256" - "fmt" - "net/http" - "time" - - "github.com/ory/x/popx" - - "github.com/ory/x/httprouterx" - - "github.com/rs/cors" - - "github.com/hashicorp/go-retryablehttp" - - "github.com/ory/hydra/fositex" - ctxx "github.com/ory/x/contextx" - "github.com/ory/x/httpx" - "github.com/ory/x/otelx" - - "github.com/ory/hydra/hsm" - - prometheus "github.com/ory/x/prometheusx" - - "github.com/pkg/errors" - - "github.com/ory/hydra/oauth2/trust" - "github.com/ory/hydra/x/oauth2cors" - "github.com/ory/x/contextx" - - "github.com/ory/hydra/persistence" - - "github.com/prometheus/client_golang/prometheus/promhttp" - - "github.com/ory/x/logrusx" - - "github.com/gorilla/sessions" - - "github.com/ory/fosite" - "github.com/ory/fosite/compose" - foauth2 "github.com/ory/fosite/handler/oauth2" - "github.com/ory/fosite/handler/openid" - "github.com/ory/herodot" - - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/x" - "github.com/ory/x/healthx" -) - -var ( - _ contextx.Provider = (*RegistryBase)(nil) -) - -type RegistryBase struct { - l *logrusx.Logger - al *logrusx.Logger - conf *config.DefaultProvider - ch *client.Handler - fh fosite.Hasher - jwtGrantH *trust.Handler - jwtGrantV *trust.GrantValidator - kh *jwk.Handler - cv *client.Validator - ctxer contextx.Contextualizer - hh *healthx.Handler - migrationStatus *popx.MigrationStatuses - kc *jwk.AEAD - cos consent.Strategy - writer herodot.Writer - fsc fosite.ScopeStrategy - atjs jwk.JWTSigner - idtjs jwk.JWTSigner - hsm hsm.Context - fscPrev string - forv *openid.OpenIDConnectRequestValidator - fop fosite.OAuth2Provider - coh *consent.Handler - oah *oauth2.Handler - sia map[string]consent.SubjectIdentifierAlgorithm - trc *otelx.Tracer - pmm *prometheus.MetricsManager - oa2mw func(h http.Handler) http.Handler - o2mc *foauth2.HMACSHAStrategy - o2jwt *foauth2.DefaultJWTStrategy - arhs []oauth2.AccessRequestHook - buildVersion string - buildHash string - buildDate string - r Registry - persister persistence.Persister - jfs fosite.JWKSFetcherStrategy - oc fosite.Configurator - oidcs jwk.JWTSigner - ats jwk.JWTSigner - hmacs *foauth2.HMACSHAStrategy - fc *fositex.Config - publicCORS *cors.Cors -} - -func (m *RegistryBase) GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy { - if m.jfs == nil { - m.jfs = fosite.NewDefaultJWKSFetcherStrategy(fosite.JWKSFetcherWithHTTPClientSource(func(ctx context.Context) *retryablehttp.Client { - return m.HTTPClient(ctx) - })) - } - return m.jfs -} - -func (m *RegistryBase) WithContextualizer(ctxer contextx.Contextualizer) Registry { - m.ctxer = ctxer - return m.r -} - -func (m *RegistryBase) Contextualizer() contextx.Contextualizer { - if m.ctxer == nil { - panic("registry Contextualizer not set") - } - return m.ctxer -} - -func (m *RegistryBase) with(r Registry) *RegistryBase { - m.r = r - return m -} - -func (m *RegistryBase) WithBuildInfo(version, hash, date string) Registry { - m.buildVersion = version - m.buildHash = hash - m.buildDate = date - return m.r -} - -func (m *RegistryBase) OAuth2AwareMiddleware(ctx context.Context) func(h http.Handler) http.Handler { - if m.oa2mw == nil { - m.oa2mw = oauth2cors.Middleware(ctx, m.r) - } - return m.oa2mw -} - -func (m *RegistryBase) addPublicCORSOnHandler(ctx context.Context) func(http.Handler) http.Handler { - corsConfig, corsEnabled := m.Config().CORS(ctx, config.PublicInterface) - if !corsEnabled { - return func(h http.Handler) http.Handler { - return h - } - } - if m.publicCORS == nil { - m.publicCORS = cors.New(corsConfig) - } - return func(h http.Handler) http.Handler { - return m.publicCORS.Handler(h) - } -} - -func (m *RegistryBase) RegisterRoutes(ctx context.Context, admin *httprouterx.RouterAdmin, public *httprouterx.RouterPublic) { - m.HealthHandler().SetHealthRoutes(admin.Router, true) - m.HealthHandler().SetVersionRoutes(admin.Router) - - m.HealthHandler().SetHealthRoutes(public.Router, false, healthx.WithMiddleware(m.addPublicCORSOnHandler(ctx))) - - admin.Handler("GET", prometheus.MetricsPrometheusPath, promhttp.Handler()) - - m.ConsentHandler().SetRoutes(admin) - m.KeyHandler().SetRoutes(admin, public, m.OAuth2AwareMiddleware(ctx)) - m.ClientHandler().SetRoutes(admin, public) - m.OAuth2Handler().SetRoutes(admin, public, m.OAuth2AwareMiddleware(ctx)) - m.JWTGrantHandler().SetRoutes(admin) -} - -func (m *RegistryBase) BuildVersion() string { - return m.buildVersion -} - -func (m *RegistryBase) BuildDate() string { - return m.buildDate -} - -func (m *RegistryBase) BuildHash() string { - return m.buildHash -} - -func (m *RegistryBase) WithConfig(c *config.DefaultProvider) Registry { - m.conf = c - return m.r -} - -func (m *RegistryBase) Writer() herodot.Writer { - if m.writer == nil { - h := herodot.NewJSONWriter(m.Logger()) - h.ErrorEnhancer = x.ErrorEnhancer - m.writer = h - } - return m.writer -} - -func (m *RegistryBase) WithLogger(l *logrusx.Logger) Registry { - m.l = l - return m.r -} - -func (m *RegistryBase) Logger() *logrusx.Logger { - if m.l == nil { - m.l = logrusx.New("Ory Hydra", m.BuildVersion()) - } - return m.l -} - -func (m *RegistryBase) AuditLogger() *logrusx.Logger { - if m.al == nil { - m.al = logrusx.NewAudit("Ory Hydra", m.BuildVersion()) - m.al.UseConfig(m.Config().Source(ctxx.RootContext)) - } - return m.al -} - -func (m *RegistryBase) ClientHasher() fosite.Hasher { - if m.fh == nil { - m.fh = x.NewHasher(m.Config()) - } - return m.fh -} - -func (m *RegistryBase) ClientHandler() *client.Handler { - if m.ch == nil { - m.ch = client.NewHandler(m.r) - } - return m.ch -} - -func (m *RegistryBase) ClientValidator() *client.Validator { - if m.cv == nil { - m.cv = client.NewValidator(m.r) - } - return m.cv -} - -func (m *RegistryBase) KeyHandler() *jwk.Handler { - if m.kh == nil { - m.kh = jwk.NewHandler(m.r) - } - return m.kh -} - -func (m *RegistryBase) JWTGrantHandler() *trust.Handler { - if m.jwtGrantH == nil { - m.jwtGrantH = trust.NewHandler(m.r) - } - return m.jwtGrantH -} - -func (m *RegistryBase) GrantValidator() *trust.GrantValidator { - if m.jwtGrantV == nil { - m.jwtGrantV = trust.NewGrantValidator() - } - return m.jwtGrantV -} - -func (m *RegistryBase) HealthHandler() *healthx.Handler { - if m.hh == nil { - m.hh = healthx.NewHandler(m.Writer(), m.buildVersion, healthx.ReadyCheckers{ - "database": func(_ *http.Request) error { - return m.r.Ping() - }, - "migrations": func(r *http.Request) error { - if m.migrationStatus != nil && !m.migrationStatus.HasPending() { - return nil - } - - status, err := m.r.Persister().MigrationStatus(r.Context()) - if err != nil { - return err - } - - if status.HasPending() { - err := errors.Errorf("migrations have not yet been fully applied: %+v", status) - m.Logger().WithField("status", fmt.Sprintf("%+v", status)).WithError(err).Warn("Instance is not yet ready because migrations have not yet been fully applied.") - return err - } - - m.migrationStatus = &status - return nil - }, - }) - } - - return m.hh -} - -func (m *RegistryBase) ConsentStrategy() consent.Strategy { - if m.cos == nil { - m.cos = consent.NewStrategy(m.r, m.Config()) - } - return m.cos -} - -func (m *RegistryBase) KeyCipher() *jwk.AEAD { - if m.kc == nil { - m.kc = jwk.NewAEAD(m.Config()) - } - return m.kc -} - -func (m *RegistryBase) CookieStore(ctx context.Context) (sessions.Store, error) { - var keys [][]byte - secrets, err := m.conf.GetCookieSecrets(ctx) - if err != nil { - return nil, err - } - - for _, k := range secrets { - encrypt := sha256.Sum256(k) - keys = append(keys, k, encrypt[:]) - } - - cs := sessions.NewCookieStore(keys...) - cs.Options.Secure = m.Config().CookieSecure(ctx) - cs.Options.HttpOnly = true - - // CookieStore MaxAge is set to 86400 * 30 by default. This prevents secure cookies retrieval with expiration > 30 days. - // MaxAge(0) disables internal MaxAge check by SecureCookie, see: - // - // https://github.com/ory/hydra/pull/2488#discussion_r618992698 - cs.MaxAge(0) - - if domain := m.Config().CookieDomain(ctx); domain != "" { - cs.Options.Domain = domain - } - - cs.Options.Path = "/" - if sameSite := m.Config().CookieSameSiteMode(ctx); sameSite != 0 { - cs.Options.SameSite = sameSite - } - - return cs, nil -} - -func (m *RegistryBase) HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client { - opts = append(opts, - httpx.ResilientClientWithLogger(m.Logger()), - httpx.ResilientClientWithMaxRetry(2), - httpx.ResilientClientWithConnectionTimeout(30*time.Second)) - - tracer := m.Tracer(ctx) - if tracer.IsLoaded() { - opts = append(opts, httpx.ResilientClientWithTracer(tracer.Tracer())) - } - - if m.Config().ClientHTTPNoPrivateIPRanges() { - opts = append(opts, httpx.ResilientClientDisallowInternalIPs()) - } - return httpx.NewResilientClient(opts...) -} - -func (m *RegistryBase) OAuth2Provider() fosite.OAuth2Provider { - if m.fop != nil { - return m.fop - } - - m.fop = fosite.NewOAuth2Provider(m.r.OAuth2Storage(), m.OAuth2ProviderConfig()) - return m.fop -} - -func (m *RegistryBase) OpenIDJWTStrategy() jwk.JWTSigner { - if m.oidcs != nil { - return m.oidcs - } - - m.oidcs = jwk.NewDefaultJWTSigner(m.Config(), m.r, x.OpenIDConnectKeyName) - return m.oidcs -} - -func (m *RegistryBase) AccessTokenJWTStrategy() jwk.JWTSigner { - if m.ats != nil { - return m.ats - } - - m.ats = jwk.NewDefaultJWTSigner(m.Config(), m.r, x.OAuth2JWTKeyName) - return m.ats -} - -func (m *RegistryBase) OAuth2HMACStrategy() *foauth2.HMACSHAStrategy { - if m.hmacs != nil { - return m.hmacs - } - - m.hmacs = compose.NewOAuth2HMACStrategy(m.OAuth2Config()) - return m.hmacs -} - -func (m *RegistryBase) OAuth2Config() *fositex.Config { - if m.fc != nil { - return m.fc - } - - m.fc = fositex.NewConfig(m.r) - return m.fc -} - -func (m *RegistryBase) OAuth2ProviderConfig() fosite.Configurator { - if m.oc != nil { - return m.oc - } - - conf := m.OAuth2Config() - hmacAtStrategy := m.OAuth2HMACStrategy() - oidcSigner := m.OpenIDJWTStrategy() - atSigner := m.AccessTokenJWTStrategy() - jwtAtStrategy := &foauth2.DefaultJWTStrategy{ - Signer: atSigner, - HMACSHAStrategy: hmacAtStrategy, - Config: conf, - } - - conf.LoadDefaultHanlders(&compose.CommonStrategy{ - CoreStrategy: fositex.NewTokenStrategy(m.Config(), hmacAtStrategy, &foauth2.DefaultJWTStrategy{ - Signer: jwtAtStrategy, - HMACSHAStrategy: hmacAtStrategy, - Config: conf, - }), - OpenIDConnectTokenStrategy: &openid.DefaultStrategy{ - Config: conf, - Signer: oidcSigner, - }, - Signer: oidcSigner, - }) - - m.oc = conf - return m.oc -} - -func (m *RegistryBase) OpenIDConnectRequestValidator() *openid.OpenIDConnectRequestValidator { - if m.forv == nil { - m.forv = openid.NewOpenIDConnectRequestValidator(&openid.DefaultStrategy{ - Config: m.OAuth2ProviderConfig(), - Signer: m.OpenIDJWTStrategy(), - }, m.OAuth2ProviderConfig()) - } - return m.forv -} - -func (m *RegistryBase) AudienceStrategy() fosite.AudienceMatchingStrategy { - return fosite.DefaultAudienceMatchingStrategy -} - -func (m *RegistryBase) ConsentHandler() *consent.Handler { - if m.coh == nil { - m.coh = consent.NewHandler(m.r, m.Config()) - } - return m.coh -} - -func (m *RegistryBase) OAuth2Handler() *oauth2.Handler { - if m.oah == nil { - m.oah = oauth2.NewHandler(m.r, m.Config()) - } - return m.oah -} - -func (m *RegistryBase) SubjectIdentifierAlgorithm(ctx context.Context) map[string]consent.SubjectIdentifierAlgorithm { - if m.sia == nil { - m.sia = map[string]consent.SubjectIdentifierAlgorithm{} - for _, t := range m.Config().SubjectTypesSupported(ctx) { - switch t { - case "public": - m.sia["public"] = consent.NewSubjectIdentifierAlgorithmPublic() - case "pairwise": - m.sia["pairwise"] = consent.NewSubjectIdentifierAlgorithmPairwise([]byte(m.Config().SubjectIdentifierAlgorithmSalt(ctx))) - } - } - } - return m.sia -} - -func (m *RegistryBase) Tracer(ctx context.Context) *otelx.Tracer { - if m.trc == nil { - t, err := otelx.New("Ory Hydra", m.l, m.conf.Tracing()) - if err != nil { - m.Logger().WithError(err).Error("Unable to initialize Tracer.") - } else { - m.trc = t - } - } - if m.trc.Tracer() == nil { - m.trc = otelx.NewNoop(m.l, m.Config().Tracing()) - } - - return m.trc -} - -func (m *RegistryBase) PrometheusManager() *prometheus.MetricsManager { - if m.pmm == nil { - m.pmm = prometheus.NewMetricsManagerWithPrefix("hydra", prometheus.HTTPMetrics, m.buildVersion, m.buildHash, m.buildDate) - } - return m.pmm -} - -func (m *RegistryBase) Persister() persistence.Persister { - return m.persister -} - -// Config returns the configuration for the given context. It may or may not be the same as the global configuration. -func (m *RegistryBase) Config() *config.DefaultProvider { - return m.conf -} - -// WithOAuth2Provider forces an oauth2 provider which is only used for testing. -func (m *RegistryBase) WithOAuth2Provider(f fosite.OAuth2Provider) { - m.fop = f -} - -// WithConsentStrategy forces a consent strategy which is only used for testing. -func (m *RegistryBase) WithConsentStrategy(c consent.Strategy) { - m.cos = c -} - -func (m *RegistryBase) AccessRequestHooks() []oauth2.AccessRequestHook { - if m.arhs == nil { - m.arhs = []oauth2.AccessRequestHook{ - oauth2.RefreshTokenHook(m), - } - } - return m.arhs -} - -func (m *RegistryBase) WithHsmContext(h hsm.Context) { - m.hsm = h -} - -func (m *RegistryBase) HSMContext() hsm.Context { - if m.hsm == nil { - m.hsm = hsm.NewContext(m.Config(), m.l) - } - return m.hsm -} - -func (m *RegistrySQL) ClientAuthenticator() x.ClientAuthenticator { - return m.OAuth2Provider().(*fosite.Fosite) -} diff --git a/driver/registry_base_test.go b/driver/registry_base_test.go deleted file mode 100644 index abf7c1a4303..00000000000 --- a/driver/registry_base_test.go +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package driver - -import ( - "context" - "errors" - "io" - "testing" - - "github.com/ory/x/randx" - - "github.com/stretchr/testify/require" - - "github.com/ory/x/httpx" - - "github.com/sirupsen/logrus" - "github.com/sirupsen/logrus/hooks/test" - "github.com/stretchr/testify/assert" - - "github.com/ory/hydra/driver/config" - "github.com/ory/x/configx" - "github.com/ory/x/contextx" - "github.com/ory/x/logrusx" - - "github.com/gorilla/sessions" -) - -func TestGetJWKSFetcherStrategyHostEnforcment(t *testing.T) { - ctx := context.Background() - l := logrusx.New("", "") - c := config.MustNew(context.Background(), l, configx.WithConfigFiles("../internal/.hydra.yaml")) - c.MustSet(ctx, config.KeyDSN, "memory") - c.MustSet(ctx, config.HSMEnabled, "false") - c.MustSet(ctx, config.ViperKeyClientHTTPNoPrivateIPRanges, true) - - registry, err := NewRegistryWithoutInit(c, l) - require.NoError(t, err) - - _, err = registry.GetJWKSFetcherStrategy().Resolve(ctx, "http://localhost:8080", true) - require.ErrorAs(t, err, new(httpx.ErrPrivateIPAddressDisallowed)) -} - -func TestRegistryBase_newKeyStrategy_handlesNetworkError(t *testing.T) { - // Test ensures any network specific error is logged with a - // specific message when attempting to create a new key strategy: issue #2338 - - hook := test.Hook{} // Test hook for asserting log messages - ctx := context.Background() - - l := logrusx.New("", "", logrusx.WithHook(&hook)) - l.Logrus().SetOutput(io.Discard) - l.Logrus().ExitFunc = func(int) {} // Override the exit func to avoid call to os.Exit - - // Create a config and set a valid but unresolvable DSN - c := config.MustNew(context.Background(), l, configx.WithConfigFiles("../internal/.hydra.yaml")) - c.MustSet(ctx, config.KeyDSN, "postgres://user:password@127.0.0.1:9999/postgres") - c.MustSet(ctx, config.HSMEnabled, "false") - - registry, err := NewRegistryWithoutInit(c, l) - if err != nil { - t.Errorf("Failed to create registry: %s", err) - return - } - - r := registry.(*RegistrySQL) - r.initialPing = failedPing(errors.New("snizzles")) - - _ = r.Init(context.Background(), true, false, &contextx.TestContextualizer{}) - - registryBase := RegistryBase{r: r, l: l} - registryBase.WithConfig(c) - - assert.Equal(t, logrus.FatalLevel, hook.LastEntry().Level) - assert.Contains(t, hook.LastEntry().Message, "snizzles") -} - -func TestRegistryBase_CookieStore_MaxAgeZero(t *testing.T) { - // Test ensures that CookieStore MaxAge option is equal to zero after initialization - - ctx := context.Background() - r := new(RegistryBase) - r.WithConfig(config.MustNew(context.Background(), logrusx.New("", ""), configx.WithValue(config.KeyGetSystemSecret, []string{randx.MustString(32, randx.AlphaNum)}))) - - s, err := r.CookieStore(ctx) - require.NoError(t, err) - cs := s.(*sessions.CookieStore) - - assert.Equal(t, cs.Options.MaxAge, 0) -} diff --git a/driver/registry_sql.go b/driver/registry_sql.go index 8162b5c13c0..7cef650f955 100644 --- a/driver/registry_sql.go +++ b/driver/registry_sql.go @@ -5,49 +5,113 @@ package driver import ( "context" + "crypto/sha256" + "fmt" + "io/fs" + "net/http" "strings" "time" + "github.com/gorilla/sessions" + "github.com/hashicorp/go-retryablehttp" "github.com/pkg/errors" - - "github.com/ory/hydra/hsm" - "github.com/ory/x/contextx" + "github.com/prometheus/client_golang/prometheus/promhttp" + "github.com/rs/cors" + + "github.com/ory/fosite" + "github.com/ory/fosite/compose" + foauth2 "github.com/ory/fosite/handler/oauth2" + "github.com/ory/fosite/handler/openid" + "github.com/ory/fosite/token/hmac" + "github.com/ory/herodot" + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/fositex" + "github.com/ory/hydra/v2/internal/kratos" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/persistence" + "github.com/ory/hydra/v2/x/oauth2cors" + "github.com/ory/x/healthx" + "github.com/ory/x/httprouterx" + "github.com/ory/x/httpx" + "github.com/ory/x/logrusx" + "github.com/ory/x/otelx" + prometheus "github.com/ory/x/prometheusx" "github.com/gobuffalo/pop/v6" - - "github.com/ory/hydra/oauth2/trust" - "github.com/ory/x/errorsx" - "github.com/ory/x/networkx" - "github.com/ory/x/popx" - + _ "github.com/jackc/pgx/v5/stdlib" "github.com/luna-duclos/instrumentedsql" - "github.com/ory/x/resilience" - - _ "github.com/jackc/pgx/v4/stdlib" - - "github.com/ory/hydra/persistence/sql" - - "github.com/jmoiron/sqlx" + "go.opentelemetry.io/otel/trace" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/hsm" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/oauth2/trust" + "github.com/ory/hydra/v2/persistence/sql" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/contextx" "github.com/ory/x/dbal" + "github.com/ory/x/errorsx" otelsql "github.com/ory/x/otelx/sql" + "github.com/ory/x/popx" + "github.com/ory/x/resilience" "github.com/ory/x/sqlcon" - - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/x" ) type RegistrySQL struct { - *RegistryBase - db *sqlx.DB + l *logrusx.Logger + al *logrusx.Logger + conf *config.DefaultProvider + ch *client.Handler + fh fosite.Hasher + jwtGrantH *trust.Handler + jwtGrantV *trust.GrantValidator + kh *jwk.Handler + cv *client.Validator + ctxer contextx.Contextualizer + hh *healthx.Handler + migrationStatus *popx.MigrationStatuses + kc *aead.AESGCM + flowc *aead.XChaCha20Poly1305 + cos consent.Strategy + writer herodot.Writer + hsm hsm.Context + forv *openid.OpenIDConnectRequestValidator + fop fosite.OAuth2Provider + coh *consent.Handler + oah *oauth2.Handler + sia map[string]consent.SubjectIdentifierAlgorithm + trc *otelx.Tracer + tracerWrapper func(*otelx.Tracer) *otelx.Tracer + pmm *prometheus.MetricsManager + oa2mw func(h http.Handler) http.Handler + arhs []oauth2.AccessRequestHook + buildVersion string + buildHash string + buildDate string + r Registry + persister persistence.Persister + jfs fosite.JWKSFetcherStrategy + oc fosite.Configurator + oidcs jwk.JWTSigner + ats jwk.JWTSigner + hmacs foauth2.CoreStrategy + enigmaHMAC *hmac.HMACStrategy + fc *fositex.Config + publicCORS *cors.Cors + kratos kratos.Client + fositeFactories []fositex.Factory + defaultKeyManager jwk.Manager initialPing func(r *RegistrySQL) error } -var _ Registry = new(RegistrySQL) +var ( + _ contextx.Provider = (*RegistrySQL)(nil) + _ Registry = (*RegistrySQL)(nil) +) // defaultInitialPing is the default function that will be called within RegistrySQL.Init to make sure // the database is reachable. It can be injected for test purposes by changing the value @@ -60,41 +124,30 @@ var defaultInitialPing = func(m *RegistrySQL) error { return nil } -func init() { - dbal.RegisterDriver( - func() dbal.Driver { - return NewRegistrySQL() - }, - ) -} - -func NewRegistrySQL() *RegistrySQL { +func NewRegistrySQL( + c *config.DefaultProvider, + l *logrusx.Logger, + version, hash, date string, +) *RegistrySQL { r := &RegistrySQL{ - RegistryBase: new(RegistryBase), + buildVersion: version, + buildHash: hash, + buildDate: date, + l: l, + conf: c, initialPing: defaultInitialPing, } - r.RegistryBase.with(r) - return r -} - -func (m *RegistrySQL) determineNetwork(c *pop.Connection, ctx context.Context) (*networkx.Network, error) { - mb, err := popx.NewMigrationBox(networkx.Migrations, popx.NewMigrator(c, m.Logger(), m.Tracer(ctx), 0)) - if err != nil { - return nil, err - } - s, err := mb.Status(ctx) - if err != nil { - return nil, err - } - if s.HasPending() { - return nil, errors.WithStack(errors.New("some migrations are pending")) - } - return networkx.NewManager(c, m.Logger(), m.Tracer(ctx)).Determine(ctx) + return r } func (m *RegistrySQL) Init( - ctx context.Context, skipNetworkInit bool, migrate bool, ctxer contextx.Contextualizer, + ctx context.Context, + skipNetworkInit bool, + migrate bool, + ctxer contextx.Contextualizer, + extraMigrations []fs.FS, + goMigrations []popx.Migration, ) error { if m.persister == nil { m.WithContextualizer(ctxer) @@ -102,6 +155,8 @@ func (m *RegistrySQL) Init( if m.Tracer(ctx).IsLoaded() { opts = []instrumentedsql.Opt{ instrumentedsql.WithTracer(otelsql.NewTracer()), + instrumentedsql.WithOmitArgs(), // don't risk leaking PII or secrets + instrumentedsql.WithOpsExcluded(instrumentedsql.OpSQLRowsNext), } } @@ -128,7 +183,7 @@ func (m *RegistrySQL) Init( return errorsx.WithStack(err) } - p, err := sql.NewPersister(ctx, c, m, m.Config(), m.l) + p, err := sql.NewPersister(ctx, c, m, m.Config(), extraMigrations, goMigrations) if err != nil { return err } @@ -192,8 +247,12 @@ func (m *RegistrySQL) alwaysCanHandle(dsn string) bool { return s == dbal.DriverMySQL || s == dbal.DriverPostgreSQL || s == dbal.DriverCockroachDB } +func (m *RegistrySQL) PingContext(ctx context.Context) error { + return m.Persister().Ping(ctx) +} + func (m *RegistrySQL) Ping() error { - return m.Persister().Ping() + return m.PingContext(context.Background()) } func (m *RegistrySQL) ClientManager() client.Manager { @@ -219,3 +278,489 @@ func (m *RegistrySQL) SoftwareKeyManager() jwk.Manager { func (m *RegistrySQL) GrantManager() trust.GrantManager { return m.Persister() } + +func (m *RegistrySQL) GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy { + if m.jfs == nil { + m.jfs = fosite.NewDefaultJWKSFetcherStrategy(fosite.JWKSFetcherWithHTTPClientSource(func(ctx context.Context) *retryablehttp.Client { + return m.HTTPClient(ctx) + })) + } + return m.jfs +} + +func (m *RegistrySQL) WithContextualizer(ctxer contextx.Contextualizer) Registry { + m.ctxer = ctxer + return m +} + +func (m *RegistrySQL) Contextualizer() contextx.Contextualizer { + if m.ctxer == nil { + panic("registry Contextualizer not set") + } + return m.ctxer +} + +func (m *RegistrySQL) OAuth2AwareMiddleware() func(h http.Handler) http.Handler { + if m.oa2mw == nil { + m.oa2mw = oauth2cors.Middleware(m) + } + return m.oa2mw +} + +func (m *RegistrySQL) addPublicCORSOnHandler(ctx context.Context) func(http.Handler) http.Handler { + corsConfig, corsEnabled := m.Config().CORS(ctx, config.PublicInterface) + if !corsEnabled { + return func(h http.Handler) http.Handler { + return h + } + } + if m.publicCORS == nil { + m.publicCORS = cors.New(corsConfig) + } + return func(h http.Handler) http.Handler { + return m.publicCORS.Handler(h) + } +} + +func (m *RegistrySQL) RegisterRoutes(ctx context.Context, admin *httprouterx.RouterAdmin, public *httprouterx.RouterPublic) { + m.HealthHandler().SetHealthRoutes(admin.Router, true) + m.HealthHandler().SetVersionRoutes(admin.Router) + + m.HealthHandler().SetHealthRoutes(public.Router, false, healthx.WithMiddleware(m.addPublicCORSOnHandler(ctx))) + + admin.Handler("GET", prometheus.MetricsPrometheusPath, promhttp.Handler()) + + m.ConsentHandler().SetRoutes(admin) + m.KeyHandler().SetRoutes(admin, public, m.OAuth2AwareMiddleware()) + m.ClientHandler().SetRoutes(admin, public) + m.OAuth2Handler().SetRoutes(admin, public, m.OAuth2AwareMiddleware()) + m.JWTGrantHandler().SetRoutes(admin) +} + +func (m *RegistrySQL) BuildVersion() string { + return m.buildVersion +} + +func (m *RegistrySQL) BuildDate() string { + return m.buildDate +} + +func (m *RegistrySQL) BuildHash() string { + return m.buildHash +} + +func (m *RegistrySQL) WithConfig(c *config.DefaultProvider) Registry { + m.conf = c + return m +} + +func (m *RegistrySQL) Writer() herodot.Writer { + if m.writer == nil { + h := herodot.NewJSONWriter(m.Logger()) + h.ErrorEnhancer = x.ErrorEnhancer + m.writer = h + } + return m.writer +} + +func (m *RegistrySQL) WithLogger(l *logrusx.Logger) Registry { + m.l = l + return m +} + +func (m *RegistrySQL) WithTracer(t trace.Tracer) Registry { + m.trc = new(otelx.Tracer).WithOTLP(t) + return m +} + +func (m *RegistrySQL) WithTracerWrapper(wrapper TracerWrapper) Registry { + m.tracerWrapper = wrapper + return m +} + +func (m *RegistrySQL) WithKratos(k kratos.Client) Registry { + m.kratos = k + return m +} + +func (m *RegistrySQL) Logger() *logrusx.Logger { + if m.l == nil { + m.l = logrusx.New("Ory Hydra", m.BuildVersion()) + } + return m.l +} + +func (m *RegistrySQL) AuditLogger() *logrusx.Logger { + if m.al == nil { + m.al = logrusx.NewAudit("Ory Hydra", m.BuildVersion()) + m.al.UseConfig(m.Config().Source(contextx.RootContext)) + } + return m.al +} + +func (m *RegistrySQL) ClientHasher() fosite.Hasher { + if m.fh == nil { + m.fh = x.NewHasher(m.Config()) + } + return m.fh +} + +func (m *RegistrySQL) ClientHandler() *client.Handler { + if m.ch == nil { + m.ch = client.NewHandler(m) + } + return m.ch +} + +func (m *RegistrySQL) ClientValidator() *client.Validator { + if m.cv == nil { + m.cv = client.NewValidator(m) + } + return m.cv +} + +func (m *RegistrySQL) KeyHandler() *jwk.Handler { + if m.kh == nil { + m.kh = jwk.NewHandler(m) + } + return m.kh +} + +func (m *RegistrySQL) JWTGrantHandler() *trust.Handler { + if m.jwtGrantH == nil { + m.jwtGrantH = trust.NewHandler(m) + } + return m.jwtGrantH +} + +func (m *RegistrySQL) GrantValidator() *trust.GrantValidator { + if m.jwtGrantV == nil { + m.jwtGrantV = trust.NewGrantValidator() + } + return m.jwtGrantV +} + +func (m *RegistrySQL) HealthHandler() *healthx.Handler { + if m.hh == nil { + m.hh = healthx.NewHandler(m.Writer(), m.buildVersion, healthx.ReadyCheckers{ + "database": func(r *http.Request) error { + return m.PingContext(r.Context()) + }, + "migrations": func(r *http.Request) error { + if m.migrationStatus != nil && !m.migrationStatus.HasPending() { + return nil + } + + status, err := m.Persister().MigrationStatus(r.Context()) + if err != nil { + return err + } + + if status.HasPending() { + err := errors.Errorf("migrations have not yet been fully applied: %+v", status) + m.Logger().WithField("status", fmt.Sprintf("%+v", status)).WithError(err).Warn("Instance is not yet ready because migrations have not yet been fully applied.") + return err + } + + m.migrationStatus = &status + return nil + }, + }) + } + + return m.hh +} + +func (m *RegistrySQL) ConsentStrategy() consent.Strategy { + if m.cos == nil { + m.cos = consent.NewStrategy(m, m.Config()) + } + return m.cos +} + +func (m *RegistrySQL) KeyCipher() *aead.AESGCM { + if m.kc == nil { + m.kc = aead.NewAESGCM(m.Config()) + } + return m.kc +} + +func (m *RegistrySQL) FlowCipher() *aead.XChaCha20Poly1305 { + if m.flowc == nil { + m.flowc = aead.NewXChaCha20Poly1305(m.Config()) + } + return m.flowc +} + +func (m *RegistrySQL) CookieStore(ctx context.Context) (sessions.Store, error) { + var keys [][]byte + secrets, err := m.conf.GetCookieSecrets(ctx) + if err != nil { + return nil, err + } + + for _, k := range secrets { + encrypt := sha256.Sum256(k) + keys = append(keys, k, encrypt[:]) + } + + cs := sessions.NewCookieStore(keys...) + cs.Options.Secure = m.Config().CookieSecure(ctx) + cs.Options.HttpOnly = true + + // CookieStore MaxAge is set to 86400 * 30 by default. This prevents secure cookies retrieval with expiration > 30 days. + // MaxAge(0) disables internal MaxAge check by SecureCookie, see: + // + // https://github.com/ory/hydra/pull/2488#discussion_r618992698 + cs.MaxAge(0) + + if domain := m.Config().CookieDomain(ctx); domain != "" { + cs.Options.Domain = domain + } + + cs.Options.Path = "/" + if sameSite := m.Config().CookieSameSiteMode(ctx); sameSite != 0 { + cs.Options.SameSite = sameSite + } + + return cs, nil +} + +func (m *RegistrySQL) HTTPClient(ctx context.Context, opts ...httpx.ResilientOptions) *retryablehttp.Client { + opts = append(opts, + httpx.ResilientClientWithLogger(m.Logger()), + httpx.ResilientClientWithMaxRetry(2), + httpx.ResilientClientWithConnectionTimeout(30*time.Second)) + + tracer := m.Tracer(ctx) + if tracer.IsLoaded() { + opts = append(opts, httpx.ResilientClientWithTracer(tracer.Tracer())) + } + + if m.Config().ClientHTTPNoPrivateIPRanges() { + opts = append( + opts, + httpx.ResilientClientDisallowInternalIPs(), + httpx.ResilientClientAllowInternalIPRequestsTo(m.Config().ClientHTTPPrivateIPExceptionURLs()...), + ) + } + return httpx.NewResilientClient(opts...) +} + +func (m *RegistrySQL) OAuth2Provider() fosite.OAuth2Provider { + if m.fop != nil { + return m.fop + } + + m.fop = fosite.NewOAuth2Provider(m.OAuth2Storage(), m.OAuth2ProviderConfig()) + return m.fop +} + +func (m *RegistrySQL) OpenIDJWTStrategy() jwk.JWTSigner { + if m.oidcs != nil { + return m.oidcs + } + + m.oidcs = jwk.NewDefaultJWTSigner(m.Config(), m, x.OpenIDConnectKeyName) + return m.oidcs +} + +func (m *RegistrySQL) AccessTokenJWTStrategy() jwk.JWTSigner { + if m.ats != nil { + return m.ats + } + + m.ats = jwk.NewDefaultJWTSigner(m.Config(), m, x.OAuth2JWTKeyName) + return m.ats +} + +func (m *RegistrySQL) OAuth2EnigmaStrategy() *hmac.HMACStrategy { + if m.enigmaHMAC != nil { + return m.enigmaHMAC + } + + m.enigmaHMAC = &hmac.HMACStrategy{Config: m.OAuth2Config()} + return m.enigmaHMAC +} + +func (m *RegistrySQL) OAuth2HMACStrategy() foauth2.CoreStrategy { + if m.hmacs != nil { + return m.hmacs + } + + m.hmacs = foauth2.NewHMACSHAStrategy(m.OAuth2EnigmaStrategy(), m.OAuth2Config()) + return m.hmacs +} + +func (m *RegistrySQL) OAuth2Config() *fositex.Config { + if m.fc != nil { + return m.fc + } + + m.fc = fositex.NewConfig(m) + return m.fc +} + +func (m *RegistrySQL) ExtraFositeFactories() []fositex.Factory { + return m.fositeFactories +} + +func (m *RegistrySQL) WithExtraFositeFactories(f []fositex.Factory) Registry { + m.fositeFactories = f + + return m +} + +func (m *RegistrySQL) OAuth2ProviderConfig() fosite.Configurator { + if m.oc != nil { + return m.oc + } + + conf := m.OAuth2Config() + hmacAtStrategy := m.OAuth2HMACStrategy() + oidcSigner := m.OpenIDJWTStrategy() + atSigner := m.AccessTokenJWTStrategy() + jwtAtStrategy := &foauth2.DefaultJWTStrategy{ + Signer: atSigner, + HMACSHAStrategy: hmacAtStrategy, + Config: conf, + } + + conf.LoadDefaultHandlers(&compose.CommonStrategy{ + CoreStrategy: fositex.NewTokenStrategy(m.Config(), hmacAtStrategy, &foauth2.DefaultJWTStrategy{ + Signer: jwtAtStrategy, + HMACSHAStrategy: hmacAtStrategy, + Config: conf, + }), + OpenIDConnectTokenStrategy: &openid.DefaultStrategy{ + Config: conf, + Signer: oidcSigner, + }, + Signer: oidcSigner, + }) + + m.oc = conf + return m.oc +} + +func (m *RegistrySQL) OpenIDConnectRequestValidator() *openid.OpenIDConnectRequestValidator { + if m.forv == nil { + m.forv = openid.NewOpenIDConnectRequestValidator(&openid.DefaultStrategy{ + Config: m.OAuth2ProviderConfig(), + Signer: m.OpenIDJWTStrategy(), + }, m.OAuth2ProviderConfig()) + } + return m.forv +} + +func (m *RegistrySQL) AudienceStrategy() fosite.AudienceMatchingStrategy { + return fosite.DefaultAudienceMatchingStrategy +} + +func (m *RegistrySQL) ConsentHandler() *consent.Handler { + if m.coh == nil { + m.coh = consent.NewHandler(m, m.Config()) + } + return m.coh +} + +func (m *RegistrySQL) OAuth2Handler() *oauth2.Handler { + if m.oah == nil { + m.oah = oauth2.NewHandler(m, m.Config()) + } + return m.oah +} + +func (m *RegistrySQL) SubjectIdentifierAlgorithm(ctx context.Context) map[string]consent.SubjectIdentifierAlgorithm { + if m.sia == nil { + m.sia = map[string]consent.SubjectIdentifierAlgorithm{} + for _, t := range m.Config().SubjectTypesSupported(ctx) { + switch t { + case "public": + m.sia["public"] = consent.NewSubjectIdentifierAlgorithmPublic() + case "pairwise": + m.sia["pairwise"] = consent.NewSubjectIdentifierAlgorithmPairwise([]byte(m.Config().SubjectIdentifierAlgorithmSalt(ctx))) + } + } + } + return m.sia +} + +func (m *RegistrySQL) Tracer(_ context.Context) *otelx.Tracer { + if m.trc == nil { + t, err := otelx.New("Ory Hydra", m.l, m.conf.Tracing()) + if err != nil { + m.Logger().WithError(err).Error("Unable to initialize Tracer.") + } else { + // Wrap the tracer if required + if m.tracerWrapper != nil { + t = m.tracerWrapper(t) + } + + m.trc = t + } + } + if m.trc.Tracer() == nil { + m.trc = otelx.NewNoop(m.l, m.Config().Tracing()) + } + + return m.trc +} + +func (m *RegistrySQL) PrometheusManager() *prometheus.MetricsManager { + if m.pmm == nil { + m.pmm = prometheus.NewMetricsManagerWithPrefix("hydra", prometheus.HTTPMetrics, m.buildVersion, m.buildHash, m.buildDate) + } + return m.pmm +} + +func (m *RegistrySQL) Persister() persistence.Persister { + return m.persister +} + +// Config returns the configuration for the given context. It may or may not be the same as the global configuration. +func (m *RegistrySQL) Config() *config.DefaultProvider { + return m.conf +} + +// WithOAuth2Provider forces an oauth2 provider which is only used for testing. +func (m *RegistrySQL) WithOAuth2Provider(f fosite.OAuth2Provider) { + m.fop = f +} + +// WithConsentStrategy forces a consent strategy which is only used for testing. +func (m *RegistrySQL) WithConsentStrategy(c consent.Strategy) { + m.cos = c +} + +func (m *RegistrySQL) AccessRequestHooks() []oauth2.AccessRequestHook { + if m.arhs == nil { + m.arhs = []oauth2.AccessRequestHook{ + oauth2.RefreshTokenHook(m), + oauth2.TokenHook(m), + } + } + return m.arhs +} + +func (m *RegistrySQL) WithHsmContext(h hsm.Context) { + m.hsm = h +} + +func (m *RegistrySQL) HSMContext() hsm.Context { + if m.hsm == nil { + m.hsm = hsm.NewContext(m.Config(), m.l) + } + return m.hsm +} + +func (m *RegistrySQL) ClientAuthenticator() x.ClientAuthenticator { + return m.OAuth2Provider().(*fosite.Fosite) +} + +func (m *RegistrySQL) Kratos() kratos.Client { + if m.kratos == nil { + m.kratos = kratos.New(m) + } + return m.kratos +} diff --git a/driver/registry_sql_test.go b/driver/registry_sql_test.go index 3cd7cd33742..38bc27f0746 100644 --- a/driver/registry_sql_test.go +++ b/driver/registry_sql_test.go @@ -13,16 +13,120 @@ import ( "github.com/stretchr/testify/assert" - "github.com/ory/hydra/client" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/persistence/sql" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/persistence/sql" "github.com/ory/x/configx" "github.com/ory/x/contextx" "github.com/ory/x/errorsx" "github.com/ory/x/logrusx" "github.com/ory/x/sqlcon/dockertest" + + "errors" + "fmt" + "io" + "net/http" + "net/http/httptest" + + "github.com/ory/x/randx" + + "github.com/ory/x/httpx" + + "github.com/gorilla/sessions" + "github.com/sirupsen/logrus" + "github.com/sirupsen/logrus/hooks/test" ) +func TestGetJWKSFetcherStrategyHostEnforcment(t *testing.T) { + ctx := context.Background() + l := logrusx.New("", "") + c := config.MustNew(context.Background(), l, configx.WithConfigFiles("../internal/.hydra.yaml")) + c.MustSet(ctx, config.KeyDSN, "memory") + c.MustSet(ctx, config.HSMEnabled, "false") + c.MustSet(ctx, config.KeyClientHTTPNoPrivateIPRanges, true) + + registry, err := NewRegistryWithoutInit(c, l) + require.NoError(t, err) + + _, err = registry.GetJWKSFetcherStrategy().Resolve(ctx, "http://localhost:8080", true) + require.ErrorAs(t, err, new(httpx.ErrPrivateIPAddressDisallowed)) +} + +func TestRegistrySQL_newKeyStrategy_handlesNetworkError(t *testing.T) { + // Test ensures any network specific error is logged with a + // specific message when attempting to create a new key strategy: issue #2338 + + hook := test.Hook{} // Test hook for asserting log messages + ctx := context.Background() + + l := logrusx.New("", "", logrusx.WithHook(&hook)) + l.Logrus().SetOutput(io.Discard) + l.Logrus().ExitFunc = func(int) {} // Override the exit func to avoid call to os.Exit + + // Create a config and set a valid but unresolvable DSN + c := config.MustNew(context.Background(), l, configx.WithConfigFiles("../internal/.hydra.yaml")) + c.MustSet(ctx, config.KeyDSN, "postgres://user:password@127.0.0.1:9999/postgres") + c.MustSet(ctx, config.HSMEnabled, "false") + + registry, err := NewRegistryWithoutInit(c, l) + if err != nil { + t.Errorf("Failed to create registry: %s", err) + return + } + + r := registry.(*RegistrySQL) + r.initialPing = failedPing(errors.New("snizzles")) + + _ = r.Init(context.Background(), true, false, &contextx.TestContextualizer{}, nil, nil) + + assert.Equal(t, logrus.FatalLevel, hook.LastEntry().Level) + assert.Contains(t, hook.LastEntry().Message, "snizzles") +} + +func TestRegistrySQL_CookieStore_MaxAgeZero(t *testing.T) { + // Test ensures that CookieStore MaxAge option is equal to zero after initialization + + ctx := context.Background() + r := new(RegistrySQL) + r.WithConfig(config.MustNew(context.Background(), logrusx.New("", ""), configx.WithValue(config.KeyGetSystemSecret, []string{randx.MustString(32, randx.AlphaNum)}))) + + s, err := r.CookieStore(ctx) + require.NoError(t, err) + cs := s.(*sessions.CookieStore) + + assert.Equal(t, cs.Options.MaxAge, 0) +} + +func TestRegistrySQL_HTTPClient(t *testing.T) { + ts := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) { + writer.WriteHeader(http.StatusOK) + })) + defer ts.Close() + + t.Setenv("CLIENTS_HTTP_PRIVATE_IP_EXCEPTION_URLS", fmt.Sprintf("[%q]", ts.URL+"/exception/*")) + + ctx := context.Background() + r := new(RegistrySQL) + r.WithConfig(config.MustNew( + ctx, + logrusx.New("", ""), + configx.WithValues(map[string]interface{}{ + config.KeyClientHTTPNoPrivateIPRanges: true, + }), + )) + + t.Run("case=matches exception glob", func(t *testing.T) { + res, err := r.HTTPClient(ctx).Get(ts.URL + "/exception/foo") + require.NoError(t, err) + assert.Equal(t, 200, res.StatusCode) + }) + + t.Run("case=does not match exception glob", func(t *testing.T) { + _, err := r.HTTPClient(ctx).Get(ts.URL + "/foo") + require.Error(t, err) + }) +} + func TestDefaultKeyManager_HsmDisabled(t *testing.T) { l := logrusx.New("", "") c := config.MustNew(context.Background(), l, configx.SkipValidation()) @@ -31,7 +135,7 @@ func TestDefaultKeyManager_HsmDisabled(t *testing.T) { reg, err := NewRegistryWithoutInit(c, l) r := reg.(*RegistrySQL) r.initialPing = sussessfulPing() - if err := r.Init(context.Background(), true, false, &contextx.Default{}); err != nil { + if err := r.Init(context.Background(), true, false, &contextx.Default{}, nil, nil); err != nil { t.Fatalf("unable to init registry: %s", err) } assert.NoError(t, err) @@ -52,7 +156,7 @@ func TestDbUnknownTableColumns(t *testing.T) { require.NoError(t, reg.Persister().Connection(ctx).RawQuery(statement).Exec()) cl := &client.Client{ - LegacyClientID: strconv.Itoa(rand.Int()), + ID: strconv.Itoa(rand.Int()), } require.NoError(t, reg.Persister().CreateClient(ctx, cl)) getClients := func(reg Registry) ([]client.Client, error) { diff --git a/flow/.snapshots/TestAcceptOAuth2ConsentRequestSession_MarshalJSON.json b/flow/.snapshots/TestAcceptOAuth2ConsentRequestSession_MarshalJSON.json new file mode 100644 index 00000000000..5a8c295bfab --- /dev/null +++ b/flow/.snapshots/TestAcceptOAuth2ConsentRequestSession_MarshalJSON.json @@ -0,0 +1 @@ +"{\"access_token\":{},\"id_token\":{}}" diff --git a/flow/.snapshots/TestAcceptOAuth2ConsentRequest_MarshalJSON.json b/flow/.snapshots/TestAcceptOAuth2ConsentRequest_MarshalJSON.json new file mode 100644 index 00000000000..1e75db45a81 --- /dev/null +++ b/flow/.snapshots/TestAcceptOAuth2ConsentRequest_MarshalJSON.json @@ -0,0 +1 @@ +"{\"grant_scope\":[],\"grant_access_token_audience\":[],\"session\":null,\"remember\":false,\"remember_for\":0,\"handled_at\":null,\"context\":{}}" diff --git a/flow/.snapshots/TestHandledLoginRequest_MarshalJSON.json b/flow/.snapshots/TestHandledLoginRequest_MarshalJSON.json new file mode 100644 index 00000000000..e49c8bdcde2 --- /dev/null +++ b/flow/.snapshots/TestHandledLoginRequest_MarshalJSON.json @@ -0,0 +1 @@ +"{\"remember\":false,\"remember_for\":0,\"extend_session_lifespan\":false,\"acr\":\"\",\"amr\":[],\"subject\":\"\",\"force_subject_identifier\":\"\",\"context\":{}}" diff --git a/flow/.snapshots/TestLoginRequest_MarshalJSON.json b/flow/.snapshots/TestLoginRequest_MarshalJSON.json new file mode 100644 index 00000000000..b74c562e2ce --- /dev/null +++ b/flow/.snapshots/TestLoginRequest_MarshalJSON.json @@ -0,0 +1 @@ +"{\"challenge\":\"\",\"requested_scope\":[],\"requested_access_token_audience\":[],\"skip\":false,\"subject\":\"\",\"oidc_context\":null,\"client\":null,\"request_url\":\"\",\"session_id\":\"\"}" diff --git a/flow/.snapshots/TestLogoutRequest_MarshalJSON.json b/flow/.snapshots/TestLogoutRequest_MarshalJSON.json new file mode 100644 index 00000000000..4132efb0269 --- /dev/null +++ b/flow/.snapshots/TestLogoutRequest_MarshalJSON.json @@ -0,0 +1 @@ +"{\"challenge\":\"\",\"subject\":\"\",\"request_url\":\"\",\"rp_initiated\":false,\"expires_at\":null,\"requested_at\":null,\"client\":null}" diff --git a/flow/.snapshots/TestOAuth2ConsentRequestOpenIDConnectContext_MarshalJSON.json b/flow/.snapshots/TestOAuth2ConsentRequestOpenIDConnectContext_MarshalJSON.json new file mode 100644 index 00000000000..71829adca73 --- /dev/null +++ b/flow/.snapshots/TestOAuth2ConsentRequestOpenIDConnectContext_MarshalJSON.json @@ -0,0 +1 @@ +"{}" diff --git a/flow/.snapshots/TestOAuth2ConsentRequest_MarshalJSON.json b/flow/.snapshots/TestOAuth2ConsentRequest_MarshalJSON.json new file mode 100644 index 00000000000..1a39fb2e6c2 --- /dev/null +++ b/flow/.snapshots/TestOAuth2ConsentRequest_MarshalJSON.json @@ -0,0 +1 @@ +"{\"challenge\":\"\",\"requested_scope\":[],\"requested_access_token_audience\":[],\"skip\":false,\"subject\":\"\",\"oidc_context\":null,\"client\":null,\"request_url\":\"\",\"login_challenge\":\"\",\"login_session_id\":\"\",\"acr\":\"\",\"amr\":[]}" diff --git a/flow/.snapshots/TestOAuth2ConsentSession_MarshalJSON.json b/flow/.snapshots/TestOAuth2ConsentSession_MarshalJSON.json new file mode 100644 index 00000000000..c08b431eac6 --- /dev/null +++ b/flow/.snapshots/TestOAuth2ConsentSession_MarshalJSON.json @@ -0,0 +1 @@ +"{\"grant_scope\":[],\"grant_access_token_audience\":[],\"session\":null,\"remember\":false,\"remember_for\":0,\"handled_at\":null,\"context\":{},\"consent_request\":null}" diff --git a/consent/types.go b/flow/consent_types.go similarity index 84% rename from consent/types.go rename to flow/consent_types.go index 80fa2c6e88b..399938a8020 100644 --- a/consent/types.go +++ b/flow/consent_types.go @@ -1,7 +1,7 @@ // Copyright © 2022 Ory Corp // SPDX-License-Identifier: Apache-2.0 -package consent +package flow import ( "database/sql" @@ -17,14 +17,14 @@ import ( "github.com/ory/x/errorsx" "github.com/ory/fosite" - "github.com/ory/hydra/client" + "github.com/ory/hydra/v2/client" "github.com/ory/x/sqlcon" "github.com/ory/x/sqlxx" ) const ( - consentRequestDeniedErrorName = "consent request denied" - loginRequestDeniedErrorName = "login request denied" + ConsentRequestDeniedErrorName = "consent request denied" + LoginRequestDeniedErrorName = "login request denied" ) // OAuth 2.0 Redirect Browser To @@ -42,14 +42,15 @@ type OAuth2RedirectTo struct { // swagger:ignore type LoginSession struct { - ID string `db:"id"` - NID uuid.UUID `db:"nid"` - AuthenticatedAt sqlxx.NullTime `db:"authenticated_at"` - Subject string `db:"subject"` - Remember bool `db:"remember"` + ID string `db:"id"` + NID uuid.UUID `db:"nid"` + AuthenticatedAt sqlxx.NullTime `db:"authenticated_at"` + Subject string `db:"subject"` + IdentityProviderSessionID sqlxx.NullString `db:"identity_provider_session_id"` + Remember bool `db:"remember"` } -func (_ LoginSession) TableName() string { +func (LoginSession) TableName() string { return "hydra_oauth2_authentication_session" } @@ -77,11 +78,12 @@ type RequestDeniedError struct { // to the public but only in the server logs. Debug string `json:"error_debug"` - valid bool + // swagger:ignore + Valid bool `json:"valid"` } func (e *RequestDeniedError) IsError() bool { - return e != nil && e.valid + return e != nil && e.Valid } func (e *RequestDeniedError) SetDefaults(name string) { @@ -94,7 +96,7 @@ func (e *RequestDeniedError) SetDefaults(name string) { } } -func (e *RequestDeniedError) toRFCError() *fosite.RFC6749Error { +func (e *RequestDeniedError) ToRFCError() *fosite.RFC6749Error { if e.Name == "" { e.Name = "request_denied" } @@ -112,7 +114,7 @@ func (e *RequestDeniedError) toRFCError() *fosite.RFC6749Error { } } -func (e *RequestDeniedError) Scan(value interface{}) error { +func (e *RequestDeniedError) Scan(value any) error { v := fmt.Sprintf("%s", value) if len(v) == 0 || v == "{}" { return nil @@ -122,7 +124,7 @@ func (e *RequestDeniedError) Scan(value interface{}) error { return errorsx.WithStack(err) } - e.valid = true + e.Valid = true return nil } @@ -172,6 +174,11 @@ type AcceptOAuth2ConsentRequest struct { // the flow. WasHandled bool `json:"-"` + // Context is an optional object which can hold arbitrary data. The data will be made available when fetching the + // consent request under the "context" field. This is useful in scenarios where login and consent endpoints share + // data. + Context sqlxx.JSONRawMessage `json:"context"` + ConsentRequest *OAuth2ConsentRequest `json:"-"` Error *RequestDeniedError `json:"-"` RequestedAt time.Time `json:"-"` @@ -181,6 +188,25 @@ type AcceptOAuth2ConsentRequest struct { SessionAccessToken sqlxx.MapStringInterface `json:"-" faker:"-"` } +func (r *AcceptOAuth2ConsentRequest) MarshalJSON() ([]byte, error) { + type Alias AcceptOAuth2ConsentRequest + alias := Alias(*r) + + if alias.Context == nil { + alias.Context = []byte("{}") + } + + if alias.GrantedScope == nil { + alias.GrantedScope = []string{} + } + + if alias.GrantedAudience == nil { + alias.GrantedAudience = []string{} + } + + return json.Marshal(alias) +} + func (r *AcceptOAuth2ConsentRequest) HasError() bool { return r.Error.IsError() } @@ -188,6 +214,8 @@ func (r *AcceptOAuth2ConsentRequest) HasError() bool { // List of OAuth 2.0 Consent Sessions // // swagger:model oAuth2ConsentSessions +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type oAuth2ConsentSessions []OAuth2ConsentSession // OAuth 2.0 Consent Session @@ -236,6 +264,11 @@ type OAuth2ConsentSession struct { // the flow. WasHandled bool `json:"-" db:"was_used"` + // Context is an optional object which can hold arbitrary data. The data will be made available when fetching the + // consent request under the "context" field. This is useful in scenarios where login and consent endpoints share + // data. + Context sqlxx.JSONRawMessage `json:"context"` + // Consent Request // // The consent request that lead to this consent session. @@ -249,6 +282,25 @@ type OAuth2ConsentSession struct { SessionAccessToken sqlxx.MapStringInterface `db:"session_access_token" json:"-"` } +func (r *OAuth2ConsentSession) MarshalJSON() ([]byte, error) { + type Alias OAuth2ConsentSession + alias := Alias(*r) + + if alias.Context == nil { + alias.Context = []byte("{}") + } + + if alias.GrantedScope == nil { + alias.GrantedScope = []string{} + } + + if alias.GrantedAudience == nil { + alias.GrantedAudience = []string{} + } + + return json.Marshal(alias) +} + // HandledLoginRequest is the request payload used to accept a login request. // // swagger:model acceptOAuth2LoginRequest @@ -265,6 +317,15 @@ type HandledLoginRequest struct { // authorization will be remembered for the duration of the browser session (using a session cookie). RememberFor int `json:"remember_for"` + // Extend OAuth2 authentication session lifespan + // + // If set to `true`, the OAuth2 authentication cookie lifespan is extended. This is for example useful if you want the user to be able to use `prompt=none` continuously. + // + // This value can only be set to `true` if the user has an authentication, which is the case if the `skip` value is `true`. + // + // required: false + ExtendSessionLifespan bool `json:"extend_session_lifespan"` + // ACR sets the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it // to express that, for example, a user authenticated using two factor authentication. ACR string `json:"acr"` @@ -280,6 +341,12 @@ type HandledLoginRequest struct { // required: true Subject string `json:"subject"` + // IdentityProviderSessionID is the session ID of the end-user that authenticated. + // If specified, we will use this value to propagate the logout. + // + // required: false + IdentityProviderSessionID string `json:"identity_provider_session_id,omitempty"` + // ForceSubjectIdentifier forces the "pairwise" user ID of the end-user that authenticated. The "pairwise" user ID refers to the // (Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg] of the OpenID // Connect specification. It allows you to set an obfuscated subject ("user") identifier that is unique to the client. @@ -316,6 +383,20 @@ type HandledLoginRequest struct { AuthenticatedAt sqlxx.NullTime `json:"-"` } +func (r *HandledLoginRequest) MarshalJSON() ([]byte, error) { + type Alias HandledLoginRequest + alias := Alias(*r) + if alias.Context == nil { + alias.Context = []byte("{}") + } + + if alias.AMR == nil { + alias.AMR = []string{} + } + + return json.Marshal(alias) +} + func (r *HandledLoginRequest) HasError() bool { return r.Error.IsError() } @@ -363,6 +444,24 @@ type OAuth2ConsentRequestOpenIDConnectContext struct { LoginHint string `json:"login_hint,omitempty"` } +func (n *OAuth2ConsentRequestOpenIDConnectContext) MarshalJSON() ([]byte, error) { + type Alias OAuth2ConsentRequestOpenIDConnectContext + alias := Alias(*n) + if alias.IDTokenHintClaims == nil { + alias.IDTokenHintClaims = map[string]interface{}{} + } + + if alias.ACRValues == nil { + alias.ACRValues = []string{} + } + + if alias.UILocales == nil { + alias.UILocales = []string{} + } + + return json.Marshal(alias) +} + func (n *OAuth2ConsentRequestOpenIDConnectContext) Scan(value interface{}) error { v := fmt.Sprintf("%s", value) if len(v) == 0 { @@ -408,10 +507,12 @@ type LogoutRequest struct { Accepted bool `json:"-" db:"accepted"` Rejected bool `db:"rejected" json:"-"` ClientID sql.NullString `json:"-" db:"client_id"` + ExpiresAt sqlxx.NullTime `json:"expires_at" db:"expires_at"` + RequestedAt sqlxx.NullTime `json:"requested_at" db:"requested_at"` Client *client.Client `json:"client" db:"-"` } -func (_ LogoutRequest) TableName() string { +func (LogoutRequest) TableName() string { return "hydra_oauth2_logout_request" } @@ -452,13 +553,9 @@ type LoginRequest struct { ID string `json:"challenge"` // RequestedScope contains the OAuth 2.0 Scope requested by the OAuth 2.0 Client. - // - // required: true RequestedScope sqlxx.StringSliceJSONFormat `json:"requested_scope"` // RequestedAudience contains the access token audience as requested by the OAuth 2.0 Client. - // - // required: true RequestedAudience sqlxx.StringSliceJSONFormat `json:"requested_access_token_audience"` // Skip, if true, implies that the client has requested the same scopes from the same user previously. @@ -514,6 +611,20 @@ type LoginRequest struct { RequestedAt time.Time `json:"-"` } +func (r *LoginRequest) MarshalJSON() ([]byte, error) { + type Alias LoginRequest + alias := Alias(*r) + if alias.RequestedScope == nil { + alias.RequestedScope = []string{} + } + + if alias.RequestedAudience == nil { + alias.RequestedAudience = []string{} + } + + return json.Marshal(alias) +} + // Contains information on an ongoing consent request. // // swagger:model oAuth2ConsentRequest @@ -589,6 +700,24 @@ type OAuth2ConsentRequest struct { RequestedAt time.Time `json:"-"` } +func (r *OAuth2ConsentRequest) MarshalJSON() ([]byte, error) { + type Alias OAuth2ConsentRequest + alias := Alias(*r) + if alias.RequestedScope == nil { + alias.RequestedScope = []string{} + } + + if alias.RequestedAudience == nil { + alias.RequestedAudience = []string{} + } + + if alias.AMR == nil { + alias.AMR = []string{} + } + + return json.Marshal(alias) +} + // Pass session data to a consent request. // // swagger:model acceptOAuth2ConsentRequestSession @@ -611,3 +740,16 @@ func NewConsentRequestSessionData() *AcceptOAuth2ConsentRequestSession { IDToken: map[string]interface{}{}, } } + +func (r *AcceptOAuth2ConsentRequestSession) MarshalJSON() ([]byte, error) { + type Alias AcceptOAuth2ConsentRequestSession + alias := Alias(*r) + if alias.AccessToken == nil { + alias.AccessToken = map[string]interface{}{} + } + + if alias.IDToken == nil { + alias.IDToken = map[string]interface{}{} + } + return json.Marshal(alias) +} diff --git a/flow/consent_types_test.go b/flow/consent_types_test.go new file mode 100644 index 00000000000..25261a04ac6 --- /dev/null +++ b/flow/consent_types_test.go @@ -0,0 +1,119 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package flow + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/ory/x/snapshotx" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ory/fosite" +) + +func TestToRFCError(t *testing.T) { + for k, tc := range []struct { + input *RequestDeniedError + expect *fosite.RFC6749Error + }{ + { + input: &RequestDeniedError{ + Name: "not empty", + Valid: true, + }, + expect: &fosite.RFC6749Error{ + ErrorField: "not empty", + DescriptionField: "", + CodeField: fosite.ErrInvalidRequest.CodeField, + DebugField: "", + }, + }, + { + input: &RequestDeniedError{ + Name: "", + Description: "not empty", + Valid: true, + }, + expect: &fosite.RFC6749Error{ + ErrorField: "request_denied", + DescriptionField: "not empty", + CodeField: fosite.ErrInvalidRequest.CodeField, + DebugField: "", + }, + }, + { + input: &RequestDeniedError{Valid: true}, + expect: &fosite.RFC6749Error{ + ErrorField: "request_denied", + DescriptionField: "", + HintField: "", + CodeField: fosite.ErrInvalidRequest.CodeField, + DebugField: "", + }, + }, + } { + t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + require.EqualValues(t, tc.input.ToRFCError(), tc.expect) + }) + } +} + +func TestRequestDeniedError(t *testing.T) { + var e *RequestDeniedError + v, err := e.Value() + require.NoError(t, err) + assert.EqualValues(t, "{}", fmt.Sprintf("%v", v)) +} + +func TestAcceptOAuth2ConsentRequest_MarshalJSON(t *testing.T) { + out, err := json.Marshal(new(AcceptOAuth2ConsentRequest)) + require.NoError(t, err) + snapshotx.SnapshotT(t, string(out)) +} + +func TestOAuth2ConsentSession_MarshalJSON(t *testing.T) { + out, err := json.Marshal(new(OAuth2ConsentSession)) + require.NoError(t, err) + snapshotx.SnapshotT(t, string(out)) +} + +func TestHandledLoginRequest_MarshalJSON(t *testing.T) { + out, err := json.Marshal(new(HandledLoginRequest)) + require.NoError(t, err) + snapshotx.SnapshotT(t, string(out)) +} + +func TestOAuth2ConsentRequestOpenIDConnectContext_MarshalJSON(t *testing.T) { + out, err := json.Marshal(new(OAuth2ConsentRequestOpenIDConnectContext)) + require.NoError(t, err) + snapshotx.SnapshotT(t, string(out)) +} + +func TestLogoutRequest_MarshalJSON(t *testing.T) { + out, err := json.Marshal(new(LogoutRequest)) + require.NoError(t, err) + snapshotx.SnapshotT(t, string(out)) +} + +func TestLoginRequest_MarshalJSON(t *testing.T) { + out, err := json.Marshal(new(LoginRequest)) + require.NoError(t, err) + snapshotx.SnapshotT(t, string(out)) +} + +func TestOAuth2ConsentRequest_MarshalJSON(t *testing.T) { + out, err := json.Marshal(new(OAuth2ConsentRequest)) + require.NoError(t, err) + snapshotx.SnapshotT(t, string(out)) +} + +func TestAcceptOAuth2ConsentRequestSession_MarshalJSON(t *testing.T) { + out, err := json.Marshal(new(AcceptOAuth2ConsentRequestSession)) + require.NoError(t, err) + snapshotx.SnapshotT(t, string(out)) +} diff --git a/flow/error.go b/flow/error.go new file mode 100644 index 00000000000..a6793b633b5 --- /dev/null +++ b/flow/error.go @@ -0,0 +1,8 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package flow + +import "github.com/ory/fosite" + +var ErrorLogoutFlowExpired = fosite.ErrRequestUnauthorized.WithHint("The logout request has expired, please try the flow again.") diff --git a/flow/flow.go b/flow/flow.go index 9915ed40719..0502bc544ba 100644 --- a/flow/flow.go +++ b/flow/flow.go @@ -4,16 +4,17 @@ package flow import ( + "context" "time" + "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" "github.com/pkg/errors" - "github.com/gobuffalo/pop/v6" - - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/oauth2/flowctx" + "github.com/ory/hydra/v2/x" "github.com/ory/x/sqlcon" "github.com/ory/x/sqlxx" ) @@ -83,18 +84,18 @@ type Flow struct { // identify the session. // // required: true - ID string `db:"login_challenge"` - NID uuid.UUID `db:"nid"` + ID string `db:"login_challenge" json:"i"` + NID uuid.UUID `db:"nid" json:"n"` // RequestedScope contains the OAuth 2.0 Scope requested by the OAuth 2.0 Client. // // required: true - RequestedScope sqlxx.StringSliceJSONFormat `db:"requested_scope"` + RequestedScope sqlxx.StringSliceJSONFormat `db:"requested_scope" json:"rs,omitempty"` // RequestedAudience contains the access token audience as requested by the OAuth 2.0 Client. // // required: true - RequestedAudience sqlxx.StringSliceJSONFormat `db:"requested_at_audience"` + RequestedAudience sqlxx.StringSliceJSONFormat `db:"requested_at_audience" json:"ra,omitempty"` // LoginSkip, if true, implies that the client has requested the same scopes from the same user previously. // If true, you can skip asking the user to grant the requested scopes, and simply forward the user to the redirect URL. @@ -102,65 +103,72 @@ type Flow struct { // This feature allows you to update / set session information. // // required: true - LoginSkip bool `db:"login_skip"` + LoginSkip bool `db:"login_skip" json:"ls,omitempty"` // Subject is the user ID of the end-user that authenticated. Now, that end user needs to grant or deny the scope // requested by the OAuth 2.0 client. If this value is set and `skip` is true, you MUST include this subject type // when accepting the login request, or the request will fail. // // required: true - Subject string `db:"subject"` + Subject string `db:"subject" json:"s,omitempty"` // OpenIDConnectContext provides context for the (potential) OpenID Connect context. Implementation of these // values in your app are optional but can be useful if you want to be fully compliant with the OpenID Connect spec. - OpenIDConnectContext *consent.OAuth2ConsentRequestOpenIDConnectContext `db:"oidc_context"` + OpenIDConnectContext *OAuth2ConsentRequestOpenIDConnectContext `db:"oidc_context" json:"oc"` // Client is the OAuth 2.0 Client that initiated the request. // // required: true - Client *client.Client `db:"-"` - - ClientID string `db:"client_id"` + Client *client.Client `db:"-" json:"c,omitempty"` + ClientID string `db:"client_id" json:"ci,omitempty"` // RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which // initiates the OAuth 2.0 Authorization Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but // might come in handy if you want to deal with additional request parameters. // // required: true - RequestURL string `db:"request_url"` + RequestURL string `db:"request_url" json:"r,omitempty"` // SessionID is the login session ID. If the user-agent reuses a login session (via cookie / remember flag) // this ID will remain the same. If the user-agent did not have an existing authentication session (e.g. remember is false) // this will be a new random value. This value is used as the "sid" parameter in the ID Token and in OIDC Front-/Back- // channel logout. Its value can generally be used to associate consecutive login requests by a certain user. - SessionID sqlxx.NullString `db:"login_session_id"` + SessionID sqlxx.NullString `db:"login_session_id" json:"si,omitempty"` + + // IdentityProviderSessionID is the session ID of the end-user that authenticated. + // If specified, we will use this value to propagate the logout. + IdentityProviderSessionID sqlxx.NullString `db:"identity_provider_session_id" json:"is,omitempty"` - LoginVerifier string `db:"login_verifier"` - LoginCSRF string `db:"login_csrf"` + LoginVerifier string `db:"login_verifier" json:"lv,omitempty"` + LoginCSRF string `db:"login_csrf" json:"lc,omitempty"` - LoginInitializedAt sqlxx.NullTime `db:"login_initialized_at"` - RequestedAt time.Time `db:"requested_at"` + LoginInitializedAt sqlxx.NullTime `db:"login_initialized_at" json:"li,omitempty"` + RequestedAt time.Time `db:"requested_at" json:"ia,omitempty"` - State int16 `db:"state"` + State int16 `db:"state" json:"q,omitempty"` // LoginRemember, if set to true, tells ORY Hydra to remember this user by telling the user agent (browser) to store // a cookie with authentication data. If the same user performs another OAuth 2.0 Authorization Request, he/she // will not be asked to log in again. - LoginRemember bool `db:"login_remember"` + LoginRemember bool `db:"login_remember" json:"lr,omitempty"` // LoginRememberFor sets how long the authentication should be remembered for in seconds. If set to `0`, the // authorization will be remembered for the duration of the browser session (using a session cookie). - LoginRememberFor int `db:"login_remember_for"` + LoginRememberFor int `db:"login_remember_for" json:"lf,omitempty"` + + // LoginExtendSessionLifespan, if set to true, session cookie expiry time will be updated when session is + // refreshed (login skip=true). + LoginExtendSessionLifespan bool `db:"login_extend_session_lifespan" json:"ll,omitempty"` // ACR sets the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it // to express that, for example, a user authenticated using two factor authentication. - ACR string `db:"acr"` + ACR string `db:"acr" json:"a,omitempty"` // AMR sets the Authentication Methods References value for this // authentication session. You can use it to specify the method a user used to // authenticate. For example, if the acr indicates a user used two factor // authentication, the amr can express they used a software-secured key. - AMR sqlxx.StringSliceJSONFormat `db:"amr"` + AMR sqlxx.StringSliceJSONFormat `db:"amr" json:"am,omitempty"` // ForceSubjectIdentifier forces the "pairwise" user ID of the end-user that authenticated. The "pairwise" user ID refers to the // (Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg] of the OpenID @@ -179,61 +187,61 @@ type Flow struct { // other unique value). // // If you fail to compute the proper value, then authentication processes which have id_token_hint set might fail. - ForceSubjectIdentifier string `db:"forced_subject_identifier"` + ForceSubjectIdentifier string `db:"forced_subject_identifier" json:"fs,omitempty"` // Context is an optional object which can hold arbitrary data. The data will be made available when fetching the // consent request under the "context" field. This is useful in scenarios where login and consent endpoints share // data. - Context sqlxx.JSONRawMessage `db:"context"` + Context sqlxx.JSONRawMessage `db:"context" json:"ct"` // LoginWasUsed set to true means that the login request was already handled. // This can happen on form double-submit or other errors. If this is set we // recommend redirecting the user to `request_url` to re-initiate the flow. - LoginWasUsed bool `db:"login_was_used"` + LoginWasUsed bool `db:"login_was_used" json:"lu,omitempty"` - LoginError *consent.RequestDeniedError `db:"login_error"` - LoginAuthenticatedAt sqlxx.NullTime `db:"login_authenticated_at"` + LoginError *RequestDeniedError `db:"login_error" json:"le,omitempty"` + LoginAuthenticatedAt sqlxx.NullTime `db:"login_authenticated_at" json:"la,omitempty"` // ConsentChallengeID is the identifier ("authorization challenge") of the consent authorization request. It is used to // identify the session. // // required: true - ConsentChallengeID sqlxx.NullString `db:"consent_challenge_id"` + ConsentChallengeID sqlxx.NullString `db:"consent_challenge_id" json:"cc,omitempty"` // ConsentSkip, if true, implies that the client has requested the same scopes from the same user previously. // If true, you must not ask the user to grant the requested scopes. You must however either allow or deny the // consent request using the usual API call. - ConsentSkip bool `db:"consent_skip"` - ConsentVerifier sqlxx.NullString `db:"consent_verifier"` - ConsentCSRF sqlxx.NullString `db:"consent_csrf"` + ConsentSkip bool `db:"consent_skip" json:"cs,omitempty"` + ConsentVerifier sqlxx.NullString `db:"consent_verifier" json:"cv,omitempty"` + ConsentCSRF sqlxx.NullString `db:"consent_csrf" json:"cr,omitempty"` // GrantedScope sets the scope the user authorized the client to use. Should be a subset of `requested_scope`. - GrantedScope sqlxx.StringSliceJSONFormat `db:"granted_scope"` + GrantedScope sqlxx.StringSliceJSONFormat `db:"granted_scope" json:"gs,omitempty"` // GrantedAudience sets the audience the user authorized the client to use. Should be a subset of `requested_access_token_audience`. - GrantedAudience sqlxx.StringSliceJSONFormat `db:"granted_at_audience"` + GrantedAudience sqlxx.StringSliceJSONFormat `db:"granted_at_audience" json:"ga,omitempty"` // ConsentRemember, if set to true, tells ORY Hydra to remember this consent authorization and reuse it if the same // client asks the same user for the same, or a subset of, scope. - ConsentRemember bool `db:"consent_remember"` + ConsentRemember bool `db:"consent_remember" json:"ce,omitempty"` // ConsentRememberFor sets how long the consent authorization should be remembered for in seconds. If set to `0`, the // authorization will be remembered indefinitely. - ConsentRememberFor *int `db:"consent_remember_for"` + ConsentRememberFor *int `db:"consent_remember_for" json:"cf"` // ConsentHandledAt contains the timestamp the consent request was handled. - ConsentHandledAt sqlxx.NullTime `db:"consent_handled_at"` + ConsentHandledAt sqlxx.NullTime `db:"consent_handled_at" json:"ch,omitempty"` // ConsentWasHandled set to true means that the request was already handled. // This can happen on form double-submit or other errors. If this is set we // recommend redirecting the user to `request_url` to re-initiate the flow. - ConsentWasHandled bool `db:"consent_was_used"` - ConsentError *consent.RequestDeniedError `db:"consent_error"` - SessionIDToken sqlxx.MapStringInterface `db:"session_id_token" faker:"-"` - SessionAccessToken sqlxx.MapStringInterface `db:"session_access_token" faker:"-"` + ConsentWasHandled bool `db:"consent_was_used" json:"cw,omitempty"` + ConsentError *RequestDeniedError `db:"consent_error" json:"cx"` + SessionIDToken sqlxx.MapStringInterface `db:"session_id_token" faker:"-" json:"st"` + SessionAccessToken sqlxx.MapStringInterface `db:"session_access_token" faker:"-" json:"sa"` } -func NewFlow(r *consent.LoginRequest) *Flow { +func NewFlow(r *LoginRequest) *Flow { return &Flow{ ID: r.ID, RequestedScope: r.RequestedScope, @@ -255,7 +263,7 @@ func NewFlow(r *consent.LoginRequest) *Flow { } } -func (f *Flow) HandleLoginRequest(h *consent.HandledLoginRequest) error { +func (f *Flow) HandleLoginRequest(h *HandledLoginRequest) error { if f.LoginWasUsed { return errors.WithStack(x.ErrConflict.WithHint("The login request was already used and can no longer be changed.")) } @@ -281,41 +289,49 @@ func (f *Flow) HandleLoginRequest(h *consent.HandledLoginRequest) error { } else { f.State = FlowStateLoginUnused } + + if f.Context != nil { + f.Context = h.Context + } + f.ID = h.ID f.Subject = h.Subject f.ForceSubjectIdentifier = h.ForceSubjectIdentifier f.LoginError = h.Error + f.IdentityProviderSessionID = sqlxx.NullString(h.IdentityProviderSessionID) f.LoginRemember = h.Remember f.LoginRememberFor = h.RememberFor + f.LoginExtendSessionLifespan = h.ExtendSessionLifespan f.ACR = h.ACR f.AMR = h.AMR - f.Context = h.Context f.LoginWasUsed = h.WasHandled f.LoginAuthenticatedAt = h.AuthenticatedAt return nil } -func (f *Flow) GetHandledLoginRequest() consent.HandledLoginRequest { - return consent.HandledLoginRequest{ - ID: f.ID, - Remember: f.LoginRemember, - RememberFor: f.LoginRememberFor, - ACR: f.ACR, - AMR: f.AMR, - Subject: f.Subject, - ForceSubjectIdentifier: f.ForceSubjectIdentifier, - Context: f.Context, - WasHandled: f.LoginWasUsed, - Error: f.LoginError, - LoginRequest: f.GetLoginRequest(), - RequestedAt: f.RequestedAt, - AuthenticatedAt: f.LoginAuthenticatedAt, +func (f *Flow) GetHandledLoginRequest() HandledLoginRequest { + return HandledLoginRequest{ + ID: f.ID, + Remember: f.LoginRemember, + RememberFor: f.LoginRememberFor, + ExtendSessionLifespan: f.LoginExtendSessionLifespan, + ACR: f.ACR, + AMR: f.AMR, + Subject: f.Subject, + IdentityProviderSessionID: f.IdentityProviderSessionID.String(), + ForceSubjectIdentifier: f.ForceSubjectIdentifier, + Context: f.Context, + WasHandled: f.LoginWasUsed, + Error: f.LoginError, + LoginRequest: f.GetLoginRequest(), + RequestedAt: f.RequestedAt, + AuthenticatedAt: f.LoginAuthenticatedAt, } } -func (f *Flow) GetLoginRequest() *consent.LoginRequest { - return &consent.LoginRequest{ +func (f *Flow) GetLoginRequest() *LoginRequest { + return &LoginRequest{ ID: f.ID, RequestedScope: f.RequestedScope, RequestedAudience: f.RequestedAudience, @@ -349,7 +365,7 @@ func (f *Flow) InvalidateLoginRequest() error { return nil } -func (f *Flow) HandleConsentRequest(r *consent.AcceptOAuth2ConsentRequest) error { +func (f *Flow) HandleConsentRequest(r *AcceptOAuth2ConsentRequest) error { if time.Time(r.HandledAt).IsZero() { return errors.New("refusing to handle a consent request with null HandledAt") } @@ -381,6 +397,9 @@ func (f *Flow) HandleConsentRequest(r *consent.AcceptOAuth2ConsentRequest) error f.ConsentHandledAt = r.HandledAt f.ConsentWasHandled = r.WasHandled f.ConsentError = r.Error + if r.Context != nil { + f.Context = r.Context + } if r.Session != nil { f.SessionIDToken = r.Session.IDToken @@ -402,8 +421,8 @@ func (f *Flow) InvalidateConsentRequest() error { return nil } -func (f *Flow) GetConsentRequest() *consent.OAuth2ConsentRequest { - return &consent.OAuth2ConsentRequest{ +func (f *Flow) GetConsentRequest() *OAuth2ConsentRequest { + cs := OAuth2ConsentRequest{ ID: f.ConsentChallengeID.String(), RequestedScope: f.RequestedScope, RequestedAudience: f.RequestedAudience, @@ -425,22 +444,27 @@ func (f *Flow) GetConsentRequest() *consent.OAuth2ConsentRequest { AuthenticatedAt: f.LoginAuthenticatedAt, RequestedAt: f.RequestedAt, } + if cs.AMR == nil { + cs.AMR = []string{} + } + return &cs } -func (f *Flow) GetHandledConsentRequest() *consent.AcceptOAuth2ConsentRequest { +func (f *Flow) GetHandledConsentRequest() *AcceptOAuth2ConsentRequest { crf := 0 if f.ConsentRememberFor != nil { crf = *f.ConsentRememberFor } - return &consent.AcceptOAuth2ConsentRequest{ + return &AcceptOAuth2ConsentRequest{ ID: f.ConsentChallengeID.String(), GrantedScope: f.GrantedScope, GrantedAudience: f.GrantedAudience, - Session: &consent.AcceptOAuth2ConsentRequestSession{AccessToken: f.SessionAccessToken, IDToken: f.SessionIDToken}, + Session: &AcceptOAuth2ConsentRequestSession{AccessToken: f.SessionAccessToken, IDToken: f.SessionIDToken}, Remember: f.ConsentRemember, RememberFor: crf, HandledAt: f.ConsentHandledAt, WasHandled: f.ConsentWasHandled, + Context: f.Context, ConsentRequest: f.GetConsentRequest(), Error: f.ConsentError, RequestedAt: f.RequestedAt, @@ -450,7 +474,7 @@ func (f *Flow) GetHandledConsentRequest() *consent.AcceptOAuth2ConsentRequest { } } -func (_ Flow) TableName() string { +func (Flow) TableName() string { return "hydra_oauth2_flow" } @@ -464,15 +488,15 @@ func (f *Flow) BeforeSave(_ *pop.Connection) error { return nil } -// TODO Populate the client field in FindInDB and FindByConsentChallengeID in -// order to avoid accessing the database twice. func (f *Flow) AfterFind(c *pop.Connection) error { + // TODO Populate the client field in FindInDB and FindByConsentChallengeID in + // order to avoid accessing the database twice. f.AfterSave(c) f.Client = &client.Client{} return sqlcon.HandleError(c.Where("id = ? AND nid = ?", f.ClientID, f.NID).First(f.Client)) } -func (f *Flow) AfterSave(c *pop.Connection) { +func (f *Flow) AfterSave(_ *pop.Connection) { if f.SessionAccessToken == nil { f.SessionAccessToken = make(map[string]interface{}) } @@ -480,3 +504,39 @@ func (f *Flow) AfterSave(c *pop.Connection) { f.SessionIDToken = make(map[string]interface{}) } } + +type CipherProvider interface { + FlowCipher() *aead.XChaCha20Poly1305 +} + +// ToLoginChallenge converts the flow into a login challenge. +func (f Flow) ToLoginChallenge(ctx context.Context, cipherProvider CipherProvider) (string, error) { + if f.Client != nil { + f.ClientID = f.Client.GetID() + } + return flowctx.Encode(ctx, cipherProvider.FlowCipher(), f, flowctx.AsLoginChallenge) +} + +// ToLoginVerifier converts the flow into a login verifier. +func (f Flow) ToLoginVerifier(ctx context.Context, cipherProvider CipherProvider) (string, error) { + if f.Client != nil { + f.ClientID = f.Client.GetID() + } + return flowctx.Encode(ctx, cipherProvider.FlowCipher(), f, flowctx.AsLoginVerifier) +} + +// ToConsentChallenge converts the flow into a consent challenge. +func (f Flow) ToConsentChallenge(ctx context.Context, cipherProvider CipherProvider) (string, error) { + if f.Client != nil { + f.ClientID = f.Client.GetID() + } + return flowctx.Encode(ctx, cipherProvider.FlowCipher(), f, flowctx.AsConsentChallenge) +} + +// ToConsentVerifier converts the flow into a consent verifier. +func (f Flow) ToConsentVerifier(ctx context.Context, cipherProvider CipherProvider) (string, error) { + if f.Client != nil { + f.ClientID = f.Client.GetID() + } + return flowctx.Encode(ctx, cipherProvider.FlowCipher(), f, flowctx.AsConsentVerifier) +} diff --git a/flow/flow_test.go b/flow/flow_test.go index 86a0c757afd..43a54176088 100644 --- a/flow/flow_test.go +++ b/flow/flow_test.go @@ -7,17 +7,15 @@ import ( "testing" "time" - "github.com/instana/testify/require" + "github.com/go-faker/faker/v4" "github.com/mohae/deepcopy" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" - "github.com/bxcodec/faker/v3" - - "github.com/ory/hydra/consent" "github.com/ory/x/sqlxx" ) -func (f *Flow) setLoginRequest(r *consent.LoginRequest) { +func (f *Flow) setLoginRequest(r *LoginRequest) { f.ID = r.ID f.RequestedScope = r.RequestedScope f.RequestedAudience = r.RequestedAudience @@ -36,13 +34,15 @@ func (f *Flow) setLoginRequest(r *consent.LoginRequest) { f.RequestedAt = r.RequestedAt } -func (f *Flow) setHandledLoginRequest(r *consent.HandledLoginRequest) { +func (f *Flow) setHandledLoginRequest(r *HandledLoginRequest) { f.ID = r.ID f.LoginRemember = r.Remember f.LoginRememberFor = r.RememberFor + f.LoginExtendSessionLifespan = r.ExtendSessionLifespan f.ACR = r.ACR f.AMR = r.AMR f.Subject = r.Subject + f.IdentityProviderSessionID = sqlxx.NullString(r.IdentityProviderSessionID) f.ForceSubjectIdentifier = r.ForceSubjectIdentifier f.Context = r.Context f.LoginWasUsed = r.WasHandled @@ -51,7 +51,7 @@ func (f *Flow) setHandledLoginRequest(r *consent.HandledLoginRequest) { f.LoginAuthenticatedAt = r.AuthenticatedAt } -func (f *Flow) setConsentRequest(r consent.OAuth2ConsentRequest) { +func (f *Flow) setConsentRequest(r OAuth2ConsentRequest) { f.ConsentChallengeID = sqlxx.NullString(r.ID) f.RequestedScope = r.RequestedScope f.RequestedAudience = r.RequestedAudience @@ -74,7 +74,7 @@ func (f *Flow) setConsentRequest(r consent.OAuth2ConsentRequest) { f.RequestedAt = r.RequestedAt } -func (f *Flow) setHandledConsentRequest(r consent.AcceptOAuth2ConsentRequest) { +func (f *Flow) setHandledConsentRequest(r AcceptOAuth2ConsentRequest) { f.ConsentChallengeID = sqlxx.NullString(r.ID) f.GrantedScope = r.GrantedScope f.GrantedAudience = r.GrantedAudience @@ -87,12 +87,15 @@ func (f *Flow) setHandledConsentRequest(r consent.AcceptOAuth2ConsentRequest) { f.LoginAuthenticatedAt = r.AuthenticatedAt f.SessionIDToken = r.SessionIDToken f.SessionAccessToken = r.SessionAccessToken + if r.Context != nil { + f.Context = r.Context + } } func TestFlow_GetLoginRequest(t *testing.T) { t.Run("GetLoginRequest should set all fields on its return value", func(t *testing.T) { f := Flow{} - expected := consent.LoginRequest{} + expected := LoginRequest{} assert.NoError(t, faker.FakeData(&expected)) f.setLoginRequest(&expected) actual := f.GetLoginRequest() @@ -103,7 +106,7 @@ func TestFlow_GetLoginRequest(t *testing.T) { func TestFlow_GetHandledLoginRequest(t *testing.T) { t.Run("GetHandledLoginRequest should set all fields on its return value", func(t *testing.T) { f := Flow{} - expected := consent.HandledLoginRequest{} + expected := HandledLoginRequest{} assert.NoError(t, faker.FakeData(&expected)) f.setHandledLoginRequest(&expected) actual := f.GetHandledLoginRequest() @@ -116,7 +119,7 @@ func TestFlow_GetHandledLoginRequest(t *testing.T) { func TestFlow_NewFlow(t *testing.T) { t.Run("NewFlow and GetLoginRequest should use all LoginRequest fields", func(t *testing.T) { - expected := &consent.LoginRequest{} + expected := &LoginRequest{} assert.NoError(t, faker.FakeData(expected)) actual := NewFlow(expected).GetLoginRequest() assert.Equal(t, expected, actual) @@ -131,7 +134,7 @@ func TestFlow_HandleLoginRequest(t *testing.T) { assert.NoError(t, faker.FakeData(&f)) f.State = FlowStateLoginInitialized - r := consent.HandledLoginRequest{} + r := HandledLoginRequest{} assert.NoError(t, faker.FakeData(&r)) r.ID = f.ID r.Subject = f.Subject @@ -151,12 +154,12 @@ func TestFlow_HandleLoginRequest(t *testing.T) { func TestFlow_InvalidateLoginRequest(t *testing.T) { t.Run("InvalidateLoginRequest should transition the flow into FlowStateLoginUsed", func(t *testing.T) { - f := NewFlow(&consent.LoginRequest{ + f := NewFlow(&LoginRequest{ ID: "t3-id", Subject: "t3-sub", WasHandled: false, }) - assert.NoError(t, f.HandleLoginRequest(&consent.HandledLoginRequest{ + assert.NoError(t, f.HandleLoginRequest(&HandledLoginRequest{ ID: "t3-id", Subject: "t3-sub", WasHandled: false, @@ -166,12 +169,12 @@ func TestFlow_InvalidateLoginRequest(t *testing.T) { assert.Equal(t, true, f.LoginWasUsed) }) t.Run("InvalidateLoginRequest should fail when flow.LoginWasUsed is true", func(t *testing.T) { - f := NewFlow(&consent.LoginRequest{ + f := NewFlow(&LoginRequest{ ID: "t3-id", Subject: "t3-sub", WasHandled: false, }) - assert.NoError(t, f.HandleLoginRequest(&consent.HandledLoginRequest{ + assert.NoError(t, f.HandleLoginRequest(&HandledLoginRequest{ ID: "t3-id", Subject: "t3-sub", WasHandled: true, @@ -185,7 +188,7 @@ func TestFlow_InvalidateLoginRequest(t *testing.T) { func TestFlow_GetConsentRequest(t *testing.T) { t.Run("GetConsentRequest should set all fields on its return value", func(t *testing.T) { f := Flow{} - expected := consent.OAuth2ConsentRequest{} + expected := OAuth2ConsentRequest{} assert.NoError(t, faker.FakeData(&expected)) f.setConsentRequest(expected) actual := f.GetConsentRequest() @@ -197,13 +200,13 @@ func TestFlow_HandleConsentRequest(t *testing.T) { f := Flow{} require.NoError(t, faker.FakeData(&f)) - expected := consent.AcceptOAuth2ConsentRequest{} + expected := AcceptOAuth2ConsentRequest{} require.NoError(t, faker.FakeData(&expected)) expected.ID = string(f.ConsentChallengeID) expected.HandledAt = sqlxx.NullTime(time.Now()) expected.RequestedAt = f.RequestedAt - expected.Session = &consent.AcceptOAuth2ConsentRequestSession{ + expected.Session = &AcceptOAuth2ConsentRequestSession{ IDToken: sqlxx.MapStringInterface{"claim1": "value1", "claim2": "value2"}, AccessToken: sqlxx.MapStringInterface{"claim3": "value3", "claim4": "value4"}, } @@ -214,7 +217,7 @@ func TestFlow_HandleConsentRequest(t *testing.T) { f.ConsentWasHandled = false fGood := deepcopy.Copy(f).(Flow) - eGood := deepcopy.Copy(expected).(consent.AcceptOAuth2ConsentRequest) + eGood := deepcopy.Copy(expected).(AcceptOAuth2ConsentRequest) require.NoError(t, f.HandleConsentRequest(&expected)) t.Run("HandleConsentRequest should fail when already handled", func(t *testing.T) { @@ -231,7 +234,7 @@ func TestFlow_HandleConsentRequest(t *testing.T) { t.Run("HandleConsentRequest should fail when HandledAt in its argument is zero", func(t *testing.T) { f := deepcopy.Copy(fGood).(Flow) - eBad := deepcopy.Copy(eGood).(consent.AcceptOAuth2ConsentRequest) + eBad := deepcopy.Copy(eGood).(AcceptOAuth2ConsentRequest) eBad.HandledAt = sqlxx.NullTime(time.Time{}) require.Error(t, f.HandleConsentRequest(&eBad)) }) @@ -248,11 +251,11 @@ func TestFlow_HandleConsentRequest(t *testing.T) { func TestFlow_GetHandledConsentRequest(t *testing.T) { t.Run("GetHandledConsentRequest should set all fields on its return value", func(t *testing.T) { f := Flow{} - expected := consent.AcceptOAuth2ConsentRequest{} + expected := AcceptOAuth2ConsentRequest{} assert.NoError(t, faker.FakeData(&expected)) expected.ConsentRequest = nil - expected.Session = &consent.AcceptOAuth2ConsentRequestSession{ + expected.Session = &AcceptOAuth2ConsentRequestSession{ IDToken: sqlxx.MapStringInterface{"claim1": "value1", "claim2": "value2"}, AccessToken: sqlxx.MapStringInterface{"claim3": "value3", "claim4": "value4"}, } diff --git a/fositex/config.go b/fositex/config.go index db512574f94..4377efb1f6d 100644 --- a/fositex/config.go +++ b/fositex/config.go @@ -16,10 +16,11 @@ import ( "github.com/ory/fosite/compose" "github.com/ory/fosite/i18n" "github.com/ory/fosite/token/jwt" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/persistence" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/persistence" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/stringslice" "github.com/ory/x/urlx" ) @@ -29,9 +30,10 @@ type configDependencies interface { x.HTTPClientProvider GetJWKSFetcherStrategy() fosite.JWKSFetcherStrategy ClientHasher() fosite.Hasher + ExtraFositeFactories() []Factory } -type factory func(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} +type Factory func(config fosite.Configurator, storage interface{}, strategy interface{}) interface{} type Config struct { deps configDependencies @@ -45,7 +47,7 @@ type Config struct { } var defaultResponseModeHandler = fosite.NewDefaultResponseModeHandler() -var defaultFactories = []factory{ +var defaultFactories = []Factory{ compose.OAuth2AuthorizeExplicitFactory, compose.OAuth2AuthorizeImplicitFactory, compose.OAuth2ClientCredentialsGrantFactory, @@ -58,6 +60,7 @@ var defaultFactories = []factory{ compose.OAuth2TokenIntrospectionFactory, compose.OAuth2PKCEFactory, compose.RFC7523AssertionGrantFactory, + compose.OIDCUserinfoVerifiableCredentialFactory, } func NewConfig(deps configDependencies) *Config { @@ -68,8 +71,9 @@ func NewConfig(deps configDependencies) *Config { return c } -func (c *Config) LoadDefaultHanlders(strategy interface{}) { - for _, factory := range defaultFactories { +func (c *Config) LoadDefaultHandlers(strategy interface{}) { + factories := append(defaultFactories, c.deps.ExtraFositeFactories()...) + for _, factory := range factories { res := factory(c, c.deps.Persister(), strategy) if ah, ok := res.(fosite.AuthorizeEndpointHandler); ok { c.authorizeEndpointHandlers.Append(ah) @@ -86,7 +90,7 @@ func (c *Config) LoadDefaultHanlders(strategy interface{}) { } } -func (c *Config) GetJWKSFetcherStrategy(ctx context.Context) fosite.JWKSFetcherStrategy { +func (c *Config) GetJWKSFetcherStrategy(context.Context) fosite.JWKSFetcherStrategy { return c.deps.GetJWKSFetcherStrategy() } @@ -94,47 +98,47 @@ func (c *Config) GetHTTPClient(ctx context.Context) *retryablehttp.Client { return c.deps.HTTPClient(ctx) } -func (c *Config) GetAuthorizeEndpointHandlers(ctx context.Context) fosite.AuthorizeEndpointHandlers { +func (c *Config) GetAuthorizeEndpointHandlers(context.Context) fosite.AuthorizeEndpointHandlers { return c.authorizeEndpointHandlers } -func (c *Config) GetTokenEndpointHandlers(ctx context.Context) fosite.TokenEndpointHandlers { +func (c *Config) GetTokenEndpointHandlers(context.Context) fosite.TokenEndpointHandlers { return c.tokenEndpointHandlers } -func (c *Config) GetTokenIntrospectionHandlers(ctx context.Context) (r fosite.TokenIntrospectionHandlers) { +func (c *Config) GetTokenIntrospectionHandlers(context.Context) (r fosite.TokenIntrospectionHandlers) { return c.tokenIntrospectionHandlers } -func (c *Config) GetRevocationHandlers(ctx context.Context) fosite.RevocationHandlers { +func (c *Config) GetRevocationHandlers(context.Context) fosite.RevocationHandlers { return c.revocationHandlers } -func (c *Config) GetGrantTypeJWTBearerCanSkipClientAuth(ctx context.Context) bool { +func (c *Config) GetGrantTypeJWTBearerCanSkipClientAuth(context.Context) bool { return false } -func (c *Config) GetAudienceStrategy(ctx context.Context) fosite.AudienceMatchingStrategy { +func (c *Config) GetAudienceStrategy(context.Context) fosite.AudienceMatchingStrategy { return fosite.DefaultAudienceMatchingStrategy } -func (c *Config) GetOmitRedirectScopeParam(ctx context.Context) bool { +func (c *Config) GetOmitRedirectScopeParam(context.Context) bool { return false } -func (c *Config) GetSanitationWhiteList(ctx context.Context) []string { +func (c *Config) GetSanitationWhiteList(context.Context) []string { return []string{"code", "redirect_uri"} } -func (c *Config) GetEnablePKCEPlainChallengeMethod(ctx context.Context) bool { +func (c *Config) GetEnablePKCEPlainChallengeMethod(context.Context) bool { return false } -func (c *Config) GetDisableRefreshTokenValidation(ctx context.Context) bool { +func (c *Config) GetDisableRefreshTokenValidation(context.Context) bool { return false } -func (c *Config) GetRefreshTokenScopes(ctx context.Context) []string { +func (c *Config) GetRefreshTokenScopes(context.Context) []string { return []string{"offline", "offline_access"} } @@ -142,12 +146,12 @@ func (c *Config) GetMinParameterEntropy(_ context.Context) int { return fosite.MinParameterEntropy } -func (c *Config) GetClientAuthenticationStrategy(ctx context.Context) fosite.ClientAuthenticationStrategy { +func (c *Config) GetClientAuthenticationStrategy(context.Context) fosite.ClientAuthenticationStrategy { // Fosite falls back to the default fosite.Fosite.DefaultClientAuthenticationStrategy when this is nil. return nil } -func (c *Config) GetResponseModeHandlerExtension(ctx context.Context) fosite.ResponseModeHandler { +func (c *Config) GetResponseModeHandlerExtension(context.Context) fosite.ResponseModeHandler { return defaultResponseModeHandler } @@ -155,20 +159,20 @@ func (c *Config) GetSendDebugMessagesToClients(ctx context.Context) bool { return c.deps.Config().GetSendDebugMessagesToClients(ctx) } -func (c *Config) GetMessageCatalog(ctx context.Context) i18n.MessageCatalog { +func (c *Config) GetMessageCatalog(context.Context) i18n.MessageCatalog { // Fosite falls back to the default messages when this is nil. return nil } -func (c *Config) GetSecretsHasher(ctx context.Context) fosite.Hasher { +func (c *Config) GetSecretsHasher(context.Context) fosite.Hasher { return c.deps.ClientHasher() } -func (c *Config) GetTokenEntropy(ctx context.Context) int { +func (c *Config) GetTokenEntropy(context.Context) int { return 32 } -func (c *Config) GetHMACHasher(ctx context.Context) func() hash.Hash { +func (c *Config) GetHMACHasher(context.Context) func() hash.Hash { return sha512.New512_256 } @@ -176,11 +180,11 @@ func (c *Config) GetIDTokenIssuer(ctx context.Context) string { return c.deps.Config().IssuerURL(ctx).String() } -func (c *Config) GetAllowedPrompts(ctx context.Context) []string { - return []string{"login", "none", "consent"} +func (c *Config) GetAllowedPrompts(context.Context) []string { + return []string{"login", "none", "consent", "registration"} } -func (c *Config) GetRedirectSecureChecker(ctx context.Context) func(context.Context, *url.URL) bool { +func (c *Config) GetRedirectSecureChecker(context.Context) func(context.Context, *url.URL) bool { return x.IsRedirectURISecure(c.deps.Config()) } @@ -189,13 +193,16 @@ func (c *Config) GetAccessTokenIssuer(ctx context.Context) string { } func (c *Config) GetJWTScopeField(ctx context.Context) jwt.JWTScopeFieldEnum { - return jwt.JWTScopeFieldList + return c.deps.Config().GetJWTScopeField(ctx) } -func (c *Config) GetFormPostHTMLTemplate(ctx context.Context) *template.Template { +func (c *Config) GetFormPostHTMLTemplate(context.Context) *template.Template { return fosite.DefaultFormPostTemplate } -func (c *Config) GetTokenURL(ctx context.Context) string { - return urlx.AppendPaths(c.deps.Config().PublicURL(ctx), oauth2.TokenPath).String() +func (c *Config) GetTokenURLs(ctx context.Context) []string { + return stringslice.Unique([]string{ + c.OAuth2TokenURL(ctx).String(), + urlx.AppendPaths(c.deps.Config().PublicURL(ctx), oauth2.TokenPath).String(), + }) } diff --git a/fositex/token_strategy.go b/fositex/token_strategy.go index 865451ac9ce..116a904c7ef 100644 --- a/fositex/token_strategy.go +++ b/fositex/token_strategy.go @@ -5,10 +5,12 @@ package fositex import ( "context" + "strings" "github.com/ory/fosite" foauth2 "github.com/ory/fosite/handler/oauth2" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" ) var _ foauth2.CoreStrategy = (*TokenStrategy)(nil) @@ -16,34 +18,34 @@ var _ foauth2.CoreStrategy = (*TokenStrategy)(nil) // TokenStrategy uses the correct token strategy (jwt, opaque) depending on the configuration. type TokenStrategy struct { c *config.DefaultProvider - hmac *foauth2.HMACSHAStrategy - jwt *foauth2.DefaultJWTStrategy + hmac foauth2.CoreStrategy + jwt foauth2.CoreStrategy } // NewTokenStrategy returns a new TokenStrategy. -func NewTokenStrategy(c *config.DefaultProvider, hmac *foauth2.HMACSHAStrategy, jwt *foauth2.DefaultJWTStrategy) *TokenStrategy { +func NewTokenStrategy(c *config.DefaultProvider, hmac foauth2.CoreStrategy, jwt *foauth2.DefaultJWTStrategy) *TokenStrategy { return &TokenStrategy{c: c, hmac: hmac, jwt: jwt} } // gs returns the configured strategy. -func (t TokenStrategy) gs(ctx context.Context) foauth2.CoreStrategy { - switch ats := t.c.AccessTokenStrategy(ctx); ats { +func (t TokenStrategy) gs(ctx context.Context, additionalSources ...config.AccessTokenStrategySource) foauth2.CoreStrategy { + switch ats := t.c.AccessTokenStrategy(ctx, additionalSources...); ats { case config.AccessTokenJWTStrategy: return t.jwt } return t.hmac } -func (t TokenStrategy) AccessTokenSignature(ctx context.Context, token string) string { - return t.gs(ctx).AccessTokenSignature(ctx, token) +func (t TokenStrategy) AccessTokenSignature(_ context.Context, token string) string { + return genericSignature(token) } func (t TokenStrategy) GenerateAccessToken(ctx context.Context, requester fosite.Requester) (token string, signature string, err error) { - return t.gs(ctx).GenerateAccessToken(ctx, requester) + return t.gs(ctx, withRequester(requester)).GenerateAccessToken(ctx, requester) } func (t TokenStrategy) ValidateAccessToken(ctx context.Context, requester fosite.Requester, token string) (err error) { - return t.gs(ctx).ValidateAccessToken(ctx, requester, token) + return t.gs(ctx, withRequester(requester)).ValidateAccessToken(ctx, requester, token) } func (t TokenStrategy) RefreshTokenSignature(ctx context.Context, token string) string { @@ -51,11 +53,11 @@ func (t TokenStrategy) RefreshTokenSignature(ctx context.Context, token string) } func (t TokenStrategy) GenerateRefreshToken(ctx context.Context, requester fosite.Requester) (token string, signature string, err error) { - return t.gs(ctx).GenerateRefreshToken(ctx, requester) + return t.gs(ctx, withRequester(requester)).GenerateRefreshToken(ctx, requester) } func (t TokenStrategy) ValidateRefreshToken(ctx context.Context, requester fosite.Requester, token string) (err error) { - return t.gs(ctx).ValidateRefreshToken(ctx, requester, token) + return t.gs(ctx, withRequester(requester)).ValidateRefreshToken(ctx, requester, token) } func (t TokenStrategy) AuthorizeCodeSignature(ctx context.Context, token string) string { @@ -63,9 +65,24 @@ func (t TokenStrategy) AuthorizeCodeSignature(ctx context.Context, token string) } func (t TokenStrategy) GenerateAuthorizeCode(ctx context.Context, requester fosite.Requester) (token string, signature string, err error) { - return t.gs(ctx).GenerateAuthorizeCode(ctx, requester) + return t.gs(ctx, withRequester(requester)).GenerateAuthorizeCode(ctx, requester) } func (t TokenStrategy) ValidateAuthorizeCode(ctx context.Context, requester fosite.Requester, token string) (err error) { - return t.gs(ctx).ValidateAuthorizeCode(ctx, requester, token) + return t.gs(ctx, withRequester(requester)).ValidateAuthorizeCode(ctx, requester, token) +} + +func withRequester(requester fosite.Requester) config.AccessTokenStrategySource { + return client.AccessTokenStrategySource(requester.GetClient()) +} + +func genericSignature(token string) string { + switch parts := strings.Split(token, "."); len(parts) { + case 2: + return parts[1] + case 3: + return parts[2] + default: + return "" + } } diff --git a/fositex/token_strategy_test.go b/fositex/token_strategy_test.go new file mode 100644 index 00000000000..5572311346a --- /dev/null +++ b/fositex/token_strategy_test.go @@ -0,0 +1,54 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package fositex + +import ( + "context" + "testing" + + "github.com/ory/fosite/token/hmac" + + "github.com/stretchr/testify/assert" + + "github.com/ory/fosite/handler/oauth2" +) + +// Test that the generic signature function implements the same signature as the +// HMAC and JWT strategies. +func TestAccessTokenSignature(t *testing.T) { + ctx := context.Background() + + t.Run("strategy=DefaultJWTStrategy", func(t *testing.T) { + strategy := new(oauth2.DefaultJWTStrategy) + for _, tc := range []struct{ token string }{ + {""}, + {"foo"}, + // tokens with two parts will be handled by the HMAC strategy + {"foo.bar.baz"}, + {"foo.bar.baz.qux"}, + } { + t.Run("case="+tc.token, func(t *testing.T) { + assert.Equal(t, + strategy.AccessTokenSignature(ctx, tc.token), + genericSignature(tc.token)) + }) + } + }) + t.Run("strategy=HMACStrategy", func(t *testing.T) { + strategy := oauth2.NewHMACSHAStrategy(&hmac.HMACStrategy{}, nil) + for _, tc := range []struct{ token string }{ + {""}, + {"foo"}, + {"foo.bar"}, + // tokens with three parts will be handled by the JWT strategy + {"foo.bar.baz.qux"}, + } { + t.Run("case="+tc.token, func(t *testing.T) { + assert.Equal(t, + strategy.AccessTokenSignature(ctx, tc.token), + genericSignature(tc.token)) + }) + } + }) +} diff --git a/go.mod b/go.mod index 2d864f080af..0c9b9277cdf 100644 --- a/go.mod +++ b/go.mod @@ -1,273 +1,249 @@ -module github.com/ory/hydra +module github.com/ory/hydra/v2 -go 1.19 +go 1.22 -replace ( - github.com/bradleyjkemp/cupaloy/v2 => github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3 - github.com/dgrijalva/jwt-go => github.com/golang-jwt/jwt/v4 v4.0.0 - github.com/gobuffalo/packr => github.com/gobuffalo/packr v1.30.1 - github.com/gogo/protobuf => github.com/gogo/protobuf v1.3.2 - github.com/mattn/go-sqlite3 => github.com/mattn/go-sqlite3 v1.14.13 - github.com/oleiade/reflections => github.com/oleiade/reflections v1.0.1 -) +toolchain go1.22.5 replace github.com/ory/hydra-client-go/v2 => ./internal/httpclient +replace github.com/gobuffalo/pop/v6 => github.com/ory/pop/v6 v6.2.1-0.20241121111754-e5dfc0f3344b + require ( - github.com/ThalesIgnite/crypto11 v1.2.4 + github.com/ThalesIgnite/crypto11 v1.2.5 github.com/bradleyjkemp/cupaloy/v2 v2.8.0 - github.com/bxcodec/faker/v3 v3.7.0 github.com/cenkalti/backoff/v3 v3.2.2 github.com/fatih/structs v1.1.0 - github.com/go-bindata/go-bindata v3.1.2+incompatible - github.com/go-swagger/go-swagger v0.30.3 - github.com/gobuffalo/pop/v6 v6.0.8 - github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7 + github.com/go-faker/faker/v4 v4.4.2 + github.com/go-jose/go-jose/v3 v3.0.3 + github.com/go-swagger/go-swagger v0.31.0 + github.com/gobuffalo/pop/v6 v6.1.2-0.20230318123913-c85387acc9a0 github.com/gobwas/glob v0.2.3 - github.com/gofrs/uuid v4.3.0+incompatible + github.com/gofrs/uuid v4.4.0+incompatible + github.com/golang-jwt/jwt/v5 v5.2.1 github.com/golang/mock v1.6.0 - github.com/google/uuid v1.3.0 - github.com/gorilla/securecookie v1.1.1 - github.com/gorilla/sessions v1.2.1 - github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 - github.com/hashicorp/go-retryablehttp v0.7.1 - github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65 - github.com/jackc/pgx/v4 v4.17.2 - github.com/jmoiron/sqlx v1.3.5 + github.com/google/uuid v1.6.0 + github.com/gorilla/securecookie v1.1.2 + github.com/gorilla/sessions v1.3.0 + github.com/hashicorp/go-retryablehttp v0.7.7 + github.com/jackc/pgx/v5 v5.6.0 github.com/julienschmidt/httprouter v1.3.0 github.com/luna-duclos/instrumentedsql v1.1.3 - github.com/miekg/pkcs11 v1.0.3 - github.com/mikefarah/yq/v4 v4.16.1 + github.com/miekg/pkcs11 v1.1.1 + github.com/mikefarah/yq/v4 v4.44.2 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/oleiade/reflections v1.0.1 - github.com/ory/analytics-go/v4 v4.0.3 - github.com/ory/fosite v0.44.0 - github.com/ory/go-acc v0.2.8 - github.com/ory/graceful v0.1.1 - github.com/ory/herodot v0.9.13 - github.com/ory/hydra-client-go/v2 v2.0.1 - github.com/ory/jsonschema/v3 v3.0.7 - github.com/ory/x v0.0.514 + github.com/ory/analytics-go/v5 v5.0.1 + github.com/ory/fosite v0.48.0 + github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe + github.com/ory/graceful v0.1.3 + github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 + github.com/ory/hydra-client-go/v2 v2.2.1 + github.com/ory/jsonschema/v3 v3.0.8 + github.com/ory/kratos-client-go v1.2.1 + github.com/ory/x v0.0.675 github.com/pborman/uuid v1.2.1 github.com/pkg/errors v0.9.1 - github.com/prometheus/client_golang v1.13.0 - github.com/rs/cors v1.8.2 - github.com/sawadashota/encrypta v0.0.2 - github.com/sirupsen/logrus v1.9.0 - github.com/spf13/cobra v1.6.1 + github.com/prometheus/client_golang v1.19.1 + github.com/rs/cors v1.11.0 + github.com/sawadashota/encrypta v0.0.5 + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.1 - github.com/tidwall/gjson v1.14.3 + github.com/stretchr/testify v1.9.0 + github.com/tidwall/gjson v1.17.3 github.com/tidwall/sjson v1.2.5 github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 github.com/toqueteos/webbrowser v1.2.0 - github.com/twmb/murmur3 v1.1.6 + github.com/twmb/murmur3 v1.1.8 github.com/urfave/negroni v1.0.0 - go.opentelemetry.io/otel v1.11.1 - go.step.sm/crypto v0.16.2 - go.uber.org/automaxprocs v1.3.0 - golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 - golang.org/x/tools v0.2.0 - gopkg.in/DataDog/dd-trace-go.v1 v1.43.0 - gopkg.in/square/go-jose.v2 v2.6.0 + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 + go.opentelemetry.io/otel v1.32.0 + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 + go.opentelemetry.io/otel/sdk v1.32.0 + go.opentelemetry.io/otel/trace v1.32.0 + go.uber.org/automaxprocs v1.5.3 + golang.org/x/crypto v0.28.0 + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 + golang.org/x/oauth2 v0.23.0 + golang.org/x/sync v0.9.0 + golang.org/x/tools v0.23.0 ) -require github.com/hashicorp/go-cleanhttp v0.5.2 // indirect - require ( - filippo.io/edwards25519 v1.0.0-rc.1 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect - github.com/DataDog/datadog-agent/pkg/obfuscate v0.39.0 // indirect - github.com/DataDog/datadog-go/v5 v5.1.1 // indirect - github.com/DataDog/sketches-go v1.4.1 // indirect + code.dny.dev/ssrf v0.2.0 // indirect + dario.cat/mergo v1.0.0 // indirect + filippo.io/edwards25519 v1.1.0 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.1.1 // indirect - github.com/Masterminds/sprig/v3 v3.2.2 // indirect - github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/sprig/v3 v3.2.3 // indirect + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect - github.com/armon/go-radix v1.0.0 // indirect - github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect - github.com/avast/retry-go/v4 v4.3.0 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 // indirect + github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect + github.com/ProtonMail/gopenpgp/v2 v2.7.5 // indirect + github.com/a8m/envsubst v1.4.2 // indirect + github.com/alecthomas/participle/v2 v2.1.1 // indirect + github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect + github.com/avast/retry-go/v4 v4.5.0 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cenkalti/backoff/v4 v4.1.3 // indirect - github.com/cespare/xxhash/v2 v2.1.2 // indirect - github.com/cockroachdb/cockroach-go/v2 v2.2.16 // indirect - github.com/containerd/continuity v0.3.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/cloudflare/circl v1.3.7 // indirect + github.com/cockroachdb/cockroach-go/v2 v2.3.5 // indirect + github.com/containerd/continuity v0.4.3 // indirect github.com/cristalhq/jwt/v4 v4.0.2 // indirect - github.com/dave/jennifer v1.4.0 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgraph-io/ristretto v0.1.1 // indirect - github.com/docker/cli v20.10.21+incompatible // indirect - github.com/docker/distribution v2.8.1+incompatible // indirect - github.com/docker/docker v20.10.21+incompatible // indirect - github.com/docker/go-connections v0.4.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/dgraph-io/ristretto v1.0.0 // indirect + github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/distribution/reference v0.6.0 // indirect + github.com/docker/cli v26.1.4+incompatible // indirect + github.com/docker/docker v26.1.5+incompatible // indirect + github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/dustin/go-humanize v1.0.0 // indirect - github.com/ecordell/optgen v0.0.6 // indirect - github.com/elastic/go-licenser v0.4.1 // indirect - github.com/elastic/go-sysinfo v1.8.1 // indirect - github.com/elastic/go-windows v1.0.1 // indirect - github.com/elliotchance/orderedmap v1.4.0 // indirect - github.com/evanphx/json-patch v5.6.0+incompatible // indirect - github.com/fatih/color v1.13.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect + github.com/elliotchance/orderedmap v1.6.0 // indirect + github.com/evanphx/json-patch/v5 v5.6.0 // indirect + github.com/fatih/color v1.17.0 // indirect github.com/felixge/fgprof v0.9.3 // indirect - github.com/felixge/httpsnoop v1.0.3 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect - github.com/go-logr/logr v1.2.3 // indirect + github.com/felixge/httpsnoop v1.0.4 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-openapi/analysis v0.21.4 // indirect - github.com/go-openapi/errors v0.20.3 // indirect - github.com/go-openapi/inflect v0.19.0 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect - github.com/go-openapi/loads v0.21.2 // indirect - github.com/go-openapi/runtime v0.24.2 // indirect - github.com/go-openapi/spec v0.20.7 // indirect - github.com/go-openapi/strfmt v0.21.3 // indirect - github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-openapi/validate v0.22.0 // indirect - github.com/go-sql-driver/mysql v1.6.0 // indirect + github.com/go-openapi/analysis v0.23.0 // indirect + github.com/go-openapi/errors v0.22.0 // indirect + github.com/go-openapi/inflect v0.21.0 // indirect + github.com/go-openapi/jsonpointer v0.21.0 // indirect + github.com/go-openapi/jsonreference v0.21.0 // indirect + github.com/go-openapi/loads v0.22.0 // indirect + github.com/go-openapi/runtime v0.28.0 // indirect + github.com/go-openapi/spec v0.21.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect + github.com/go-openapi/swag v0.23.0 // indirect + github.com/go-openapi/validate v0.24.0 // indirect + github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/gobuffalo/envy v1.10.2 // indirect github.com/gobuffalo/fizz v1.14.4 // indirect - github.com/gobuffalo/flect v0.3.0 // indirect - github.com/gobuffalo/github_flavored_markdown v1.1.3 // indirect + github.com/gobuffalo/flect v1.0.2 // indirect + github.com/gobuffalo/github_flavored_markdown v1.1.4 // indirect github.com/gobuffalo/helpers v0.6.7 // indirect github.com/gobuffalo/nulls v0.4.2 // indirect - github.com/gobuffalo/plush/v4 v4.1.16 // indirect + github.com/gobuffalo/plush/v4 v4.1.21 // indirect github.com/gobuffalo/tags/v3 v3.1.4 // indirect github.com/gobuffalo/validate/v3 v3.3.3 // indirect - github.com/goccy/go-yaml v1.9.6 // indirect + github.com/goccy/go-json v0.10.3 // indirect + github.com/goccy/go-yaml v1.11.3 // indirect github.com/gofrs/flock v0.8.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/glog v1.0.0 // indirect - github.com/golang/protobuf v1.5.2 // indirect - github.com/google/pprof v0.0.0-20221010195024-131d412537ea // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/pprof v0.0.0-20230808223545-4887780b67fb // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect - github.com/gorilla/css v1.0.0 // indirect - github.com/gorilla/handlers v1.5.1 // indirect + github.com/gorilla/css v1.0.1 // indirect + github.com/gorilla/handlers v1.5.2 // indirect github.com/gorilla/websocket v1.5.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 // indirect + github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/huandu/xstrings v1.3.2 // indirect - github.com/imdario/mergo v0.3.13 // indirect - github.com/inconshreveable/mousetrap v1.0.1 // indirect + github.com/huandu/xstrings v1.4.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect - github.com/instana/go-sensor v1.46.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgconn v1.13.0 // indirect + github.com/jackc/pgconn v1.14.3 // indirect github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect - github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/pgtype v1.12.0 // indirect + github.com/jackc/pgproto3/v2 v2.3.3 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/puddle/v2 v2.2.1 // indirect github.com/jandelgado/gcov2lcov v1.0.5 // indirect - github.com/jcchavezs/porto v0.4.0 // indirect github.com/jessevdk/go-flags v1.5.0 // indirect - github.com/jinzhu/copier v0.3.5 // indirect - github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect - github.com/joho/godotenv v1.4.0 // indirect + github.com/jinzhu/copier v0.4.0 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/knadh/koanf v1.4.4 // indirect - github.com/kr/pretty v0.3.0 // indirect + github.com/knadh/koanf/maps v0.1.1 // indirect + github.com/knadh/koanf/parsers/json v0.1.0 // indirect + github.com/knadh/koanf/parsers/toml v0.1.0 // indirect + github.com/knadh/koanf/parsers/yaml v0.1.0 // indirect + github.com/knadh/koanf/providers/posflag v0.1.0 // indirect + github.com/knadh/koanf/v2 v2.0.1 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // indirect - github.com/lib/pq v1.10.7 // indirect - github.com/looplab/fsm v0.3.0 // indirect - github.com/magiconair/properties v1.8.6 // indirect + github.com/lib/pq v1.10.9 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect - github.com/mattn/go-isatty v0.0.16 // indirect - github.com/mattn/go-sqlite3 v2.0.3+incompatible // indirect - github.com/mattn/goveralls v0.0.11 // indirect - github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect - github.com/microcosm-cc/bluemonday v1.0.21 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-sqlite3 v1.14.22 // indirect + github.com/mattn/goveralls v0.0.12 // indirect + github.com/microcosm-cc/bluemonday v1.0.26 // indirect github.com/mitchellh/copystructure v1.2.0 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect - github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect - github.com/nyaruka/phonenumbers v1.1.1 // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect + github.com/moby/term v0.5.0 // indirect + github.com/nyaruka/phonenumbers v1.1.7 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0-rc2 // indirect - github.com/opencontainers/runc v1.1.4 // indirect - github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 // indirect - github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 // indirect - github.com/openzipkin/zipkin-go v0.4.1 // indirect - github.com/ory/dockertest/v3 v3.9.1 // indirect + github.com/opencontainers/image-spec v1.1.0 // indirect + github.com/opencontainers/runc v1.1.14 // indirect + github.com/openzipkin/zipkin-go v0.4.3 // indirect + github.com/ory/dockertest/v3 v3.10.1-0.20240704115616-d229e74b748d // indirect github.com/ory/go-convenience v0.1.0 // indirect - github.com/ory/viper v1.7.5 // indirect github.com/pelletier/go-toml v1.9.5 // indirect - github.com/pelletier/go-toml/v2 v2.0.1 // indirect - github.com/philhofer/fwd v1.1.1 // indirect + github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/profile v1.7.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/prometheus/client_model v0.3.0 // indirect - github.com/prometheus/common v0.37.0 // indirect - github.com/prometheus/procfs v0.8.0 // indirect - github.com/rogpeppe/go-internal v1.9.0 // indirect - github.com/santhosh-tekuri/jsonschema v1.2.4 // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_model v0.5.0 // indirect + github.com/prometheus/common v0.48.0 // indirect + github.com/prometheus/procfs v0.12.0 // indirect + github.com/rogpeppe/go-internal v1.13.1 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 // indirect github.com/segmentio/backo-go v1.0.1 // indirect - github.com/sergi/go-diff v1.2.0 // indirect + github.com/sergi/go-diff v1.3.1 // indirect github.com/shopspring/decimal v1.3.1 // indirect github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d // indirect + github.com/sourcegraph/conc v0.3.0 // indirect github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e // indirect - github.com/spf13/afero v1.9.2 // indirect - github.com/spf13/cast v1.5.0 // indirect - github.com/spf13/jwalterweatherman v1.1.0 // indirect - github.com/spf13/viper v1.12.0 // indirect - github.com/subosito/gotenv v1.4.1 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/viper v1.18.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/thales-e-security/pool v0.0.2 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect - github.com/timtadh/data-structures v0.5.3 // indirect - github.com/timtadh/lexmachine v0.2.2 // indirect - github.com/tinylib/msgp v1.1.6 // indirect - github.com/uber/jaeger-client-go v2.30.0+incompatible // indirect - github.com/uber/jaeger-lib v2.4.1+incompatible // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c // indirect - go.elastic.co/apm v1.15.0 // indirect - go.elastic.co/apm/module/apmhttp v1.15.0 // indirect - go.elastic.co/apm/module/apmot v1.15.0 // indirect - go.elastic.co/fastjson v1.1.0 // indirect - go.mongodb.org/mongo-driver v1.10.3 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 // indirect - go.opentelemetry.io/contrib/propagators/b3 v1.11.1 // indirect - go.opentelemetry.io/contrib/propagators/jaeger v1.11.1 // indirect - go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2 // indirect - go.opentelemetry.io/otel/bridge/opentracing v1.11.1 // indirect - go.opentelemetry.io/otel/exporters/jaeger v1.11.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0 // indirect - go.opentelemetry.io/otel/exporters/zipkin v1.11.1 // indirect - go.opentelemetry.io/otel/metric v0.33.0 // indirect - go.opentelemetry.io/otel/sdk v1.11.1 // indirect - go.opentelemetry.io/otel/trace v1.11.1 // indirect - go.opentelemetry.io/proto/otlp v0.18.0 // indirect - go.uber.org/atomic v1.10.0 // indirect - golang.org/x/crypto v0.1.0 // indirect - golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect - golang.org/x/mod v0.6.0 // indirect - golang.org/x/net v0.1.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.1.0 // indirect - golang.org/x/text v0.4.0 // indirect - golang.org/x/time v0.1.0 // indirect - golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect - google.golang.org/appengine v1.6.7 // indirect - google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 // indirect - google.golang.org/grpc v1.50.1 // indirect - google.golang.org/protobuf v1.28.1 // indirect + github.com/yuin/gopher-lua v1.1.1 // indirect + go.mongodb.org/mongo-driver v1.14.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0 // indirect + go.opentelemetry.io/contrib/propagators/b3 v1.32.0 // indirect + go.opentelemetry.io/contrib/propagators/jaeger v1.32.0 // indirect + go.opentelemetry.io/contrib/samplers/jaegerremote v0.26.0 // indirect + go.opentelemetry.io/otel/exporters/jaeger v1.17.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect + go.opentelemetry.io/otel/exporters/zipkin v1.32.0 // indirect + go.opentelemetry.io/otel/metric v1.32.0 // indirect + go.opentelemetry.io/proto/otlp v1.3.1 // indirect + go.uber.org/multierr v1.11.0 // indirect + golang.org/x/mod v0.19.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sys v0.27.0 // indirect + golang.org/x/text v0.20.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 // indirect + google.golang.org/grpc v1.67.1 // indirect + google.golang.org/protobuf v1.35.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - howett.net/plist v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index c50b60e5969..c29c141d383 100644 --- a/go.sum +++ b/go.sum @@ -1,971 +1,444 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= -cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= -cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= -cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= -cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= -cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= -cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= -cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= -cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= -cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= -cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= -cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= -cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= -cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= -cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= -cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= -cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= -cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= -cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= -cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= -cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= -cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= -cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= -cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= -cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk= -cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= -cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= -cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= -cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= -cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= -cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= -cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= -cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= -cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= -cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= -dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= -filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= -filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.39.0 h1:kXdXGOYeH2pKa3tdNGdrixT2tnXrJ4xLE9WypL4X7HE= -github.com/DataDog/datadog-agent/pkg/obfuscate v0.39.0/go.mod h1:MxVcCIC42tBIjPm93BHdh9/vw2LivRiptj3HygI+GGQ= -github.com/DataDog/datadog-go/v5 v5.1.0/go.mod h1:KhiYb2Badlv9/rofz+OznKoEF5XKTonWyhx5K83AP8E= -github.com/DataDog/datadog-go/v5 v5.1.1 h1:JLZ6s2K1pG2h9GkvEvMdEGqMDyVLEAccdX5TltWcLMU= -github.com/DataDog/datadog-go/v5 v5.1.1/go.mod h1:KhiYb2Badlv9/rofz+OznKoEF5XKTonWyhx5K83AP8E= -github.com/DataDog/sketches-go v1.4.1 h1:j5G6as+9FASM2qC36lvpvQAj9qsv/jUs3FtO8CwZNAY= -github.com/DataDog/sketches-go v1.4.1/go.mod h1:xJIXldczJyyjnbDop7ZZcLxJdV3+7Kra7H1KMgpgkLk= -github.com/HdrHistogram/hdrhistogram-go v1.1.2 h1:5IcZpTvzydCQeHzK4Ef/D5rrSqwxob0t8PQPMybUNFM= +code.dny.dev/ssrf v0.2.0 h1:wCBP990rQQ1CYfRpW+YK1+8xhwUjv189AQ3WMo1jQaI= +code.dny.dev/ssrf v0.2.0/go.mod h1:B+91l25OnyaLIeCx0WRJN5qfJ/4/ZTZxRXgm0lj/2w8= +dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= +dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= -github.com/Masterminds/semver/v3 v3.1.1 h1:hLg3sBzpNErnxhQtUy/mmLR2I9foDujNK030IGemrRc= github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= -github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8= -github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk= -github.com/Microsoft/go-winio v0.5.0/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= +github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= -github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= -github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0= -github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= -github.com/ThalesIgnite/crypto11 v1.2.4 h1:3MebRK/U0mA2SmSthXAIZAdUA9w8+ZuKem2O6HuR1f8= -github.com/ThalesIgnite/crypto11 v1.2.4/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= -github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3 h1:/SkiUr3JJzun9QN9cpUVCPri2ZwOFJ3ani+F3vdoCiY= -github.com/aeneasr/cupaloy/v2 v2.6.1-0.20210924214125-3dfdd01210a3/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= -github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= -github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= -github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= -github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= -github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= -github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= -github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= -github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d h1:Byv0BzEl3/e6D5CLfI0j/7hiIEtvGVFPCZ7Ei2oq8iQ= -github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= -github.com/avast/retry-go/v4 v4.3.0 h1:cqI48aXx0BExKoM7XPklDpoHAg7/srPPLAfWG5z62jo= -github.com/avast/retry-go/v4 v4.3.0/go.mod h1:bqOlT4nxk4phk9buiQFaghzjpqdchOSwPgjdfdQBtdg= -github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= -github.com/aws/aws-sdk-go-v2/config v1.8.3/go.mod h1:4AEiLtAb8kLs7vgw2ZV3p2VZ1+hBavOc84hqxVNpCyw= -github.com/aws/aws-sdk-go-v2/credentials v1.4.3/go.mod h1:FNNC6nQZQUuyhq5aE5c7ata8o9e4ECGmS4lAXC7o1mQ= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.6.0/go.mod h1:gqlclDEZp4aqJOancXK6TN24aKhT0W0Ae9MHk3wzTMM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.2.4/go.mod h1:ZcBrrI3zBKlhGFNYWvju0I3TR93I7YIgAfy82Fh4lcQ= -github.com/aws/aws-sdk-go-v2/service/appconfig v1.4.2/go.mod h1:FZ3HkCe+b10uFZZkFdvf98LHW21k49W8o8J366lqVKY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.3.2/go.mod h1:72HRZDLMtmVQiLG2tLfQcaWLCssELvGl+Zf2WVxMmR8= -github.com/aws/aws-sdk-go-v2/service/sso v1.4.2/go.mod h1:NBvT9R1MEF+Ud6ApJKM0G+IkPchKS7p7c2YPKwHmBOk= -github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g= -github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95 h1:KLq8BE0KwCL+mmXnjLWEAOYO+2l2AE4YMmqG1ZpZHBs= +github.com/ProtonMail/go-crypto v0.0.0-20230717121422-5aa5874ade95/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= +github.com/ProtonMail/gopenpgp/v2 v2.7.5 h1:STOY3vgES59gNgoOt2w0nyHBjKViB/qSg7NjbQWPJkA= +github.com/ProtonMail/gopenpgp/v2 v2.7.5/go.mod h1:IhkNEDaxec6NyzSI0PlxapinnwPVIESk8/76da3Ct3g= +github.com/ThalesIgnite/crypto11 v1.2.5 h1:1IiIIEqYmBvUYFeMnHqRft4bwf/O36jryEUpY+9ef8E= +github.com/ThalesIgnite/crypto11 v1.2.5/go.mod h1:ILDKtnCKiQ7zRoNxcp36Y1ZR8LBPmR2E23+wTQe/MlE= +github.com/a8m/envsubst v1.4.2 h1:4yWIHXOLEJHQEFd4UjrWDrYeYlV7ncFWJOCBRLOZHQg= +github.com/a8m/envsubst v1.4.2/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= +github.com/alecthomas/assert/v2 v2.3.0 h1:mAsH2wmvjsuvyBvAmCtm7zFsBlb8mIHx5ySLVdDZXL0= +github.com/alecthomas/assert/v2 v2.3.0/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ= +github.com/alecthomas/participle/v2 v2.1.1 h1:hrjKESvSqGHzRb4yW1ciisFJ4p3MGYih6icjJvbsmV8= +github.com/alecthomas/participle/v2 v2.1.1/go.mod h1:Y1+hAs8DHPmc3YUFzqllV+eSQ9ljPTk0ZkPMtEdAx2c= +github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= +github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= +github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= +github.com/avast/retry-go/v4 v4.5.0 h1:QoRAZZ90cj5oni2Lsgl2GW8mNTnUCnmpx/iKpwVisHg= +github.com/avast/retry-go/v4 v4.5.0/go.mod h1:7hLEXp0oku2Nir2xBAsg0PTphp9z71bN5Aq1fboC3+I= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= -github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= -github.com/bxcodec/faker/v3 v3.7.0 h1:qWAFFwcyVS0ukF0UoJju1wBLO0cuPQ7JdVBPggM8kNo= -github.com/bxcodec/faker/v3 v3.7.0/go.mod h1:gF31YgnMSMKgkvl+fyEo1xuSMbEuieyqfeslGYFjneM= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= +github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= +github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0= github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M= github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs= -github.com/cenkalti/backoff/v4 v4.1.3 h1:cFAlzYUlVYDysBEH2T5hyJZMh3+5+WCBvSnK6Q8UtC4= -github.com/cenkalti/backoff/v4 v4.1.3/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= -github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= -github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= -github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= -github.com/cockroachdb/cockroach-go/v2 v2.2.16 h1:t9dmZuC9J2W8IDQDSIGXmP+fBuEJSsrGXxWQz4cYqBY= -github.com/cockroachdb/cockroach-go/v2 v2.2.16/go.mod h1:xZ2VHjUEb/cySv0scXBx7YsBnHtLHkR1+w/w73b5i3M= -github.com/codegangsta/negroni v1.0.0/go.mod h1:v0y3T5G7Y1UlFfyxFn/QLRU4a2EuNau2iZY63YTKWo0= -github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= -github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg= -github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM= -github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= -github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= -github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= -github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= -github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= -github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= -github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= +github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cockroachdb/cockroach-go/v2 v2.3.5 h1:Khtm8K6fTTz/ZCWPzU9Ne3aOW9VyAnj4qIPCJgKtwK0= +github.com/cockroachdb/cockroach-go/v2 v2.3.5/go.mod h1:1wNJ45eSXW9AnOc3skntW9ZUZz6gxrQK3cOj3rK+BC8= +github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= +github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= +github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= +github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= +github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cristalhq/jwt/v4 v4.0.2 h1:g/AD3h0VicDamtlM70GWGElp8kssQEv+5wYd7L9WOhU= github.com/cristalhq/jwt/v4 v4.0.2/go.mod h1:HnYraSNKDRag1DZP92rYHyrjyQHnVEHPNqesmzs+miQ= -github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= -github.com/dave/jennifer v1.4.0 h1:tNJFJmLDVTLu+v05mVZ88RINa3vQqnyyWkTKWYz0CwE= -github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE= -github.com/dgraph-io/ristretto v0.0.2/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= -github.com/dgraph-io/ristretto v0.1.0/go.mod h1:fux0lOrBhrVCJd3lcTHsIJhq1T2rokOu6v9Vcb3Q9ug= -github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= -github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA= -github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= -github.com/docker/cli v20.10.21+incompatible h1:qVkgyYUnOLQ98LtXBrwd/duVqPT2X4SHndOuGsfwyhU= -github.com/docker/cli v20.10.21+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= -github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v20.10.21+incompatible h1:UTLdBmHk3bEY+w8qeO5KttOhy6OmXWsl/FEet9Uswog= -github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= -github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgraph-io/ristretto v1.0.0 h1:SYG07bONKMlFDUYu5pEu3DGAh8c2OFNzKm6G9J4Si84= +github.com/dgraph-io/ristretto v1.0.0/go.mod h1:jTi2FiYEhQ1NsMmA7DeBykizjOuY88NhKBkepyu1jPc= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= +github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= +github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= +github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= +github.com/docker/cli v26.1.4+incompatible h1:I8PHdc0MtxEADqYJZvhBrW9bo8gawKwwenxRM7/rLu8= +github.com/docker/cli v26.1.4+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v26.1.5+incompatible h1:NEAxTwEjxV6VbBMBoGG3zPqbiJosIApZjxlbrG9q3/g= +github.com/docker/docker v26.1.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= +github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/dustin/go-humanize v0.0.0-20180713052910-9f541cc9db5d/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= -github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= -github.com/ecordell/optgen v0.0.6 h1:aSknPe6ZUBrjwHGp2+6XfmfCGYGD6W0ZDfCmmsrS7s4= -github.com/ecordell/optgen v0.0.6/go.mod h1:bAPkLVWcBlTX5EkXW0UTPRj3+yjq2I6VLgH8OasuQEM= -github.com/elastic/go-licenser v0.3.1/go.mod h1:D8eNQk70FOCVBl3smCGQt/lv7meBeQno2eI1S5apiHQ= -github.com/elastic/go-licenser v0.4.1 h1:1xDURsc8pL5zYT9R29425J3vkHdt4RT5TNEMeRN48x4= -github.com/elastic/go-licenser v0.4.1/go.mod h1:V56wHMpmdURfibNBggaSBfqgPxyT1Tldns1i87iTEvU= -github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= -github.com/elastic/go-sysinfo v1.8.1 h1:4Yhj+HdV6WjbCRgGdZpPJ8lZQlXZLKDAeIkmQ/VRvi4= -github.com/elastic/go-sysinfo v1.8.1/go.mod h1:JfllUnzoQV/JRYymbH3dO1yggI3mV2oTKSXsDHM+uIM= -github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= -github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= -github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= -github.com/elliotchance/orderedmap v1.4.0 h1:wZtfeEONCbx6in1CZyE6bELEt/vFayMvsxqI5SgsR+A= -github.com/elliotchance/orderedmap v1.4.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= -github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= -github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= -github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U= -github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= -github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= -github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= -github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= -github.com/fatih/structs v1.0.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elliotchance/orderedmap v1.6.0 h1:xjn+kbbKXeDq6v9RVE+WYwRbYfAZKvlWfcJNxM8pvEw= +github.com/elliotchance/orderedmap v1.6.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= +github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww= +github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/felixge/fgprof v0.9.3 h1:VvyZxILNuCiUCSXtPtYmmtGvb65nqXh2QFWc0Wpf2/g= github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw= -github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/felixge/httpsnoop v1.0.3 h1:s/nj+GCswXYzN5v2DpNMuMQYe+0DDwt5WVCU6CWBdXk= -github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k= -github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= -github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= -github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE= -github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo= -github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0= -github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-faker/faker/v4 v4.4.2 h1:96WeU9QKEqRUVYdjHquY2/5bAqmVM0IfGKHV5mbfqmQ= +github.com/go-faker/faker/v4 v4.4.2/go.mod h1:4K3v4AbKXYNHMQNaREMc9/kRB9j5JJzpFo6KHRvrcIw= +github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= +github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= -github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= -github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-openapi/analysis v0.21.2/go.mod h1:HZwRk4RRisyG8vx2Oe6aqeSQcoxRp47Xkp3+K6q+LdY= -github.com/go-openapi/analysis v0.21.4 h1:ZDFLvSNxpDaomuCueM0BlSXxpANBlFYiBvr+GXrvIHc= -github.com/go-openapi/analysis v0.21.4/go.mod h1:4zQ35W4neeZTqh3ol0rv/O8JBbka9QyAgQRPp9y3pfo= -github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.2/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M= -github.com/go-openapi/errors v0.20.3 h1:rz6kiC84sqNQoqrtulzaL/VERgkoCyB6WdEkc2ujzUc= -github.com/go-openapi/errors v0.20.3/go.mod h1:Z3FlZ4I8jEGxjUK+bugx3on2mIAk4txuAOhlsB1FSgk= -github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= -github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= -github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= -github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= -github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/loads v0.21.1/go.mod h1:/DtAMXXneXFjbQMGEtbamCZb+4x7eGwkvZCvBmwUG+g= -github.com/go-openapi/loads v0.21.2 h1:r2a/xFIYeZ4Qd2TnGpWDIQNcP80dIaZgf704za8enro= -github.com/go-openapi/loads v0.21.2/go.mod h1:Jq58Os6SSGz0rzh62ptiu8Z31I+OTHqmULx5e/gJbNw= -github.com/go-openapi/runtime v0.24.2 h1:yX9HMGQbz32M87ECaAhGpJjBmErO3QLcgdZj9BzGx7c= -github.com/go-openapi/runtime v0.24.2/go.mod h1:AKurw9fNre+h3ELZfk6ILsfvPN+bvvlaU/M9q/r9hpk= -github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I= -github.com/go-openapi/spec v0.20.6/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/spec v0.20.7 h1:1Rlu/ZrOCCob0n+JKKJAWhNWMPW8bOZRg8FJaY+0SKI= -github.com/go-openapi/spec v0.20.7/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= -github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg= -github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.2/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k= -github.com/go-openapi/strfmt v0.21.3 h1:xwhj5X6CjXEZZHMWy1zKJxvW9AfHC9pkyUjLvHtKG7o= -github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg= -github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= -github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= -github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= -github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/validate v0.21.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-openapi/validate v0.22.0 h1:b0QecH6VslW/TxtpKgzpO1SNG7GU2FsaqKdP1E2T50Y= -github.com/go-openapi/validate v0.22.0/go.mod h1:rjnrwK57VJ7A8xqfpAOEKRH8yQSGUriMu5/zuPSQ1hg= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-openapi/analysis v0.23.0 h1:aGday7OWupfMs+LbmLZG4k0MYXIANxcuBTYUC03zFCU= +github.com/go-openapi/analysis v0.23.0/go.mod h1:9mz9ZWaSlV8TvjQHLl2mUW2PbZtemkE8yA5v22ohupo= +github.com/go-openapi/errors v0.22.0 h1:c4xY/OLxUBSTiepAg3j/MHuAv5mJhnf53LLMWFB+u/w= +github.com/go-openapi/errors v0.22.0/go.mod h1:J3DmZScxCDufmIMsdOuDHxJbdOGC0xtUynjIx092vXE= +github.com/go-openapi/inflect v0.21.0 h1:FoBjBTQEcbg2cJUWX6uwL9OyIW8eqc9k4KhN4lfbeYk= +github.com/go-openapi/inflect v0.21.0/go.mod h1:INezMuUu7SJQc2AyR3WO0DqqYUJSj8Kb4hBd7WtjlAw= +github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ= +github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY= +github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ= +github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= +github.com/go-openapi/loads v0.22.0 h1:ECPGd4jX1U6NApCGG1We+uEozOAvXvJSF4nnwHZ8Aco= +github.com/go-openapi/loads v0.22.0/go.mod h1:yLsaTCS92mnSAZX5WWoxszLj0u+Ojl+Zs5Stn1oF+rs= +github.com/go-openapi/runtime v0.28.0 h1:gpPPmWSNGo214l6n8hzdXYhPuJcGtziTOgUpvsFWGIQ= +github.com/go-openapi/runtime v0.28.0/go.mod h1:QN7OzcS+XuYmkQLw05akXk0jRH/eZ3kb18+1KwW9gyc= +github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY= +github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk= +github.com/go-openapi/strfmt v0.23.0 h1:nlUS6BCqcnAk0pyhi9Y+kdDVZdZMHfEKQiS4HaMgO/c= +github.com/go-openapi/strfmt v0.23.0/go.mod h1:NrtIpfKtWIygRkKVsxh7XQMDQW5HKQl6S5ik2elW+K4= +github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= +github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= +github.com/go-openapi/validate v0.24.0 h1:LdfDKwNbpB6Vn40xhTdNZAnfLECL81w+VX3BumrGD58= +github.com/go-openapi/validate v0.24.0/go.mod h1:iyeX1sEufmv3nPbBdX3ieNviWnOZaJ1+zquzJEf2BAQ= github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= -github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-stack/stack v1.8.1/go.mod h1:dcoOX6HbPZSZptuspn9bctJ+N/CnF5gGygcUP3XYfe4= -github.com/go-swagger/go-swagger v0.30.3 h1:HuzvdMRed/9Q8vmzVcfNBQByZVtT79DNZxZ18OprdoI= -github.com/go-swagger/go-swagger v0.30.3/go.mod h1:neDPes8r8PCz2JPvHRDj8BTULLh4VJUt7n6MpQqxhHM= -github.com/go-swagger/scan-repo-boundary v0.0.0-20180623220736-973b3573c013 h1:l9rI6sNaZgNC0LnF3MiE+qTmyBA/tZAg1rtyrGbUMK0= -github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= -github.com/gobuffalo/attrs v1.0.3/go.mod h1:KvDJCE0avbufqS0Bw3UV7RQynESY0jjod+572ctX4t8= -github.com/gobuffalo/buffalo v0.12.8-0.20181004233540-fac9bb505aa8/go.mod h1:sLyT7/dceRXJUxSsE813JTQtA3Eb1vjxWfo/N//vXIY= -github.com/gobuffalo/buffalo-plugins v1.0.2/go.mod h1:pOp/uF7X3IShFHyobahTkTLZaeUXwb0GrUTb9ngJWTs= -github.com/gobuffalo/buffalo-plugins v1.0.4/go.mod h1:pWS1vjtQ6uD17MVFWf7i3zfThrEKWlI5+PYLw/NaDB4= -github.com/gobuffalo/depgen v0.0.0-20190329151759-d478694a28d3/go.mod h1:3STtPUQYuzV0gBVOY3vy6CfMm/ljR4pABfrTeHNLHUY= -github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= -github.com/gobuffalo/envy v1.6.4/go.mod h1:Abh+Jfw475/NWtYMEt+hnJWRiC8INKWibIMyNt1w2Mc= -github.com/gobuffalo/envy v1.6.15/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-swagger/go-swagger v0.31.0 h1:H8eOYQnY2u7vNKWDNykv2xJP3pBhRG/R+SOCAmKrLlc= +github.com/go-swagger/go-swagger v0.31.0/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po= github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= -github.com/gobuffalo/events v1.0.3/go.mod h1:Txo8WmqScapa7zimEQIwgiJBvMECMe9gJjsKNPN3uZw= -github.com/gobuffalo/fizz v1.0.12/go.mod h1:C0sltPxpYK8Ftvf64kbsQa2yiCZY4RZviurNxXdAKwc= github.com/gobuffalo/fizz v1.14.4 h1:8uume7joF6niTNWN582IQ2jhGTUoa9g1fiV/tIoGdBs= github.com/gobuffalo/fizz v1.14.4/go.mod h1:9/2fGNXNeIFOXEEgTPJwiK63e44RjG+Nc4hfMm1ArGM= -github.com/gobuffalo/flect v0.0.0-20180907193754-dc14d8acaf9f/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= -github.com/gobuffalo/flect v0.0.0-20181002182613-4571df4b1daf/go.mod h1:rCiQgmAE4axgBNl3jZWzS5rETRYTGOsrixTRaCPzNdA= -github.com/gobuffalo/flect v0.1.0/go.mod h1:d2ehjJqGOH/Kjqcoz+F7jHTBbmDb38yXA598Hb50EGs= -github.com/gobuffalo/flect v0.1.1/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/flect v0.1.3/go.mod h1:8JCgGVbRjJhVgD6399mQr4fx5rRfGKVzFjbj6RE/9UI= -github.com/gobuffalo/flect v0.3.0 h1:erfPWM+K1rFNIQeRPdeEXxo8yFr/PO17lhRnS8FUrtk= github.com/gobuffalo/flect v0.3.0/go.mod h1:5pf3aGnsvqvCj50AVni7mJJF8ICxGZ8HomberC3pXLE= -github.com/gobuffalo/genny v0.0.0-20180924032338-7af3a40f2252/go.mod h1:tUTQOogrr7tAQnhajMSH6rv1BVev34H2sa1xNHMy94g= -github.com/gobuffalo/genny v0.0.0-20181003150629-3786a0744c5d/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= -github.com/gobuffalo/genny v0.0.0-20181005145118-318a41a134cc/go.mod h1:WAd8HmjMVrnkAZbmfgH5dLBUchsZfqzp/WS5sQz+uTM= -github.com/gobuffalo/genny v0.0.0-20190329151137-27723ad26ef9/go.mod h1:rWs4Z12d1Zbf19rlsn0nurr75KqhYp52EAGGxTbBhNk= -github.com/gobuffalo/genny v0.0.0-20190403191548-3ca520ef0d9e/go.mod h1:80lIj3kVJWwOrXWWMRzzdhW3DsrdjILVil/SFKBzF28= -github.com/gobuffalo/genny v0.1.0/go.mod h1:XidbUqzak3lHdS//TPu2OgiFB+51Ur5f7CSnXZ/JDvo= -github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= -github.com/gobuffalo/genny/v2 v2.1.0/go.mod h1:4yoTNk4bYuP3BMM6uQKYPvtP6WsXFGm2w2EFYZdRls8= -github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= -github.com/gobuffalo/github_flavored_markdown v1.0.4/go.mod h1:uRowCdK+q8d/RF0Kt3/DSalaIXbb0De/dmTqMQdkQ4I= -github.com/gobuffalo/github_flavored_markdown v1.0.5/go.mod h1:U0643QShPF+OF2tJvYNiYDLDGDuQmJZXsf/bHOJPsMY= -github.com/gobuffalo/github_flavored_markdown v1.1.3 h1:rSMPtx9ePkFB22vJ+dH+m/EUBS8doQ3S8LeEXcdwZHk= +github.com/gobuffalo/flect v1.0.2 h1:eqjPGSo2WmjgY2XlpGwo2NXgL3RucAKo4k4qQMNA5sA= +github.com/gobuffalo/flect v1.0.2/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= github.com/gobuffalo/github_flavored_markdown v1.1.3/go.mod h1:IzgO5xS6hqkDmUh91BW/+Qxo/qYnvfzoz3A7uLkg77I= -github.com/gobuffalo/gogen v0.0.0-20190315121717-8f38393713f5/go.mod h1:V9QVDIxsgKNZs6L2IYiGR8datgMhB577vzTDqypH360= -github.com/gobuffalo/gogen v0.1.0/go.mod h1:8NTelM5qd8RZ15VjQTFkAW6qOMx5wBbW4dSCS3BY8gg= -github.com/gobuffalo/gogen v0.1.1/go.mod h1:y8iBtmHmGc4qa3urIyo1shvOD8JftTtfcKi+71xfDNE= +github.com/gobuffalo/github_flavored_markdown v1.1.4 h1:WacrEGPXUDX+BpU1GM/Y0ADgMzESKNWls9hOTG1MHVs= +github.com/gobuffalo/github_flavored_markdown v1.1.4/go.mod h1:Vl9686qrVVQou4GrHRK/KOG3jCZOKLUqV8MMOAYtlso= github.com/gobuffalo/helpers v0.6.7 h1:C9CedoRSfgWg2ZoIkVXgjI5kgmSpL34Z3qdnzpfNVd8= github.com/gobuffalo/helpers v0.6.7/go.mod h1:j0u1iC1VqlCaJEEVkZN8Ia3TEzfj/zoXANqyJExTMTA= -github.com/gobuffalo/here v0.6.7 h1:hpfhh+kt2y9JLDfhYUxxCRxQol540jsVfKUZzjlbp8o= github.com/gobuffalo/httptest v1.5.2 h1:GpGy520SfY1QEmyPvaqmznTpG4gEQqQ82HtHqyNEreM= -github.com/gobuffalo/licenser v0.0.0-20180924033006-eae28e638a42/go.mod h1:Ubo90Np8gpsSZqNScZZkVXXAo5DGhTb+WYFIjlnog8w= -github.com/gobuffalo/logger v0.0.0-20190315122211-86e12af44bc2/go.mod h1:QdxcLw541hSGtBnhUc4gaNIXRjiDppFGaDqzbrBd3v8= -github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= -github.com/gobuffalo/logger v1.0.7/go.mod h1:u40u6Bq3VVvaMcy5sRBclD8SXhBYPS0Qk95ubt+1xJM= -github.com/gobuffalo/makr v1.1.5/go.mod h1:Y+o0btAH1kYAMDJW/TX3+oAXEu0bmSLLoC9mIFxtzOw= -github.com/gobuffalo/mapi v1.0.0/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.1/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= -github.com/gobuffalo/mapi v1.0.2/go.mod h1:4VAGh89y6rVOvm5A8fKFxYG+wIW6LO1FMTG9hnKStFc= +github.com/gobuffalo/httptest v1.5.2/go.mod h1:FA23yjsWLGj92mVV74Qtc8eqluc11VqcWr8/C1vxt4g= github.com/gobuffalo/nulls v0.4.2 h1:GAqBR29R3oPY+WCC7JL9KKk9erchaNuV6unsOSZGQkw= github.com/gobuffalo/nulls v0.4.2/go.mod h1:EElw2zmBYafU2R9W4Ii1ByIj177wA/pc0JdjtD0EsH8= -github.com/gobuffalo/packd v0.0.0-20190315124812-a385830c7fc0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v0.1.0/go.mod h1:M2Juc+hhDXf/PnmBANFCqx4DM3wRbgDvnVWeG2RIxq4= -github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= -github.com/gobuffalo/packd v1.0.2/go.mod h1:sUc61tDqGMXON80zpKGp92lDb86Km28jfvX7IAyxFT8= -github.com/gobuffalo/packr v1.30.1/go.mod h1:ljMyFO2EcrnzsHsN99cvbq055Y9OhRrIaviy289eRuk= -github.com/gobuffalo/packr/v2 v2.0.9/go.mod h1:emmyGweYTm6Kdper+iywB6YK5YzuKchGtJQZ0Odn4pQ= -github.com/gobuffalo/packr/v2 v2.2.0/go.mod h1:CaAwI0GPIAv+5wKLtv8Afwl+Cm78K/I/VCm/3ptBN+0= -github.com/gobuffalo/packr/v2 v2.5.1/go.mod h1:8f9c96ITobJlPzI44jj+4tHnEKNt0xXWSVlXRN9X1Iw= -github.com/gobuffalo/plush v3.7.16+incompatible/go.mod h1:rQ4zdtUUyZNqULlc6bqd5scsPfLKfT0+TGMChgduDvI= -github.com/gobuffalo/plush/v4 v4.1.16 h1:Y6jVVTLdg1BxRXDIbTJz+J8QRzEAtv5ZwYpGdIFR7VU= github.com/gobuffalo/plush/v4 v4.1.16/go.mod h1:6t7swVsarJ8qSLw1qyAH/KbrcSTwdun2ASEQkOznakg= -github.com/gobuffalo/pop v4.8.2+incompatible/go.mod h1:DwBz3SD5SsHpTZiTubcsFWcVDpJWGsxjVjMPnkiThWg= -github.com/gobuffalo/pop/v6 v6.0.8 h1:9+5ShHYh3x9NDFCITfm/gtKDDRSgOwiY7kA0Hf7N9aQ= -github.com/gobuffalo/pop/v6 v6.0.8/go.mod h1:f4JQ4Zvkffcevz+t+XAwBLStD7IQs19DiIGIDFYw1eA= -github.com/gobuffalo/release v1.0.35/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= -github.com/gobuffalo/release v1.0.38/go.mod h1:VtHFAKs61vO3wboCec5xr9JPTjYyWYcvaM3lclkc4x4= -github.com/gobuffalo/shoulders v1.0.1/go.mod h1:V33CcVmaQ4gRUmHKwq1fiTXuf8Gp/qjQBUL5tHPmvbA= -github.com/gobuffalo/syncx v0.0.0-20190224160051-33c29581e754/go.mod h1:HhnNqWY95UYwwW3uSASeV7vtgYkT2t16hJgV3AEPUpw= -github.com/gobuffalo/tags v2.0.11+incompatible/go.mod h1:9XmhOkyaB7UzvuY4UoZO4s67q8/xRMVJEaakauVQYeY= +github.com/gobuffalo/plush/v4 v4.1.21 h1:YVfauGshxyQ+beh4jHR6Ct3NEXohn+1EboMjzdUDo30= +github.com/gobuffalo/plush/v4 v4.1.21/go.mod h1:WiKHJx3qBvfaDVlrv8zT7NCd3dEMaVR/fVxW4wqV17M= github.com/gobuffalo/tags/v3 v3.1.4 h1:X/ydLLPhgXV4h04Hp2xlbI2oc5MDaa7eub6zw8oHjsM= github.com/gobuffalo/tags/v3 v3.1.4/go.mod h1:ArRNo3ErlHO8BtdA0REaZxijuWnWzF6PUXngmMXd2I0= -github.com/gobuffalo/uuid v2.0.3+incompatible/go.mod h1:ErhIzkRhm0FtRuiE/PeORqcw4cVi1RtSpnwYrxuvkfE= -github.com/gobuffalo/validate v2.0.3+incompatible/go.mod h1:N+EtDe0J8252BgfzQUChBgfd6L93m9weay53EWFVsMM= github.com/gobuffalo/validate/v3 v3.3.3 h1:o7wkIGSvZBYBd6ChQoLxkz2y1pfmhbI4jNJYh6PuNJ4= github.com/gobuffalo/validate/v3 v3.3.3/go.mod h1:YC7FsbJ/9hW/VjQdmXPvFqvRis4vrRYFxr69WiNZw6g= -github.com/gobuffalo/x v0.0.0-20181003152136-452098b06085/go.mod h1:WevpGD+5YOreDJznWevcn8NTmQEW5STSBgIkpkjzqXc= -github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7 h1:N0iqtKwkicU8M2rLirTDJxdwuL8I2/8MjMlEayaNSgE= -github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdKWzMc4odGQQdG2e2DIEmANy5aSJ9yesY= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= -github.com/goccy/go-yaml v1.9.6 h1:KhAu1zf9JXnm3vbG49aDE0E5uEBUsM4uwD31/58ZWyI= -github.com/goccy/go-yaml v1.9.6/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= -github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= +github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= +github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= +github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.3.0+incompatible h1:CaSVZxm5B+7o45rtab4jC2G37WGYX1zQfuU2i6DSvnc= -github.com/gofrs/uuid v4.3.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ= -github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4= -github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= -github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= -github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= -github.com/google/pprof v0.0.0-20221010195024-131d412537ea h1:R3VfsTXMMK4JCWZDdxScmnTzu9n9YRsDvguLis0U/b8= -github.com/google/pprof v0.0.0-20221010195024-131d412537ea/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/pprof v0.0.0-20230808223545-4887780b67fb h1:oqpb3Cwpc7EOml5PVGMYbSGmwNui2R7i8IW83gs4W0c= +github.com/google/pprof v0.0.0-20230808223545-4887780b67fb/go.mod h1:Jh3hGz2jkYak8qXPD19ryItVnUgpgeqzdkY/D0EaeuA= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= -github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= -github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= -github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= -github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4= -github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.1.2/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= -github.com/gorilla/sessions v1.1.3/go.mod h1:8KCfur6+4Mqcc6S0FEfKuN15Vl5MgXW92AE8ovaJD0w= -github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI= -github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= +github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= +github.com/gorilla/handlers v1.5.2 h1:cLTUSsNkgcwhgRqvCNmdbRWG0A3N4F+M2nWKdScwyEE= +github.com/gorilla/handlers v1.5.2/go.mod h1:dX+xVpaxdSw+q0Qek8SSsl3dfMk3jNddUkMzo0GtH0w= +github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= +github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= +github.com/gorilla/sessions v1.3.0 h1:XYlkq7KcpOB2ZhHBPv5WpjMIxrQosiZanfoy1HLZFzg= +github.com/gorilla/sessions v1.3.0/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= +github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= -github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= -github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0 h1:kr3j8iIMR4ywO/O0rvksXaJvauGGCMg2zAZIiNZ9uIQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.12.0/go.mod h1:ummNFgdgLhhX7aIiy35vVmQNS0rWXknfPE0qe6fmFXg= -github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69 h1:7xsUJsB2NrdcttQPa7JLEaGzvdbk7KvfrjgHZXOQRo0= -github.com/gtank/cryptopasta v0.0.0-20170601214702-1f550f6f2f69/go.mod h1:YLEMZOtU+AZ7dhN9T/IpGhXVGly2bvkJQ+zxj3WeVQo= -github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q= -github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ= -github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8= -github.com/hashicorp/consul/sdk v0.8.0/go.mod h1:GBvyrGALthsZObzUGsfgHZQDXjg4lOjagTIwIR1vPms= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0 h1:ad0vkEBuk23VJzZR9nkLVG0YAoN9coASF1GusYX6AlU= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.23.0/go.mod h1:igFoXX2ELCW06bol23DWPB5BEWfZISOzSP5K2sbLea0= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= -github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= -github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM= -github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= -github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= -github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= -github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= -github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY= -github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= -github.com/hashicorp/go-retryablehttp v0.6.8/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ= -github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= -github.com/hashicorp/go-rootcerts v1.0.1/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= -github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= -github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjGlgmH/UkBUC97A= -github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= -github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= -github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= -github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= -github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= -github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= -github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= -github.com/hashicorp/memberlist v0.3.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= -github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= -github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= -github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q= -github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M= -github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= -github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs= -github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.3.2 h1:L18LIDzqlW6xN2rEkpdV8+oL/IXWJ1APd+vsdYy4Wdw= -github.com/huandu/xstrings v1.3.2/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= +github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= +github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= +github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= -github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk= -github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= -github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s= github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4= -github.com/instana/go-sensor v1.46.0 h1:Qx2VgTPZHzRgKSMAlH0Gm8nb/y7BfsUGuRst9XsM17Y= -github.com/instana/go-sensor v1.46.0/go.mod h1:E42MelHWFz11qqaLwvgt0j98v2s2O/bq22UDkGaG0Gg= -github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65 h1:T25FL3WEzgmKB0m6XCJNZ65nw09/QIp3T1yXr487D+A= -github.com/instana/testify v1.6.2-0.20200721153833-94b1851f4d65/go.mod h1:nYhEREG/B7HUY7P+LKOrqy53TpIqmJ9JyUShcaEKtGw= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.12.0/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= -github.com/jackc/pgconn v1.12.1/go.mod h1:ZkhRC59Llhrq3oSfrikvwQ5NaxYExr6twkdkMLaKono= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= +github.com/jackc/pgconn v1.14.3 h1:bVoTr12EGANZz66nZPkMInAV/KHD2TxH9npjXXgiB3w= +github.com/jackc/pgconn v1.14.3/go.mod h1:RZbme4uasqzybK2RK5c65VsHxoyaml09lx3tXOcO/VM= github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.0/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.11.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx v3.2.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.16.0/go.mod h1:N0A9sFdWzkw/Jy1lwoiB64F2+ugFZi987zRxcPez/wI= -github.com/jackc/pgx/v4 v4.16.1/go.mod h1:SIhx0D5hoADaiXZVyv+3gSm3LCIIINTVO0PficsvWGQ= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.2.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jandelgado/gcov2lcov v1.0.4/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= +github.com/jackc/pgproto3/v2 v2.3.3 h1:1HLSx5H+tXR9pW3in3zaztoEwQYRC9SQaYUHjTSUOag= +github.com/jackc/pgproto3/v2 v2.3.3/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgtype v1.14.0 h1:y+xUdabmyMkJLyApYuPj38mW+aAIqCe5uuBB51rH3Vw= +github.com/jackc/pgtype v1.14.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= +github.com/jackc/pgx/v4 v4.18.2 h1:xVpYkNR5pk5bMCZGfClbO962UIqVABcAGt7ha1s/FeU= +github.com/jackc/pgx/v4 v4.18.2/go.mod h1:Ey4Oru5tH5sB6tV7hDmfWFahwF15Eb7DNXlRKx2CkVw= +github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY= +github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw= +github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= +github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jandelgado/gcov2lcov v1.0.5 h1:rkBt40h0CVK4oCb8Dps950gvfd1rYvQ8+cWa346lVU0= github.com/jandelgado/gcov2lcov v1.0.5/go.mod h1:NnSxK6TMlg1oGDBfGelGbjgorT5/L3cchlbtgFYZSss= -github.com/jcchavezs/porto v0.1.0/go.mod h1:fESH0gzDHiutHRdX2hv27ojnOVFco37hg1W6E9EZF4A= -github.com/jcchavezs/porto v0.4.0 h1:Zj7RligrxmDdKGo6fBO2xYAHxEgrVBfs1YAja20WbV4= -github.com/jcchavezs/porto v0.4.0/go.mod h1:fESH0gzDHiutHRdX2hv27ojnOVFco37hg1W6E9EZF4A= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= -github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.4/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= -github.com/jmoiron/sqlx v0.0.0-20180614180643-0dae4fefe7c0/go.mod h1:IiEW3SEiiErVyFdH8NTuWjSifiEQKUoyK3LNqr2kCHU= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= +github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8= +github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 h1:rp+c0RAYOWj8l6qbCUTSiRLG/iKnW3K3/QfPPuSsBt4= -github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= -github.com/joho/godotenv v1.2.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/joho/godotenv v1.4.0/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= -github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= -github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= -github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaRPx4tDPEn4= -github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/knadh/koanf v1.4.4 h1:d2jY5nCCeoaiqvEKSBW9rEc93EfNy/XWgWsSB3j7JEA= -github.com/knadh/koanf v1.4.4/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs= -github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/knadh/koanf/maps v0.1.1 h1:G5TjmUh2D7G2YWf5SQQqSiHRJEjaicvU0KpypqB3NIs= +github.com/knadh/koanf/maps v0.1.1/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI= +github.com/knadh/koanf/parsers/json v0.1.0 h1:dzSZl5pf5bBcW0Acnu20Djleto19T0CfHcvZ14NJ6fU= +github.com/knadh/koanf/parsers/json v0.1.0/go.mod h1:ll2/MlXcZ2BfXD6YJcjVFzhG9P0TdJ207aIBKQhV2hY= +github.com/knadh/koanf/parsers/toml v0.1.0 h1:S2hLqS4TgWZYj4/7mI5m1CQQcWurxUz6ODgOub/6LCI= +github.com/knadh/koanf/parsers/toml v0.1.0/go.mod h1:yUprhq6eo3GbyVXFFMdbfZSo928ksS+uo0FFqNMnO18= +github.com/knadh/koanf/parsers/yaml v0.1.0 h1:ZZ8/iGfRLvKSaMEECEBPM1HQslrZADk8fP1XFUxVI5w= +github.com/knadh/koanf/parsers/yaml v0.1.0/go.mod h1:cvbUDC7AL23pImuQP0oRw/hPuccrNBS2bps8asS0CwY= +github.com/knadh/koanf/providers/posflag v0.1.0 h1:mKJlLrKPcAP7Ootf4pBZWJ6J+4wHYujwipe7Ie3qW6U= +github.com/knadh/koanf/providers/posflag v0.1.0/go.mod h1:SYg03v/t8ISBNrMBRMlojH8OsKowbkXV7giIbBVgbz0= +github.com/knadh/koanf/providers/rawbytes v0.1.0 h1:dpzgu2KO6uf6oCb4aP05KDmKmAmI51k5pe8RYKQ0qME= +github.com/knadh/koanf/providers/rawbytes v0.1.0/go.mod h1:mMTB1/IcJ/yE++A2iEZbY1MLygX7vttU+C+S/YmPu9c= +github.com/knadh/koanf/v2 v2.0.1 h1:1dYGITt1I23x8cfx8ZnldtezdyaZtfAuRtIFOiRzK7g= +github.com/knadh/koanf/v2 v2.0.1/go.mod h1:ZeiIlIDXTE7w1lMT6UVcNiRAS2/rCeLn/GdLNvY1Dus= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/laher/mergefs v0.1.1 h1:nV2bTS57vrmbMxeR6uvJpI8LyGl3QHj4bLBZO3aUV58= +github.com/laher/mergefs v0.1.1/go.mod h1:FSY1hYy94on4Tz60waRMGdO1awwS23BacqJlqf9lJ9Q= github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.6/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw= -github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/looplab/fsm v0.1.0/go.mod h1:m2VaOfDHxqXBBMgc26m6yUOwkFn8H2AlJDE+jd/uafI= -github.com/looplab/fsm v0.3.0 h1:kIgNS3Yyud1tyxhG8kDqh853B7QqwnlWdgL3TD2s3Sw= -github.com/looplab/fsm v0.3.0/go.mod h1:PmD3fFvQEIsjMEfvZdrCDZ6y8VwKTwWNjlpEr6IKPO4= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/luna-duclos/instrumentedsql v1.1.3 h1:t7mvC0z1jUt5A0UQ6I/0H31ryymuQRnJcWCiqV3lSAA= github.com/luna-duclos/instrumentedsql v1.1.3/go.mod h1:9J1njvFds+zN7y85EDhN9XNQLANWwZt2ULeIC8yMNYs= -github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/magiconair/properties v1.8.4/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= -github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= -github.com/markbates/deplist v1.0.5/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM= -github.com/markbates/going v1.0.2/go.mod h1:UWCk3zm0UKefHZ7l8BNqi26UyiEMniznk8naLdTcy6c= -github.com/markbates/grift v1.0.4/go.mod h1:wbmtW74veyx+cgfwFhlnnMWqhoz55rnHR47oMXzsyVs= -github.com/markbates/hmax v1.0.0/go.mod h1:cOkR9dktiESxIMu+65oc/r/bdY4bE8zZw3OLhLx0X2c= -github.com/markbates/inflect v1.0.0/go.mod h1:oTeZL2KHA7CUX6X+fovmK9OvIOFuqu0TwdQrZjLTh88= -github.com/markbates/inflect v1.0.1/go.mod h1:uv3UVNBe5qBIfCm8O8Q+DW+S1EopeyINj+Ikhc7rnCk= -github.com/markbates/oncer v0.0.0-20180924031910-e862a676800b/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/oncer v0.0.0-20180924034138-723ad0170a46/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= -github.com/markbates/pkger v0.17.1 h1:/MKEtWqtc0mZvu9OinB9UzVN9iYCwLWuyUv4Bw+PCno= -github.com/markbates/refresh v1.4.10/go.mod h1:NDPHvotuZmTmesXxr95C9bjlw1/0frJwtME2dzcVKhc= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/markbates/sigtx v1.0.0/go.mod h1:QF1Hv6Ic6Ca6W+T+DL0Y/ypborFKyvUY9HmuCD4VeTc= -github.com/markbates/willie v1.0.9/go.mod h1:fsrFVWl91+gXpx/6dv715j7i11fYPfZ9ZGfH0DQzY7w= -github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= -github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94= -github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= -github.com/mattn/go-sqlite3 v1.14.13 h1:1tj15ngiFfcZzii7yd82foL+ks+ouQcj8j/TPq3fk1I= -github.com/mattn/go-sqlite3 v1.14.13/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= -github.com/mattn/goveralls v0.0.11 h1:eJXea6R6IFlL1QMKNMzDvvHv/hwGrnvyig4N+0+XiMM= -github.com/mattn/goveralls v0.0.11/go.mod h1:gU8SyhNswsJKchEV93xRQxX6X3Ei4PJdQk/6ZHvrvRk= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= -github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= -github.com/microcosm-cc/bluemonday v1.0.1/go.mod h1:hsXNsILzKxV+sX77C5b8FSuKF00vh2OMYv+xgHpAMF4= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= +github.com/mattn/goveralls v0.0.12 h1:PEEeF0k1SsTjOBQ8FOmrOAoCu4ytuMaWCnWe94zxbCg= +github.com/mattn/goveralls v0.0.12/go.mod h1:44ImGEUfmqH8bBtaMrYKsM65LXfNLWmwaxFGjZwgMSQ= github.com/microcosm-cc/bluemonday v1.0.20/go.mod h1:yfBmMi8mxvaZut3Yytv+jTXRY8mxyjJ0/kQBTElld50= -github.com/microcosm-cc/bluemonday v1.0.21 h1:dNH3e4PSyE4vNX+KlRGHT5KrSvjeUkoNPwEORjffHJg= -github.com/microcosm-cc/bluemonday v1.0.21/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= -github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= -github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= -github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= +github.com/microcosm-cc/bluemonday v1.0.22/go.mod h1:ytNkv4RrDrLJ2pqlsSI46O6IVXmZOBBD4SaJyDwwTkM= +github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= +github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/miekg/pkcs11 v1.0.3 h1:iMwmD7I5225wv84WxIG/bmxz9AXjWvTWIbM/TYHvWtw= -github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mikefarah/yq/v4 v4.16.1 h1:Xeu/LdePmqceqcmZoG3caOLA79LJj0RvGpSjUfHaqK8= -github.com/mikefarah/yq/v4 v4.16.1/go.mod h1:mfI3lycn5DjU6N4kfpiR4S7ylu0xZj9XgKSooXYis3g= -github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= -github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= +github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= +github.com/mikefarah/yq/v4 v4.44.2 h1:J+ezWCDTg+SUs0jXdcE0HIPH1+rEr0Tbn9Y1SwiWtH0= +github.com/mikefarah/yq/v4 v4.44.2/go.mod h1:9bnz36uZJDEyxdIjRronBcqStS953k3y3DrSRXr4F/w= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= -github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= -github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= -github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= -github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg= -github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY= -github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.0.0/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= -github.com/mitchellh/mapstructure v1.3.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= -github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= -github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= -github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGEJq24YyJ2ban8EO0RUVSJlF1pGsEvoLEACr/Q= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= -github.com/nyaruka/phonenumbers v1.0.73/go.mod h1:3aiS+PS3DuYwkbK3xdcmRwMiPNECZ0oENH8qUT1lY7Q= -github.com/nyaruka/phonenumbers v1.1.1 h1:fyoZmpLN2VCmAnc51XcrNOUVP2wT1ZzQl348ggIaXII= -github.com/nyaruka/phonenumbers v1.1.1/go.mod h1:cGaEsOrLjIL0iKGqJR5Rfywy86dSkbApEpXuM9KySNA= -github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/nyaruka/phonenumbers v1.1.7 h1:5UUI9hE79Kk0dymSquXbMYB7IlNDNhvu2aNlJpm9et8= +github.com/nyaruka/phonenumbers v1.1.7/go.mod h1:DC7jZd321FqUe+qWSNcHi10tyIyGNXGcNbfkPvdp1Vs= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oleiade/reflections v1.0.1 h1:D1XO3LVEYroYskEsoSiGItp9RUxG6jWnCVvrqH0HHQM= github.com/oleiade/reflections v1.0.1/go.mod h1:rdFxbxq4QXVZWj0F+e9jqjDkc7dbp97vkRixKo2JR60= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= -github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0-rc2 h1:2zx/Stx4Wc5pIPDvIxHXvXtQFW/7XWJGmnM7r3wg034= -github.com/opencontainers/image-spec v1.1.0-rc2/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ= -github.com/opencontainers/runc v1.1.4 h1:nRCz/8sKg6K6jgYAFLDlXzPeITBZJyX28DBVhWD+5dg= -github.com/opencontainers/runc v1.1.4/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= -github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492 h1:lM6RxxfUMrYL/f8bWEUqdXrANWtrL7Nndbm9iFN0DlU= -github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= -github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0 h1:uhcF5Jd7rP9DVEL10Siffyepr6SvlKbUsjH5JpNCRi8= -github.com/openzipkin-contrib/zipkin-go-opentracing v0.5.0/go.mod h1:+oCZ5GXXr7KPI/DNOQORPTq5AWHfALJj9c72b0+YsEY= -github.com/openzipkin/zipkin-go v0.4.1 h1:kNd/ST2yLLWhaWrkgchya40TJabe8Hioj9udfPcEO5A= -github.com/openzipkin/zipkin-go v0.4.1/go.mod h1:qY0VqDSN1pOBN94dBc6w2GJlWLiovAyg7Qt6/I9HecM= -github.com/ory/analytics-go/v4 v4.0.3 h1:2zNBQLlm3UiD8U7DdUGLLUBm62ZA5GtbEJ3S5U+xEOI= -github.com/ory/analytics-go/v4 v4.0.3/go.mod h1:A3Chm/3TmM8jw4nqRss+gFhAYHRI5j/HFYH3C1FRahU= -github.com/ory/dockertest/v3 v3.9.1 h1:v4dkG+dlu76goxMiTT2j8zV7s4oPPEppKT8K8p2f1kY= -github.com/ory/dockertest/v3 v3.9.1/go.mod h1:42Ir9hmvaAPm0Mgibk6mBPi7SFvTXxEcnztDYOJ//uM= -github.com/ory/fosite v0.44.0 h1:Z3UjyO11/wlIoa3BotOqcTkfm7kUNA8F7dd8mOMfx0o= -github.com/ory/fosite v0.44.0/go.mod h1:o/G4kAeNn65l6MCod2+KmFfU6JQBSojS7eXys6lKGzM= -github.com/ory/go-acc v0.2.6/go.mod h1:4Kb/UnPcT8qRAk3IAxta+hvVapdxTLWtrr7bFLlEgpw= -github.com/ory/go-acc v0.2.8 h1:rOHHAPQjf0u7eHFGWpiXK+gIu/e0GRSJNr9pDukdNC4= -github.com/ory/go-acc v0.2.8/go.mod h1:iCRZUdGb/7nqvSn8xWZkhfVrtXRZ9Wru2E5rabCjFPI= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/runc v1.1.14 h1:rgSuzbmgz5DUJjeSnw337TxDbRuqjs6iqQck/2weR6w= +github.com/opencontainers/runc v1.1.14/go.mod h1:E4C2z+7BxR7GHXp0hAY53mek+x49X1LjPNeMTfRGvOA= +github.com/openzipkin/zipkin-go v0.4.3 h1:9EGwpqkgnwdEIJ+Od7QVSEIH+ocmm5nPat0G7sjsSdg= +github.com/openzipkin/zipkin-go v0.4.3/go.mod h1:M9wCJZFWCo2RiY+o1eBCEMe0Dp2S5LDHcMZmk3RmK7c= +github.com/ory/analytics-go/v5 v5.0.1 h1:LX8T5B9FN8KZXOtxgN+R3I4THRRVB6+28IKgKBpXmAM= +github.com/ory/analytics-go/v5 v5.0.1/go.mod h1:lWCiCjAaJkKfgR/BN5DCLMol8BjKS1x+4jxBxff/FF0= +github.com/ory/dockertest/v3 v3.10.1-0.20240704115616-d229e74b748d h1:By96ZSVuH5LyjXLVVMfvJoLVGHaT96LdOnwgFSLVf0E= +github.com/ory/dockertest/v3 v3.10.1-0.20240704115616-d229e74b748d/go.mod h1:F2FIjwwAk6CsNAs//B8+aPFQF0t84pbM8oliyNXwQrk= +github.com/ory/fosite v0.48.0 h1:zxNPNrCBsFwujviVPhbHZzSHZNzjBFZ36MeBFz6tCuU= +github.com/ory/fosite v0.48.0/go.mod h1:M+C+Ng1UDNgwX4SaErnuZwEw26uDN7I3kNUt0WyValI= +github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe h1:rvu4obdvqR0fkSIJ8IfgzKOWwZ5kOT2UNfLq81Qk7rc= +github.com/ory/go-acc v0.2.9-0.20230103102148-6b1c9a70dbbe/go.mod h1:z4n3u6as84LbV4YmgjHhnwtccQqzf4cZlSk9f1FhygI= github.com/ory/go-convenience v0.1.0 h1:zouLKfF2GoSGnJwGq+PE/nJAE6dj2Zj5QlTgmMTsTS8= github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs= -github.com/ory/graceful v0.1.1 h1:zx+8tDObLPrG+7Tc8jKYlXsqWnLtOQA1IZ/FAAKHMXU= -github.com/ory/graceful v0.1.1/go.mod h1:zqu70l95WrKHF4AZ6tXHvAqAvpY6M7g6ttaAVcMm7KU= -github.com/ory/herodot v0.9.13 h1:cN/Z4eOkErl/9W7hDIDLb79IO/bfsH+8yscBjRpB4IU= -github.com/ory/herodot v0.9.13/go.mod h1:IWDs9kSvFQqw/cQ8zi5ksyYvITiUU4dI7glUrhZcJYo= -github.com/ory/jsonschema/v3 v3.0.7 h1:GQ9qfZDiJqs4l2d3p56dozCChvejQFZyLKGHYzDzOSo= -github.com/ory/jsonschema/v3 v3.0.7/go.mod h1:g8c8YOtN4TrR2wYeMdT02GDmzJDI0fEW2nI26BECafY= -github.com/ory/viper v1.7.5 h1:+xVdq7SU3e1vNaCsk/ixsfxE4zylk1TJUiJrY647jUE= -github.com/ory/viper v1.7.5/go.mod h1:ypOuyJmEUb3oENywQZRgeAMwqgOyDqwboO1tj3DjTaM= -github.com/ory/x v0.0.514 h1:QCRqmZbsqRTMIMA+mR1qjjpStdEeVGTXI0jMO0iTfVw= -github.com/ory/x v0.0.514/go.mod h1:xUtRpoiRARyJNPVk/fcCNKzyp25Foxt9GPlj8pd7egY= -github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= -github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= +github.com/ory/graceful v0.1.3 h1:FaeXcHZh168WzS+bqruqWEw/HgXWLdNv2nJ+fbhxbhc= +github.com/ory/graceful v0.1.3/go.mod h1:4zFz687IAF7oNHHiB586U4iL+/4aV09o/PYLE34t2bA= +github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88 h1:J0CIFKdpUeqKbVMw7pQ1qLtUnflRM1JWAcOEq7Hp4yg= +github.com/ory/herodot v0.10.3-0.20230626083119-d7e5192f0d88/go.mod h1:MMNmY6MG1uB6fnXYFaHoqdV23DTWctlPsmRCeq/2+wc= +github.com/ory/jsonschema/v3 v3.0.8 h1:Ssdb3eJ4lDZ/+XnGkvQS/te0p+EkolqwTsDOCxr/FmU= +github.com/ory/jsonschema/v3 v3.0.8/go.mod h1:ZPzqjDkwd3QTnb2Z6PAS+OTvBE2x5i6m25wCGx54W/0= +github.com/ory/kratos-client-go v1.2.1 h1:Q3T/adfAfAkHFcV1LGLnwz4QkY6ghBdX9zde5T8uO/4= +github.com/ory/kratos-client-go v1.2.1/go.mod h1:WiQYlrqW4Atj6Js7oDN5ArbZxo0nTO2u/e1XaDv2yMI= +github.com/ory/pop/v6 v6.2.1-0.20241121111754-e5dfc0f3344b h1:BIzoOe2/wynZBQak1po0tzgvARseIKsR2bF6b+SZoKE= +github.com/ory/pop/v6 v6.2.1-0.20241121111754-e5dfc0f3344b/go.mod h1:okVAYKGtgunD/wbW3NGhZTndJCS+6FqO+cA89rQ4doc= +github.com/ory/x v0.0.675 h1:K6GpVo99BXBFv2UiwMjySNNNqCFKGswynrt7vWQJFU8= +github.com/ory/x v0.0.675/go.mod h1:zJmnDtKje2FCP4EeFvRsKk94XXiqKCSGJMZcirAfhUs= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= -github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= -github.com/pelletier/go-toml v1.8.0/go.mod h1:D6yutnOGMveHEPV7VQOuvI/gXY61bv+9bAOTRnLElKs= -github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= -github.com/pelletier/go-toml/v2 v2.0.1 h1:8e3L2cCQzLFi2CR4g7vGFuFxX7Jl1kKX8gW+iV0GUKU= -github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo= +github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= +github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc= github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= -github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ= -github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA= github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo= -github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= -github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI= -github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= -github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= -github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= -github.com/prometheus/client_golang v1.11.0/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.11.1/go.mod h1:Z6t4BnS23TR94PD6BsDNk8yVqroYurpAkEiz0P2BEV0= -github.com/prometheus/client_golang v1.12.1/go.mod h1:3Z9XVyYiZYEO+YQWt3RD2R3jrbd179Rt297l4aS6nDY= -github.com/prometheus/client_golang v1.13.0 h1:b71QUfeo5M8gq2+evJdTPfZhYMAU0uKPkyPJ7TPsloU= -github.com/prometheus/client_golang v1.13.0/go.mod h1:vTeo+zgvILHsnnj/39Ou/1fPN5nJFOEMgftOUOmlvYQ= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= -github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= -github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= -github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= -github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= -github.com/prometheus/common v0.37.0 h1:ccBbHCgIiT9uSoFY0vX8H3zsNR5eLt17/RQLUvn8pXE= -github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190425082905-87a4384529e0/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= -github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= -github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= -github.com/prometheus/procfs v0.8.0 h1:ODq8ZFEaYeCaZOJlZZdJA2AbQR98dSHSM1KW/You5mo= -github.com/prometheus/procfs v0.8.0/go.mod h1:z7EfXMXOkbkqb9IINtpCn86r/to3BnA0uaxHdg830/4= -github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= -github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA= -github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U= +github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= +github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw= +github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI= +github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE= +github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc= +github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo= +github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo= github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= -github.com/rs/cors v1.8.2 h1:KCooALfAYGs415Cwu5ABvv9n9509fSiG5SQJn/AQo4U= -github.com/rs/cors v1.8.2/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= -github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= +github.com/rs/cors v1.11.0 h1:0B9GE/r9Bc2UxRMMtymBkHTenPkHDv0CW4Y98GBY+po= +github.com/rs/cors v1.11.0/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= -github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= -github.com/santhosh-tekuri/jsonschema v1.2.4 h1:hNhW8e7t+H1vgY+1QeEQpveR6D4+OwKPXCfD2aieJis= -github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= -github.com/sawadashota/encrypta v0.0.2 h1:R46/RxYmYdxI3VOt63B637OVBHzu+fazPyLo5CqK6QE= -github.com/sawadashota/encrypta v0.0.2/go.mod h1:pcPebEvF012kXmZXvfVzwFEr/GUE/ZntaR805jk0nsE= -github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sawadashota/encrypta v0.0.5 h1:boMQmISmg62WEgU5AMu3WDLhi5TAP2iidYP+AxgxMJM= +github.com/sawadashota/encrypta v0.0.5/go.mod h1:jeRi1jWo+bQoBVwXLPhuArSZTA6TOqXj/+wqnFiScik= github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761 h1:0b8DF5kR0PhRoRXDiEEdzrgBc8UqVY4JWLkQJCRsLME= github.com/seatgeek/logrus-gelf-formatter v0.0.0-20210414080842-5b05eb8ff761/go.mod h1:/THDZYi7F/BsVEcYzYPqdcWFQ+1C2InkawTKfLOAnzg= -github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/segmentio/analytics-go v3.1.0+incompatible/go.mod h1:C7CYBtQWk4vRk2RyLu0qOcbHJ18E3F1HV2C/8JvKN48= github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/fNVxRNWfBc= github.com/segmentio/backo-go v1.0.1 h1:68RQccglxZeyURy93ASB/2kc9QudzgIDexJ927N++y4= @@ -973,80 +446,37 @@ github.com/segmentio/backo-go v1.0.1/go.mod h1:9/Rh6yILuLysoQnZ2oNooD2g7aBnvM7r/ github.com/segmentio/conf v1.2.0/go.mod h1:Y3B9O/PqqWqjyxyWWseyj/quPEtMu1zDp/kVbSWWaB0= github.com/segmentio/go-snakecase v1.1.0/go.mod h1:jk1miR5MS7Na32PZUykG89Arm+1BUSYhuGR6b7+hJto= github.com/segmentio/objconv v1.0.1/go.mod h1:auayaH5k3137Cl4SoXTgrzQcuQDmvuVtZgS0fb1Ahys= -github.com/serenize/snaker v0.0.0-20171204205717-a683aaf2d516/go.mod h1:Yow6lPLSAXx2ifx470yD/nUe22Dv5vBvxK/UK9UUTVs= -github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= -github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shurcooL/go v0.0.0-20180423040247-9e1955d9fb6e/go.mod h1:TDJrrUr11Vxrven61rcy3hJMUqaf/CLWYhHNPmT14Lk= -github.com/shurcooL/go-goon v0.0.0-20170922171312-37c2f522c041/go.mod h1:N5mDOmsrJOB+vfqUK+7DmDyjhSLIIBnXo9lvZJj3MWQ= -github.com/shurcooL/highlight_diff v0.0.0-20170515013008-09bb4053de1b/go.mod h1:ZpfEhSmds4ytuByIcDnOLkTHGUI6KNqRNPDLHDk+mUU= -github.com/shurcooL/highlight_go v0.0.0-20170515013102-78fb10f4a5f8/go.mod h1:UDKB5a1T23gOMUJrI+uSuH0VRDStOiUVSjBTRDVBVag= -github.com/shurcooL/octicon v0.0.0-20180602230221-c42b0e3b24d9/go.mod h1:eWdoE5JD4R5UVWDucdOPg1g2fqQRq78IQa9zlOV1vpQ= -github.com/shurcooL/sanitized_anchor_name v0.0.0-20170918181015-86672fcb3f95/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= -github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc= -github.com/sirupsen/logrus v1.1.0/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= -github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= -github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d h1:yKm7XZV6j9Ev6lojP2XaIshpT4ymkqhMeSghO5Ps00E= github.com/sourcegraph/annotate v0.0.0-20160123013949-f4cad6c6324d/go.mod h1:UdhH50NIW0fCiwBSr0co2m7BnFLdv4fQTgdqdJTHFeE= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e h1:qpG93cPwA5f7s/ZPBJnGOYQNK/vKsaDaseuKT5Asee8= github.com/sourcegraph/syntaxhighlight v0.0.0-20170531221838-bd320f5d308e/go.mod h1:HuIsMU8RRBOtsCgI77wP899iHVBQpCmg4ErYMZB+2IA= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= -github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= -github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= -github.com/spf13/afero v1.5.1/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= -github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= -github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= -github.com/spf13/cast v1.2.0/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg= -github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.3.2-0.20200723214538-8d17101741c8/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= -github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= -github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= -github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= -github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE= -github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= -github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA= -github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= -github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= -github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= -github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= -github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/viper v1.2.1/go.mod h1:P4AexN0a+C9tGAnUFNwDMYYZv3pjFuvmeiMyKRaNVlI= -github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= -github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= -github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ= -github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -1055,55 +485,32 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= -github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs= -github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= -github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= -github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/tidwall/gjson v1.17.3 h1:bwWLZU7icoKRG+C+0PNwIKC6FCJO/Q3p2pZvuP0jN94= +github.com/tidwall/gjson v1.17.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY= github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= -github.com/timtadh/data-structures v0.5.3 h1:F2tEjoG9qWIyUjbvXVgJqEOGJPMIiYn7U5W5mE+i/vQ= -github.com/timtadh/data-structures v0.5.3/go.mod h1:9R4XODhJ8JdWFEI8P/HJKqxuJctfBQw6fDibMQny2oU= -github.com/timtadh/lexmachine v0.2.2 h1:g55RnjdYazm5wnKv59pwFcBJHOyvTPfDEoz21s4PHmY= -github.com/timtadh/lexmachine v0.2.2/go.mod h1:GBJvD5OAfRn/gnp92zb9KTgHLB7akKyxmVivoYCcjQI= -github.com/tinylib/msgp v1.1.6 h1:i+SbKraHhnrf9M5MYmvQhFnbLhAXSDWF8WWsuyRdocw= -github.com/tinylib/msgp v1.1.6/go.mod h1:75BAfg2hauQhs3qedfdDZmWAPcFMAvJE5b9rGOMufyw= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80 h1:nrZ3ySNYwJbSpD6ce9duiP+QkD3JuLCcWkdaehUS/3Y= github.com/tomnomnom/linkheader v0.0.0-20180905144013-02ca5825eb80/go.mod h1:iFyPdL66DjUD96XmzVL3ZntbzcflLnznH0fr99w5VqE= github.com/toqueteos/webbrowser v1.2.0 h1:tVP/gpK69Fx+qMJKsLE7TD8LuGWPnEV71wBN9rrstGQ= github.com/toqueteos/webbrowser v1.2.0/go.mod h1:XWoZq4cyp9WeUeak7w7LXRUQf1F1ATJMir8RTqb4ayM= -github.com/twmb/murmur3 v1.1.6 h1:mqrRot1BRxm+Yct+vavLMou2/iJt0tNVTTC0QoIjaZg= -github.com/twmb/murmur3 v1.1.6/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= -github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o= -github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk= -github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg= -github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U= -github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA= -github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= +github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/urfave/negroni v1.0.0 h1:kIimOitoypq34K7TG7DUaJ9kq/N4Ofuwi1sjz0KipXc= github.com/urfave/negroni v1.0.0/go.mod h1:Meg73S6kFm/4PpbYdq35yYWoCZ9mS/YSx+lKnmiohz4= -github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= -github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.2/go.mod h1:8F9zXuvzgwmyT5DUm4GUfZGDdT3W+LCvS6+da4O5kxM= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= @@ -1111,648 +518,190 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= -github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c h1:3lbZUMbMiGUW/LMkfsEABsc5zNT9+b1CvsJx47JzJ8g= github.com/xtgo/uuid v0.0.0-20140804021211-a0b114877d4c/go.mod h1:UrdRz5enIKZ63MEE3IF9l2/ebyx59GyGgPi+tICQdmM= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= -go.elastic.co/apm v1.15.0 h1:uPk2g/whK7c7XiZyz/YCUnAUBNPiyNeE3ARX3G6Gx7Q= -go.elastic.co/apm v1.15.0/go.mod h1:dylGv2HKR0tiCV+wliJz1KHtDyuD8SPe69oV7VyK6WY= -go.elastic.co/apm/module/apmhttp v1.15.0 h1:Le/DhI0Cqpr9wG/NIGOkbz7+rOMqJrfE4MRG6q/+leU= -go.elastic.co/apm/module/apmhttp v1.15.0/go.mod h1:NruY6Jq8ALLzWUVUQ7t4wIzn+onKoiP5woJJdTV7GMg= -go.elastic.co/apm/module/apmot v1.15.0 h1:yqarZ4HCIb6dLAzEVSWdppAuRhfrCfm2Z6UL+ubai2A= -go.elastic.co/apm/module/apmot v1.15.0/go.mod h1:BjFz2KOlnjXdnSo0p6nhDDaIEYYX8c6uVHwvkZiLqtQ= -go.elastic.co/fastjson v1.1.0 h1:3MrGBWWVIxe/xvsbpghtkFoPciPhOCmjsR/HfwEeQR4= -go.elastic.co/fastjson v1.1.0/go.mod h1:boNGISWMjQsUPy/t6yqt2/1Wx4YNPSe+mZjlyw9vKKI= -go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= -go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A= -go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g= -go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY= -go.mongodb.org/mongo-driver v1.7.3/go.mod h1:NqaYOwnXWr5Pm7AOpO5QFxKJ503nbMse/R79oO62zWg= -go.mongodb.org/mongo-driver v1.7.5/go.mod h1:VXEWRZ6URJIkUq2SCAyapmhH0ZLRBP+FT4xhp5Zvxng= -go.mongodb.org/mongo-driver v1.8.3/go.mod h1:0sQWfOeY63QTntERDJJ/0SuKK0T1uVSgKCuAROlKEPY= -go.mongodb.org/mongo-driver v1.10.0/go.mod h1:wsihk0Kdgv8Kqu1Anit4sfK+22vSFbUrAVEYRhCXrA8= -go.mongodb.org/mongo-driver v1.10.3 h1:XDQEvmh6z1EUsXuIkXE9TaVeqHw6SwS1uf93jFs0HBA= -go.mongodb.org/mongo-driver v1.10.3/go.mod h1:z4XpeoU6w+9Vht+jAFyLgVrD+jGSQQe0+CBWFHNiHt8= -go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= -go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= -go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= -go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4 h1:toN8e0U4RWQL4f8H+1eFtaeWe/IkSM3+81qJEDOgShs= -go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.36.4/go.mod h1:u4OeI4ujQmFbpZOOysLUfYrRWOmEVmvzkM2zExVorXM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4 h1:aUEBEdCa6iamGzg6fuYxDA8ThxvOG240mAvWDU+XLio= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.36.4/go.mod h1:l2MdsbKTocpPS5nQZscqTR9jd8u96VYZdcpF8Sye7mA= -go.opentelemetry.io/contrib/propagators/b3 v1.11.1 h1:icQ6ttRV+r/2fnU46BIo/g/mPu6Rs5Ug8Rtohe3KqzI= -go.opentelemetry.io/contrib/propagators/b3 v1.11.1/go.mod h1:ECIveyMXgnl4gorxFcA7RYjJY/Ql9n20ubhbfDc3QfA= -go.opentelemetry.io/contrib/propagators/jaeger v1.11.1 h1:Gw+P9NQzw4bjNGZXsoDhwwDWLnk4Y1waF8MQZAq/eYM= -go.opentelemetry.io/contrib/propagators/jaeger v1.11.1/go.mod h1:dP/N3ZFADH8azBcZfGXEFNBXpEmPTXYcNj9rkw1+2Oc= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2 h1:Izp9RqrioK/y7J/RXy2c7zd83iKQ4N3td3AMNKNzHiI= -go.opentelemetry.io/contrib/samplers/jaegerremote v0.5.2/go.mod h1:Z0aRlRERn9v/3J2K+ATa6ffKyb8/i+/My/gTzFr3dII= -go.opentelemetry.io/otel v1.11.1 h1:4WLLAmcfkmDk2ukNXJyq3/kiz/3UzCaYq6PskJsaou4= -go.opentelemetry.io/otel v1.11.1/go.mod h1:1nNhXBbWSD0nsL38H6btgnFN2k4i0sNLHNNMZMSbUGE= -go.opentelemetry.io/otel/bridge/opentracing v1.11.1 h1:/ZBsgjXWUpiZ5M9zm+Ft3kuDUGErIGcEJbKRIsFN6jA= -go.opentelemetry.io/otel/bridge/opentracing v1.11.1/go.mod h1:vw9hN4H+G0ek+XQtxP+Mm1McLcmdx2FXHNrWn2bBqxU= -go.opentelemetry.io/otel/exporters/jaeger v1.11.1 h1:F9Io8lqWdGyIbY3/SOGki34LX/l+7OL0gXNxjqwcbuQ= -go.opentelemetry.io/otel/exporters/jaeger v1.11.1/go.mod h1:lRa2w3bQ4R4QN6zYsDgy7tEezgoKEu7Ow2g35Y75+KI= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1 h1:X2GndnMCsUPh6CiY2a+frAbNsXaPLbB0soHRYhAZ5Ig= -go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.11.1/go.mod h1:i8vjiSzbiUC7wOQplijSXMYUpNM93DtlS5CbUT+C6oQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0 h1:NN90Cuna0CnBg8YNu1Q0V35i2E8LDByFOwHRCq/ZP9I= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.9.0/go.mod h1:0EsCXjZAiiZGnLdEUXM9YjCKuuLZMYyglh2QDXcYKVA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0 h1:FAF9l8Wjxi9Ad2k/vLTfHZyzXYX72C62wBGpV3G6AIo= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.9.0/go.mod h1:smUdtylgc0YQiUr2PuifS4hBXhAS5xtR6WQhxP1wiNA= -go.opentelemetry.io/otel/exporters/zipkin v1.11.1 h1:JlJ3/oQoyqlrPDCfsSVFcHgGeHvZq+hr1VPWtiYCXTo= -go.opentelemetry.io/otel/exporters/zipkin v1.11.1/go.mod h1:T4S6aVwIS1+MHA+dJHCcPROtZe6ORwnv5vMKPRapsFw= -go.opentelemetry.io/otel/metric v0.33.0 h1:xQAyl7uGEYvrLAiV/09iTJlp1pZnQ9Wl793qbVvED1E= -go.opentelemetry.io/otel/metric v0.33.0/go.mod h1:QlTYc+EnYNq/M2mNk1qDDMRLpqCOj2f/r5c7Fd5FYaI= -go.opentelemetry.io/otel/sdk v1.11.1 h1:F7KmQgoHljhUuJyA+9BiU+EkJfyX5nVVF4wyzWZpKxs= -go.opentelemetry.io/otel/sdk v1.11.1/go.mod h1:/l3FE4SupHJ12TduVjUkZtlfFqDCQJlOlithYrdktys= -go.opentelemetry.io/otel/trace v1.11.1 h1:ofxdnzsNrGBYXbP7t7zpUK281+go5rF7dvdIZXF8gdQ= -go.opentelemetry.io/otel/trace v1.11.1/go.mod h1:f/Q9G7vzk5u91PhbmKbg1Qn0rzH1LJ4vbPHFGkTPtOk= -go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v0.18.0 h1:W5hyXNComRa23tGpKwG+FRAc4rfF6ZUg1JReK+QHS80= -go.opentelemetry.io/proto/otlp v0.18.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U= -go.step.sm/crypto v0.16.2 h1:Pr9aazTwWBBZNogUsOqhOrPSdwAa9pPs+lMB602lnDA= -go.step.sm/crypto v0.16.2/go.mod h1:1WkTOTY+fOX/RY4TnZREp6trQAsBHRQ7nu6QJBiNQF8= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -go.uber.org/automaxprocs v1.3.0 h1:II28aZoGdaglS5vVNnspf28lnZpXScxtIozx1lAjdb0= -go.uber.org/automaxprocs v1.3.0/go.mod h1:9CWT6lKIep8U41DDaPiH6eFscnTyjfTANNQNx6LrIcA= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo= -go4.org/intern v0.0.0-20211027215823-ae77deb06f29 h1:UXLjNohABv4S58tHmeuIZDO6e3mHpW2Dx33gaNt03LE= -go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvoA/jbNzuAWLQE2kG820zMAkcilx6BMjGbL/E4= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +github.com/yuin/gopher-lua v1.1.1 h1:kYKnWBjvbNP4XLT3+bPEwAXJx262OhaHDWDVOPjL46M= +github.com/yuin/gopher-lua v1.1.1/go.mod h1:GBR0iDaNXjAgGg9zfCvksxSRnQx76gclCIb7kdAd1Pw= +go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= +go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0 h1:7F3XCD6WYzDkwbi8I8N+oYJWquPVScnRosKGgqjsR8c= +go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.57.0/go.mod h1:Dk3C0BfIlZDZ5c6eVS7TYiH2vssuyUU3vUsgbrR+5V4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0 h1:DheMAlT6POBP+gh8RUH19EOTnQIor5QE0uSRPtzCpSw= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.57.0/go.mod h1:wZcGmeVO9nzP67aYSLDqXNWK87EZWhi7JWj1v7ZXf94= +go.opentelemetry.io/contrib/propagators/b3 v1.32.0 h1:MazJBz2Zf6HTN/nK/s3Ru1qme+VhWU5hm83QxEP+dvw= +go.opentelemetry.io/contrib/propagators/b3 v1.32.0/go.mod h1:B0s70QHYPrJwPOwD1o3V/R8vETNOG9N3qZf4LDYvA30= +go.opentelemetry.io/contrib/propagators/jaeger v1.32.0 h1:K/fOyTMD6GELKTIJBaJ9k3ppF2Njt8MeUGBOwfaWXXA= +go.opentelemetry.io/contrib/propagators/jaeger v1.32.0/go.mod h1:ISE6hda//MTWvtngG7p4et3OCngsrTVfl7c6DjN17f8= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.26.0 h1:/SKXyZLAnuj981HVc8G5ZylYK3qD2W6AYR6cJx5kIHw= +go.opentelemetry.io/contrib/samplers/jaegerremote v0.26.0/go.mod h1:cOEzME0M2OKeHB45lJiOKfvUCdg/r75mf7YS5w0tbmE= +go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U= +go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0 h1:D7UpUy2Xc2wsi1Ras6V40q806WM07rqoCWzXu7Sqy+4= +go.opentelemetry.io/otel/exporters/jaeger v1.17.0/go.mod h1:nPCqOnEH9rNLKqH/+rrUjiMzHJdV1BlpKcTwRTyKkKI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0 h1:cMyu9O88joYEaI47CnQkxO1XZdpoTF9fEnW2duIddhw= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.32.0/go.mod h1:6Am3rn7P9TVVeXYG+wtcGE7IE1tsQ+bP3AuWcKt/gOI= +go.opentelemetry.io/otel/exporters/zipkin v1.32.0 h1:6O8HgLHPXtXE9QEKEWkBImL9mEKCGEl+m+OncVO53go= +go.opentelemetry.io/otel/exporters/zipkin v1.32.0/go.mod h1:+MFvorlowjy0iWnsKaNxC1kzczSxe71mw85h4p8yEvg= +go.opentelemetry.io/otel/metric v1.32.0 h1:xV2umtmNcThh2/a/aCP+h64Xx5wsj8qqnkYZktzNa0M= +go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzauciCRLoc/SyMv8= +go.opentelemetry.io/otel/sdk v1.32.0 h1:RNxepc9vK59A8XsgZQouW8ue8Gkb4jpWtJm9ge5lEG4= +go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU= +go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM= +go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= +go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A= +go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4= +go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= +go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220517005047-85d78b3ac167/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= -golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= -golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= -golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= -golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug= -golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180816102801-aaf60122140d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180921000356-2f5d2388922f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180926154720-4dfa2610cdf3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= +golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= -golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= -golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM= -golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= -golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221002022538-bcab6841153b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= -golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783 h1:nt+Q6cXKz4MosCSpnbMtqiQ8Oz0pxTef2B4Vca2lvfk= -golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190412183630-56d357773e84/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= +golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180906133057-8cf3aee42992/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180921163948-d47a0f339242/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180927150500-dad3d9fb7b6e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181005133103-4497e2df6f9e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ= +golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190419153524-e8e3143a4f4a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190531175056-4c3a928424d2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211102192858-4dd72447c267/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s= +golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0 h1:g6Z6vPFA9dYBAF7DWcH6sCcOntplXsDKcliusYijMlw= -golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA= -golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= +golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= +golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20181006002542-f60d9635b16a/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190329151228-23e29df326fe/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190416151739-9c9e1878f421/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190531172133-b3315ee88b7d/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624180213-70d37148ca0c/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= -golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= -golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200509030707-2212a7e161a5/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= -golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= -golang.org/x/tools v0.0.0-20201022035929-9cf592e881e9/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4= +golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= +golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk= -golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= -google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= -google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= -google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= -google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= -google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= -google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= -google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= -google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= -google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= -google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= -google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= -google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= -google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= -google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= -google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= -google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= -google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200806141610-86f49bd18e98/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= -google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20211020151524-b7c3a969101a/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= -google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71 h1:GEgb2jF5zxsFJpJfg9RoDDWm7tiwc/DDSTE2BtLUkXU= -google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= -google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= -google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= -google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= -google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= -google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= -google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= -google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= -google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= -google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= -google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28 h1:M0KvPgPmDZHPlbRbaNU1APr28TvwvvdUPlSv7PUvy8g= +google.golang.org/genproto/googleapis/api v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:dguCy7UOdZhTvLzDyt15+rOrawrpM4q7DD9dQ1P11P4= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28 h1:XVhgTWWV3kGQlwJHR3upFWZeTsei6Oks1apkZSeonIE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241104194629-dd2ea8efbc28/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99 h1:qA8rMbz1wQ4DOFfM2ouD29DG9aHWBm6ZOy9BGxiUMmY= google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99/go.mod h1:Ly7ZA/ARzg8fnPU9TyZIxoz33sEUuWX7txiqs8lPTgE= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/DataDog/dd-trace-go.v1 v1.43.0 h1:UE3SNh7T7ZnCrYsDZuUuwN3LFSc5aphaszUF+wMm4Sk= -gopkg.in/DataDog/dd-trace-go.v1 v1.43.0/go.mod h1:YL9g+nlUY7ByCffD5pDytAqy99GNbytRV0EBpKuldM4= -gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= -gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo= gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/mold.v2 v2.2.0/go.mod h1:XMyyRsGtakkDPbxXbrA5VODo6bUXyvoDjLd5l3T0XoA= -gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= -gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/mail.v2 v2.0.0-20180731213649-a0242b2233b4/go.mod h1:htwXN1Qh09vZJ1NVKxQqHPBaCBbzKhp5GzuJEA4VJWw= gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE= gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= -gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= -gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/validator.v2 v2.0.0-20180514200540-135c24b11c19/go.mod h1:o4V0GXN9/CAmCsvJ0oXYZvrZOe7syiDZSN1GWGZTGzc= -gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg= -gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200605160147-a5ece683394c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.3.5/go.mod h1:EGCWefLFQSVFrHGy4J8EtiHCWX5Q8t0yz2Jt9aKkGzU= -gorm.io/gorm v1.23.4/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gorm.io/gorm v1.23.5/go.mod h1:l2lP/RyAtc1ynaTjFksBde/O8v9oOGIApu2/xRitmZk= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= -howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM= -howett.net/plist v1.0.0/go.mod h1:lqaXoTrLY4hg8tnEzNru53gicrbv7rrk+2xJA/7hw9g= -inet.af/netaddr v0.0.0-20220617031823-097006376321 h1:B4dC8ySKTQXasnjDTMsoCMf1sQG4WsMej0WXaHxunmU= -rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= -rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= -rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= -sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc= +gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= +gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/go_mod_indirect_pins.go b/go_mod_indirect_pins.go index 405389eee81..f61c9788cf7 100644 --- a/go_mod_indirect_pins.go +++ b/go_mod_indirect_pins.go @@ -7,13 +7,10 @@ package main import ( - _ "github.com/go-bindata/go-bindata/go-bindata" _ "github.com/go-swagger/go-swagger/cmd/swagger" _ "github.com/golang/mock/mockgen" _ "github.com/mikefarah/yq/v4" _ "golang.org/x/tools/cmd/goimports" - _ "golang.org/x/tools/cmd/stringer" - _ "gopkg.in/DataDog/dd-trace-go.v1/ddtrace" _ "github.com/ory/go-acc" ) diff --git a/health/doc.go b/health/doc.go index bad9c42139c..a0b2f45cbe8 100644 --- a/health/doc.go +++ b/health/doc.go @@ -24,6 +24,8 @@ package health // Responses: // 200: healthStatus // 500: errorOAuth2 +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions func swaggerPublicIsInstanceAlive() {} // Alive returns an ok status if the instance is ready to handle HTTP requests. @@ -47,6 +49,8 @@ func swaggerPublicIsInstanceAlive() {} // Responses: // 200: healthStatus // 500: errorOAuth2 +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions func swaggerAdminIsInstanceAlive() {} // Ready returns an ok status if the instance is ready to handle HTTP requests and all ReadyCheckers are ok. @@ -70,6 +74,8 @@ func swaggerAdminIsInstanceAlive() {} // Responses: // 200: healthStatus // 503: healthNotReadyStatus +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions func swaggerAdminIsInstanceReady() {} // Ready returns an ok status if the instance is ready to handle HTTP requests and all ReadyCheckers are ok. @@ -93,6 +99,8 @@ func swaggerAdminIsInstanceReady() {} // Responses: // 200: healthStatus // 503: healthNotReadyStatus +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions func swaggerPublicIsInstanceReady() {} // Version returns this service's versions. @@ -111,4 +119,6 @@ func swaggerPublicIsInstanceReady() {} // // Responses: // 200: version +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions func swaggerGetVersion() {} diff --git a/health/handler_test.go b/health/handler_test.go index ed0a91b0d37..4b717a02c79 100644 --- a/health/handler_test.go +++ b/health/handler_test.go @@ -15,9 +15,9 @@ import ( "github.com/stretchr/testify/require" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/x" "github.com/ory/x/healthx" ) diff --git a/hsm/hsm.go b/hsm/hsm.go index 38304962c9d..0d11528b723 100644 --- a/hsm/hsm.go +++ b/hsm/hsm.go @@ -11,7 +11,7 @@ import ( "github.com/ThalesIgnite/crypto11" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver/config" "github.com/ory/x/logrusx" ) diff --git a/hsm/manager_hsm.go b/hsm/manager_hsm.go index 61dceb2b086..75badb1cc5f 100644 --- a/hsm/manager_hsm.go +++ b/hsm/manager_hsm.go @@ -16,7 +16,7 @@ import ( "net/http" "sync" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver/config" "github.com/ory/x/otelx" "github.com/pkg/errors" @@ -24,16 +24,18 @@ import ( "github.com/pborman/uuid" "github.com/ory/fosite" - "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/jwk" "github.com/miekg/pkcs11" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/ThalesIgnite/crypto11" + "github.com/go-jose/go-jose/v3" + "github.com/go-jose/go-jose/v3/cryptosigner" "go.opentelemetry.io/otel" - "gopkg.in/square/go-jose.v2" - "gopkg.in/square/go-jose.v2/cryptosigner" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" ) const tracingComponent = "github.com/ory/hydra/hsm" @@ -42,7 +44,7 @@ type KeyManager struct { jwk.Manager sync.RWMutex Context - KeySetPrefix string + c config.DefaultProvider } var ErrPreGeneratedKeys = &fosite.RFC6749Error{ @@ -53,28 +55,26 @@ var ErrPreGeneratedKeys = &fosite.RFC6749Error{ func NewKeyManager(hsm Context, config *config.DefaultProvider) *KeyManager { return &KeyManager{ - Context: hsm, - KeySetPrefix: config.HSMKeySetPrefix(), + Context: hsm, + c: *config, } } -func (m *KeyManager) GenerateAndPersistKeySet(ctx context.Context, set, kid, alg, use string) (*jose.JSONWebKeySet, error) { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - "kid": kid, - "alg": alg, - "use": use, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m *KeyManager) GenerateAndPersistKeySet(ctx context.Context, set, kid, alg, use string) (_ *jose.JSONWebKeySet, err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.GenerateAndPersistKeySet", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", kid), + attribute.String("alg", alg), + attribute.String("use", use))) + defer otelx.End(span, &err) m.Lock() defer m.Unlock() set = m.prefixKeySet(set) - err := m.deleteExistingKeySet(set) + err = m.deleteExistingKeySet(set) if err != nil { return nil, err } @@ -119,14 +119,10 @@ func (m *KeyManager) GenerateAndPersistKeySet(ctx context.Context, set, kid, alg } } -func (m *KeyManager) GetKey(ctx context.Context, set, kid string) (*jose.JSONWebKeySet, error) { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.GetKey") - defer span.End() - attrs := map[string]string{ - "set": set, - "kid": kid, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m *KeyManager) GetKey(ctx context.Context, set, kid string) (_ *jose.JSONWebKeySet, err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.GetKey", + trace.WithAttributes(attribute.String("set", set), attribute.String("kid", kid))) + defer otelx.End(span, &err) m.RLock() defer m.RUnlock() @@ -142,7 +138,7 @@ func (m *KeyManager) GetKey(ctx context.Context, set, kid string) (*jose.JSONWeb return nil, errors.WithStack(x.ErrNotFound) } - id, alg, use, err := getKeySetAttributes(m, keyPair, []byte(kid)) + id, alg, use, err := m.getKeySetAttributes(ctx, keyPair, []byte(kid)) if err != nil { return nil, err } @@ -150,13 +146,9 @@ func (m *KeyManager) GetKey(ctx context.Context, set, kid string) (*jose.JSONWeb return createKeySet(keyPair, id, alg, use) } -func (m *KeyManager) GetKeySet(ctx context.Context, set string) (*jose.JSONWebKeySet, error) { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.GetKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m *KeyManager) GetKeySet(ctx context.Context, set string) (_ *jose.JSONWebKeySet, err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.GetKeySet", trace.WithAttributes(attribute.String("set", set))) + otelx.End(span, &err) m.RLock() defer m.RUnlock() @@ -174,7 +166,7 @@ func (m *KeyManager) GetKeySet(ctx context.Context, set string) (*jose.JSONWebKe var keys []jose.JSONWebKey for _, keyPair := range keyPairs { - kid, alg, use, err := getKeySetAttributes(m, keyPair, nil) + kid, alg, use, err := m.getKeySetAttributes(ctx, keyPair, nil) if err != nil { return nil, err } @@ -186,14 +178,12 @@ func (m *KeyManager) GetKeySet(ctx context.Context, set string) (*jose.JSONWebKe }, nil } -func (m *KeyManager) DeleteKey(ctx context.Context, set, kid string) error { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.GetKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - "kid": kid, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m *KeyManager) DeleteKey(ctx context.Context, set, kid string) (err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.DeleteKey", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", kid))) + defer otelx.End(span, &err) m.Lock() defer m.Unlock() @@ -216,13 +206,9 @@ func (m *KeyManager) DeleteKey(ctx context.Context, set, kid string) error { return nil } -func (m *KeyManager) DeleteKeySet(ctx context.Context, set string) error { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.GetKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m *KeyManager) DeleteKeySet(ctx context.Context, set string) (err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "hsm.DeleteKeySet", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) m.Lock() defer m.Unlock() @@ -263,7 +249,7 @@ func (m *KeyManager) UpdateKeySet(_ context.Context, _ string, _ *jose.JSONWebKe return errors.WithStack(ErrPreGeneratedKeys) } -func getKeySetAttributes(m *KeyManager, key crypto11.Signer, kid []byte) (string, string, string, error) { +func (m *KeyManager) getKeySetAttributes(ctx context.Context, key crypto11.Signer, kid []byte) (string, string, string, error) { if kid == nil { ckaId, err := m.GetAttribute(key, crypto11.CkaId) if err != nil { @@ -276,8 +262,9 @@ func getKeySetAttributes(m *KeyManager, key crypto11.Signer, kid []byte) (string switch k := key.Public().(type) { case *rsa.PublicKey: alg = "RS256" - // TODO Should we validate minimal key length by checking CKA_MODULUS_BITS? - // TODO see https://github.com/ory/hydra/issues/2905 + if k.N.BitLen() < 4096 && !m.c.IsDevelopmentMode(ctx) { + return "", "", "", errors.WithStack(jwk.ErrMinimalRsaKeyLength) + } case *ecdsa.PublicKey: if k.Curve == elliptic.P521() { alg = "ES512" @@ -361,17 +348,9 @@ func createKeys(key crypto11.Signer, kid, alg, use string) []jose.JSONWebKey { Certificates: []*x509.Certificate{}, CertificateThumbprintSHA1: []uint8{}, CertificateThumbprintSHA256: []uint8{}, - }, { - Algorithm: alg, - Use: use, - Key: key.Public(), - KeyID: kid, - Certificates: []*x509.Certificate{}, - CertificateThumbprintSHA1: []uint8{}, - CertificateThumbprintSHA256: []uint8{}, }} } func (m *KeyManager) prefixKeySet(set string) string { - return fmt.Sprintf("%s%s", m.KeySetPrefix, set) + return fmt.Sprintf("%s%s", m.c.HSMKeySetPrefix(), set) } diff --git a/hsm/manager_hsm_test.go b/hsm/manager_hsm_test.go index 006459d9572..17f4be0dfc9 100644 --- a/hsm/manager_hsm_test.go +++ b/hsm/manager_hsm_test.go @@ -17,27 +17,27 @@ import ( "reflect" "testing" - "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/jwk" "github.com/ory/x/contextx" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/persistence/sql" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/persistence/sql" "github.com/ory/x/configx" "github.com/ory/x/logrusx" "github.com/ThalesIgnite/crypto11" + "github.com/go-jose/go-jose/v3" + "github.com/go-jose/go-jose/v3/cryptosigner" "github.com/golang/mock/gomock" "github.com/miekg/pkcs11" "github.com/pborman/uuid" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/square/go-jose.v2" - "gopkg.in/square/go-jose.v2/cryptosigner" - "github.com/ory/hydra/hsm" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/hsm" + "github.com/ory/hydra/v2/x" ) func TestDefaultKeyManager_HSMEnabled(t *testing.T) { @@ -48,12 +48,10 @@ func TestDefaultKeyManager_HSMEnabled(t *testing.T) { c := config.MustNew(context.Background(), l, configx.SkipValidation()) c.MustSet(context.Background(), config.KeyDSN, "memory") c.MustSet(context.Background(), config.HSMEnabled, "true") - reg := driver.NewRegistrySQL() - reg.WithLogger(l) - reg.WithConfig(c) + reg, err := driver.NewRegistryWithoutInit(c, l) + require.NoError(t, err) reg.WithHsmContext(mockHsmContext) - err := reg.Init(context.Background(), false, true, &contextx.TestContextualizer{}) - assert.NoError(t, err) + assert.NoError(t, reg.Init(context.Background(), false, true, &contextx.TestContextualizer{}, nil, nil)) assert.IsType(t, &jwk.ManagerStrategy{}, reg.KeyManager()) assert.IsType(t, &sql.Persister{}, reg.SoftwareKeyManager()) } @@ -62,78 +60,97 @@ func TestKeyManager_HsmKeySetPrefix(t *testing.T) { ctrl := gomock.NewController(t) hsmContext := NewMockContext(ctrl) defer ctrl.Finish() + l := logrusx.New("", "") + c := config.MustNew(context.Background(), l, configx.SkipValidation()) + keySetPrefix := "application_specific_prefix." + c.MustSet(context.Background(), config.HSMKeySetPrefix, keySetPrefix) + m := hsm.NewKeyManager(hsmContext, c) - rsaKey, err := rsa.GenerateKey(rand.Reader, 512) + rsaKey3072, err := rsa.GenerateKey(rand.Reader, 3072) + require.NoError(t, err) + rsaKey4096, err := rsa.GenerateKey(rand.Reader, 4096) require.NoError(t, err) ecdsaKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) require.NoError(t, err) - rsaKeyPair := NewMockSignerDecrypter(ctrl) - rsaKeyPair.EXPECT().Public().Return(&rsaKey.PublicKey).AnyTimes() + rsaKeyPair3072 := NewMockSignerDecrypter(ctrl) + rsaKeyPair3072.EXPECT().Public().Return(&rsaKey3072.PublicKey).AnyTimes() + + rsaKeyPair4096 := NewMockSignerDecrypter(ctrl) + rsaKeyPair4096.EXPECT().Public().Return(&rsaKey4096.PublicKey).AnyTimes() ecdsaKeyPair := NewMockSignerDecrypter(ctrl) ecdsaKeyPair.EXPECT().Public().Return(&ecdsaKey.PublicKey).AnyTimes() var kid = uuid.New() - keySetPrefix := "application_specific_prefix." expectedPrefixedOpenIDConnectKeyName := fmt.Sprintf("%s%s", keySetPrefix, x.OpenIDConnectKeyName) - m := &hsm.KeyManager{ - Context: hsmContext, - KeySetPrefix: keySetPrefix, - } - t.Run("case=GenerateAndPersistKeySet", func(t *testing.T) { privateAttrSet, publicAttrSet := expectedKeyAttributes(t, expectedPrefixedOpenIDConnectKeyName, kid) hsmContext.EXPECT().FindKeyPairs(gomock.Nil(), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return(nil, nil) - hsmContext.EXPECT().GenerateRSAKeyPairWithAttributes(gomock.Eq(publicAttrSet), gomock.Eq(privateAttrSet), gomock.Eq(4096)).Return(rsaKeyPair, nil) + hsmContext.EXPECT().GenerateRSAKeyPairWithAttributes(gomock.Eq(publicAttrSet), gomock.Eq(privateAttrSet), gomock.Eq(4096)).Return(rsaKeyPair4096, nil) got, err := m.GenerateAndPersistKeySet(context.TODO(), x.OpenIDConnectKeyName, kid, "RS256", "sig") assert.NoError(t, err) - expectedKeySet := expectedKeySet(rsaKeyPair, kid, "RS256", "sig") + expectedKeySet := expectedKeySet(rsaKeyPair4096, kid, "RS256", "sig") if !reflect.DeepEqual(got, expectedKeySet) { t.Errorf("GenerateAndPersistKeySet() got = %v, want %v", got, expectedKeySet) } }) t.Run("case=GetKey", func(t *testing.T) { - hsmContext.EXPECT().FindKeyPair(gomock.Eq([]byte(kid)), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return(rsaKeyPair, nil) - hsmContext.EXPECT().GetAttribute(gomock.Eq(rsaKeyPair), gomock.Eq(crypto11.CkaDecrypt)).Return(nil, nil) + hsmContext.EXPECT().FindKeyPair(gomock.Eq([]byte(kid)), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return(rsaKeyPair4096, nil) + hsmContext.EXPECT().GetAttribute(gomock.Eq(rsaKeyPair4096), gomock.Eq(crypto11.CkaDecrypt)).Return(nil, nil) got, err := m.GetKey(context.TODO(), x.OpenIDConnectKeyName, kid) assert.NoError(t, err) - expectedKeySet := expectedKeySet(rsaKeyPair, kid, "RS256", "sig") + expectedKeySet := expectedKeySet(rsaKeyPair4096, kid, "RS256", "sig") if !reflect.DeepEqual(got, expectedKeySet) { t.Errorf("GetKey() got = %v, want %v", got, expectedKeySet) } }) + t.Run("case=GetKeyMinimalRsaKeyLengthError", func(t *testing.T) { + hsmContext.EXPECT().FindKeyPair(gomock.Eq([]byte(kid)), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return(rsaKeyPair3072, nil) + + _, err := m.GetKey(context.TODO(), x.OpenIDConnectKeyName, kid) + + assert.ErrorIs(t, err, jwk.ErrMinimalRsaKeyLength) + }) t.Run("case=GetKeySet", func(t *testing.T) { - hsmContext.EXPECT().FindKeyPairs(gomock.Nil(), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return([]crypto11.Signer{rsaKeyPair}, nil) - hsmContext.EXPECT().GetAttribute(gomock.Eq(rsaKeyPair), gomock.Eq(crypto11.CkaId)).Return(pkcs11.NewAttribute(pkcs11.CKA_ID, []byte(kid)), nil) - hsmContext.EXPECT().GetAttribute(gomock.Eq(rsaKeyPair), gomock.Eq(crypto11.CkaDecrypt)).Return(nil, nil) + hsmContext.EXPECT().FindKeyPairs(gomock.Nil(), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return([]crypto11.Signer{rsaKeyPair4096}, nil) + hsmContext.EXPECT().GetAttribute(gomock.Eq(rsaKeyPair4096), gomock.Eq(crypto11.CkaId)).Return(pkcs11.NewAttribute(pkcs11.CKA_ID, []byte(kid)), nil) + hsmContext.EXPECT().GetAttribute(gomock.Eq(rsaKeyPair4096), gomock.Eq(crypto11.CkaDecrypt)).Return(nil, nil) got, err := m.GetKeySet(context.TODO(), x.OpenIDConnectKeyName) assert.NoError(t, err) - expectedKeySet := expectedKeySet(rsaKeyPair, kid, "RS256", "sig") + expectedKeySet := expectedKeySet(rsaKeyPair4096, kid, "RS256", "sig") if !reflect.DeepEqual(got, expectedKeySet) { t.Errorf("GetKey() got = %v, want %v", got, expectedKeySet) } }) + t.Run("case=GetKeySetMinimalRsaKeyLengthError", func(t *testing.T) { + hsmContext.EXPECT().FindKeyPairs(gomock.Nil(), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return([]crypto11.Signer{rsaKeyPair3072}, nil) + hsmContext.EXPECT().GetAttribute(gomock.Eq(rsaKeyPair3072), gomock.Eq(crypto11.CkaId)).Return(pkcs11.NewAttribute(pkcs11.CKA_ID, []byte(kid)), nil) + + _, err := m.GetKeySet(context.TODO(), x.OpenIDConnectKeyName) + + assert.ErrorIs(t, err, jwk.ErrMinimalRsaKeyLength) + }) t.Run("case=DeleteKey", func(t *testing.T) { - hsmContext.EXPECT().FindKeyPair(gomock.Eq([]byte(kid)), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return(rsaKeyPair, nil) - rsaKeyPair.EXPECT().Delete().Return(nil) + hsmContext.EXPECT().FindKeyPair(gomock.Eq([]byte(kid)), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return(rsaKeyPair4096, nil) + rsaKeyPair4096.EXPECT().Delete().Return(nil) err := m.DeleteKey(context.TODO(), x.OpenIDConnectKeyName, kid) assert.NoError(t, err) }) t.Run("case=DeleteKeySet", func(t *testing.T) { - hsmContext.EXPECT().FindKeyPairs(gomock.Nil(), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return([]crypto11.Signer{rsaKeyPair}, nil) - rsaKeyPair.EXPECT().Delete().Return(nil) + hsmContext.EXPECT().FindKeyPairs(gomock.Nil(), gomock.Eq([]byte(expectedPrefixedOpenIDConnectKeyName))).Return([]crypto11.Signer{rsaKeyPair4096}, nil) + rsaKeyPair4096.EXPECT().Delete().Return(nil) err := m.DeleteKeySet(context.TODO(), x.OpenIDConnectKeyName) @@ -145,8 +162,11 @@ func TestKeyManager_GenerateAndPersistKeySet(t *testing.T) { ctrl := gomock.NewController(t) hsmContext := NewMockContext(ctrl) defer ctrl.Finish() + l := logrusx.New("", "") + c := config.MustNew(context.Background(), l, configx.SkipValidation()) + m := hsm.NewKeyManager(hsmContext, c) - rsaKey, err := rsa.GenerateKey(rand.Reader, 512) + rsaKey, err := rsa.GenerateKey(rand.Reader, 4096) require.NoError(t, err) ecdsaKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) @@ -303,9 +323,6 @@ func TestKeyManager_GenerateAndPersistKeySet(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.setup(t) - m := &hsm.KeyManager{ - Context: hsmContext, - } got, err := m.GenerateAndPersistKeySet(tt.args.ctx, tt.args.set, tt.args.kid, tt.args.alg, tt.args.use) if tt.wantErr != nil { require.Nil(t, got) @@ -326,8 +343,11 @@ func TestKeyManager_GetKey(t *testing.T) { ctrl := gomock.NewController(t) hsmContext := NewMockContext(ctrl) defer ctrl.Finish() + l := logrusx.New("", "") + c := config.MustNew(context.Background(), l, configx.SkipValidation()) + m := hsm.NewKeyManager(hsmContext, c) - rsaKey, err := rsa.GenerateKey(rand.Reader, 512) + rsaKey, err := rsa.GenerateKey(rand.Reader, 4096) require.NoError(t, err) rsaKeyPair := NewMockSignerDecrypter(ctrl) rsaKeyPair.EXPECT().Public().Return(&rsaKey.PublicKey).AnyTimes() @@ -493,9 +513,6 @@ func TestKeyManager_GetKey(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.setup(t) - m := &hsm.KeyManager{ - Context: hsmContext, - } got, err := m.GetKey(tt.args.ctx, tt.args.set, tt.args.kid) if tt.wantErr != nil { require.Nil(t, got) @@ -516,8 +533,11 @@ func TestKeyManager_GetKeySet(t *testing.T) { ctrl := gomock.NewController(t) hsmContext := NewMockContext(ctrl) defer ctrl.Finish() + l := logrusx.New("", "") + c := config.MustNew(context.Background(), l, configx.SkipValidation()) + m := hsm.NewKeyManager(hsmContext, c) - rsaKey, err := rsa.GenerateKey(rand.Reader, 512) + rsaKey, err := rsa.GenerateKey(rand.Reader, 4096) require.NoError(t, err) rsaKid := uuid.New() rsaKeyPair := NewMockSignerDecrypter(ctrl) @@ -641,9 +661,6 @@ func TestKeyManager_GetKeySet(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.setup(t) - m := &hsm.KeyManager{ - Context: hsmContext, - } got, err := m.GetKeySet(tt.args.ctx, tt.args.set) if tt.wantErr != nil { require.Nil(t, got) @@ -664,6 +681,9 @@ func TestKeyManager_DeleteKey(t *testing.T) { ctrl := gomock.NewController(t) hsmContext := NewMockContext(ctrl) defer ctrl.Finish() + l := logrusx.New("", "") + c := config.MustNew(context.Background(), l, configx.SkipValidation()) + m := hsm.NewKeyManager(hsmContext, c) rsaKeyPair := NewMockSignerDecrypter(ctrl) @@ -733,9 +753,6 @@ func TestKeyManager_DeleteKey(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.setup(t) - m := &hsm.KeyManager{ - Context: hsmContext, - } if err := m.DeleteKey(tt.args.ctx, tt.args.set, tt.args.kid); len(tt.wantErrMsg) != 0 { require.EqualError(t, err, tt.wantErrMsg) } @@ -747,6 +764,9 @@ func TestKeyManager_DeleteKeySet(t *testing.T) { ctrl := gomock.NewController(t) hsmContext := NewMockContext(ctrl) defer ctrl.Finish() + l := logrusx.New("", "") + c := config.MustNew(context.Background(), l, configx.SkipValidation()) + m := hsm.NewKeyManager(hsmContext, c) rsaKeyPair1 := NewMockSignerDecrypter(ctrl) rsaKeyPair2 := NewMockSignerDecrypter(ctrl) @@ -812,9 +832,6 @@ func TestKeyManager_DeleteKeySet(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tt.setup(t) - m := &hsm.KeyManager{ - Context: hsmContext, - } if err := m.DeleteKeySet(tt.args.ctx, tt.args.set); len(tt.wantErrMsg) != 0 { require.EqualError(t, err, tt.wantErrMsg) } @@ -883,13 +900,5 @@ func createJSONWebKeys(keyPair *MockSignerDecrypter, kid string, alg string, use Certificates: []*x509.Certificate{}, CertificateThumbprintSHA1: []uint8{}, CertificateThumbprintSHA256: []uint8{}, - }, { - Algorithm: alg, - Use: use, - Key: keyPair.Public(), - KeyID: kid, - Certificates: []*x509.Certificate{}, - CertificateThumbprintSHA1: []uint8{}, - CertificateThumbprintSHA256: []uint8{}, }} } diff --git a/hsm/manager_nohsm.go b/hsm/manager_nohsm.go index 01e3a98b32a..4a28bc425e9 100644 --- a/hsm/manager_nohsm.go +++ b/hsm/manager_nohsm.go @@ -10,14 +10,14 @@ import ( "context" "sync" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver/config" "github.com/ory/x/logrusx" "github.com/pkg/errors" - "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/jwk" - "gopkg.in/square/go-jose.v2" + "github.com/go-jose/go-jose/v3" ) type Context interface { diff --git a/internal/.hydra.yaml b/internal/.hydra.yaml index 37c38723d63..bb02d986ad6 100644 --- a/internal/.hydra.yaml +++ b/internal/.hydra.yaml @@ -136,11 +136,13 @@ tracing: providers: jaeger: local_agent_address: 127.0.0.1:6831 - propagation: jaeger - max_tag_value_length: 1024 sampling: - type: const - value: 1 + trace_id_ratio: 1 server_url: http://sampling zipkin: server_url: http://zipkin/api/v2/spans + otlp: + insecure: true + server_url: localhost:4318 + sampling: + sampling_ratio: 1.0 diff --git a/internal/certification/scripts/install.sh b/internal/certification/scripts/install.sh index 6690b7df6ab..3982585f6f0 100644 --- a/internal/certification/scripts/install.sh +++ b/internal/certification/scripts/install.sh @@ -36,14 +36,13 @@ sudo add-apt-repository \ $(lsb_release -cs) \ stable" sudo apt-get update -sudo apt-get -y install docker-ce python-pip +sudo apt-get -y install docker-ce # Dockerize export DOCKERIZE_VERSION=v0.6.1 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 -sudo pip install docker-compose git clone https://github.com/ory/hydra-login-consent-node.git diff --git a/internal/config/config.yaml b/internal/config/config.yaml index 7ff8bbc37fc..49615d95966 100644 --- a/internal/config/config.yaml +++ b/internal/config/config.yaml @@ -139,7 +139,7 @@ serve: # Access Log configuration for public server. request_log: - # Disable access log for health endpoints. + # Disable access log for health and metrics endpoints. disable_for_health: false # admin controls the admin daemon serving admin API endpoints like /jwk, /client, ... @@ -402,6 +402,18 @@ oauth2: session: # store encrypted data in database, default true encrypt_at_rest: true + ## refresh_token_rotation + # By default Refresh Tokens are rotated and invalidated with each use. See https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#section-4.13.2 for more details + refresh_token_rotation: + # + ## grace_period + # + # Set the grace period for refresh tokens to be reused. Such reused tokens will result in multiple refresh tokens being issued. + # + # Examples: + # - 5s + # - 1m + grace_period: 0s # The secrets section configures secrets used for encryption and signing of several systems. All secrets can be rotated, # for more information on this topic navigate to: @@ -443,21 +455,12 @@ tracing: jaeger: # The address of the jaeger-agent where spans should be sent to local_agent_address: 127.0.0.1:6831 - # The tracing header format - propagation: jaeger - # The maximum length of jaeger tag value - max_tag_value_length: 1024 sampling: - # The type of the sampler you want to use. Supports: - # - const - # - probabilistic - # - ratelimiting - type: const # The value passed to the sampler type that has been configured. # Supported values: This is dependant on the sampling strategy used: # - const: 0 or 1 (all or nothing) # - rateLimiting: a constant rate (e.g. setting this to 3 will sample requests with the rate of 3 traces per second) # - probabilistic: a value between 0..1 - value: 1.0 + trace_id_ratio: 1.0 # The address of jaeger-agent's HTTP sampling server server_url: http://localhost:5778/sampling diff --git a/internal/driver.go b/internal/driver.go index 23dea1b66ca..38a8d8144d4 100644 --- a/internal/driver.go +++ b/internal/driver.go @@ -5,22 +5,20 @@ package internal import ( "context" - "sync" "testing" - "github.com/ory/x/configx" - + "github.com/go-jose/go-jose/v3" "github.com/stretchr/testify/require" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/configx" "github.com/ory/x/contextx" - "github.com/ory/x/sqlcon/dockertest" - - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/jwk" "github.com/ory/x/logrusx" + "github.com/ory/x/sqlcon/dockertest" ) func resetConfig(p *config.DefaultProvider) { @@ -45,19 +43,19 @@ func NewConfigurationWithDefaultsAndHTTPS() *config.DefaultProvider { return p } -func NewRegistryMemory(t *testing.T, c *config.DefaultProvider, ctxer contextx.Contextualizer) driver.Registry { +func NewRegistryMemory(t testing.TB, c *config.DefaultProvider, ctxer contextx.Contextualizer) driver.Registry { return newRegistryDefault(t, "memory", c, true, ctxer) } -func NewMockedRegistry(t *testing.T, ctxer contextx.Contextualizer) driver.Registry { +func NewMockedRegistry(t testing.TB, ctxer contextx.Contextualizer) driver.Registry { return newRegistryDefault(t, "memory", NewConfigurationWithDefaults(), true, ctxer) } -func NewRegistrySQLFromURL(t *testing.T, url string, migrate bool, ctxer contextx.Contextualizer) driver.Registry { +func NewRegistrySQLFromURL(t testing.TB, url string, migrate bool, ctxer contextx.Contextualizer) driver.Registry { return newRegistryDefault(t, url, NewConfigurationWithDefaults(), migrate, ctxer) } -func newRegistryDefault(t *testing.T, url string, c *config.DefaultProvider, migrate bool, ctxer contextx.Contextualizer) driver.Registry { +func newRegistryDefault(t testing.TB, url string, c *config.DefaultProvider, migrate bool, ctxer contextx.Contextualizer) driver.Registry { ctx := context.Background() c.MustSet(ctx, config.KeyLogLevel, "trace") c.MustSet(ctx, config.KeyDSN, url) @@ -77,16 +75,16 @@ func CleanAndMigrate(reg driver.Registry) func(*testing.T) { } } -func ConnectToMySQL(t *testing.T) string { - return dockertest.RunTestMySQLWithVersion(t, "11.8") +func ConnectToMySQL(t testing.TB) string { + return dockertest.RunTestMySQLWithVersion(t, "8.0") } -func ConnectToPG(t *testing.T) string { - return dockertest.RunTestPostgreSQLWithVersion(t, "11.8") +func ConnectToPG(t testing.TB) string { + return dockertest.RunTestPostgreSQLWithVersion(t, "16") } -func ConnectToCRDB(t *testing.T) string { - return dockertest.RunTestCockroachDBWithVersion(t, "v22.1.2") +func ConnectToCRDB(t testing.TB) string { + return dockertest.RunTestCockroachDBWithVersion(t, "latest-v24.1") } func ConnectDatabases(t *testing.T, migrate bool, ctxer contextx.Contextualizer) (pg, mysql, crdb driver.Registry, clean func(*testing.T)) { @@ -134,8 +132,8 @@ func ConnectDatabases(t *testing.T, migrate bool, ctxer contextx.Contextualizer) return } -func MustEnsureRegistryKeys(r driver.Registry, key string) { - if err := jwk.EnsureAsymmetricKeypairExists(context.Background(), r, "RS256", key); err != nil { +func MustEnsureRegistryKeys(ctx context.Context, r driver.Registry, key string) { + if err := jwk.EnsureAsymmetricKeypairExists(ctx, r, string(jose.ES256), key); err != nil { panic(err) } } diff --git a/internal/fosite_store.go b/internal/fosite_store.go index 0960b0423c6..49405ef7e7a 100644 --- a/internal/fosite_store.go +++ b/internal/fosite_store.go @@ -6,27 +6,27 @@ package internal import ( "context" - "github.com/ory/hydra/client" - "github.com/ory/hydra/driver" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver" ) func AddFositeExamples(r driver.Registry) { for _, c := range []client.Client{ { - LegacyClientID: "my-client", - Secret: "foobar", - RedirectURIs: []string{"http://localhost:3846/callback"}, - ResponseTypes: []string{"id_token", "code", "token"}, - GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, - Scope: "fosite,openid,photos,offline", + ID: "my-client", + Secret: "foobar", + RedirectURIs: []string{"http://localhost:3846/callback"}, + ResponseTypes: []string{"id_token", "code", "token"}, + GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, + Scope: "fosite,openid,photos,offline", }, { - LegacyClientID: "encoded:client", - Secret: "encoded&password", - RedirectURIs: []string{"http://localhost:3846/callback"}, - ResponseTypes: []string{"id_token", "code", "token"}, - GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, - Scope: "fosite,openid,photos,offline", + ID: "encoded:client", + Secret: "encoded&password", + RedirectURIs: []string{"http://localhost:3846/callback"}, + ResponseTypes: []string{"id_token", "code", "token"}, + GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, + Scope: "fosite,openid,photos,offline", }, } { // #nosec G601 diff --git a/internal/httpclient/.openapi-generator/FILES b/internal/httpclient/.openapi-generator/FILES index c83b13fa739..d0e465ce1c3 100644 --- a/internal/httpclient/.openapi-generator/FILES +++ b/internal/httpclient/.openapi-generator/FILES @@ -14,6 +14,8 @@ docs/AcceptOAuth2ConsentRequest.md docs/AcceptOAuth2ConsentRequestSession.md docs/AcceptOAuth2LoginRequest.md docs/CreateJsonWebKeySet.md +docs/CreateVerifiableCredentialRequestBody.md +docs/CredentialSupportedDraft00.md docs/ErrorOAuth2.md docs/GenericError.md docs/GetVersion200Response.md @@ -25,9 +27,9 @@ docs/IsReady503Response.md docs/JsonPatch.md docs/JsonWebKey.md docs/JsonWebKeySet.md -docs/JwkApi.md -docs/MetadataApi.md -docs/OAuth2Api.md +docs/JwkAPI.md +docs/MetadataAPI.md +docs/OAuth2API.md docs/OAuth2Client.md docs/OAuth2ClientTokenLifespans.md docs/OAuth2ConsentRequest.md @@ -38,11 +40,12 @@ docs/OAuth2LoginRequest.md docs/OAuth2LogoutRequest.md docs/OAuth2RedirectTo.md docs/OAuth2TokenExchange.md -docs/OidcApi.md +docs/OidcAPI.md docs/OidcConfiguration.md docs/OidcUserInfo.md docs/Pagination.md docs/PaginationHeaders.md +docs/RFC6749ErrorJson.md docs/RejectOAuth2Request.md docs/TokenPagination.md docs/TokenPaginationHeaders.md @@ -51,8 +54,11 @@ docs/TokenPaginationResponseHeaders.md docs/TrustOAuth2JwtGrantIssuer.md docs/TrustedOAuth2JwtGrantIssuer.md docs/TrustedOAuth2JwtGrantJsonWebKey.md +docs/VerifiableCredentialPrimingResponse.md +docs/VerifiableCredentialProof.md +docs/VerifiableCredentialResponse.md docs/Version.md -docs/WellknownApi.md +docs/WellknownAPI.md git_push.sh go.mod go.sum @@ -60,6 +66,8 @@ model_accept_o_auth2_consent_request.go model_accept_o_auth2_consent_request_session.go model_accept_o_auth2_login_request.go model_create_json_web_key_set.go +model_create_verifiable_credential_request_body.go +model_credential_supported_draft00.go model_error_o_auth2.go model_generic_error.go model_get_version_200_response.go @@ -86,6 +94,7 @@ model_oidc_user_info.go model_pagination.go model_pagination_headers.go model_reject_o_auth2_request.go +model_rfc6749_error_json.go model_token_pagination.go model_token_pagination_headers.go model_token_pagination_request_parameters.go @@ -93,6 +102,9 @@ model_token_pagination_response_headers.go model_trust_o_auth2_jwt_grant_issuer.go model_trusted_o_auth2_jwt_grant_issuer.go model_trusted_o_auth2_jwt_grant_json_web_key.go +model_verifiable_credential_priming_response.go +model_verifiable_credential_proof.go +model_verifiable_credential_response.go model_version.go response.go utils.go diff --git a/internal/httpclient/.openapi-generator/VERSION b/internal/httpclient/.openapi-generator/VERSION index 6d54bbd7751..4b49d9bb63e 100644 --- a/internal/httpclient/.openapi-generator/VERSION +++ b/internal/httpclient/.openapi-generator/VERSION @@ -1 +1 @@ -6.0.1 \ No newline at end of file +7.2.0 \ No newline at end of file diff --git a/internal/httpclient/README.md b/internal/httpclient/README.md index 0a0f60380d1..a2f17fd7fe5 100644 --- a/internal/httpclient/README.md +++ b/internal/httpclient/README.md @@ -14,7 +14,7 @@ This API client was generated by the [OpenAPI Generator](https://openapi-generat Install the following dependencies: -```shell +```sh go get github.com/stretchr/testify/assert go get golang.org/x/oauth2 go get golang.org/x/net/context @@ -22,13 +22,13 @@ go get golang.org/x/net/context Put the package under your project folder and add the following in import: -```golang -import openapi "github.com/ory/hydra-client-go" +```go +import openapi "github.com/ory/hydra-client-go/v2" ``` To use a proxy, set the environment variable `HTTP_PROXY`: -```golang +```go os.Setenv("HTTP_PROXY", "http://proxy_name:proxy_port") ``` @@ -38,17 +38,17 @@ Default configuration comes with `Servers` field that contains server objects as ### Select Server Configuration -For using other server than the one defined on index 0 set context value `sw.ContextServerIndex` of type `int`. +For using other server than the one defined on index 0 set context value `openapi.ContextServerIndex` of type `int`. -```golang +```go ctx := context.WithValue(context.Background(), openapi.ContextServerIndex, 1) ``` ### Templated Server URL -Templated server URL is formatted using default variables from configuration or from context value `sw.ContextServerVariables` of type `map[string]string`. +Templated server URL is formatted using default variables from configuration or from context value `openapi.ContextServerVariables` of type `map[string]string`. -```golang +```go ctx := context.WithValue(context.Background(), openapi.ContextServerVariables, map[string]string{ "basePath": "v2", }) @@ -60,9 +60,9 @@ Note, enum values are always validated and all unused variables are silently ign Each operation can use different server URL defined using `OperationServers` map in the `Configuration`. An operation is uniquely identified by `"{classname}Service.{nickname}"` string. -Similar rules for overriding default operation server index and variables applies by using `sw.ContextOperationServerIndices` and `sw.ContextOperationServerVariables` context maps. +Similar rules for overriding default operation server index and variables applies by using `openapi.ContextOperationServerIndices` and `openapi.ContextOperationServerVariables` context maps. -``` +```go ctx := context.WithValue(context.Background(), openapi.ContextOperationServerIndices, map[string]int{ "{classname}Service.{nickname}": 2, }) @@ -79,52 +79,53 @@ All URIs are relative to *http://localhost* Class | Method | HTTP request | Description ------------ | ------------- | ------------- | ------------- -*JwkApi* | [**CreateJsonWebKeySet**](docs/JwkApi.md#createjsonwebkeyset) | **Post** /admin/keys/{set} | Create JSON Web Key -*JwkApi* | [**DeleteJsonWebKey**](docs/JwkApi.md#deletejsonwebkey) | **Delete** /admin/keys/{set}/{kid} | Delete JSON Web Key -*JwkApi* | [**DeleteJsonWebKeySet**](docs/JwkApi.md#deletejsonwebkeyset) | **Delete** /admin/keys/{set} | Delete JSON Web Key Set -*JwkApi* | [**GetJsonWebKey**](docs/JwkApi.md#getjsonwebkey) | **Get** /admin/keys/{set}/{kid} | Get JSON Web Key -*JwkApi* | [**GetJsonWebKeySet**](docs/JwkApi.md#getjsonwebkeyset) | **Get** /admin/keys/{set} | Retrieve a JSON Web Key Set -*JwkApi* | [**SetJsonWebKey**](docs/JwkApi.md#setjsonwebkey) | **Put** /admin/keys/{set}/{kid} | Set JSON Web Key -*JwkApi* | [**SetJsonWebKeySet**](docs/JwkApi.md#setjsonwebkeyset) | **Put** /admin/keys/{set} | Update a JSON Web Key Set -*MetadataApi* | [**GetVersion**](docs/MetadataApi.md#getversion) | **Get** /version | Return Running Software Version. -*MetadataApi* | [**IsAlive**](docs/MetadataApi.md#isalive) | **Get** /health/alive | Check HTTP Server Status -*MetadataApi* | [**IsReady**](docs/MetadataApi.md#isready) | **Get** /health/ready | Check HTTP Server and Database Status -*OAuth2Api* | [**AcceptOAuth2ConsentRequest**](docs/OAuth2Api.md#acceptoauth2consentrequest) | **Put** /admin/oauth2/auth/requests/consent/accept | Accept OAuth 2.0 Consent Request -*OAuth2Api* | [**AcceptOAuth2LoginRequest**](docs/OAuth2Api.md#acceptoauth2loginrequest) | **Put** /admin/oauth2/auth/requests/login/accept | Accept OAuth 2.0 Login Request -*OAuth2Api* | [**AcceptOAuth2LogoutRequest**](docs/OAuth2Api.md#acceptoauth2logoutrequest) | **Put** /admin/oauth2/auth/requests/logout/accept | Accept OAuth 2.0 Session Logout Request -*OAuth2Api* | [**CreateOAuth2Client**](docs/OAuth2Api.md#createoauth2client) | **Post** /admin/clients | Create OAuth 2.0 Client -*OAuth2Api* | [**DeleteOAuth2Client**](docs/OAuth2Api.md#deleteoauth2client) | **Delete** /admin/clients/{id} | Delete OAuth 2.0 Client -*OAuth2Api* | [**DeleteOAuth2Token**](docs/OAuth2Api.md#deleteoauth2token) | **Delete** /admin/oauth2/tokens | Delete OAuth 2.0 Access Tokens from specific OAuth 2.0 Client -*OAuth2Api* | [**DeleteTrustedOAuth2JwtGrantIssuer**](docs/OAuth2Api.md#deletetrustedoauth2jwtgrantissuer) | **Delete** /admin/trust/grants/jwt-bearer/issuers/{id} | Delete Trusted OAuth2 JWT Bearer Grant Type Issuer -*OAuth2Api* | [**GetOAuth2Client**](docs/OAuth2Api.md#getoauth2client) | **Get** /admin/clients/{id} | Get an OAuth 2.0 Client -*OAuth2Api* | [**GetOAuth2ConsentRequest**](docs/OAuth2Api.md#getoauth2consentrequest) | **Get** /admin/oauth2/auth/requests/consent | Get OAuth 2.0 Consent Request -*OAuth2Api* | [**GetOAuth2LoginRequest**](docs/OAuth2Api.md#getoauth2loginrequest) | **Get** /admin/oauth2/auth/requests/login | Get OAuth 2.0 Login Request -*OAuth2Api* | [**GetOAuth2LogoutRequest**](docs/OAuth2Api.md#getoauth2logoutrequest) | **Get** /admin/oauth2/auth/requests/logout | Get OAuth 2.0 Session Logout Request -*OAuth2Api* | [**GetTrustedOAuth2JwtGrantIssuer**](docs/OAuth2Api.md#gettrustedoauth2jwtgrantissuer) | **Get** /admin/trust/grants/jwt-bearer/issuers/{id} | Get Trusted OAuth2 JWT Bearer Grant Type Issuer -*OAuth2Api* | [**IntrospectOAuth2Token**](docs/OAuth2Api.md#introspectoauth2token) | **Post** /admin/oauth2/introspect | Introspect OAuth2 Access and Refresh Tokens -*OAuth2Api* | [**ListOAuth2Clients**](docs/OAuth2Api.md#listoauth2clients) | **Get** /admin/clients | List OAuth 2.0 Clients -*OAuth2Api* | [**ListOAuth2ConsentSessions**](docs/OAuth2Api.md#listoauth2consentsessions) | **Get** /admin/oauth2/auth/sessions/consent | List OAuth 2.0 Consent Sessions of a Subject -*OAuth2Api* | [**ListTrustedOAuth2JwtGrantIssuers**](docs/OAuth2Api.md#listtrustedoauth2jwtgrantissuers) | **Get** /admin/trust/grants/jwt-bearer/issuers | List Trusted OAuth2 JWT Bearer Grant Type Issuers -*OAuth2Api* | [**OAuth2Authorize**](docs/OAuth2Api.md#oauth2authorize) | **Get** /oauth2/auth | OAuth 2.0 Authorize Endpoint -*OAuth2Api* | [**Oauth2TokenExchange**](docs/OAuth2Api.md#oauth2tokenexchange) | **Post** /oauth2/token | The OAuth 2.0 Token Endpoint -*OAuth2Api* | [**PatchOAuth2Client**](docs/OAuth2Api.md#patchoauth2client) | **Patch** /admin/clients/{id} | Patch OAuth 2.0 Client -*OAuth2Api* | [**RejectOAuth2ConsentRequest**](docs/OAuth2Api.md#rejectoauth2consentrequest) | **Put** /admin/oauth2/auth/requests/consent/reject | Reject OAuth 2.0 Consent Request -*OAuth2Api* | [**RejectOAuth2LoginRequest**](docs/OAuth2Api.md#rejectoauth2loginrequest) | **Put** /admin/oauth2/auth/requests/login/reject | Reject OAuth 2.0 Login Request -*OAuth2Api* | [**RejectOAuth2LogoutRequest**](docs/OAuth2Api.md#rejectoauth2logoutrequest) | **Put** /admin/oauth2/auth/requests/logout/reject | Reject OAuth 2.0 Session Logout Request -*OAuth2Api* | [**RevokeOAuth2ConsentSessions**](docs/OAuth2Api.md#revokeoauth2consentsessions) | **Delete** /admin/oauth2/auth/sessions/consent | Revoke OAuth 2.0 Consent Sessions of a Subject -*OAuth2Api* | [**RevokeOAuth2LoginSessions**](docs/OAuth2Api.md#revokeoauth2loginsessions) | **Delete** /admin/oauth2/auth/sessions/login | Revokes All OAuth 2.0 Login Sessions of a Subject -*OAuth2Api* | [**RevokeOAuth2Token**](docs/OAuth2Api.md#revokeoauth2token) | **Post** /oauth2/revoke | Revoke OAuth 2.0 Access or Refresh Token -*OAuth2Api* | [**SetOAuth2Client**](docs/OAuth2Api.md#setoauth2client) | **Put** /admin/clients/{id} | Set OAuth 2.0 Client -*OAuth2Api* | [**SetOAuth2ClientLifespans**](docs/OAuth2Api.md#setoauth2clientlifespans) | **Put** /admin/clients/{id}/lifespans | Set OAuth2 Client Token Lifespans -*OAuth2Api* | [**TrustOAuth2JwtGrantIssuer**](docs/OAuth2Api.md#trustoauth2jwtgrantissuer) | **Post** /admin/trust/grants/jwt-bearer/issuers | Trust OAuth2 JWT Bearer Grant Type Issuer -*OidcApi* | [**CreateOidcDynamicClient**](docs/OidcApi.md#createoidcdynamicclient) | **Post** /oauth2/register | Register OAuth2 Client using OpenID Dynamic Client Registration -*OidcApi* | [**DeleteOidcDynamicClient**](docs/OidcApi.md#deleteoidcdynamicclient) | **Delete** /oauth2/register/{id} | Delete OAuth 2.0 Client using the OpenID Dynamic Client Registration Management Protocol -*OidcApi* | [**DiscoverOidcConfiguration**](docs/OidcApi.md#discoveroidcconfiguration) | **Get** /.well-known/openid-configuration | OpenID Connect Discovery -*OidcApi* | [**GetOidcDynamicClient**](docs/OidcApi.md#getoidcdynamicclient) | **Get** /oauth2/register/{id} | Get OAuth2 Client using OpenID Dynamic Client Registration -*OidcApi* | [**GetOidcUserInfo**](docs/OidcApi.md#getoidcuserinfo) | **Get** /userinfo | OpenID Connect Userinfo -*OidcApi* | [**RevokeOidcSession**](docs/OidcApi.md#revokeoidcsession) | **Get** /oauth2/sessions/logout | OpenID Connect Front- and Back-channel Enabled Logout -*OidcApi* | [**SetOidcDynamicClient**](docs/OidcApi.md#setoidcdynamicclient) | **Put** /oauth2/register/{id} | Set OAuth2 Client using OpenID Dynamic Client Registration -*WellknownApi* | [**DiscoverJsonWebKeys**](docs/WellknownApi.md#discoverjsonwebkeys) | **Get** /.well-known/jwks.json | Discover Well-Known JSON Web Keys +*JwkAPI* | [**CreateJsonWebKeySet**](docs/JwkAPI.md#createjsonwebkeyset) | **Post** /admin/keys/{set} | Create JSON Web Key +*JwkAPI* | [**DeleteJsonWebKey**](docs/JwkAPI.md#deletejsonwebkey) | **Delete** /admin/keys/{set}/{kid} | Delete JSON Web Key +*JwkAPI* | [**DeleteJsonWebKeySet**](docs/JwkAPI.md#deletejsonwebkeyset) | **Delete** /admin/keys/{set} | Delete JSON Web Key Set +*JwkAPI* | [**GetJsonWebKey**](docs/JwkAPI.md#getjsonwebkey) | **Get** /admin/keys/{set}/{kid} | Get JSON Web Key +*JwkAPI* | [**GetJsonWebKeySet**](docs/JwkAPI.md#getjsonwebkeyset) | **Get** /admin/keys/{set} | Retrieve a JSON Web Key Set +*JwkAPI* | [**SetJsonWebKey**](docs/JwkAPI.md#setjsonwebkey) | **Put** /admin/keys/{set}/{kid} | Set JSON Web Key +*JwkAPI* | [**SetJsonWebKeySet**](docs/JwkAPI.md#setjsonwebkeyset) | **Put** /admin/keys/{set} | Update a JSON Web Key Set +*MetadataAPI* | [**GetVersion**](docs/MetadataAPI.md#getversion) | **Get** /version | Return Running Software Version. +*MetadataAPI* | [**IsAlive**](docs/MetadataAPI.md#isalive) | **Get** /health/alive | Check HTTP Server Status +*MetadataAPI* | [**IsReady**](docs/MetadataAPI.md#isready) | **Get** /health/ready | Check HTTP Server and Database Status +*OAuth2API* | [**AcceptOAuth2ConsentRequest**](docs/OAuth2API.md#acceptoauth2consentrequest) | **Put** /admin/oauth2/auth/requests/consent/accept | Accept OAuth 2.0 Consent Request +*OAuth2API* | [**AcceptOAuth2LoginRequest**](docs/OAuth2API.md#acceptoauth2loginrequest) | **Put** /admin/oauth2/auth/requests/login/accept | Accept OAuth 2.0 Login Request +*OAuth2API* | [**AcceptOAuth2LogoutRequest**](docs/OAuth2API.md#acceptoauth2logoutrequest) | **Put** /admin/oauth2/auth/requests/logout/accept | Accept OAuth 2.0 Session Logout Request +*OAuth2API* | [**CreateOAuth2Client**](docs/OAuth2API.md#createoauth2client) | **Post** /admin/clients | Create OAuth 2.0 Client +*OAuth2API* | [**DeleteOAuth2Client**](docs/OAuth2API.md#deleteoauth2client) | **Delete** /admin/clients/{id} | Delete OAuth 2.0 Client +*OAuth2API* | [**DeleteOAuth2Token**](docs/OAuth2API.md#deleteoauth2token) | **Delete** /admin/oauth2/tokens | Delete OAuth 2.0 Access Tokens from specific OAuth 2.0 Client +*OAuth2API* | [**DeleteTrustedOAuth2JwtGrantIssuer**](docs/OAuth2API.md#deletetrustedoauth2jwtgrantissuer) | **Delete** /admin/trust/grants/jwt-bearer/issuers/{id} | Delete Trusted OAuth2 JWT Bearer Grant Type Issuer +*OAuth2API* | [**GetOAuth2Client**](docs/OAuth2API.md#getoauth2client) | **Get** /admin/clients/{id} | Get an OAuth 2.0 Client +*OAuth2API* | [**GetOAuth2ConsentRequest**](docs/OAuth2API.md#getoauth2consentrequest) | **Get** /admin/oauth2/auth/requests/consent | Get OAuth 2.0 Consent Request +*OAuth2API* | [**GetOAuth2LoginRequest**](docs/OAuth2API.md#getoauth2loginrequest) | **Get** /admin/oauth2/auth/requests/login | Get OAuth 2.0 Login Request +*OAuth2API* | [**GetOAuth2LogoutRequest**](docs/OAuth2API.md#getoauth2logoutrequest) | **Get** /admin/oauth2/auth/requests/logout | Get OAuth 2.0 Session Logout Request +*OAuth2API* | [**GetTrustedOAuth2JwtGrantIssuer**](docs/OAuth2API.md#gettrustedoauth2jwtgrantissuer) | **Get** /admin/trust/grants/jwt-bearer/issuers/{id} | Get Trusted OAuth2 JWT Bearer Grant Type Issuer +*OAuth2API* | [**IntrospectOAuth2Token**](docs/OAuth2API.md#introspectoauth2token) | **Post** /admin/oauth2/introspect | Introspect OAuth2 Access and Refresh Tokens +*OAuth2API* | [**ListOAuth2Clients**](docs/OAuth2API.md#listoauth2clients) | **Get** /admin/clients | List OAuth 2.0 Clients +*OAuth2API* | [**ListOAuth2ConsentSessions**](docs/OAuth2API.md#listoauth2consentsessions) | **Get** /admin/oauth2/auth/sessions/consent | List OAuth 2.0 Consent Sessions of a Subject +*OAuth2API* | [**ListTrustedOAuth2JwtGrantIssuers**](docs/OAuth2API.md#listtrustedoauth2jwtgrantissuers) | **Get** /admin/trust/grants/jwt-bearer/issuers | List Trusted OAuth2 JWT Bearer Grant Type Issuers +*OAuth2API* | [**OAuth2Authorize**](docs/OAuth2API.md#oauth2authorize) | **Get** /oauth2/auth | OAuth 2.0 Authorize Endpoint +*OAuth2API* | [**Oauth2TokenExchange**](docs/OAuth2API.md#oauth2tokenexchange) | **Post** /oauth2/token | The OAuth 2.0 Token Endpoint +*OAuth2API* | [**PatchOAuth2Client**](docs/OAuth2API.md#patchoauth2client) | **Patch** /admin/clients/{id} | Patch OAuth 2.0 Client +*OAuth2API* | [**RejectOAuth2ConsentRequest**](docs/OAuth2API.md#rejectoauth2consentrequest) | **Put** /admin/oauth2/auth/requests/consent/reject | Reject OAuth 2.0 Consent Request +*OAuth2API* | [**RejectOAuth2LoginRequest**](docs/OAuth2API.md#rejectoauth2loginrequest) | **Put** /admin/oauth2/auth/requests/login/reject | Reject OAuth 2.0 Login Request +*OAuth2API* | [**RejectOAuth2LogoutRequest**](docs/OAuth2API.md#rejectoauth2logoutrequest) | **Put** /admin/oauth2/auth/requests/logout/reject | Reject OAuth 2.0 Session Logout Request +*OAuth2API* | [**RevokeOAuth2ConsentSessions**](docs/OAuth2API.md#revokeoauth2consentsessions) | **Delete** /admin/oauth2/auth/sessions/consent | Revoke OAuth 2.0 Consent Sessions of a Subject +*OAuth2API* | [**RevokeOAuth2LoginSessions**](docs/OAuth2API.md#revokeoauth2loginsessions) | **Delete** /admin/oauth2/auth/sessions/login | Revokes OAuth 2.0 Login Sessions by either a Subject or a SessionID +*OAuth2API* | [**RevokeOAuth2Token**](docs/OAuth2API.md#revokeoauth2token) | **Post** /oauth2/revoke | Revoke OAuth 2.0 Access or Refresh Token +*OAuth2API* | [**SetOAuth2Client**](docs/OAuth2API.md#setoauth2client) | **Put** /admin/clients/{id} | Set OAuth 2.0 Client +*OAuth2API* | [**SetOAuth2ClientLifespans**](docs/OAuth2API.md#setoauth2clientlifespans) | **Put** /admin/clients/{id}/lifespans | Set OAuth2 Client Token Lifespans +*OAuth2API* | [**TrustOAuth2JwtGrantIssuer**](docs/OAuth2API.md#trustoauth2jwtgrantissuer) | **Post** /admin/trust/grants/jwt-bearer/issuers | Trust OAuth2 JWT Bearer Grant Type Issuer +*OidcAPI* | [**CreateOidcDynamicClient**](docs/OidcAPI.md#createoidcdynamicclient) | **Post** /oauth2/register | Register OAuth2 Client using OpenID Dynamic Client Registration +*OidcAPI* | [**CreateVerifiableCredential**](docs/OidcAPI.md#createverifiablecredential) | **Post** /credentials | Issues a Verifiable Credential +*OidcAPI* | [**DeleteOidcDynamicClient**](docs/OidcAPI.md#deleteoidcdynamicclient) | **Delete** /oauth2/register/{id} | Delete OAuth 2.0 Client using the OpenID Dynamic Client Registration Management Protocol +*OidcAPI* | [**DiscoverOidcConfiguration**](docs/OidcAPI.md#discoveroidcconfiguration) | **Get** /.well-known/openid-configuration | OpenID Connect Discovery +*OidcAPI* | [**GetOidcDynamicClient**](docs/OidcAPI.md#getoidcdynamicclient) | **Get** /oauth2/register/{id} | Get OAuth2 Client using OpenID Dynamic Client Registration +*OidcAPI* | [**GetOidcUserInfo**](docs/OidcAPI.md#getoidcuserinfo) | **Get** /userinfo | OpenID Connect Userinfo +*OidcAPI* | [**RevokeOidcSession**](docs/OidcAPI.md#revokeoidcsession) | **Get** /oauth2/sessions/logout | OpenID Connect Front- and Back-channel Enabled Logout +*OidcAPI* | [**SetOidcDynamicClient**](docs/OidcAPI.md#setoidcdynamicclient) | **Put** /oauth2/register/{id} | Set OAuth2 Client using OpenID Dynamic Client Registration +*WellknownAPI* | [**DiscoverJsonWebKeys**](docs/WellknownAPI.md#discoverjsonwebkeys) | **Get** /.well-known/jwks.json | Discover Well-Known JSON Web Keys ## Documentation For Models @@ -133,6 +134,8 @@ Class | Method | HTTP request | Description - [AcceptOAuth2ConsentRequestSession](docs/AcceptOAuth2ConsentRequestSession.md) - [AcceptOAuth2LoginRequest](docs/AcceptOAuth2LoginRequest.md) - [CreateJsonWebKeySet](docs/CreateJsonWebKeySet.md) + - [CreateVerifiableCredentialRequestBody](docs/CreateVerifiableCredentialRequestBody.md) + - [CredentialSupportedDraft00](docs/CredentialSupportedDraft00.md) - [ErrorOAuth2](docs/ErrorOAuth2.md) - [GenericError](docs/GenericError.md) - [GetVersion200Response](docs/GetVersion200Response.md) @@ -158,6 +161,7 @@ Class | Method | HTTP request | Description - [OidcUserInfo](docs/OidcUserInfo.md) - [Pagination](docs/Pagination.md) - [PaginationHeaders](docs/PaginationHeaders.md) + - [RFC6749ErrorJson](docs/RFC6749ErrorJson.md) - [RejectOAuth2Request](docs/RejectOAuth2Request.md) - [TokenPagination](docs/TokenPagination.md) - [TokenPaginationHeaders](docs/TokenPaginationHeaders.md) @@ -166,40 +170,41 @@ Class | Method | HTTP request | Description - [TrustOAuth2JwtGrantIssuer](docs/TrustOAuth2JwtGrantIssuer.md) - [TrustedOAuth2JwtGrantIssuer](docs/TrustedOAuth2JwtGrantIssuer.md) - [TrustedOAuth2JwtGrantJsonWebKey](docs/TrustedOAuth2JwtGrantJsonWebKey.md) + - [VerifiableCredentialPrimingResponse](docs/VerifiableCredentialPrimingResponse.md) + - [VerifiableCredentialProof](docs/VerifiableCredentialProof.md) + - [VerifiableCredentialResponse](docs/VerifiableCredentialResponse.md) - [Version](docs/Version.md) ## Documentation For Authorization - +Authentication schemes defined for the API: ### basic - **Type**: HTTP basic authentication Example -```golang -auth := context.WithValue(context.Background(), sw.ContextBasicAuth, sw.BasicAuth{ - UserName: "username", - Password: "password", +```go +auth := context.WithValue(context.Background(), openapi.ContextBasicAuth, openapi.BasicAuth{ + UserName: "username", + Password: "password", }) r, err := client.Service.Operation(auth, args) ``` - ### bearer - **Type**: HTTP Bearer token authentication Example -```golang -auth := context.WithValue(context.Background(), sw.ContextAccessToken, "BEARER_TOKEN_STRING") +```go +auth := context.WithValue(context.Background(), openapi.ContextAccessToken, "BEARER_TOKEN_STRING") r, err := client.Service.Operation(auth, args) ``` - ### oauth2 @@ -213,20 +218,20 @@ r, err := client.Service.Operation(auth, args) Example -```golang -auth := context.WithValue(context.Background(), sw.ContextAccessToken, "ACCESSTOKENSTRING") +```go +auth := context.WithValue(context.Background(), openapi.ContextAccessToken, "ACCESSTOKENSTRING") r, err := client.Service.Operation(auth, args) ``` Or via OAuth2 module to automatically refresh tokens and perform user authentication. -```golang +```go import "golang.org/x/oauth2" /* Perform OAuth2 round trip request and obtain a token */ tokenSource := oauth2cfg.TokenSource(createContext(httpClient), &token) -auth := context.WithValue(oauth2.NoContext, sw.ContextOAuth2, tokenSource) +auth := context.WithValue(oauth2.NoContext, openapi.ContextOAuth2, tokenSource) r, err := client.Service.Operation(auth, args) ``` diff --git a/internal/httpclient/api/openapi.yaml b/internal/httpclient/api/openapi.yaml index b75395441f0..b0fa5a54ade 100644 --- a/internal/httpclient/api/openapi.yaml +++ b/internal/httpclient/api/openapi.yaml @@ -24,10 +24,13 @@ tags: paths: /.well-known/jwks.json: get: - description: "This endpoint returns JSON Web Keys required to verifying OpenID\ - \ Connect ID Tokens and,\nif enabled, OAuth 2.0 JWT Access Tokens. This endpoint\ - \ can be used with client libraries like\n[node-jwks-rsa](https://github.com/auth0/node-jwks-rsa)\ - \ among others." + description: |- + This endpoint returns JSON Web Keys required to verifying OpenID Connect ID Tokens and, + if enabled, OAuth 2.0 JWT Access Tokens. This endpoint can be used with client libraries like + [node-jwks-rsa](https://github.com/auth0/node-jwks-rsa) among others. + + Adding custom keys requires first creating a keyset via the createJsonWebKeySet operation, + and then configuring the webfinger.jwks.broadcast_keys configuration value to include the keyset name. operationId: discoverJsonWebKeys responses: "200": @@ -47,11 +50,11 @@ paths: - wellknown /.well-known/openid-configuration: get: - description: "A mechanism for an OpenID Connect Relying Party to discover the\ - \ End-User's OpenID Provider and obtain information needed to interact with\ - \ it, including its OAuth 2.0 endpoint locations.\n\nPopular libraries for\ - \ OpenID Connect clients include oidc-client-js (JavaScript), go-oidc (Golang),\ - \ and others.\nFor a full list of clients go here: https://openid.net/developers/certified/" + description: |- + A mechanism for an OpenID Connect Relying Party to discover the End-User's OpenID Provider and obtain information needed to interact with it, including its OAuth 2.0 endpoint locations. + + Popular libraries for OpenID Connect clients include oidc-client-js (JavaScript), go-oidc (Golang), and others. + For a full list of clients go here: https://openid.net/developers/certified/ operationId: discoverOidcConfiguration responses: "200": @@ -71,12 +74,16 @@ paths: - oidc /admin/clients: get: - description: "This endpoint lists all clients in the database, and never returns\ - \ client secrets.\nAs a default it lists the first 100 clients." + description: |- + This endpoint lists all clients in the database, and never returns client secrets. + As a default it lists the first 100 clients. operationId: listOAuth2Clients parameters: - - description: "Items per Page\n\nThis is the number of items per page to return.\n\ - For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + - description: |- + Items per Page + + This is the number of items per page to return. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). explode: true in: query name: page_size @@ -88,8 +95,11 @@ paths: minimum: 1 type: integer style: form - - description: "Next Page Token\n\nThe next page token.\nFor details on pagination\ - \ please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + - description: |- + Next Page Token + + The next page token. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). explode: true in: query name: page_token @@ -134,9 +144,9 @@ paths: tags: - oAuth2 post: - description: "Create a new OAuth 2.0 client. If you pass `client_secret` the\ - \ secret is used, otherwise a random secret\nis generated. The secret is echoed\ - \ in the response. It is not possible to retrieve it later on." + description: |- + Create a new OAuth 2.0 client. If you pass `client_secret` the secret is used, otherwise a random secret + is generated. The secret is echoed in the response. It is not possible to retrieve it later on. operationId: createOAuth2Client requestBody: content: @@ -170,11 +180,13 @@ paths: - oAuth2 /admin/clients/{id}: delete: - description: "Delete an existing OAuth 2.0 Client by its ID.\n\nOAuth 2.0 clients\ - \ are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0\ - \ clients are\ngenerated for applications which want to consume your OAuth\ - \ 2.0 or OpenID Connect capabilities.\n\nMake sure that this endpoint is well\ - \ protected and only callable by first-party components." + description: |- + Delete an existing OAuth 2.0 Client by its ID. + + OAuth 2.0 clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are + generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities. + + Make sure that this endpoint is well protected and only callable by first-party components. operationId: deleteOAuth2Client parameters: - description: The id of the OAuth 2.0 Client. @@ -187,8 +199,9 @@ paths: style: simple responses: "204": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -199,10 +212,11 @@ paths: tags: - oAuth2 get: - description: "Get an OAuth 2.0 client by its ID. This endpoint never returns\ - \ the client secret.\n\nOAuth 2.0 clients are used to perform OAuth 2.0 and\ - \ OpenID Connect flows. Usually, OAuth 2.0 clients are\ngenerated for applications\ - \ which want to consume your OAuth 2.0 or OpenID Connect capabilities." + description: |- + Get an OAuth 2.0 client by its ID. This endpoint never returns the client secret. + + OAuth 2.0 clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are + generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities. operationId: getOAuth2Client parameters: - description: The id of the OAuth 2.0 Client. @@ -230,13 +244,13 @@ paths: tags: - oAuth2 patch: - description: "Patch an existing OAuth 2.0 Client using JSON Patch. If you pass\ - \ `client_secret`\nthe secret will be updated and returned via the API. This\ - \ is the\nonly time you will be able to retrieve the client secret, so write\ - \ it down and keep it safe.\n\nOAuth 2.0 clients are used to perform OAuth\ - \ 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are\ngenerated\ - \ for applications which want to consume your OAuth 2.0 or OpenID Connect\ - \ capabilities." + description: |- + Patch an existing OAuth 2.0 Client using JSON Patch. If you pass `client_secret` + the secret will be updated and returned via the API. This is the + only time you will be able to retrieve the client secret, so write it down and keep it safe. + + OAuth 2.0 clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are + generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities. operationId: patchOAuth2Client parameters: - description: The id of the OAuth 2.0 Client. @@ -278,13 +292,14 @@ paths: tags: - oAuth2 put: - description: "Replaces an existing OAuth 2.0 Client with the payload you send.\ - \ If you pass `client_secret` the secret is used,\notherwise the existing\ - \ secret is used.\n\nIf set, the secret is echoed in the response. It is not\ - \ possible to retrieve it later on.\n\nOAuth 2.0 Clients are used to perform\ - \ OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are\ngenerated\ - \ for applications which want to consume your OAuth 2.0 or OpenID Connect\ - \ capabilities." + description: |- + Replaces an existing OAuth 2.0 Client with the payload you send. If you pass `client_secret` the secret is used, + otherwise the existing secret is used. + + If set, the secret is echoed in the response. It is not possible to retrieve it later on. + + OAuth 2.0 Clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are + generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities. operationId: setOAuth2Client parameters: - description: OAuth 2.0 Client ID @@ -369,13 +384,10 @@ paths: - oAuth2 /admin/keys/{set}: delete: - description: "Use this endpoint to delete a complete JSON Web Key Set and all\ - \ the keys in that set.\n\nA JSON Web Key (JWK) is a JavaScript Object Notation\ - \ (JSON) data structure that represents a cryptographic key. A JWK Set is\ - \ a JSON data structure that represents a set of JWKs. A JSON Web Key is identified\ - \ by its set and key id. ORY Hydra uses this functionality to store cryptographic\ - \ keys used for TLS and JSON Web Tokens (such as OpenID Connect ID tokens),\ - \ and allows storing user-defined keys as well." + description: |- + Use this endpoint to delete a complete JSON Web Key Set and all the keys in that set. + + A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that represents a cryptographic key. A JWK Set is a JSON data structure that represents a set of JWKs. A JSON Web Key is identified by its set and key id. ORY Hydra uses this functionality to store cryptographic keys used for TLS and JSON Web Tokens (such as OpenID Connect ID tokens), and allows storing user-defined keys as well. operationId: deleteJsonWebKeySet parameters: - description: The JSON Web Key Set @@ -388,8 +400,9 @@ paths: style: simple responses: "204": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -400,13 +413,10 @@ paths: tags: - jwk get: - description: "This endpoint can be used to retrieve JWK Sets stored in ORY Hydra.\n\ - \nA JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure\ - \ that represents a cryptographic key. A JWK Set is a JSON data structure\ - \ that represents a set of JWKs. A JSON Web Key is identified by its set and\ - \ key id. ORY Hydra uses this functionality to store cryptographic keys used\ - \ for TLS and JSON Web Tokens (such as OpenID Connect ID tokens), and allows\ - \ storing user-defined keys as well." + description: |- + This endpoint can be used to retrieve JWK Sets stored in ORY Hydra. + + A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that represents a cryptographic key. A JWK Set is a JSON data structure that represents a set of JWKs. A JSON Web Key is identified by its set and key id. ORY Hydra uses this functionality to store cryptographic keys used for TLS and JSON Web Tokens (such as OpenID Connect ID tokens), and allows storing user-defined keys as well. operationId: getJsonWebKeySet parameters: - description: JSON Web Key Set ID @@ -434,16 +444,10 @@ paths: tags: - jwk post: - description: "This endpoint is capable of generating JSON Web Key Sets for you.\ - \ There a different strategies available, such as symmetric cryptographic\ - \ keys (HS256, HS512) and asymetric cryptographic keys (RS256, ECDSA). If\ - \ the specified JSON Web Key Set does not exist, it will be created.\n\nA\ - \ JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure\ - \ that represents a cryptographic key. A JWK Set is a JSON data structure\ - \ that represents a set of JWKs. A JSON Web Key is identified by its set and\ - \ key id. ORY Hydra uses this functionality to store cryptographic keys used\ - \ for TLS and JSON Web Tokens (such as OpenID Connect ID tokens), and allows\ - \ storing user-defined keys as well." + description: |- + This endpoint is capable of generating JSON Web Key Sets for you. There a different strategies available, such as symmetric cryptographic keys (HS256, HS512) and asymetric cryptographic keys (RS256, ECDSA). If the specified JSON Web Key Set does not exist, it will be created. + + A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that represents a cryptographic key. A JWK Set is a JSON data structure that represents a set of JWKs. A JSON Web Key is identified by its set and key id. ORY Hydra uses this functionality to store cryptographic keys used for TLS and JSON Web Tokens (such as OpenID Connect ID tokens), and allows storing user-defined keys as well. operationId: createJsonWebKeySet parameters: - description: The JSON Web Key Set ID @@ -478,13 +482,10 @@ paths: tags: - jwk put: - description: "Use this method if you do not want to let Hydra generate the JWKs\ - \ for you, but instead save your own.\n\nA JSON Web Key (JWK) is a JavaScript\ - \ Object Notation (JSON) data structure that represents a cryptographic key.\ - \ A JWK Set is a JSON data structure that represents a set of JWKs. A JSON\ - \ Web Key is identified by its set and key id. ORY Hydra uses this functionality\ - \ to store cryptographic keys used for TLS and JSON Web Tokens (such as OpenID\ - \ Connect ID tokens), and allows storing user-defined keys as well." + description: |- + Use this method if you do not want to let Hydra generate the JWKs for you, but instead save your own. + + A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that represents a cryptographic key. A JWK Set is a JSON data structure that represents a set of JWKs. A JSON Web Key is identified by its set and key id. ORY Hydra uses this functionality to store cryptographic keys used for TLS and JSON Web Tokens (such as OpenID Connect ID tokens), and allows storing user-defined keys as well. operationId: setJsonWebKeySet parameters: - description: The JSON Web Key Set ID @@ -519,13 +520,13 @@ paths: - jwk /admin/keys/{set}/{kid}: delete: - description: "Use this endpoint to delete a single JSON Web Key.\n\nA JSON Web\ - \ Key (JWK) is a JavaScript Object Notation (JSON) data structure that represents\ - \ a cryptographic key. A\nJWK Set is a JSON data structure that represents\ - \ a set of JWKs. A JSON Web Key is identified by its set and key id. ORY Hydra\ - \ uses\nthis functionality to store cryptographic keys used for TLS and JSON\ - \ Web Tokens (such as OpenID Connect ID tokens),\nand allows storing user-defined\ - \ keys as well." + description: |- + Use this endpoint to delete a single JSON Web Key. + + A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that represents a cryptographic key. A + JWK Set is a JSON data structure that represents a set of JWKs. A JSON Web Key is identified by its set and key id. ORY Hydra uses + this functionality to store cryptographic keys used for TLS and JSON Web Tokens (such as OpenID Connect ID tokens), + and allows storing user-defined keys as well. operationId: deleteJsonWebKey parameters: - description: The JSON Web Key Set @@ -546,8 +547,9 @@ paths: style: simple responses: "204": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -595,13 +597,10 @@ paths: tags: - jwk put: - description: "Use this method if you do not want to let Hydra generate the JWKs\ - \ for you, but instead save your own.\n\nA JSON Web Key (JWK) is a JavaScript\ - \ Object Notation (JSON) data structure that represents a cryptographic key.\ - \ A JWK Set is a JSON data structure that represents a set of JWKs. A JSON\ - \ Web Key is identified by its set and key id. ORY Hydra uses this functionality\ - \ to store cryptographic keys used for TLS and JSON Web Tokens (such as OpenID\ - \ Connect ID tokens), and allows storing user-defined keys as well." + description: |- + Use this method if you do not want to let Hydra generate the JWKs for you, but instead save your own. + + A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that represents a cryptographic key. A JWK Set is a JSON data structure that represents a set of JWKs. A JSON Web Key is identified by its set and key id. ORY Hydra uses this functionality to store cryptographic keys used for TLS and JSON Web Tokens (such as OpenID Connect ID tokens), and allows storing user-defined keys as well. operationId: setJsonWebKey parameters: - description: The JSON Web Key Set ID @@ -644,17 +643,17 @@ paths: - jwk /admin/oauth2/auth/requests/consent: get: - description: "When an authorization code, hybrid, or implicit OAuth 2.0 Flow\ - \ is initiated, Ory asks the login provider\nto authenticate the subject and\ - \ then tell Ory now about it. If the subject authenticated, he/she must now\ - \ be asked if\nthe OAuth 2.0 Client which initiated the flow should be allowed\ - \ to access the resources on the subject's behalf.\n\nThe consent challenge\ - \ is appended to the consent provider's URL to which the subject's user-agent\ - \ (browser) is redirected to. The consent\nprovider uses that challenge to\ - \ fetch information on the OAuth2 request and then tells Ory if the subject\ - \ accepted\nor rejected the request.\n\nThe default consent provider is available\ - \ via the Ory Managed Account Experience. To customize the consent provider,\ - \ please\nhead over to the OAuth 2.0 documentation." + description: |- + When an authorization code, hybrid, or implicit OAuth 2.0 Flow is initiated, Ory asks the login provider + to authenticate the subject and then tell Ory now about it. If the subject authenticated, he/she must now be asked if + the OAuth 2.0 Client which initiated the flow should be allowed to access the resources on the subject's behalf. + + The consent challenge is appended to the consent provider's URL to which the subject's user-agent (browser) is redirected to. The consent + provider uses that challenge to fetch information on the OAuth2 request and then tells Ory if the subject accepted + or rejected the request. + + The default consent provider is available via the Ory Managed Account Experience. To customize the consent provider, please + head over to the OAuth 2.0 documentation. operationId: getOAuth2ConsentRequest parameters: - description: OAuth 2.0 Consent Request Challenge @@ -689,22 +688,23 @@ paths: - oAuth2 /admin/oauth2/auth/requests/consent/accept: put: - description: "When an authorization code, hybrid, or implicit OAuth 2.0 Flow\ - \ is initiated, Ory asks the login provider\nto authenticate the subject and\ - \ then tell Ory now about it. If the subject authenticated, he/she must now\ - \ be asked if\nthe OAuth 2.0 Client which initiated the flow should be allowed\ - \ to access the resources on the subject's behalf.\n\nThe consent challenge\ - \ is appended to the consent provider's URL to which the subject's user-agent\ - \ (browser) is redirected to. The consent\nprovider uses that challenge to\ - \ fetch information on the OAuth2 request and then tells Ory if the subject\ - \ accepted\nor rejected the request.\n\nThis endpoint tells Ory that the subject\ - \ has authorized the OAuth 2.0 client to access resources on his/her behalf.\n\ - The consent provider includes additional information, such as session data\ - \ for access and ID tokens, and if the\nconsent request should be used as\ - \ basis for future requests.\n\nThe response contains a redirect URL which\ - \ the consent provider should redirect the user-agent to.\n\nThe default consent\ - \ provider is available via the Ory Managed Account Experience. To customize\ - \ the consent provider, please\nhead over to the OAuth 2.0 documentation." + description: |- + When an authorization code, hybrid, or implicit OAuth 2.0 Flow is initiated, Ory asks the login provider + to authenticate the subject and then tell Ory now about it. If the subject authenticated, he/she must now be asked if + the OAuth 2.0 Client which initiated the flow should be allowed to access the resources on the subject's behalf. + + The consent challenge is appended to the consent provider's URL to which the subject's user-agent (browser) is redirected to. The consent + provider uses that challenge to fetch information on the OAuth2 request and then tells Ory if the subject accepted + or rejected the request. + + This endpoint tells Ory that the subject has authorized the OAuth 2.0 client to access resources on his/her behalf. + The consent provider includes additional information, such as session data for access and ID tokens, and if the + consent request should be used as basis for future requests. + + The response contains a redirect URL which the consent provider should redirect the user-agent to. + + The default consent provider is available via the Ory Managed Account Experience. To customize the consent provider, please + head over to the OAuth 2.0 documentation. operationId: acceptOAuth2ConsentRequest parameters: - description: OAuth 2.0 Consent Request Challenge @@ -739,21 +739,22 @@ paths: - oAuth2 /admin/oauth2/auth/requests/consent/reject: put: - description: "When an authorization code, hybrid, or implicit OAuth 2.0 Flow\ - \ is initiated, Ory asks the login provider\nto authenticate the subject and\ - \ then tell Ory now about it. If the subject authenticated, he/she must now\ - \ be asked if\nthe OAuth 2.0 Client which initiated the flow should be allowed\ - \ to access the resources on the subject's behalf.\n\nThe consent challenge\ - \ is appended to the consent provider's URL to which the subject's user-agent\ - \ (browser) is redirected to. The consent\nprovider uses that challenge to\ - \ fetch information on the OAuth2 request and then tells Ory if the subject\ - \ accepted\nor rejected the request.\n\nThis endpoint tells Ory that the subject\ - \ has not authorized the OAuth 2.0 client to access resources on his/her behalf.\n\ - The consent provider must include a reason why the consent was not granted.\n\ - \nThe response contains a redirect URL which the consent provider should redirect\ - \ the user-agent to.\n\nThe default consent provider is available via the\ - \ Ory Managed Account Experience. To customize the consent provider, please\n\ - head over to the OAuth 2.0 documentation." + description: |- + When an authorization code, hybrid, or implicit OAuth 2.0 Flow is initiated, Ory asks the login provider + to authenticate the subject and then tell Ory now about it. If the subject authenticated, he/she must now be asked if + the OAuth 2.0 Client which initiated the flow should be allowed to access the resources on the subject's behalf. + + The consent challenge is appended to the consent provider's URL to which the subject's user-agent (browser) is redirected to. The consent + provider uses that challenge to fetch information on the OAuth2 request and then tells Ory if the subject accepted + or rejected the request. + + This endpoint tells Ory that the subject has not authorized the OAuth 2.0 client to access resources on his/her behalf. + The consent provider must include a reason why the consent was not granted. + + The response contains a redirect URL which the consent provider should redirect the user-agent to. + + The default consent provider is available via the Ory Managed Account Experience. To customize the consent provider, please + head over to the OAuth 2.0 documentation. operationId: rejectOAuth2ConsentRequest parameters: - description: OAuth 2.0 Consent Request Challenge @@ -788,17 +789,16 @@ paths: - oAuth2 /admin/oauth2/auth/requests/login: get: - description: "When an authorization code, hybrid, or implicit OAuth 2.0 Flow\ - \ is initiated, Ory asks the login provider\nto authenticate the subject and\ - \ then tell the Ory OAuth2 Service about it.\n\nPer default, the login provider\ - \ is Ory itself. You may use a different login provider which needs to be\ - \ a web-app\nyou write and host, and it must be able to authenticate (\"show\ - \ the subject a login screen\")\na subject (in OAuth2 the proper name for\ - \ subject is \"resource owner\").\n\nThe authentication challenge is appended\ - \ to the login provider URL to which the subject's user-agent (browser) is\ - \ redirected to. The login\nprovider uses that challenge to fetch information\ - \ on the OAuth2 request and then accept or reject the requested authentication\ - \ process." + description: |- + When an authorization code, hybrid, or implicit OAuth 2.0 Flow is initiated, Ory asks the login provider + to authenticate the subject and then tell the Ory OAuth2 Service about it. + + Per default, the login provider is Ory itself. You may use a different login provider which needs to be a web-app + you write and host, and it must be able to authenticate ("show the subject a login screen") + a subject (in OAuth2 the proper name for subject is "resource owner"). + + The authentication challenge is appended to the login provider URL to which the subject's user-agent (browser) is redirected to. The login + provider uses that challenge to fetch information on the OAuth2 request and then accept or reject the requested authentication process. operationId: getOAuth2LoginRequest parameters: - description: OAuth 2.0 Login Request Challenge @@ -833,17 +833,18 @@ paths: - oAuth2 /admin/oauth2/auth/requests/login/accept: put: - description: "When an authorization code, hybrid, or implicit OAuth 2.0 Flow\ - \ is initiated, Ory asks the login provider\nto authenticate the subject and\ - \ then tell the Ory OAuth2 Service about it.\n\nThe authentication challenge\ - \ is appended to the login provider URL to which the subject's user-agent\ - \ (browser) is redirected to. The login\nprovider uses that challenge to fetch\ - \ information on the OAuth2 request and then accept or reject the requested\ - \ authentication process.\n\nThis endpoint tells Ory that the subject has\ - \ successfully authenticated and includes additional information such as\n\ - the subject's ID and if Ory should remember the subject's subject agent for\ - \ future authentication attempts by setting\na cookie.\n\nThe response contains\ - \ a redirect URL which the login provider should redirect the user-agent to." + description: |- + When an authorization code, hybrid, or implicit OAuth 2.0 Flow is initiated, Ory asks the login provider + to authenticate the subject and then tell the Ory OAuth2 Service about it. + + The authentication challenge is appended to the login provider URL to which the subject's user-agent (browser) is redirected to. The login + provider uses that challenge to fetch information on the OAuth2 request and then accept or reject the requested authentication process. + + This endpoint tells Ory that the subject has successfully authenticated and includes additional information such as + the subject's ID and if Ory should remember the subject's subject agent for future authentication attempts by setting + a cookie. + + The response contains a redirect URL which the login provider should redirect the user-agent to. operationId: acceptOAuth2LoginRequest parameters: - description: OAuth 2.0 Login Request Challenge @@ -878,16 +879,17 @@ paths: - oAuth2 /admin/oauth2/auth/requests/login/reject: put: - description: "When an authorization code, hybrid, or implicit OAuth 2.0 Flow\ - \ is initiated, Ory asks the login provider\nto authenticate the subject and\ - \ then tell the Ory OAuth2 Service about it.\n\nThe authentication challenge\ - \ is appended to the login provider URL to which the subject's user-agent\ - \ (browser) is redirected to. The login\nprovider uses that challenge to fetch\ - \ information on the OAuth2 request and then accept or reject the requested\ - \ authentication process.\n\nThis endpoint tells Ory that the subject has\ - \ not authenticated and includes a reason why the authentication\nwas denied.\n\ - \nThe response contains a redirect URL which the login provider should redirect\ - \ the user-agent to." + description: |- + When an authorization code, hybrid, or implicit OAuth 2.0 Flow is initiated, Ory asks the login provider + to authenticate the subject and then tell the Ory OAuth2 Service about it. + + The authentication challenge is appended to the login provider URL to which the subject's user-agent (browser) is redirected to. The login + provider uses that challenge to fetch information on the OAuth2 request and then accept or reject the requested authentication process. + + This endpoint tells Ory that the subject has not authenticated and includes a reason why the authentication + was denied. + + The response contains a redirect URL which the login provider should redirect the user-agent to. operationId: rejectOAuth2LoginRequest parameters: - description: OAuth 2.0 Login Request Challenge @@ -956,10 +958,10 @@ paths: - oAuth2 /admin/oauth2/auth/requests/logout/accept: put: - description: "When a user or an application requests Ory OAuth 2.0 to remove\ - \ the session state of a subject, this endpoint is used to confirm that logout\ - \ request.\n\nThe response contains a redirect URL which the consent provider\ - \ should redirect the user-agent to." + description: |- + When a user or an application requests Ory OAuth 2.0 to remove the session state of a subject, this endpoint is used to confirm that logout request. + + The response contains a redirect URL which the consent provider should redirect the user-agent to. operationId: acceptOAuth2LogoutRequest parameters: - description: OAuth 2.0 Logout Request Challenge @@ -988,10 +990,11 @@ paths: - oAuth2 /admin/oauth2/auth/requests/logout/reject: put: - description: "When a user or an application requests Ory OAuth 2.0 to remove\ - \ the session state of a subject, this endpoint is used to deny that logout\ - \ request.\nNo HTTP request body is required.\n\nThe response is empty as\ - \ the logout provider has to chose what action to perform next." + description: |- + When a user or an application requests Ory OAuth 2.0 to remove the session state of a subject, this endpoint is used to deny that logout request. + No HTTP request body is required. + + The response is empty as the logout provider has to chose what action to perform next. operationId: rejectOAuth2LogoutRequest parameters: - explode: true @@ -1003,8 +1006,9 @@ paths: style: form responses: "204": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -1032,8 +1036,10 @@ paths: schema: type: string style: form - - description: "OAuth 2.0 Client ID\n\nIf set, deletes only those consent sessions\ - \ that have been granted to the specified OAuth 2.0 Client ID." + - description: |- + OAuth 2.0 Client ID + + If set, deletes only those consent sessions that have been granted to the specified OAuth 2.0 Client ID. explode: true in: query name: client @@ -1054,8 +1060,9 @@ paths: style: form responses: "204": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -1066,14 +1073,17 @@ paths: tags: - oAuth2 get: - description: "This endpoint lists all subject's granted consent sessions, including\ - \ client and granted scope.\nIf the subject is unknown or has not granted\ - \ any consent sessions yet, the endpoint returns an\nempty JSON array with\ - \ status code 200 OK." + description: |- + This endpoint lists all subject's granted consent sessions, including client and granted scope. + If the subject is unknown or has not granted any consent sessions yet, the endpoint returns an + empty JSON array with status code 200 OK. operationId: listOAuth2ConsentSessions parameters: - - description: "Items per Page\n\nThis is the number of items per page to return.\n\ - For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + - description: |- + Items per Page + + This is the number of items per page to return. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). explode: true in: query name: page_size @@ -1085,8 +1095,11 @@ paths: minimum: 1 type: integer style: form - - description: "Next Page Token\n\nThe next page token.\nFor details on pagination\ - \ please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + - description: |- + Next Page Token + + The next page token. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). explode: true in: query name: page_token @@ -1130,10 +1143,15 @@ paths: - oAuth2 /admin/oauth2/auth/sessions/login: delete: - description: "This endpoint invalidates a subject's authentication session.\ - \ After revoking the authentication session, the subject\nhas to re-authenticate\ - \ at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens\ - \ and\ndoes not work with OpenID Connect Front- or Back-channel logout." + description: |- + This endpoint invalidates authentication sessions. After revoking the authentication session(s), the subject + has to re-authenticate at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens. + + If you send the subject in a query param, all authentication sessions that belong to that subject are revoked. + No OpenID Connect Front- or Back-channel logout is performed in this case. + + Alternatively, you can send a SessionID via `sid` query param, in which case, only the session that is connected + to that SessionID is revoked. OpenID Connect Back-channel logout is performed in this case. operationId: revokeOAuth2LoginSessions parameters: - description: |- @@ -1143,30 +1161,41 @@ paths: explode: true in: query name: subject - required: true + required: false + schema: + type: string + style: form + - description: |- + Login Session ID + + The login session to revoke. + explode: true + in: query + name: sid + required: false schema: type: string style: form responses: "204": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: schema: $ref: '#/components/schemas/errorOAuth2' description: errorOAuth2 - summary: Revokes All OAuth 2.0 Login Sessions of a Subject + summary: Revokes OAuth 2.0 Login Sessions by either a Subject or a SessionID tags: - oAuth2 /admin/oauth2/introspect: post: - description: "The introspection endpoint allows to check if a token (both refresh\ - \ and access) is active or not. An active token\nis neither expired nor revoked.\ - \ If a token is active, additional information on the token will be included.\ - \ You can\nset additional data for a token by setting `session.access_token`\ - \ during the consent flow." + description: |- + The introspection endpoint allows to check if a token (both refresh and access) is active or not. An active token + is neither expired nor revoked. If a token is active, additional information on the token will be included. You can + set additional data for a token by setting `session.access_token` during the consent flow. operationId: introspectOAuth2Token requestBody: content: @@ -1205,8 +1234,9 @@ paths: style: form responses: "204": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -1263,9 +1293,10 @@ paths: tags: - oAuth2 post: - description: "Use this endpoint to establish a trust relationship for a JWT\ - \ issuer\nto perform JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication\n\ - and Authorization Grants [RFC7523](https://datatracker.ietf.org/doc/html/rfc7523)." + description: |- + Use this endpoint to establish a trust relationship for a JWT issuer + to perform JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication + and Authorization Grants [RFC7523](https://datatracker.ietf.org/doc/html/rfc7523). operationId: trustOAuth2JwtGrantIssuer requestBody: content: @@ -1291,11 +1322,12 @@ paths: - oAuth2 /admin/trust/grants/jwt-bearer/issuers/{id}: delete: - description: "Use this endpoint to delete trusted JWT Bearer Grant Type Issuer.\ - \ The ID is the one returned when you\ncreated the trust relationship.\n\n\ - Once deleted, the associated issuer will no longer be able to perform the\ - \ JSON Web Token (JWT) Profile\nfor OAuth 2.0 Client Authentication and Authorization\ - \ Grant." + description: |- + Use this endpoint to delete trusted JWT Bearer Grant Type Issuer. The ID is the one returned when you + created the trust relationship. + + Once deleted, the associated issuer will no longer be able to perform the JSON Web Token (JWT) Profile + for OAuth 2.0 Client Authentication and Authorization Grant. operationId: deleteTrustedOAuth2JwtGrantIssuer parameters: - description: The id of the desired grant @@ -1308,8 +1340,9 @@ paths: style: simple responses: "204": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -1349,15 +1382,55 @@ paths: summary: Get Trusted OAuth2 JWT Bearer Grant Type Issuer tags: - oAuth2 + /credentials: + post: + description: |- + This endpoint creates a verifiable credential that attests that the user + authenticated with the provided access token owns a certain public/private key + pair. + + More information can be found at + https://openid.net/specs/openid-connect-userinfo-vc-1_0.html. + operationId: createVerifiableCredential + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CreateVerifiableCredentialRequestBody' + x-originalParamName: Body + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/verifiableCredentialResponse' + description: verifiableCredentialResponse + "400": + content: + application/json: + schema: + $ref: '#/components/schemas/verifiableCredentialPrimingResponse' + description: verifiableCredentialPrimingResponse + default: + content: + application/json: + schema: + $ref: '#/components/schemas/errorOAuth2' + description: errorOAuth2 + summary: Issues a Verifiable Credential + tags: + - oidc /health/alive: get: - description: "This endpoint returns a HTTP 200 status code when Ory Hydra is\ - \ accepting incoming\nHTTP requests. This status does currently not include\ - \ checks whether the database connection is working.\n\nIf the service supports\ - \ TLS Edge Termination, this endpoint does not require the\n`X-Forwarded-Proto`\ - \ header to be set.\n\nBe aware that if you are running multiple nodes of\ - \ this service, the health status will never\nrefer to the cluster state,\ - \ only to a single instance." + description: |- + This endpoint returns a HTTP 200 status code when Ory Hydra is accepting incoming + HTTP requests. This status does currently not include checks whether the database connection is working. + + If the service supports TLS Edge Termination, this endpoint does not require the + `X-Forwarded-Proto` header to be set. + + Be aware that if you are running multiple nodes of this service, the health status will never + refer to the cluster state, only to a single instance. operationId: isAlive responses: "200": @@ -1377,12 +1450,15 @@ paths: - metadata /health/ready: get: - description: "This endpoint returns a HTTP 200 status code when Ory Hydra is\ - \ up running and the environment dependencies (e.g.\nthe database) are responsive\ - \ as well.\n\nIf the service supports TLS Edge Termination, this endpoint\ - \ does not require the\n`X-Forwarded-Proto` header to be set.\n\nBe aware\ - \ that if you are running multiple nodes of Ory Hydra, the health status will\ - \ never\nrefer to the cluster state, only to a single instance." + description: |- + This endpoint returns a HTTP 200 status code when Ory Hydra is up running and the environment dependencies (e.g. + the database) are responsive as well. + + If the service supports TLS Edge Termination, this endpoint does not require the + `X-Forwarded-Proto` header to be set. + + Be aware that if you are running multiple nodes of Ory Hydra, the health status will never + refer to the cluster state, only to a single instance. operationId: isReady responses: "200": @@ -1406,12 +1482,14 @@ paths: Use open source libraries to perform OAuth 2.0 and OpenID Connect available for any programming language. You can find a list of libraries at https://oauth.net/code/ - The Ory SDK is not yet able to this endpoint properly. + This endpoint should not be used via the Ory SDK and is only included for technical reasons. + Instead, use one of the libraries linked above. operationId: oAuth2Authorize responses: "302": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -1468,18 +1546,18 @@ paths: - oidc /oauth2/register/{id}: delete: - description: "This endpoint behaves like the administrative counterpart (`deleteOAuth2Client`)\ - \ but is capable of facing the\npublic internet directly and can be used in\ - \ self-service. It implements the OpenID Connect\nDynamic Client Registration\ - \ Protocol. This feature needs to be enabled in the configuration. This endpoint\n\ - is disabled by default. It can be enabled by an administrator.\n\nTo use this\ - \ endpoint, you will need to present the client's authentication credentials.\ - \ If the OAuth2 Client\nuses the Token Endpoint Authentication Method `client_secret_post`,\ - \ you need to present the client secret in the URL query.\nIf it uses `client_secret_basic`,\ - \ present the Client ID and the Client Secret in the Authorization header.\n\ - \nOAuth 2.0 clients are used to perform OAuth 2.0 and OpenID Connect flows.\ - \ Usually, OAuth 2.0 clients are\ngenerated for applications which want to\ - \ consume your OAuth 2.0 or OpenID Connect capabilities." + description: |- + This endpoint behaves like the administrative counterpart (`deleteOAuth2Client`) but is capable of facing the + public internet directly and can be used in self-service. It implements the OpenID Connect + Dynamic Client Registration Protocol. This feature needs to be enabled in the configuration. This endpoint + is disabled by default. It can be enabled by an administrator. + + To use this endpoint, you will need to present the client's authentication credentials. If the OAuth2 Client + uses the Token Endpoint Authentication Method `client_secret_post`, you need to present the client secret in the URL query. + If it uses `client_secret_basic`, present the Client ID and the Client Secret in the Authorization header. + + OAuth 2.0 clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are + generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities. operationId: deleteOidcDynamicClient parameters: - description: The id of the OAuth 2.0 Client. @@ -1492,8 +1570,9 @@ paths: style: simple responses: "204": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -1507,14 +1586,14 @@ paths: tags: - oidc get: - description: "This endpoint behaves like the administrative counterpart (`getOAuth2Client`)\ - \ but is capable of facing the\npublic internet directly and can be used in\ - \ self-service. It implements the OpenID Connect\nDynamic Client Registration\ - \ Protocol.\n\nTo use this endpoint, you will need to present the client's\ - \ authentication credentials. If the OAuth2 Client\nuses the Token Endpoint\ - \ Authentication Method `client_secret_post`, you need to present the client\ - \ secret in the URL query.\nIf it uses `client_secret_basic`, present the\ - \ Client ID and the Client Secret in the Authorization header." + description: |- + This endpoint behaves like the administrative counterpart (`getOAuth2Client`) but is capable of facing the + public internet directly and can be used in self-service. It implements the OpenID Connect + Dynamic Client Registration Protocol. + + To use this endpoint, you will need to present the client's authentication credentials. If the OAuth2 Client + uses the Token Endpoint Authentication Method `client_secret_post`, you need to present the client secret in the URL query. + If it uses `client_secret_basic`, present the Client ID and the Client Secret in the Authorization header. operationId: getOidcDynamicClient parameters: - description: The id of the OAuth 2.0 Client. @@ -1544,20 +1623,22 @@ paths: tags: - oidc put: - description: "This endpoint behaves like the administrative counterpart (`setOAuth2Client`)\ - \ but is capable of facing the\npublic internet directly to be used by third\ - \ parties. It implements the OpenID Connect\nDynamic Client Registration Protocol.\n\ - \nThis feature is disabled per default. It can be enabled by a system administrator.\n\ - \nIf you pass `client_secret` the secret is used, otherwise the existing secret\ - \ is used. If set, the secret is echoed in the response.\nIt is not possible\ - \ to retrieve it later on.\n\nTo use this endpoint, you will need to present\ - \ the client's authentication credentials. If the OAuth2 Client\nuses the\ - \ Token Endpoint Authentication Method `client_secret_post`, you need to present\ - \ the client secret in the URL query.\nIf it uses `client_secret_basic`, present\ - \ the Client ID and the Client Secret in the Authorization header.\n\nOAuth\ - \ 2.0 clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually,\ - \ OAuth 2.0 clients are\ngenerated for applications which want to consume\ - \ your OAuth 2.0 or OpenID Connect capabilities." + description: |- + This endpoint behaves like the administrative counterpart (`setOAuth2Client`) but is capable of facing the + public internet directly to be used by third parties. It implements the OpenID Connect + Dynamic Client Registration Protocol. + + This feature is disabled per default. It can be enabled by a system administrator. + + If you pass `client_secret` the secret is used, otherwise the existing secret is used. If set, the secret is echoed in the response. + It is not possible to retrieve it later on. + + To use this endpoint, you will need to present the client's authentication credentials. If the OAuth2 Client + uses the Token Endpoint Authentication Method `client_secret_post`, you need to present the client secret in the URL query. + If it uses `client_secret_basic`, present the Client ID and the Client Secret in the Authorization header. + + OAuth 2.0 clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are + generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities. operationId: setOidcDynamicClient parameters: - description: OAuth 2.0 Client ID @@ -1602,12 +1683,11 @@ paths: - oidc /oauth2/revoke: post: - description: "Revoking a token (both access and refresh) means that the tokens\ - \ will be invalid. A revoked access token can no\nlonger be used to make access\ - \ requests, and a revoked refresh token can no longer be used to refresh an\ - \ access token.\nRevoking a refresh token also invalidates the access token\ - \ that was created with it. A token may only be revoked by\nthe client the\ - \ token was generated for." + description: |- + Revoking a token (both access and refresh) means that the tokens will be invalid. A revoked access token can no + longer be used to make access requests, and a revoked refresh token can no longer be used to refresh an access token. + Revoking a refresh token also invalidates the access token that was created with it. A token may only be revoked by + the client the token was generated for. operationId: revokeOAuth2Token requestBody: content: @@ -1616,8 +1696,9 @@ paths: $ref: '#/components/schemas/revokeOAuth2Token_request' responses: "200": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. default: content: application/json: @@ -1642,8 +1723,9 @@ paths: operationId: revokeOidcSession responses: "302": - description: "Empty responses are sent when, for example, resources are\ - \ deleted. The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. summary: OpenID Connect Front- and Back-channel Enabled Logout tags: - oidc @@ -1653,7 +1735,8 @@ paths: Use open source libraries to perform OAuth 2.0 and OpenID Connect available for any programming language. You can find a list of libraries here https://oauth.net/code/ - The Ory SDK is not yet able to this endpoint properly. + This endpoint should not be used via the Ory SDK and is only included for technical reasons. + Instead, use one of the libraries linked above. operationId: oauth2TokenExchange requestBody: content: @@ -1681,11 +1764,13 @@ paths: - oAuth2 /userinfo: get: - description: "This endpoint returns the payload of the ID Token, including `session.id_token`\ - \ values, of\nthe provided OAuth 2.0 Access Token's consent request.\n\nIn\ - \ the case of authentication error, a WWW-Authenticate header might be set\ - \ in the response\nwith more information about the error. See [the spec](https://datatracker.ietf.org/doc/html/rfc6750#section-3)\n\ - for more details about header format." + description: |- + This endpoint returns the payload of the ID Token, including `session.id_token` values, of + the provided OAuth 2.0 Access Token's consent request. + + In the case of authentication error, a WWW-Authenticate header might be set in the response + with more information about the error. See [the spec](https://datatracker.ietf.org/doc/html/rfc6750#section-3) + for more details about header format. operationId: getOidcUserInfo responses: "200": @@ -1707,11 +1792,14 @@ paths: - oidc /version: get: - description: "This endpoint returns the version of Ory Hydra.\n\nIf the service\ - \ supports TLS Edge Termination, this endpoint does not require the\n`X-Forwarded-Proto`\ - \ header to be set.\n\nBe aware that if you are running multiple nodes of\ - \ this service, the version will never\nrefer to the cluster state, only to\ - \ a single instance." + description: |- + This endpoint returns the version of Ory Hydra. + + If the service supports TLS Edge Termination, this endpoint does not require the + `X-Forwarded-Proto` header to be set. + + Be aware that if you are running multiple nodes of this service, the version will never + refer to the cluster state, only to a single instance. operationId: getVersion responses: "200": @@ -1726,8 +1814,9 @@ paths: components: responses: emptyResponse: - description: "Empty responses are sent when, for example, resources are deleted.\ - \ The HTTP status code for empty responses is\ntypically 201." + description: |- + Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is + typically 204. errorOAuth2BadRequest: content: application/json: @@ -1755,6 +1844,28 @@ components: type: array description: Paginated OAuth2 Client List Response schemas: + CreateVerifiableCredentialRequestBody: + example: + types: + - types + - types + format: format + proof: + proof_type: proof_type + jwt: jwt + properties: + format: + type: string + proof: + $ref: '#/components/schemas/VerifiableCredentialProof' + types: + items: + type: string + type: array + title: CreateVerifiableCredentialRequestBody contains the request body to request + a verifiable credential. + type: object + DefaultError: {} JSONRawMessage: title: "JSONRawMessage represents a json.RawMessage that works well with JSON,\ \ SQL, and Swagger." @@ -1780,6 +1891,21 @@ components: format: uuid4 nullable: true type: string + RFC6749ErrorJson: + properties: + error: + type: string + error_debug: + type: string + error_description: + type: string + error_hint: + type: string + status_code: + format: int64 + type: integer + title: RFC6749ErrorJson is a helper struct for JSON encoding/decoding of RFC6749Error. + type: object StringSliceJSONFormat: items: type: string @@ -1792,8 +1918,22 @@ components: UUID: format: uuid4 type: string + VerifiableCredentialProof: + example: + proof_type: proof_type + jwt: jwt + properties: + jwt: + type: string + proof_type: + type: string + title: VerifiableCredentialProof contains the proof of a verifiable credential. + type: object acceptOAuth2ConsentRequest: properties: + context: + title: "JSONRawMessage represents a json.RawMessage that works well with\ + \ JSON, SQL, and Swagger." grant_access_token_audience: items: type: string @@ -1811,14 +1951,14 @@ components: title: NullTime implements sql.NullTime functionality. type: string remember: - description: "Remember, if set to true, tells ORY Hydra to remember this\ - \ consent authorization and reuse it if the same\nclient asks the same\ - \ user for the same, or a subset of, scope." + description: |- + Remember, if set to true, tells ORY Hydra to remember this consent authorization and reuse it if the same + client asks the same user for the same, or a subset of, scope. type: boolean remember_for: - description: "RememberFor sets how long the consent authorization should\ - \ be remembered for in seconds. If set to `0`, the\nauthorization will\ - \ be remembered indefinitely." + description: |- + RememberFor sets how long the consent authorization should be remembered for in seconds. If set to `0`, the + authorization will be remembered indefinitely. format: int64 type: integer session: @@ -1831,13 +1971,11 @@ components: id_token: "" properties: access_token: - description: "AccessToken sets session data for the access and refresh token,\ - \ as well as any future tokens issued by the\nrefresh grant. Keep in mind\ - \ that this data will be available to anyone performing OAuth 2.0 Challenge\ - \ Introspection.\nIf only your services can perform OAuth 2.0 Challenge\ - \ Introspection, this is usually fine. But if third parties\ncan access\ - \ that endpoint as well, sensitive data from the session might be exposed\ - \ to them. Use with care!" + description: |- + AccessToken sets session data for the access and refresh token, as well as any future tokens issued by the + refresh grant. Keep in mind that this data will be available to anyone performing OAuth 2.0 Challenge Introspection. + If only your services can perform OAuth 2.0 Challenge Introspection, this is usually fine. But if third parties + can access that endpoint as well, sensitive data from the session might be exposed to them. Use with care! id_token: description: |- IDToken sets session data for the OpenID Connect ID token. Keep in mind that the session'id payloads are readable @@ -1847,9 +1985,9 @@ components: acceptOAuth2LoginRequest: properties: acr: - description: "ACR sets the Authentication AuthorizationContext Class Reference\ - \ value for this authentication session. You can use it\nto express that,\ - \ for example, a user authenticated using two factor authentication." + description: |- + ACR sets the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it + to express that, for example, a user authenticated using two factor authentication. type: string amr: items: @@ -1860,36 +1998,49 @@ components: context: title: "JSONRawMessage represents a json.RawMessage that works well with\ \ JSON, SQL, and Swagger." + extend_session_lifespan: + description: |- + Extend OAuth2 authentication session lifespan + + If set to `true`, the OAuth2 authentication cookie lifespan is extended. This is for example useful if you want the user to be able to use `prompt=none` continuously. + + This value can only be set to `true` if the user has an authentication, which is the case if the `skip` value is `true`. + type: boolean force_subject_identifier: - description: "ForceSubjectIdentifier forces the \"pairwise\" user ID of\ - \ the end-user that authenticated. The \"pairwise\" user ID refers to\ - \ the\n(Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg]\ - \ of the OpenID\nConnect specification. It allows you to set an obfuscated\ - \ subject (\"user\") identifier that is unique to the client.\n\nPlease\ - \ note that this changes the user ID on endpoint /userinfo and sub claim\ - \ of the ID Token. It does not change the\nsub claim in the OAuth 2.0\ - \ Introspection.\n\nPer default, ORY Hydra handles this value with its\ - \ own algorithm. In case you want to set this yourself\nyou can use this\ - \ field. Please note that setting this field has no effect if `pairwise`\ - \ is not configured in\nORY Hydra or the OAuth 2.0 Client does not expect\ - \ a pairwise identifier (set via `subject_type` key in the client's\n\ - configuration).\n\nPlease also be aware that ORY Hydra is unable to properly\ - \ compute this value during authentication. This implies\nthat you have\ - \ to compute this value on every authentication process (probably depending\ - \ on the client ID or some\nother unique value).\n\nIf you fail to compute\ - \ the proper value, then authentication processes which have id_token_hint\ - \ set might fail." + description: |- + ForceSubjectIdentifier forces the "pairwise" user ID of the end-user that authenticated. The "pairwise" user ID refers to the + (Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg] of the OpenID + Connect specification. It allows you to set an obfuscated subject ("user") identifier that is unique to the client. + + Please note that this changes the user ID on endpoint /userinfo and sub claim of the ID Token. It does not change the + sub claim in the OAuth 2.0 Introspection. + + Per default, ORY Hydra handles this value with its own algorithm. In case you want to set this yourself + you can use this field. Please note that setting this field has no effect if `pairwise` is not configured in + ORY Hydra or the OAuth 2.0 Client does not expect a pairwise identifier (set via `subject_type` key in the client's + configuration). + + Please also be aware that ORY Hydra is unable to properly compute this value during authentication. This implies + that you have to compute this value on every authentication process (probably depending on the client ID or some + other unique value). + + If you fail to compute the proper value, then authentication processes which have id_token_hint set might fail. + type: string + identity_provider_session_id: + description: |- + IdentityProviderSessionID is the session ID of the end-user that authenticated. + If specified, we will use this value to propagate the logout. type: string remember: - description: "Remember, if set to true, tells ORY Hydra to remember this\ - \ user by telling the user agent (browser) to store\na cookie with authentication\ - \ data. If the same user performs another OAuth 2.0 Authorization Request,\ - \ he/she\nwill not be asked to log in again." + description: |- + Remember, if set to true, tells ORY Hydra to remember this user by telling the user agent (browser) to store + a cookie with authentication data. If the same user performs another OAuth 2.0 Authorization Request, he/she + will not be asked to log in again. type: boolean remember_for: - description: "RememberFor sets how long the authentication should be remembered\ - \ for in seconds. If set to `0`, the\nauthorization will be remembered\ - \ for the duration of the browser session (using a session cookie)." + description: |- + RememberFor sets how long the authentication should be remembered for in seconds. If set to `0`, the + authorization will be remembered for the duration of the browser session (using a session cookie). format: int64 type: integer subject: @@ -1903,8 +2054,10 @@ components: description: Create JSON Web Key Set Request Body properties: alg: - description: "JSON Web Key Algorithm\n\nThe algorithm to be used for creating\ - \ the key. Supports `RS256`, `ES256`, `ES512`, `HS512`, and `HS256`." + description: |- + JSON Web Key Algorithm + + The algorithm to be used for creating the key. Supports `RS256`, `ES256`, `ES512`, `HS512`, and `HS256`. type: string kid: description: |- @@ -1926,6 +2079,52 @@ components: - kid - use type: object + credentialSupportedDraft00: + description: Includes information about the supported verifiable credentials. + example: + types: + - types + - types + cryptographic_suites_supported: + - cryptographic_suites_supported + - cryptographic_suites_supported + cryptographic_binding_methods_supported: + - cryptographic_binding_methods_supported + - cryptographic_binding_methods_supported + format: format + properties: + cryptographic_binding_methods_supported: + description: |- + OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported + + Contains a list of cryptographic binding methods supported for signing the proof. + items: + type: string + type: array + cryptographic_suites_supported: + description: |- + OpenID Connect Verifiable Credentials Cryptographic Suites Supported + + Contains a list of cryptographic suites methods supported for signing the proof. + items: + type: string + type: array + format: + description: |- + OpenID Connect Verifiable Credentials Format + + Contains the format that is supported by this authorization server. + type: string + types: + description: |- + OpenID Connect Verifiable Credentials Types + + Contains the types of verifiable credentials supported. + items: + type: string + type: array + title: Verifiable Credentials Metadata (Draft 00) + type: object errorOAuth2: description: Error example: @@ -2017,6 +2216,7 @@ components: description: Errors contains a list of errors that caused the not ready status. type: object + title: The not ready status of the service. type: object healthStatus: example: @@ -2025,10 +2225,12 @@ components: status: description: Status always contains "ok". type: string + title: The health status of the service. type: object introspectedOAuth2Token: - description: "Introspection contains an access token's session data as specified\ - \ by\n[IETF RFC 7662](https://tools.ietf.org/html/rfc7662)" + description: |- + Introspection contains an access token's session data as specified by + [IETF RFC 7662](https://tools.ietf.org/html/rfc7662) example: ext: key: "" @@ -2049,14 +2251,16 @@ components: username: username properties: active: - description: "Active is a boolean indicator of whether or not the presented\ - \ token\nis currently active. The specifics of a token's \"active\" state\n\ - will vary depending on the implementation of the authorization\nserver\ - \ and the information it keeps about its tokens, but a \"true\"\nvalue\ - \ return for the \"active\" property will generally indicate\nthat a given\ - \ token has been issued by this authorization server,\nhas not been revoked\ - \ by the resource owner, and is within its\ngiven time window of validity\ - \ (e.g., after its issuance time and\nbefore its expiration time)." + description: |- + Active is a boolean indicator of whether or not the presented token + is currently active. The specifics of a token's "active" state + will vary depending on the implementation of the authorization + server and the information it keeps about its tokens, but a "true" + value return for the "active" property will generally indicate + that a given token has been issued by this authorization server, + has not been revoked by the resource owner, and is within its + given time window of validity (e.g., after its issuance time and + before its expiration time). type: boolean aud: description: Audience contains a list of the token's intended audiences. @@ -2069,9 +2273,9 @@ components: requested this token. type: string exp: - description: "Expires at is an integer timestamp, measured in the number\ - \ of seconds\nsince January 1 1970 UTC, indicating when this token will\ - \ expire." + description: |- + Expires at is an integer timestamp, measured in the number of seconds + since January 1 1970 UTC, indicating when this token will expire. format: int64 type: integer ext: @@ -2079,18 +2283,20 @@ components: description: Extra is arbitrary data set by the session. type: object iat: - description: "Issued at is an integer timestamp, measured in the number\ - \ of seconds\nsince January 1 1970 UTC, indicating when this token was\n\ - originally issued." + description: |- + Issued at is an integer timestamp, measured in the number of seconds + since January 1 1970 UTC, indicating when this token was + originally issued. format: int64 type: integer iss: description: IssuerURL is a string representing the issuer of this token type: string nbf: - description: "NotBefore is an integer timestamp, measured in the number\ - \ of seconds\nsince January 1 1970 UTC, indicating when this token is\ - \ not to be\nused before." + description: |- + NotBefore is an integer timestamp, measured in the number of seconds + since January 1 1970 UTC, indicating when this token is not to be + used before. format: int64 type: integer obfuscated_subject: @@ -2104,9 +2310,10 @@ components: scopes associated with this token. type: string sub: - description: "Subject of the token, as defined in JWT [RFC7519].\nUsually\ - \ a machine-readable identifier of the resource owner who\nauthorized\ - \ this token." + description: |- + Subject of the token, as defined in JWT [RFC7519]. + Usually a machine-readable identifier of the resource owner who + authorized this token. type: string token_type: description: "TokenType is the introspected token's type, typically `Bearer`." @@ -2127,8 +2334,10 @@ components: description: A JSONPatch document as defined by RFC 6902 properties: from: - description: "This field is used together with operation \"move\" and uses\ - \ JSON Pointer notation.\n\nLearn more [about JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901#section-5)." + description: |- + This field is used together with operation "move" and uses JSON Pointer notation. + + Learn more [about JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901#section-5). example: /name type: string op: @@ -2137,13 +2346,17 @@ components: example: replace type: string path: - description: "The path to the target path. Uses JSON pointer notation.\n\ - \nLearn more [about JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901#section-5)." + description: |- + The path to the target path. Uses JSON pointer notation. + + Learn more [about JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901#section-5). example: /name type: string value: - description: "The value to be used within the operations.\n\nLearn more\ - \ [about JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901#section-5)." + description: |- + The value to be used within the operations. + + Learn more [about JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901#section-5). example: foobar required: - op @@ -2177,11 +2390,12 @@ components: alg: RS256 properties: alg: - description: "The \"alg\" (algorithm) parameter identifies the algorithm\ - \ intended for\nuse with the key. The values used should either be registered\ - \ in the\nIANA \"JSON Web Signature and Encryption Algorithms\" registry\n\ - established by [JWA] or be a value that contains a Collision-\nResistant\ - \ Name." + description: |- + The "alg" (algorithm) parameter identifies the algorithm intended for + use with the key. The values used should either be registered in the + IANA "JSON Web Signature and Encryption Algorithms" registry + established by [JWA] or be a value that contains a Collision- + Resistant Name. example: RS256 type: string crv: @@ -2203,23 +2417,25 @@ components: example: GawgguFyGrWKav7AX4VKUg type: string kid: - description: "The \"kid\" (key ID) parameter is used to match a specific\ - \ key. This\nis used, for instance, to choose among a set of keys within\ - \ a JWK Set\nduring key rollover. The structure of the \"kid\" value\ - \ is\nunspecified. When \"kid\" values are used within a JWK Set, different\n\ - keys within the JWK Set SHOULD use distinct \"kid\" values. (One\nexample\ - \ in which different keys might use the same \"kid\" value is if\nthey\ - \ have different \"kty\" (key type) values but are considered to be\n\ - equivalent alternatives by the application using them.) The \"kid\"\n\ - value is a case-sensitive string." + description: |- + The "kid" (key ID) parameter is used to match a specific key. This + is used, for instance, to choose among a set of keys within a JWK Set + during key rollover. The structure of the "kid" value is + unspecified. When "kid" values are used within a JWK Set, different + keys within the JWK Set SHOULD use distinct "kid" values. (One + example in which different keys might use the same "kid" value is if + they have different "kty" (key type) values but are considered to be + equivalent alternatives by the application using them.) The "kid" + value is a case-sensitive string. example: 1603dfe0af8f4596 type: string kty: - description: "The \"kty\" (key type) parameter identifies the cryptographic\ - \ algorithm\nfamily used with the key, such as \"RSA\" or \"EC\". \"kty\"\ - \ values should\neither be registered in the IANA \"JSON Web Key Types\"\ - \ registry\nestablished by [JWA] or be a value that contains a Collision-\n\ - Resistant Name. The \"kty\" value is a case-sensitive string." + description: |- + The "kty" (key type) parameter identifies the cryptographic algorithm + family used with the key, such as "RSA" or "EC". "kty" values should + either be registered in the IANA "JSON Web Key Types" registry + established by [JWA] or be a value that contains a Collision- + Resistant Name. The "kty" value is a case-sensitive string. example: RSA type: string "n": @@ -2246,12 +2462,14 @@ components: example: f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU type: string x5c: - description: "The \"x5c\" (X.509 certificate chain) parameter contains a\ - \ chain of one\nor more PKIX certificates [RFC5280]. The certificate\ - \ chain is\nrepresented as a JSON array of certificate value strings.\ - \ Each\nstring in the array is a base64-encoded (Section 4 of [RFC4648]\ - \ --\nnot base64url-encoded) DER [ITU.X690.1994] PKIX certificate value.\n\ - The PKIX certificate containing the key value MUST be the first\ncertificate." + description: |- + The "x5c" (X.509 certificate chain) parameter contains a chain of one + or more PKIX certificates [RFC5280]. The certificate chain is + represented as a JSON array of certificate value strings. Each + string in the array is a base64-encoded (Section 4 of [RFC4648] -- + not base64url-encoded) DER [ITU.X690.1994] PKIX certificate value. + The PKIX certificate containing the key value MUST be the first + certificate. items: type: string type: array @@ -2308,11 +2526,14 @@ components: alg: RS256 properties: keys: - description: "List of JSON Web Keys\n\nThe value of the \"keys\" parameter\ - \ is an array of JSON Web Key (JWK)\nvalues. By default, the order of\ - \ the JWK values within the array does\nnot imply an order of preference\ - \ among them, although applications\nof JWK Sets can choose to assign\ - \ a meaning to the order for their\npurposes, if desired." + description: |- + List of JSON Web Keys + + The value of the "keys" parameter is an array of JSON Web Key (JWK) + values. By default, the order of the JWK values within the array does + not imply an order of preference among them, although applications + of JWK Sets can choose to assign a meaning to the order for their + purposes, if desired. items: $ref: '#/components/schemas/jsonWebKey' type: array @@ -2329,9 +2550,9 @@ components: title: NullTime implements sql.NullTime functionality. type: string oAuth2Client: - description: "OAuth 2.0 Clients are used to perform OAuth 2.0 and OpenID Connect\ - \ flows. Usually, OAuth 2.0 clients are\ngenerated for applications which\ - \ want to consume your OAuth 2.0 or OpenID Connect capabilities." + description: |- + OAuth 2.0 Clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are + generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities. example: metadata: "" token_endpoint_auth_signing_alg: token_endpoint_auth_signing_alg @@ -2347,7 +2568,7 @@ components: refresh_token_grant_access_token_lifespan: refresh_token_grant_access_token_lifespan registration_access_token: registration_access_token client_id: client_id - token_endpoint_auth_method: token_endpoint_auth_method + token_endpoint_auth_method: client_secret_basic userinfo_signed_response_alg: userinfo_signed_response_alg authorization_code_grant_id_token_lifespan: authorization_code_grant_id_token_lifespan authorization_code_grant_refresh_token_lifespan: authorization_code_grant_refresh_token_lifespan @@ -2363,6 +2584,7 @@ components: client_name: client_name policy_uri: policy_uri owner: owner + skip_consent: true audience: - audience - audience @@ -2381,10 +2603,12 @@ components: sector_identifier_uri: sector_identifier_uri frontchannel_logout_session_required: true frontchannel_logout_uri: frontchannel_logout_uri + skip_logout_consent: true refresh_token_grant_id_token_lifespan: refresh_token_grant_id_token_lifespan implicit_grant_id_token_lifespan: implicit_grant_id_token_lifespan client_secret_expires_at: 0 implicit_grant_access_token_lifespan: implicit_grant_access_token_lifespan + access_token_strategy: access_token_strategy jwks_uri: jwks_uri request_object_signing_alg: request_object_signing_alg tos_uri: tos_uri @@ -2395,6 +2619,14 @@ components: - response_types - response_types properties: + access_token_strategy: + description: |- + OAuth 2.0 Access Token Strategy + + AccessTokenStrategy is the strategy used to generate access tokens. + Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens + Setting the stragegy here overrides the global setting in `strategies.access_token`. + type: string allowed_cors_origins: items: type: string @@ -2426,11 +2658,12 @@ components: title: Time duration type: string backchannel_logout_session_required: - description: "OpenID Connect Back-Channel Logout Session Required\n\nBoolean\ - \ value specifying whether the RP requires that a sid (session ID) Claim\ - \ be included in the Logout\nToken to identify the RP session with the\ - \ OP when the backchannel_logout_uri is used.\nIf omitted, the default\ - \ value is false." + description: |- + OpenID Connect Back-Channel Logout Session Required + + Boolean value specifying whether the RP requires that a sid (session ID) Claim be included in the Logout + Token to identify the RP session with the OP when the backchannel_logout_uri is used. + If omitted, the default value is false. type: boolean backchannel_logout_uri: description: |- @@ -2448,7 +2681,7 @@ components: description: |- OAuth 2.0 Client ID - The ID is autogenerated and immutable. + The ID is immutable. If no ID is provided, a UUID4 will be generated. type: string client_name: description: |- @@ -2458,9 +2691,11 @@ components: end-user during authorization. type: string client_secret: - description: "OAuth 2.0 Client Secret\n\nThe secret will be included in\ - \ the create request as cleartext, and then\nnever again. The secret is\ - \ kept in hashed format and is not recoverable once lost." + description: |- + OAuth 2.0 Client Secret + + The secret will be included in the create request as cleartext, and then + never again. The secret is kept in hashed format and is not recoverable once lost. type: string client_secret_expires_at: description: |- @@ -2470,9 +2705,12 @@ components: format: int64 type: integer client_uri: - description: "OAuth 2.0 Client URI\n\nClientURI is a URL string of a web\ - \ page providing information about the client.\nIf present, the server\ - \ SHOULD display this URL to the end-user in\na clickable fashion." + description: |- + OAuth 2.0 Client URI + + ClientURI is a URL string of a web page providing information about the client. + If present, the server SHOULD display this URL to the end-user in + a clickable fashion. type: string contacts: items: @@ -2488,19 +2726,21 @@ components: format: date-time type: string frontchannel_logout_session_required: - description: "OpenID Connect Front-Channel Logout Session Required\n\nBoolean\ - \ value specifying whether the RP requires that iss (issuer) and sid (session\ - \ ID) query parameters be\nincluded to identify the RP session with the\ - \ OP when the frontchannel_logout_uri is used.\nIf omitted, the default\ - \ value is false." + description: |- + OpenID Connect Front-Channel Logout Session Required + + Boolean value specifying whether the RP requires that iss (issuer) and sid (session ID) query parameters be + included to identify the RP session with the OP when the frontchannel_logout_uri is used. + If omitted, the default value is false. type: boolean frontchannel_logout_uri: - description: "OpenID Connect Front-Channel Logout URI\n\nRP URL that will\ - \ cause the RP to log itself out when rendered in an iframe by the OP.\ - \ An iss (issuer) query\nparameter and a sid (session ID) query parameter\ - \ MAY be included by the OP to enable the RP to validate the\nrequest\ - \ and to determine which of the potentially multiple sessions is to be\ - \ logged out; if either is\nincluded, both MUST be." + description: |- + OpenID Connect Front-Channel Logout URI + + RP URL that will cause the RP to log itself out when rendered in an iframe by the OP. An iss (issuer) query + parameter and a sid (session ID) query parameter MAY be included by the OP to enable the RP to validate the + request and to determine which of the potentially multiple sessions is to be logged out; if either is + included, both MUST be. type: string grant_types: items: @@ -2521,31 +2761,28 @@ components: title: Time duration type: string jwks: - description: "OAuth 2.0 Client JSON Web Key Set\n\nClient's JSON Web Key\ - \ Set [JWK] document, passed by value. The semantics of the jwks parameter\ - \ are the same as\nthe jwks_uri parameter, other than that the JWK Set\ - \ is passed by value, rather than by reference. This parameter\nis intended\ - \ only to be used by Clients that, for some reason, are unable to use\ - \ the jwks_uri parameter, for\ninstance, by native applications that might\ - \ not have a location to host the contents of the JWK Set. If a Client\n\ - can use jwks_uri, it MUST NOT use jwks. One significant downside of jwks\ - \ is that it does not enable key rotation\n(which jwks_uri does, as described\ - \ in Section 10 of OpenID Connect Core 1.0 [OpenID.Core]). The jwks_uri\ - \ and jwks\nparameters MUST NOT be used together." + description: |- + OAuth 2.0 Client JSON Web Key Set + + Client's JSON Web Key Set [JWK] document, passed by value. The semantics of the jwks parameter are the same as + the jwks_uri parameter, other than that the JWK Set is passed by value, rather than by reference. This parameter + is intended only to be used by Clients that, for some reason, are unable to use the jwks_uri parameter, for + instance, by native applications that might not have a location to host the contents of the JWK Set. If a Client + can use jwks_uri, it MUST NOT use jwks. One significant downside of jwks is that it does not enable key rotation + (which jwks_uri does, as described in Section 10 of OpenID Connect Core 1.0 [OpenID.Core]). The jwks_uri and jwks + parameters MUST NOT be used together. jwks_uri: - description: "OAuth 2.0 Client JSON Web Key Set URL\n\nURL for the Client's\ - \ JSON Web Key Set [JWK] document. If the Client signs requests to the\ - \ Server, it contains\nthe signing key(s) the Server uses to validate\ - \ signatures from the Client. The JWK Set MAY also contain the\nClient's\ - \ encryption keys(s), which are used by the Server to encrypt responses\ - \ to the Client. When both signing\nand encryption keys are made available,\ - \ a use (Key Use) parameter value is REQUIRED for all keys in the referenced\n\ - JWK Set to indicate each key's intended usage. Although some algorithms\ - \ allow the same key to be used for both\nsignatures and encryption, doing\ - \ so is NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY\ - \ be used\nto provide X.509 representations of keys provided. When used,\ - \ the bare key values MUST still be present and MUST\nmatch those in the\ - \ certificate." + description: |- + OAuth 2.0 Client JSON Web Key Set URL + + URL for the Client's JSON Web Key Set [JWK] document. If the Client signs requests to the Server, it contains + the signing key(s) the Server uses to validate signatures from the Client. The JWK Set MAY also contain the + Client's encryption keys(s), which are used by the Server to encrypt responses to the Client. When both signing + and encryption keys are made available, a use (Key Use) parameter value is REQUIRED for all keys in the referenced + JWK Set to indicate each key's intended usage. Although some algorithms allow the same key to be used for both + signatures and encryption, doing so is NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used + to provide X.509 representations of keys provided. When used, the bare key values MUST still be present and MUST + match those in the certificate. type: string jwt_bearer_grant_access_token_lifespan: description: "Specify a time duration in milliseconds, seconds, minutes,\ @@ -2569,10 +2806,12 @@ components: Owner is a string identifying the owner of the OAuth 2.0 Client. type: string policy_uri: - description: "OAuth 2.0 Client Policy URI\n\nPolicyURI is a URL string that\ - \ points to a human-readable privacy policy document\nthat describes how\ - \ the deployment organization collects, uses,\nretains, and discloses\ - \ personal data." + description: |- + OAuth 2.0 Client Policy URI + + PolicyURI is a URL string that points to a human-readable privacy policy document + that describes how the deployment organization collects, uses, + retains, and discloses personal data. type: string post_logout_redirect_uris: items: @@ -2605,19 +2844,24 @@ components: title: Time duration type: string registration_access_token: - description: "OpenID Connect Dynamic Client Registration Access Token\n\n\ - RegistrationAccessToken can be used to update, get, or delete the OAuth2\ - \ Client. It is sent when creating a client\nusing Dynamic Client Registration." + description: |- + OpenID Connect Dynamic Client Registration Access Token + + RegistrationAccessToken can be used to update, get, or delete the OAuth2 Client. It is sent when creating a client + using Dynamic Client Registration. type: string registration_client_uri: - description: "OpenID Connect Dynamic Client Registration URL\n\nRegistrationClientURI\ - \ is the URL used to update, get, or delete the OAuth2 Client." + description: |- + OpenID Connect Dynamic Client Registration URL + + RegistrationClientURI is the URL used to update, get, or delete the OAuth2 Client. type: string request_object_signing_alg: - description: "OpenID Connect Request Object Signing Algorithm\n\nJWS [JWS]\ - \ alg algorithm [JWA] that MUST be used for signing Request Objects sent\ - \ to the OP. All Request Objects\nfrom this Client MUST be rejected, if\ - \ not signed with this algorithm." + description: |- + OpenID Connect Request Object Signing Algorithm + + JWS [JWS] alg algorithm [JWA] that MUST be used for signing Request Objects sent to the OP. All Request Objects + from this Client MUST be rejected, if not signed with this algorithm. type: string request_uris: items: @@ -2632,9 +2876,12 @@ components: \ JSON for SQL storage." type: array scope: - description: "OAuth 2.0 Client Scope\n\nScope is a string containing a space-separated\ - \ list of scope values (as\ndescribed in Section 3.3 of OAuth 2.0 [RFC6749])\ - \ that the client\ncan use when requesting access tokens." + description: |- + OAuth 2.0 Client Scope + + Scope is a string containing a space-separated list of scope values (as + described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client + can use when requesting access tokens. example: scope1 scope-2 scope.3 scope:4 type: string sector_identifier_uri: @@ -2644,6 +2891,16 @@ components: URL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. The URL references a file with a single JSON array of redirect_uri values. type: string + skip_consent: + description: |- + SkipConsent skips the consent screen for this client. This field can only + be set from the admin API. + type: boolean + skip_logout_consent: + description: |- + SkipLogoutConsent skips the logout consent screen for this client. This field can only + be set from the admin API. + type: boolean subject_type: description: |- OpenID Connect Subject Type @@ -2652,14 +2909,16 @@ components: list of the supported subject_type values for this server. Valid types include `pairwise` and `public`. type: string token_endpoint_auth_method: - description: "OAuth 2.0 Token Endpoint Authentication Method\n\nRequested\ - \ Client Authentication method for the Token Endpoint. The options are:\n\ - \n`client_secret_post`: (default) Send `client_id` and `client_secret`\ - \ as `application/x-www-form-urlencoded` in the HTTP body.\n`client_secret_basic`:\ - \ Send `client_id` and `client_secret` as `application/x-www-form-urlencoded`\ - \ encoded in the HTTP Authorization header.\n`private_key_jwt`: Use JSON\ - \ Web Tokens to authenticate the client.\n`none`: Used for public clients\ - \ (native apps, mobile apps) which can not have secrets." + default: client_secret_basic + description: |- + OAuth 2.0 Token Endpoint Authentication Method + + Requested Client Authentication method for the Token Endpoint. The options are: + + `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. + `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. + `private_key_jwt`: Use JSON Web Tokens to authenticate the client. + `none`: Used for public clients (native apps, mobile apps) which can not have secrets. type: string token_endpoint_auth_signing_alg: description: |- @@ -2684,12 +2943,12 @@ components: format: date-time type: string userinfo_signed_response_alg: - description: "OpenID Connect Request Userinfo Signed Response Algorithm\n\ - \nJWS alg algorithm [JWA] REQUIRED for signing UserInfo Responses. If\ - \ this is specified, the response will be JWT\n[JWT] serialized, and signed\ - \ using JWS. The default, if omitted, is for the UserInfo Response to\ - \ return the Claims\nas a UTF-8 encoded JSON object using the application/json\ - \ content-type." + description: |- + OpenID Connect Request Userinfo Signed Response Algorithm + + JWS alg algorithm [JWA] REQUIRED for signing UserInfo Responses. If this is specified, the response will be JWT + [JWT] serialized, and signed using JWS. The default, if omitted, is for the UserInfo Response to return the Claims + as a UTF-8 encoded JSON object using the application/json content-type. type: string title: OAuth 2.0 Client type: object @@ -2799,7 +3058,7 @@ components: refresh_token_grant_access_token_lifespan: refresh_token_grant_access_token_lifespan registration_access_token: registration_access_token client_id: client_id - token_endpoint_auth_method: token_endpoint_auth_method + token_endpoint_auth_method: client_secret_basic userinfo_signed_response_alg: userinfo_signed_response_alg authorization_code_grant_id_token_lifespan: authorization_code_grant_id_token_lifespan authorization_code_grant_refresh_token_lifespan: authorization_code_grant_refresh_token_lifespan @@ -2815,6 +3074,7 @@ components: client_name: client_name policy_uri: policy_uri owner: owner + skip_consent: true audience: - audience - audience @@ -2833,10 +3093,12 @@ components: sector_identifier_uri: sector_identifier_uri frontchannel_logout_session_required: true frontchannel_logout_uri: frontchannel_logout_uri + skip_logout_consent: true refresh_token_grant_id_token_lifespan: refresh_token_grant_id_token_lifespan implicit_grant_id_token_lifespan: implicit_grant_id_token_lifespan client_secret_expires_at: 0 implicit_grant_access_token_lifespan: implicit_grant_access_token_lifespan + access_token_strategy: access_token_strategy jwks_uri: jwks_uri request_object_signing_alg: request_object_signing_alg tos_uri: tos_uri @@ -2852,9 +3114,9 @@ components: - requested_scope properties: acr: - description: "ACR represents the Authentication AuthorizationContext Class\ - \ Reference value for this authentication session. You can use it\nto\ - \ express that, for example, a user authenticated using two factor authentication." + description: |- + ACR represents the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it + to express that, for example, a user authenticated using two factor authentication. type: string amr: items: @@ -2887,11 +3149,10 @@ components: oidc_context: $ref: '#/components/schemas/oAuth2ConsentRequestOpenIDConnectContext' request_url: - description: "RequestURL is the original OAuth 2.0 Authorization URL requested\ - \ by the OAuth 2.0 client. It is the URL which\ninitiates the OAuth 2.0\ - \ Authorization Code or OAuth 2.0 Implicit flow. This URL is typically\ - \ not needed, but\nmight come in handy if you want to deal with additional\ - \ request parameters." + description: |- + RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which + initiates the OAuth 2.0 Authorization Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but + might come in handy if you want to deal with additional request parameters. type: string requested_access_token_audience: items: @@ -2906,15 +3167,15 @@ components: \ JSON for SQL storage." type: array skip: - description: "Skip, if true, implies that the client has requested the same\ - \ scopes from the same user previously.\nIf true, you must not ask the\ - \ user to grant the requested scopes. You must however either allow or\ - \ deny the\nconsent request using the usual API call." + description: |- + Skip, if true, implies that the client has requested the same scopes from the same user previously. + If true, you must not ask the user to grant the requested scopes. You must however either allow or deny the + consent request using the usual API call. type: boolean subject: - description: "Subject is the user ID of the end-user that authenticated.\ - \ Now, that end user needs to grant or deny the scope\nrequested by the\ - \ OAuth 2.0 client." + description: |- + Subject is the user ID of the end-user that authenticated. Now, that end user needs to grant or deny the scope + requested by the OAuth 2.0 client. type: string required: - challenge @@ -2934,36 +3195,29 @@ components: display: display properties: acr_values: - description: "ACRValues is the Authentication AuthorizationContext Class\ - \ Reference requested in the OAuth 2.0 Authorization request.\nIt is a\ - \ parameter defined by OpenID Connect and expresses which level of authentication\ - \ (e.g. 2FA) is required.\n\nOpenID Connect defines it as follows:\n>\ - \ Requested Authentication AuthorizationContext Class Reference values.\ - \ Space-separated string that specifies the acr values\nthat the Authorization\ - \ Server is being requested to use for processing this Authentication\ - \ Request, with the\nvalues appearing in order of preference. The Authentication\ - \ AuthorizationContext Class satisfied by the authentication\nperformed\ - \ is returned as the acr Claim Value, as specified in Section 2. The acr\ - \ Claim is requested as a\nVoluntary Claim by this parameter." + description: |- + ACRValues is the Authentication AuthorizationContext Class Reference requested in the OAuth 2.0 Authorization request. + It is a parameter defined by OpenID Connect and expresses which level of authentication (e.g. 2FA) is required. + + OpenID Connect defines it as follows: + > Requested Authentication AuthorizationContext Class Reference values. Space-separated string that specifies the acr values + that the Authorization Server is being requested to use for processing this Authentication Request, with the + values appearing in order of preference. The Authentication AuthorizationContext Class satisfied by the authentication + performed is returned as the acr Claim Value, as specified in Section 2. The acr Claim is requested as a + Voluntary Claim by this parameter. items: type: string type: array display: - description: "Display is a string value that specifies how the Authorization\ - \ Server displays the authentication and consent user interface pages\ - \ to the End-User.\nThe defined values are:\npage: The Authorization Server\ - \ SHOULD display the authentication and consent UI consistent with a full\ - \ User Agent page view. If the display parameter is not specified, this\ - \ is the default display mode.\npopup: The Authorization Server SHOULD\ - \ display the authentication and consent UI consistent with a popup User\ - \ Agent window. The popup User Agent window should be of an appropriate\ - \ size for a login-focused dialog and should not obscure the entire window\ - \ that it is popping up over.\ntouch: The Authorization Server SHOULD\ - \ display the authentication and consent UI consistent with a device that\ - \ leverages a touch interface.\nwap: The Authorization Server SHOULD display\ - \ the authentication and consent UI consistent with a \"feature phone\"\ - \ type display.\n\nThe Authorization Server MAY also attempt to detect\ - \ the capabilities of the User Agent and present an appropriate display." + description: |- + Display is a string value that specifies how the Authorization Server displays the authentication and consent user interface pages to the End-User. + The defined values are: + page: The Authorization Server SHOULD display the authentication and consent UI consistent with a full User Agent page view. If the display parameter is not specified, this is the default display mode. + popup: The Authorization Server SHOULD display the authentication and consent UI consistent with a popup User Agent window. The popup User Agent window should be of an appropriate size for a login-focused dialog and should not obscure the entire window that it is popping up over. + touch: The Authorization Server SHOULD display the authentication and consent UI consistent with a device that leverages a touch interface. + wap: The Authorization Server SHOULD display the authentication and consent UI consistent with a "feature phone" type display. + + The Authorization Server MAY also attempt to detect the capabilities of the User Agent and present an appropriate display. type: string id_token_hint_claims: additionalProperties: {} @@ -2979,14 +3233,12 @@ components: phone number in the format specified for the phone_number Claim. The use of this parameter is optional. type: string ui_locales: - description: "UILocales is the End-User'id preferred languages and scripts\ - \ for the user interface, represented as a\nspace-separated list of BCP47\ - \ [RFC5646] language tag values, ordered by preference. For instance,\ - \ the value\n\"fr-CA fr en\" represents a preference for French as spoken\ - \ in Canada, then French (without a region designation),\nfollowed by\ - \ English (without a region designation). An error SHOULD NOT result if\ - \ some or all of the requested\nlocales are not supported by the OpenID\ - \ Provider." + description: |- + UILocales is the End-User'id preferred languages and scripts for the user interface, represented as a + space-separated list of BCP47 [RFC5646] language tag values, ordered by preference. For instance, the value + "fr-CA fr en" represents a preference for French as spoken in Canada, then French (without a region designation), + followed by English (without a region designation). An error SHOULD NOT result if some or all of the requested + locales are not supported by the OpenID Provider. items: type: string type: array @@ -3036,7 +3288,7 @@ components: refresh_token_grant_access_token_lifespan: refresh_token_grant_access_token_lifespan registration_access_token: registration_access_token client_id: client_id - token_endpoint_auth_method: token_endpoint_auth_method + token_endpoint_auth_method: client_secret_basic userinfo_signed_response_alg: userinfo_signed_response_alg authorization_code_grant_id_token_lifespan: authorization_code_grant_id_token_lifespan authorization_code_grant_refresh_token_lifespan: authorization_code_grant_refresh_token_lifespan @@ -3052,6 +3304,7 @@ components: client_name: client_name policy_uri: policy_uri owner: owner + skip_consent: true audience: - audience - audience @@ -3070,10 +3323,12 @@ components: sector_identifier_uri: sector_identifier_uri frontchannel_logout_session_required: true frontchannel_logout_uri: frontchannel_logout_uri + skip_logout_consent: true refresh_token_grant_id_token_lifespan: refresh_token_grant_id_token_lifespan implicit_grant_id_token_lifespan: implicit_grant_id_token_lifespan client_secret_expires_at: 0 implicit_grant_access_token_lifespan: implicit_grant_access_token_lifespan + access_token_strategy: access_token_strategy jwks_uri: jwks_uri request_object_signing_alg: request_object_signing_alg tos_uri: tos_uri @@ -3096,6 +3351,7 @@ components: session: access_token: "" id_token: "" + context: "" grant_access_token_audience: - grant_access_token_audience - grant_access_token_audience @@ -3107,6 +3363,9 @@ components: properties: consent_request: $ref: '#/components/schemas/oAuth2ConsentRequest' + context: + title: "JSONRawMessage represents a json.RawMessage that works well with\ + \ JSON, SQL, and Swagger." expires_at: $ref: '#/components/schemas/oAuth2ConsentSession_expires_at' grant_access_token_audience: @@ -3126,14 +3385,18 @@ components: title: NullTime implements sql.NullTime functionality. type: string remember: - description: "Remember Consent\n\nRemember, if set to true, tells ORY Hydra\ - \ to remember this consent authorization and reuse it if the same\nclient\ - \ asks the same user for the same, or a subset of, scope." + description: |- + Remember Consent + + Remember, if set to true, tells ORY Hydra to remember this consent authorization and reuse it if the same + client asks the same user for the same, or a subset of, scope. type: boolean remember_for: - description: "Remember Consent For\n\nRememberFor sets how long the consent\ - \ authorization should be remembered for in seconds. If set to `0`, the\n\ - authorization will be remembered indefinitely." + description: |- + Remember Consent For + + RememberFor sets how long the consent authorization should be remembered for in seconds. If set to `0`, the + authorization will be remembered indefinitely. format: int64 type: integer session: @@ -3178,7 +3441,7 @@ components: refresh_token_grant_access_token_lifespan: refresh_token_grant_access_token_lifespan registration_access_token: registration_access_token client_id: client_id - token_endpoint_auth_method: token_endpoint_auth_method + token_endpoint_auth_method: client_secret_basic userinfo_signed_response_alg: userinfo_signed_response_alg authorization_code_grant_id_token_lifespan: authorization_code_grant_id_token_lifespan authorization_code_grant_refresh_token_lifespan: authorization_code_grant_refresh_token_lifespan @@ -3194,6 +3457,7 @@ components: client_name: client_name policy_uri: policy_uri owner: owner + skip_consent: true audience: - audience - audience @@ -3212,10 +3476,12 @@ components: sector_identifier_uri: sector_identifier_uri frontchannel_logout_session_required: true frontchannel_logout_uri: frontchannel_logout_uri + skip_logout_consent: true refresh_token_grant_id_token_lifespan: refresh_token_grant_id_token_lifespan implicit_grant_id_token_lifespan: implicit_grant_id_token_lifespan client_secret_expires_at: 0 implicit_grant_access_token_lifespan: implicit_grant_access_token_lifespan + access_token_strategy: access_token_strategy jwks_uri: jwks_uri request_object_signing_alg: request_object_signing_alg tos_uri: tos_uri @@ -3242,11 +3508,10 @@ components: oidc_context: $ref: '#/components/schemas/oAuth2ConsentRequestOpenIDConnectContext' request_url: - description: "RequestURL is the original OAuth 2.0 Authorization URL requested\ - \ by the OAuth 2.0 client. It is the URL which\ninitiates the OAuth 2.0\ - \ Authorization Code or OAuth 2.0 Implicit flow. This URL is typically\ - \ not needed, but\nmight come in handy if you want to deal with additional\ - \ request parameters." + description: |- + RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which + initiates the OAuth 2.0 Authorization Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but + might come in handy if you want to deal with additional request parameters. type: string requested_access_token_audience: items: @@ -3268,25 +3533,22 @@ components: channel logout. It's value can generally be used to associate consecutive login requests by a certain user. type: string skip: - description: "Skip, if true, implies that the client has requested the same\ - \ scopes from the same user previously.\nIf true, you can skip asking\ - \ the user to grant the requested scopes, and simply forward the user\ - \ to the redirect URL.\n\nThis feature allows you to update / set session\ - \ information." + description: |- + Skip, if true, implies that the client has requested the same scopes from the same user previously. + If true, you can skip asking the user to grant the requested scopes, and simply forward the user to the redirect URL. + + This feature allows you to update / set session information. type: boolean subject: - description: "Subject is the user ID of the end-user that authenticated.\ - \ Now, that end user needs to grant or deny the scope\nrequested by the\ - \ OAuth 2.0 client. If this value is set and `skip` is true, you MUST\ - \ include this subject type\nwhen accepting the login request, or the\ - \ request will fail." + description: |- + Subject is the user ID of the end-user that authenticated. Now, that end user needs to grant or deny the scope + requested by the OAuth 2.0 client. If this value is set and `skip` is true, you MUST include this subject type + when accepting the login request, or the request will fail. type: string required: - challenge - client - request_url - - requested_access_token_audience - - requested_scope - skip - subject title: Contains information on an ongoing login request. @@ -3310,7 +3572,7 @@ components: refresh_token_grant_access_token_lifespan: refresh_token_grant_access_token_lifespan registration_access_token: registration_access_token client_id: client_id - token_endpoint_auth_method: token_endpoint_auth_method + token_endpoint_auth_method: client_secret_basic userinfo_signed_response_alg: userinfo_signed_response_alg authorization_code_grant_id_token_lifespan: authorization_code_grant_id_token_lifespan authorization_code_grant_refresh_token_lifespan: authorization_code_grant_refresh_token_lifespan @@ -3326,6 +3588,7 @@ components: client_name: client_name policy_uri: policy_uri owner: owner + skip_consent: true audience: - audience - audience @@ -3344,10 +3607,12 @@ components: sector_identifier_uri: sector_identifier_uri frontchannel_logout_session_required: true frontchannel_logout_uri: frontchannel_logout_uri + skip_logout_consent: true refresh_token_grant_id_token_lifespan: refresh_token_grant_id_token_lifespan implicit_grant_id_token_lifespan: implicit_grant_id_token_lifespan client_secret_expires_at: 0 implicit_grant_access_token_lifespan: implicit_grant_access_token_lifespan + access_token_strategy: access_token_strategy jwks_uri: jwks_uri request_object_signing_alg: request_object_signing_alg tos_uri: tos_uri @@ -3404,7 +3669,7 @@ components: access_token: access_token refresh_token: refresh_token scope: scope - id_token: 6 + id_token: id_token token_type: token_type expires_in: 0 properties: @@ -3412,19 +3677,19 @@ components: description: The access token issued by the authorization server. type: string expires_in: - description: "The lifetime in seconds of the access token. For\nexample,\ - \ the value \"3600\" denotes that the access token will\nexpire in one\ - \ hour from the time the response was generated." + description: |- + The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. format: int64 type: integer id_token: description: To retrieve a refresh token request the id_token scope. - format: int64 - type: integer + type: string refresh_token: - description: "The refresh token, which can be used to obtain new\naccess\ - \ tokens. To retrieve it add the scope \"offline\" to your access token\ - \ request." + description: |- + The refresh token, which can be used to obtain new + access tokens. To retrieve it add the scope "offline" to your access token request. type: string scope: description: The scope of the access token @@ -3481,8 +3746,30 @@ components: code_challenge_methods_supported: - code_challenge_methods_supported - code_challenge_methods_supported + credentials_endpoint_draft_00: credentials_endpoint_draft_00 frontchannel_logout_session_supported: true jwks_uri: "https://{slug}.projects.oryapis.com/.well-known/jwks.json" + credentials_supported_draft_00: + - types: + - types + - types + cryptographic_suites_supported: + - cryptographic_suites_supported + - cryptographic_suites_supported + cryptographic_binding_methods_supported: + - cryptographic_binding_methods_supported + - cryptographic_binding_methods_supported + format: format + - types: + - types + - types + cryptographic_suites_supported: + - cryptographic_suites_supported + - cryptographic_suites_supported + cryptographic_binding_methods_supported: + - cryptographic_binding_methods_supported + - cryptographic_binding_methods_supported + format: format subject_types_supported: - subject_types_supported - subject_types_supported @@ -3499,36 +3786,56 @@ components: example: https://playground.ory.sh/ory-hydra/public/oauth2/auth type: string backchannel_logout_session_supported: - description: "OpenID Connect Back-Channel Logout Session Required\n\nBoolean\ - \ value specifying whether the OP can pass a sid (session ID) Claim in\ - \ the Logout Token to identify the RP\nsession with the OP. If supported,\ - \ the sid Claim is also included in ID Tokens issued by the OP" + description: |- + OpenID Connect Back-Channel Logout Session Required + + Boolean value specifying whether the OP can pass a sid (session ID) Claim in the Logout Token to identify the RP + session with the OP. If supported, the sid Claim is also included in ID Tokens issued by the OP type: boolean backchannel_logout_supported: - description: "OpenID Connect Back-Channel Logout Supported\n\nBoolean value\ - \ specifying whether the OP supports back-channel logout, with true indicating\ - \ support." + description: |- + OpenID Connect Back-Channel Logout Supported + + Boolean value specifying whether the OP supports back-channel logout, with true indicating support. type: boolean claims_parameter_supported: - description: "OpenID Connect Claims Parameter Parameter Supported\n\nBoolean\ - \ value specifying whether the OP supports use of the claims parameter,\ - \ with true indicating support." + description: |- + OpenID Connect Claims Parameter Parameter Supported + + Boolean value specifying whether the OP supports use of the claims parameter, with true indicating support. type: boolean claims_supported: - description: "OpenID Connect Supported Claims\n\nJSON array containing a\ - \ list of the Claim Names of the Claims that the OpenID Provider MAY be\ - \ able to supply\nvalues for. Note that for privacy or other reasons,\ - \ this might not be an exhaustive list." + description: |- + OpenID Connect Supported Claims + + JSON array containing a list of the Claim Names of the Claims that the OpenID Provider MAY be able to supply + values for. Note that for privacy or other reasons, this might not be an exhaustive list. items: type: string type: array code_challenge_methods_supported: - description: "OAuth 2.0 PKCE Supported Code Challenge Methods\n\nJSON array\ - \ containing a list of Proof Key for Code Exchange (PKCE) [RFC7636] code\ - \ challenge methods supported\nby this authorization server." + description: |- + OAuth 2.0 PKCE Supported Code Challenge Methods + + JSON array containing a list of Proof Key for Code Exchange (PKCE) [RFC7636] code challenge methods supported + by this authorization server. items: type: string type: array + credentials_endpoint_draft_00: + description: |- + OpenID Connect Verifiable Credentials Endpoint + + Contains the URL of the Verifiable Credentials Endpoint. + type: string + credentials_supported_draft_00: + description: |- + OpenID Connect Verifiable Credentials Supported + + JSON array containing a list of the Verifiable Credentials supported by this authorization server. + items: + $ref: '#/components/schemas/credentialSupportedDraft00' + type: array end_session_endpoint: description: |- OpenID Connect End-Session Endpoint @@ -3536,16 +3843,18 @@ components: URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP. type: string frontchannel_logout_session_supported: - description: "OpenID Connect Front-Channel Logout Session Required\n\nBoolean\ - \ value specifying whether the OP can pass iss (issuer) and sid (session\ - \ ID) query parameters to identify\nthe RP session with the OP when the\ - \ frontchannel_logout_uri is used. If supported, the sid Claim is also\n\ - included in ID Tokens issued by the OP." + description: |- + OpenID Connect Front-Channel Logout Session Required + + Boolean value specifying whether the OP can pass iss (issuer) and sid (session ID) query parameters to identify + the RP session with the OP when the frontchannel_logout_uri is used. If supported, the sid Claim is also + included in ID Tokens issued by the OP. type: boolean frontchannel_logout_supported: - description: "OpenID Connect Front-Channel Logout Supported\n\nBoolean value\ - \ specifying whether the OP supports HTTP-based logout, with true indicating\ - \ support." + description: |- + OpenID Connect Front-Channel Logout Supported + + Boolean value specifying whether the OP supports HTTP-based logout, with true indicating support. type: boolean grant_types_supported: description: |- @@ -3573,26 +3882,25 @@ components: type: string type: array issuer: - description: "OpenID Connect Issuer URL\n\nAn URL using the https scheme\ - \ with no query or fragment component that the OP asserts as its IssuerURL\ - \ Identifier.\nIf IssuerURL discovery is supported , this value MUST be\ - \ identical to the issuer value returned\nby WebFinger. This also MUST\ - \ be identical to the iss Claim value in ID Tokens issued from this IssuerURL." + description: |- + OpenID Connect Issuer URL + + An URL using the https scheme with no query or fragment component that the OP asserts as its IssuerURL Identifier. + If IssuerURL discovery is supported , this value MUST be identical to the issuer value returned + by WebFinger. This also MUST be identical to the iss Claim value in ID Tokens issued from this IssuerURL. example: https://playground.ory.sh/ory-hydra/public/ type: string jwks_uri: - description: "OpenID Connect Well-Known JSON Web Keys URL\n\nURL of the\ - \ OP's JSON Web Key Set [JWK] document. This contains the signing key(s)\ - \ the RP uses to validate\nsignatures from the OP. The JWK Set MAY also\ - \ contain the Server's encryption key(s), which are used by RPs\nto encrypt\ - \ requests to the Server. When both signing and encryption keys are made\ - \ available, a use (Key Use)\nparameter value is REQUIRED for all keys\ - \ in the referenced JWK Set to indicate each key's intended usage.\nAlthough\ - \ some algorithms allow the same key to be used for both signatures and\ - \ encryption, doing so is\nNOT RECOMMENDED, as it is less secure. The\ - \ JWK x5c parameter MAY be used to provide X.509 representations of\n\ - keys provided. When used, the bare key values MUST still be present and\ - \ MUST match those in the certificate." + description: |- + OpenID Connect Well-Known JSON Web Keys URL + + URL of the OP's JSON Web Key Set [JWK] document. This contains the signing key(s) the RP uses to validate + signatures from the OP. The JWK Set MAY also contain the Server's encryption key(s), which are used by RPs + to encrypt requests to the Server. When both signing and encryption keys are made available, a use (Key Use) + parameter value is REQUIRED for all keys in the referenced JWK Set to indicate each key's intended usage. + Although some algorithms allow the same key to be used for both signatures and encryption, doing so is + NOT RECOMMENDED, as it is less secure. The JWK x5c parameter MAY be used to provide X.509 representations of + keys provided. When used, the bare key values MUST still be present and MUST match those in the certificate. example: "https://{slug}.projects.oryapis.com/.well-known/jwks.json" type: string registration_endpoint: @@ -3600,25 +3908,27 @@ components: example: https://playground.ory.sh/ory-hydra/admin/client type: string request_object_signing_alg_values_supported: - description: "OpenID Connect Supported Request Object Signing Algorithms\n\ - \nJSON array containing a list of the JWS signing algorithms (alg values)\ - \ supported by the OP for Request Objects,\nwhich are described in Section\ - \ 6.1 of OpenID Connect Core 1.0 [OpenID.Core]. These algorithms are used\ - \ both when\nthe Request Object is passed by value (using the request\ - \ parameter) and when it is passed by reference\n(using the request_uri\ - \ parameter)." + description: |- + OpenID Connect Supported Request Object Signing Algorithms + + JSON array containing a list of the JWS signing algorithms (alg values) supported by the OP for Request Objects, + which are described in Section 6.1 of OpenID Connect Core 1.0 [OpenID.Core]. These algorithms are used both when + the Request Object is passed by value (using the request parameter) and when it is passed by reference + (using the request_uri parameter). items: type: string type: array request_parameter_supported: - description: "OpenID Connect Request Parameter Supported\n\nBoolean value\ - \ specifying whether the OP supports use of the request parameter, with\ - \ true indicating support." + description: |- + OpenID Connect Request Parameter Supported + + Boolean value specifying whether the OP supports use of the request parameter, with true indicating support. type: boolean request_uri_parameter_supported: - description: "OpenID Connect Request URI Parameter Supported\n\nBoolean\ - \ value specifying whether the OP supports use of the request_uri parameter,\ - \ with true indicating support." + description: |- + OpenID Connect Request URI Parameter Supported + + Boolean value specifying whether the OP supports use of the request_uri parameter, with true indicating support. type: boolean require_request_uri_registration: description: |- @@ -3636,10 +3946,11 @@ components: type: string type: array response_types_supported: - description: "OAuth 2.0 Supported Response Types\n\nJSON array containing\ - \ a list of the OAuth 2.0 response_type values that this OP supports.\ - \ Dynamic OpenID\nProviders MUST support the code, id_token, and the token\ - \ id_token Response Type values." + description: |- + OAuth 2.0 Supported Response Types + + JSON array containing a list of the OAuth 2.0 response_type values that this OP supports. Dynamic OpenID + Providers MUST support the code, id_token, and the token id_token Response Type values. items: type: string type: array @@ -3650,11 +3961,11 @@ components: URL of the authorization server's OAuth 2.0 revocation endpoint. type: string scopes_supported: - description: "OAuth 2.0 Supported Scope Values\n\nJSON array containing\ - \ a list of the OAuth 2.0 [RFC6749] scope values that this server supports.\ - \ The server MUST\nsupport the openid scope value. Servers MAY choose\ - \ not to advertise some supported scope values even when this parameter\ - \ is used" + description: |- + OAuth 2.0 Supported Scope Values + + JSON array containing a list of the OAuth 2.0 [RFC6749] scope values that this server supports. The server MUST + support the openid scope value. Servers MAY choose not to advertise some supported scope values even when this parameter is used items: type: string type: array @@ -3672,11 +3983,11 @@ components: example: https://playground.ory.sh/ory-hydra/public/oauth2/token type: string token_endpoint_auth_methods_supported: - description: "OAuth 2.0 Supported Client Authentication Methods\n\nJSON\ - \ array containing a list of Client Authentication methods supported by\ - \ this Token Endpoint. The options are\nclient_secret_post, client_secret_basic,\ - \ client_secret_jwt, and private_key_jwt, as described in Section 9 of\ - \ OpenID Connect Core 1.0" + description: |- + OAuth 2.0 Supported Client Authentication Methods + + JSON array containing a list of Client Authentication methods supported by this Token Endpoint. The options are + client_secret_post, client_secret_basic, client_secret_jwt, and private_key_jwt, as described in Section 9 of OpenID Connect Core 1.0 items: type: string type: array @@ -3695,10 +4006,10 @@ components: type: string type: array userinfo_signing_alg_values_supported: - description: "OpenID Connect Supported Userinfo Signing Algorithm\n\nJSON\ - \ array containing a list of the JWS [JWS] signing algorithms (alg values)\ - \ [JWA] supported by the UserInfo Endpoint to encode the Claims in a JWT\ - \ [JWT]." + description: |- + OpenID Connect Supported Userinfo Signing Algorithm + + JSON array containing a list of the JWS [JWS] signing algorithms (alg values) [JWA] supported by the UserInfo Endpoint to encode the Claims in a JWT [JWT]. items: type: string type: array @@ -3856,36 +4167,49 @@ components: properties: page_size: default: 250 - description: "Items per page\n\nThis is the number of items per page to\ - \ return.\nFor details on pagination please head over to the [pagination\ - \ documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + description: |- + Items per page + + This is the number of items per page to return. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). format: int64 maximum: 1000 minimum: 1 type: integer page_token: default: "1" - description: "Next Page Token\n\nThe next page token.\nFor details on pagination\ - \ please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + description: |- + Next Page Token + + The next page token. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). minimum: 1 type: string type: object paginationHeaders: properties: link: - description: "The link header contains pagination links.\n\nFor details\ - \ on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).\n\ - \nin: header" + description: |- + The link header contains pagination links. + + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). + + in: header type: string x-total-count: - description: "The total number of clients.\n\nin: header" + description: |- + The total number of clients. + + in: header type: string type: object rejectOAuth2Request: properties: error: - description: "The error should follow the OAuth2 error format (e.g. `invalid_request`,\ - \ `login_required`).\n\nDefaults to `request_denied`." + description: |- + The error should follow the OAuth2 error format (e.g. `invalid_request`, `login_required`). + + Defaults to `request_denied`. type: string error_debug: description: |- @@ -3911,69 +4235,92 @@ components: properties: page_size: default: 250 - description: "Items per page\n\nThis is the number of items per page to\ - \ return.\nFor details on pagination please head over to the [pagination\ - \ documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + description: |- + Items per page + + This is the number of items per page to return. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). format: int64 maximum: 1000 minimum: 1 type: integer page_token: default: "1" - description: "Next Page Token\n\nThe next page token.\nFor details on pagination\ - \ please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + description: |- + Next Page Token + + The next page token. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). minimum: 1 type: string type: object tokenPaginationHeaders: properties: link: - description: "The link header contains pagination links.\n\nFor details\ - \ on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination).\n\ - \nin: header" + description: |- + The link header contains pagination links. + + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). + + in: header type: string x-total-count: - description: "The total number of clients.\n\nin: header" + description: |- + The total number of clients. + + in: header type: string type: object tokenPaginationRequestParameters: - description: "The `Link` HTTP header contains multiple links (`first`, `next`,\ - \ `last`, `previous`) formatted as:\n`;\ - \ rel=\"{page}\"`\n\nFor details on pagination please head over to the [pagination\ - \ documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + description: |- + The `Link` HTTP header contains multiple links (`first`, `next`, `last`, `previous`) formatted as: + `; rel="{page}"` + + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). properties: page_size: default: 250 - description: "Items per Page\n\nThis is the number of items per page to\ - \ return.\nFor details on pagination please head over to the [pagination\ - \ documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + description: |- + Items per Page + + This is the number of items per page to return. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). format: int64 maximum: 500 minimum: 1 type: integer page_token: default: "1" - description: "Next Page Token\n\nThe next page token.\nFor details on pagination\ - \ please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + description: |- + Next Page Token + + The next page token. + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). minimum: 1 type: string title: Pagination Request Parameters type: object tokenPaginationResponseHeaders: - description: "The `Link` HTTP header contains multiple links (`first`, `next`,\ - \ `last`, `previous`) formatted as:\n`;\ - \ rel=\"{page}\"`\n\nFor details on pagination please head over to the [pagination\ - \ documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination)." + description: |- + The `Link` HTTP header contains multiple links (`first`, `next`, `last`, `previous`) formatted as: + `; rel="{page}"` + + For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). properties: link: - description: "The Link HTTP Header\n\nThe `Link` header contains a comma-delimited\ - \ list of links to the following pages:\n\nfirst: The first page of results.\n\ - next: The next page of results.\nprev: The previous page of results.\n\ - last: The last page of results.\n\nPages are omitted if they do not exist.\ - \ For example, if there is no next page, the `next` link is omitted. Examples:\n\ - \n; rel=\"first\",;\ - \ rel=\"next\",; rel=\"prev\",;\ - \ rel=\"last\"" + description: |- + The Link HTTP Header + + The `Link` header contains a comma-delimited list of links to the following pages: + + first: The first page of results. + next: The next page of results. + prev: The previous page of results. + last: The last page of results. + + Pages are omitted if they do not exist. For example, if there is no next page, the `next` link is omitted. Examples: + + ; rel="first",; rel="next",; rel="prev",; rel="last" type: string x-total-count: description: |- @@ -4099,6 +4446,42 @@ components: example: https://jwt-idp.example.com type: string type: object + unexpectedError: + type: string + verifiableCredentialPrimingResponse: + properties: + c_nonce: + type: string + c_nonce_expires_in: + format: int64 + type: integer + error: + type: string + error_debug: + type: string + error_description: + type: string + error_hint: + type: string + format: + type: string + status_code: + format: int64 + type: integer + title: VerifiableCredentialPrimingResponse contains the nonce to include in + the proof-of-possession JWT. + type: object + verifiableCredentialResponse: + example: + credential_draft_00: credential_draft_00 + format: format + properties: + credential_draft_00: + type: string + format: + type: string + title: VerifiableCredentialResponse contains the verifiable credential. + type: object version: properties: version: @@ -4108,16 +4491,17 @@ components: introspectOAuth2Token_request: properties: scope: - description: "An optional, space separated list of required scopes. If the\ - \ access token was not granted one of the\nscopes, the result of active\ - \ will be false." + description: |- + An optional, space separated list of required scopes. If the access token was not granted one of the + scopes, the result of active will be false. type: string x-formData-name: scope token: - description: "The string value of the token. For access tokens, this\nis\ - \ the \"access_token\" value returned from the token endpoint\ndefined\ - \ in OAuth 2.0. For refresh tokens, this is the \"refresh_token\"\nvalue\ - \ returned." + description: |- + The string value of the token. For access tokens, this + is the "access_token" value returned from the token endpoint + defined in OAuth 2.0. For refresh tokens, this is the "refresh_token" + value returned. required: - token type: string diff --git a/internal/httpclient/api_jwk.go b/internal/httpclient/api_jwk.go index eac14c93c1f..76c32a6e4d6 100644 --- a/internal/httpclient/api_jwk.go +++ b/internal/httpclient/api_jwk.go @@ -14,18 +14,18 @@ package openapi import ( "bytes" "context" - "io/ioutil" + "io" "net/http" "net/url" "strings" ) -// JwkApiService JwkApi service -type JwkApiService service +// JwkAPIService JwkAPI service +type JwkAPIService service type ApiCreateJsonWebKeySetRequest struct { ctx context.Context - ApiService *JwkApiService + ApiService *JwkAPIService set string createJsonWebKeySet *CreateJsonWebKeySet } @@ -50,7 +50,7 @@ A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that @param set The JSON Web Key Set ID @return ApiCreateJsonWebKeySetRequest */ -func (a *JwkApiService) CreateJsonWebKeySet(ctx context.Context, set string) ApiCreateJsonWebKeySetRequest { +func (a *JwkAPIService) CreateJsonWebKeySet(ctx context.Context, set string) ApiCreateJsonWebKeySetRequest { return ApiCreateJsonWebKeySetRequest{ ApiService: a, ctx: ctx, @@ -61,7 +61,7 @@ func (a *JwkApiService) CreateJsonWebKeySet(ctx context.Context, set string) Api // Execute executes the request // // @return JsonWebKeySet -func (a *JwkApiService) CreateJsonWebKeySetExecute(r ApiCreateJsonWebKeySetRequest) (*JsonWebKeySet, *http.Response, error) { +func (a *JwkAPIService) CreateJsonWebKeySetExecute(r ApiCreateJsonWebKeySetRequest) (*JsonWebKeySet, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} @@ -69,13 +69,13 @@ func (a *JwkApiService) CreateJsonWebKeySetExecute(r ApiCreateJsonWebKeySetReque localVarReturnValue *JsonWebKeySet ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkApiService.CreateJsonWebKeySet") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkAPIService.CreateJsonWebKeySet") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/keys/{set}" - localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterToString(r.set, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterValueToString(r.set, "set")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -113,9 +113,9 @@ func (a *JwkApiService) CreateJsonWebKeySetExecute(r ApiCreateJsonWebKeySetReque return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -131,6 +131,7 @@ func (a *JwkApiService) CreateJsonWebKeySetExecute(r ApiCreateJsonWebKeySetReque newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -149,7 +150,7 @@ func (a *JwkApiService) CreateJsonWebKeySetExecute(r ApiCreateJsonWebKeySetReque type ApiDeleteJsonWebKeyRequest struct { ctx context.Context - ApiService *JwkApiService + ApiService *JwkAPIService set string kid string } @@ -173,7 +174,7 @@ and allows storing user-defined keys as well. @param kid The JSON Web Key ID (kid) @return ApiDeleteJsonWebKeyRequest */ -func (a *JwkApiService) DeleteJsonWebKey(ctx context.Context, set string, kid string) ApiDeleteJsonWebKeyRequest { +func (a *JwkAPIService) DeleteJsonWebKey(ctx context.Context, set string, kid string) ApiDeleteJsonWebKeyRequest { return ApiDeleteJsonWebKeyRequest{ ApiService: a, ctx: ctx, @@ -183,21 +184,21 @@ func (a *JwkApiService) DeleteJsonWebKey(ctx context.Context, set string, kid st } // Execute executes the request -func (a *JwkApiService) DeleteJsonWebKeyExecute(r ApiDeleteJsonWebKeyRequest) (*http.Response, error) { +func (a *JwkAPIService) DeleteJsonWebKeyExecute(r ApiDeleteJsonWebKeyRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkApiService.DeleteJsonWebKey") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkAPIService.DeleteJsonWebKey") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/keys/{set}/{kid}" - localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterToString(r.set, "")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"kid"+"}", url.PathEscape(parameterToString(r.kid, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterValueToString(r.set, "set")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"kid"+"}", url.PathEscape(parameterValueToString(r.kid, "kid")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -230,9 +231,9 @@ func (a *JwkApiService) DeleteJsonWebKeyExecute(r ApiDeleteJsonWebKeyRequest) (* return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -248,6 +249,7 @@ func (a *JwkApiService) DeleteJsonWebKeyExecute(r ApiDeleteJsonWebKeyRequest) (* newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -257,7 +259,7 @@ func (a *JwkApiService) DeleteJsonWebKeyExecute(r ApiDeleteJsonWebKeyRequest) (* type ApiDeleteJsonWebKeySetRequest struct { ctx context.Context - ApiService *JwkApiService + ApiService *JwkAPIService set string } @@ -276,7 +278,7 @@ A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that @param set The JSON Web Key Set @return ApiDeleteJsonWebKeySetRequest */ -func (a *JwkApiService) DeleteJsonWebKeySet(ctx context.Context, set string) ApiDeleteJsonWebKeySetRequest { +func (a *JwkAPIService) DeleteJsonWebKeySet(ctx context.Context, set string) ApiDeleteJsonWebKeySetRequest { return ApiDeleteJsonWebKeySetRequest{ ApiService: a, ctx: ctx, @@ -285,20 +287,20 @@ func (a *JwkApiService) DeleteJsonWebKeySet(ctx context.Context, set string) Api } // Execute executes the request -func (a *JwkApiService) DeleteJsonWebKeySetExecute(r ApiDeleteJsonWebKeySetRequest) (*http.Response, error) { +func (a *JwkAPIService) DeleteJsonWebKeySetExecute(r ApiDeleteJsonWebKeySetRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkApiService.DeleteJsonWebKeySet") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkAPIService.DeleteJsonWebKeySet") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/keys/{set}" - localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterToString(r.set, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterValueToString(r.set, "set")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -331,9 +333,9 @@ func (a *JwkApiService) DeleteJsonWebKeySetExecute(r ApiDeleteJsonWebKeySetReque return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -349,6 +351,7 @@ func (a *JwkApiService) DeleteJsonWebKeySetExecute(r ApiDeleteJsonWebKeySetReque newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -358,7 +361,7 @@ func (a *JwkApiService) DeleteJsonWebKeySetExecute(r ApiDeleteJsonWebKeySetReque type ApiGetJsonWebKeyRequest struct { ctx context.Context - ApiService *JwkApiService + ApiService *JwkAPIService set string kid string } @@ -377,7 +380,7 @@ This endpoint returns a singular JSON Web Key contained in a set. It is identifi @param kid JSON Web Key ID @return ApiGetJsonWebKeyRequest */ -func (a *JwkApiService) GetJsonWebKey(ctx context.Context, set string, kid string) ApiGetJsonWebKeyRequest { +func (a *JwkAPIService) GetJsonWebKey(ctx context.Context, set string, kid string) ApiGetJsonWebKeyRequest { return ApiGetJsonWebKeyRequest{ ApiService: a, ctx: ctx, @@ -389,7 +392,7 @@ func (a *JwkApiService) GetJsonWebKey(ctx context.Context, set string, kid strin // Execute executes the request // // @return JsonWebKeySet -func (a *JwkApiService) GetJsonWebKeyExecute(r ApiGetJsonWebKeyRequest) (*JsonWebKeySet, *http.Response, error) { +func (a *JwkAPIService) GetJsonWebKeyExecute(r ApiGetJsonWebKeyRequest) (*JsonWebKeySet, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -397,14 +400,14 @@ func (a *JwkApiService) GetJsonWebKeyExecute(r ApiGetJsonWebKeyRequest) (*JsonWe localVarReturnValue *JsonWebKeySet ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkApiService.GetJsonWebKey") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkAPIService.GetJsonWebKey") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/keys/{set}/{kid}" - localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterToString(r.set, "")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"kid"+"}", url.PathEscape(parameterToString(r.kid, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterValueToString(r.set, "set")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"kid"+"}", url.PathEscape(parameterValueToString(r.kid, "kid")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -437,9 +440,9 @@ func (a *JwkApiService) GetJsonWebKeyExecute(r ApiGetJsonWebKeyRequest) (*JsonWe return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -455,6 +458,7 @@ func (a *JwkApiService) GetJsonWebKeyExecute(r ApiGetJsonWebKeyRequest) (*JsonWe newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -473,7 +477,7 @@ func (a *JwkApiService) GetJsonWebKeyExecute(r ApiGetJsonWebKeyRequest) (*JsonWe type ApiGetJsonWebKeySetRequest struct { ctx context.Context - ApiService *JwkApiService + ApiService *JwkAPIService set string } @@ -492,7 +496,7 @@ A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that @param set JSON Web Key Set ID @return ApiGetJsonWebKeySetRequest */ -func (a *JwkApiService) GetJsonWebKeySet(ctx context.Context, set string) ApiGetJsonWebKeySetRequest { +func (a *JwkAPIService) GetJsonWebKeySet(ctx context.Context, set string) ApiGetJsonWebKeySetRequest { return ApiGetJsonWebKeySetRequest{ ApiService: a, ctx: ctx, @@ -503,7 +507,7 @@ func (a *JwkApiService) GetJsonWebKeySet(ctx context.Context, set string) ApiGet // Execute executes the request // // @return JsonWebKeySet -func (a *JwkApiService) GetJsonWebKeySetExecute(r ApiGetJsonWebKeySetRequest) (*JsonWebKeySet, *http.Response, error) { +func (a *JwkAPIService) GetJsonWebKeySetExecute(r ApiGetJsonWebKeySetRequest) (*JsonWebKeySet, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -511,13 +515,13 @@ func (a *JwkApiService) GetJsonWebKeySetExecute(r ApiGetJsonWebKeySetRequest) (* localVarReturnValue *JsonWebKeySet ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkApiService.GetJsonWebKeySet") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkAPIService.GetJsonWebKeySet") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/keys/{set}" - localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterToString(r.set, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterValueToString(r.set, "set")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -550,9 +554,9 @@ func (a *JwkApiService) GetJsonWebKeySetExecute(r ApiGetJsonWebKeySetRequest) (* return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -568,6 +572,7 @@ func (a *JwkApiService) GetJsonWebKeySetExecute(r ApiGetJsonWebKeySetRequest) (* newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -586,7 +591,7 @@ func (a *JwkApiService) GetJsonWebKeySetExecute(r ApiGetJsonWebKeySetRequest) (* type ApiSetJsonWebKeyRequest struct { ctx context.Context - ApiService *JwkApiService + ApiService *JwkAPIService set string kid string jsonWebKey *JsonWebKey @@ -613,7 +618,7 @@ A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that @param kid JSON Web Key ID @return ApiSetJsonWebKeyRequest */ -func (a *JwkApiService) SetJsonWebKey(ctx context.Context, set string, kid string) ApiSetJsonWebKeyRequest { +func (a *JwkAPIService) SetJsonWebKey(ctx context.Context, set string, kid string) ApiSetJsonWebKeyRequest { return ApiSetJsonWebKeyRequest{ ApiService: a, ctx: ctx, @@ -625,7 +630,7 @@ func (a *JwkApiService) SetJsonWebKey(ctx context.Context, set string, kid strin // Execute executes the request // // @return JsonWebKey -func (a *JwkApiService) SetJsonWebKeyExecute(r ApiSetJsonWebKeyRequest) (*JsonWebKey, *http.Response, error) { +func (a *JwkAPIService) SetJsonWebKeyExecute(r ApiSetJsonWebKeyRequest) (*JsonWebKey, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -633,14 +638,14 @@ func (a *JwkApiService) SetJsonWebKeyExecute(r ApiSetJsonWebKeyRequest) (*JsonWe localVarReturnValue *JsonWebKey ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkApiService.SetJsonWebKey") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkAPIService.SetJsonWebKey") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/keys/{set}/{kid}" - localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterToString(r.set, "")), -1) - localVarPath = strings.Replace(localVarPath, "{"+"kid"+"}", url.PathEscape(parameterToString(r.kid, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterValueToString(r.set, "set")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"kid"+"}", url.PathEscape(parameterValueToString(r.kid, "kid")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -675,9 +680,9 @@ func (a *JwkApiService) SetJsonWebKeyExecute(r ApiSetJsonWebKeyRequest) (*JsonWe return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -693,6 +698,7 @@ func (a *JwkApiService) SetJsonWebKeyExecute(r ApiSetJsonWebKeyRequest) (*JsonWe newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -711,7 +717,7 @@ func (a *JwkApiService) SetJsonWebKeyExecute(r ApiSetJsonWebKeyRequest) (*JsonWe type ApiSetJsonWebKeySetRequest struct { ctx context.Context - ApiService *JwkApiService + ApiService *JwkAPIService set string jsonWebKeySet *JsonWebKeySet } @@ -736,7 +742,7 @@ A JSON Web Key (JWK) is a JavaScript Object Notation (JSON) data structure that @param set The JSON Web Key Set ID @return ApiSetJsonWebKeySetRequest */ -func (a *JwkApiService) SetJsonWebKeySet(ctx context.Context, set string) ApiSetJsonWebKeySetRequest { +func (a *JwkAPIService) SetJsonWebKeySet(ctx context.Context, set string) ApiSetJsonWebKeySetRequest { return ApiSetJsonWebKeySetRequest{ ApiService: a, ctx: ctx, @@ -747,7 +753,7 @@ func (a *JwkApiService) SetJsonWebKeySet(ctx context.Context, set string) ApiSet // Execute executes the request // // @return JsonWebKeySet -func (a *JwkApiService) SetJsonWebKeySetExecute(r ApiSetJsonWebKeySetRequest) (*JsonWebKeySet, *http.Response, error) { +func (a *JwkAPIService) SetJsonWebKeySetExecute(r ApiSetJsonWebKeySetRequest) (*JsonWebKeySet, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -755,13 +761,13 @@ func (a *JwkApiService) SetJsonWebKeySetExecute(r ApiSetJsonWebKeySetRequest) (* localVarReturnValue *JsonWebKeySet ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkApiService.SetJsonWebKeySet") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "JwkAPIService.SetJsonWebKeySet") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/keys/{set}" - localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterToString(r.set, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"set"+"}", url.PathEscape(parameterValueToString(r.set, "set")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -796,9 +802,9 @@ func (a *JwkApiService) SetJsonWebKeySetExecute(r ApiSetJsonWebKeySetRequest) (* return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -814,6 +820,7 @@ func (a *JwkApiService) SetJsonWebKeySetExecute(r ApiSetJsonWebKeySetRequest) (* newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } diff --git a/internal/httpclient/api_metadata.go b/internal/httpclient/api_metadata.go index c57ea8ff5db..5f7d316b9fc 100644 --- a/internal/httpclient/api_metadata.go +++ b/internal/httpclient/api_metadata.go @@ -14,17 +14,17 @@ package openapi import ( "bytes" "context" - "io/ioutil" + "io" "net/http" "net/url" ) -// MetadataApiService MetadataApi service -type MetadataApiService service +// MetadataAPIService MetadataAPI service +type MetadataAPIService service type ApiGetVersionRequest struct { ctx context.Context - ApiService *MetadataApiService + ApiService *MetadataAPIService } func (r ApiGetVersionRequest) Execute() (*GetVersion200Response, *http.Response, error) { @@ -45,7 +45,7 @@ refer to the cluster state, only to a single instance. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiGetVersionRequest */ -func (a *MetadataApiService) GetVersion(ctx context.Context) ApiGetVersionRequest { +func (a *MetadataAPIService) GetVersion(ctx context.Context) ApiGetVersionRequest { return ApiGetVersionRequest{ ApiService: a, ctx: ctx, @@ -55,7 +55,7 @@ func (a *MetadataApiService) GetVersion(ctx context.Context) ApiGetVersionReques // Execute executes the request // // @return GetVersion200Response -func (a *MetadataApiService) GetVersionExecute(r ApiGetVersionRequest) (*GetVersion200Response, *http.Response, error) { +func (a *MetadataAPIService) GetVersionExecute(r ApiGetVersionRequest) (*GetVersion200Response, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -63,7 +63,7 @@ func (a *MetadataApiService) GetVersionExecute(r ApiGetVersionRequest) (*GetVers localVarReturnValue *GetVersion200Response ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MetadataApiService.GetVersion") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MetadataAPIService.GetVersion") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -101,9 +101,9 @@ func (a *MetadataApiService) GetVersionExecute(r ApiGetVersionRequest) (*GetVers return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -130,7 +130,7 @@ func (a *MetadataApiService) GetVersionExecute(r ApiGetVersionRequest) (*GetVers type ApiIsAliveRequest struct { ctx context.Context - ApiService *MetadataApiService + ApiService *MetadataAPIService } func (r ApiIsAliveRequest) Execute() (*HealthStatus, *http.Response, error) { @@ -152,7 +152,7 @@ refer to the cluster state, only to a single instance. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiIsAliveRequest */ -func (a *MetadataApiService) IsAlive(ctx context.Context) ApiIsAliveRequest { +func (a *MetadataAPIService) IsAlive(ctx context.Context) ApiIsAliveRequest { return ApiIsAliveRequest{ ApiService: a, ctx: ctx, @@ -162,7 +162,7 @@ func (a *MetadataApiService) IsAlive(ctx context.Context) ApiIsAliveRequest { // Execute executes the request // // @return HealthStatus -func (a *MetadataApiService) IsAliveExecute(r ApiIsAliveRequest) (*HealthStatus, *http.Response, error) { +func (a *MetadataAPIService) IsAliveExecute(r ApiIsAliveRequest) (*HealthStatus, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -170,7 +170,7 @@ func (a *MetadataApiService) IsAliveExecute(r ApiIsAliveRequest) (*HealthStatus, localVarReturnValue *HealthStatus ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MetadataApiService.IsAlive") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MetadataAPIService.IsAlive") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -208,9 +208,9 @@ func (a *MetadataApiService) IsAliveExecute(r ApiIsAliveRequest) (*HealthStatus, return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -227,6 +227,7 @@ func (a *MetadataApiService) IsAliveExecute(r ApiIsAliveRequest) (*HealthStatus, newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v } return localVarReturnValue, localVarHTTPResponse, newErr @@ -246,7 +247,7 @@ func (a *MetadataApiService) IsAliveExecute(r ApiIsAliveRequest) (*HealthStatus, type ApiIsReadyRequest struct { ctx context.Context - ApiService *MetadataApiService + ApiService *MetadataAPIService } func (r ApiIsReadyRequest) Execute() (*IsReady200Response, *http.Response, error) { @@ -268,7 +269,7 @@ refer to the cluster state, only to a single instance. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiIsReadyRequest */ -func (a *MetadataApiService) IsReady(ctx context.Context) ApiIsReadyRequest { +func (a *MetadataAPIService) IsReady(ctx context.Context) ApiIsReadyRequest { return ApiIsReadyRequest{ ApiService: a, ctx: ctx, @@ -278,7 +279,7 @@ func (a *MetadataApiService) IsReady(ctx context.Context) ApiIsReadyRequest { // Execute executes the request // // @return IsReady200Response -func (a *MetadataApiService) IsReadyExecute(r ApiIsReadyRequest) (*IsReady200Response, *http.Response, error) { +func (a *MetadataAPIService) IsReadyExecute(r ApiIsReadyRequest) (*IsReady200Response, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -286,7 +287,7 @@ func (a *MetadataApiService) IsReadyExecute(r ApiIsReadyRequest) (*IsReady200Res localVarReturnValue *IsReady200Response ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MetadataApiService.IsReady") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MetadataAPIService.IsReady") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -324,9 +325,9 @@ func (a *MetadataApiService) IsReadyExecute(r ApiIsReadyRequest) (*IsReady200Res return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -343,6 +344,7 @@ func (a *MetadataApiService) IsReadyExecute(r ApiIsReadyRequest) (*IsReady200Res newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v } return localVarReturnValue, localVarHTTPResponse, newErr diff --git a/internal/httpclient/api_o_auth2.go b/internal/httpclient/api_o_auth2.go index 7d4ebb8c853..90a496a643e 100644 --- a/internal/httpclient/api_o_auth2.go +++ b/internal/httpclient/api_o_auth2.go @@ -14,18 +14,18 @@ package openapi import ( "bytes" "context" - "io/ioutil" + "io" "net/http" "net/url" "strings" ) -// OAuth2ApiService OAuth2Api service -type OAuth2ApiService service +// OAuth2APIService OAuth2API service +type OAuth2APIService service type ApiAcceptOAuth2ConsentRequestRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService consentChallenge *string acceptOAuth2ConsentRequest *AcceptOAuth2ConsentRequest } @@ -68,7 +68,7 @@ head over to the OAuth 2.0 documentation. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiAcceptOAuth2ConsentRequestRequest */ -func (a *OAuth2ApiService) AcceptOAuth2ConsentRequest(ctx context.Context) ApiAcceptOAuth2ConsentRequestRequest { +func (a *OAuth2APIService) AcceptOAuth2ConsentRequest(ctx context.Context) ApiAcceptOAuth2ConsentRequestRequest { return ApiAcceptOAuth2ConsentRequestRequest{ ApiService: a, ctx: ctx, @@ -78,7 +78,7 @@ func (a *OAuth2ApiService) AcceptOAuth2ConsentRequest(ctx context.Context) ApiAc // Execute executes the request // // @return OAuth2RedirectTo -func (a *OAuth2ApiService) AcceptOAuth2ConsentRequestExecute(r ApiAcceptOAuth2ConsentRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { +func (a *OAuth2APIService) AcceptOAuth2ConsentRequestExecute(r ApiAcceptOAuth2ConsentRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -86,7 +86,7 @@ func (a *OAuth2ApiService) AcceptOAuth2ConsentRequestExecute(r ApiAcceptOAuth2Co localVarReturnValue *OAuth2RedirectTo ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.AcceptOAuth2ConsentRequest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.AcceptOAuth2ConsentRequest") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -100,7 +100,7 @@ func (a *OAuth2ApiService) AcceptOAuth2ConsentRequestExecute(r ApiAcceptOAuth2Co return localVarReturnValue, nil, reportError("consentChallenge is required and must be specified") } - localVarQueryParams.Add("consent_challenge", parameterToString(*r.consentChallenge, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "consent_challenge", r.consentChallenge, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{"application/json"} @@ -130,9 +130,9 @@ func (a *OAuth2ApiService) AcceptOAuth2ConsentRequestExecute(r ApiAcceptOAuth2Co return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -148,6 +148,7 @@ func (a *OAuth2ApiService) AcceptOAuth2ConsentRequestExecute(r ApiAcceptOAuth2Co newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -166,7 +167,7 @@ func (a *OAuth2ApiService) AcceptOAuth2ConsentRequestExecute(r ApiAcceptOAuth2Co type ApiAcceptOAuth2LoginRequestRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService loginChallenge *string acceptOAuth2LoginRequest *AcceptOAuth2LoginRequest } @@ -204,7 +205,7 @@ The response contains a redirect URL which the login provider should redirect th @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiAcceptOAuth2LoginRequestRequest */ -func (a *OAuth2ApiService) AcceptOAuth2LoginRequest(ctx context.Context) ApiAcceptOAuth2LoginRequestRequest { +func (a *OAuth2APIService) AcceptOAuth2LoginRequest(ctx context.Context) ApiAcceptOAuth2LoginRequestRequest { return ApiAcceptOAuth2LoginRequestRequest{ ApiService: a, ctx: ctx, @@ -214,7 +215,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LoginRequest(ctx context.Context) ApiAcce // Execute executes the request // // @return OAuth2RedirectTo -func (a *OAuth2ApiService) AcceptOAuth2LoginRequestExecute(r ApiAcceptOAuth2LoginRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { +func (a *OAuth2APIService) AcceptOAuth2LoginRequestExecute(r ApiAcceptOAuth2LoginRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -222,7 +223,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LoginRequestExecute(r ApiAcceptOAuth2Logi localVarReturnValue *OAuth2RedirectTo ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.AcceptOAuth2LoginRequest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.AcceptOAuth2LoginRequest") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -236,7 +237,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LoginRequestExecute(r ApiAcceptOAuth2Logi return localVarReturnValue, nil, reportError("loginChallenge is required and must be specified") } - localVarQueryParams.Add("login_challenge", parameterToString(*r.loginChallenge, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "login_challenge", r.loginChallenge, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{"application/json"} @@ -266,9 +267,9 @@ func (a *OAuth2ApiService) AcceptOAuth2LoginRequestExecute(r ApiAcceptOAuth2Logi return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -284,6 +285,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LoginRequestExecute(r ApiAcceptOAuth2Logi newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -302,7 +304,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LoginRequestExecute(r ApiAcceptOAuth2Logi type ApiAcceptOAuth2LogoutRequestRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService logoutChallenge *string } @@ -326,7 +328,7 @@ The response contains a redirect URL which the consent provider should redirect @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiAcceptOAuth2LogoutRequestRequest */ -func (a *OAuth2ApiService) AcceptOAuth2LogoutRequest(ctx context.Context) ApiAcceptOAuth2LogoutRequestRequest { +func (a *OAuth2APIService) AcceptOAuth2LogoutRequest(ctx context.Context) ApiAcceptOAuth2LogoutRequestRequest { return ApiAcceptOAuth2LogoutRequestRequest{ ApiService: a, ctx: ctx, @@ -336,7 +338,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LogoutRequest(ctx context.Context) ApiAcc // Execute executes the request // // @return OAuth2RedirectTo -func (a *OAuth2ApiService) AcceptOAuth2LogoutRequestExecute(r ApiAcceptOAuth2LogoutRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { +func (a *OAuth2APIService) AcceptOAuth2LogoutRequestExecute(r ApiAcceptOAuth2LogoutRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -344,7 +346,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LogoutRequestExecute(r ApiAcceptOAuth2Log localVarReturnValue *OAuth2RedirectTo ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.AcceptOAuth2LogoutRequest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.AcceptOAuth2LogoutRequest") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -358,7 +360,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LogoutRequestExecute(r ApiAcceptOAuth2Log return localVarReturnValue, nil, reportError("logoutChallenge is required and must be specified") } - localVarQueryParams.Add("logout_challenge", parameterToString(*r.logoutChallenge, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "logout_challenge", r.logoutChallenge, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -386,9 +388,9 @@ func (a *OAuth2ApiService) AcceptOAuth2LogoutRequestExecute(r ApiAcceptOAuth2Log return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -404,6 +406,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LogoutRequestExecute(r ApiAcceptOAuth2Log newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -422,7 +425,7 @@ func (a *OAuth2ApiService) AcceptOAuth2LogoutRequestExecute(r ApiAcceptOAuth2Log type ApiCreateOAuth2ClientRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService oAuth2Client *OAuth2Client } @@ -445,7 +448,7 @@ is generated. The secret is echoed in the response. It is not possible to retrie @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiCreateOAuth2ClientRequest */ -func (a *OAuth2ApiService) CreateOAuth2Client(ctx context.Context) ApiCreateOAuth2ClientRequest { +func (a *OAuth2APIService) CreateOAuth2Client(ctx context.Context) ApiCreateOAuth2ClientRequest { return ApiCreateOAuth2ClientRequest{ ApiService: a, ctx: ctx, @@ -455,7 +458,7 @@ func (a *OAuth2ApiService) CreateOAuth2Client(ctx context.Context) ApiCreateOAut // Execute executes the request // // @return OAuth2Client -func (a *OAuth2ApiService) CreateOAuth2ClientExecute(r ApiCreateOAuth2ClientRequest) (*OAuth2Client, *http.Response, error) { +func (a *OAuth2APIService) CreateOAuth2ClientExecute(r ApiCreateOAuth2ClientRequest) (*OAuth2Client, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} @@ -463,7 +466,7 @@ func (a *OAuth2ApiService) CreateOAuth2ClientExecute(r ApiCreateOAuth2ClientRequ localVarReturnValue *OAuth2Client ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.CreateOAuth2Client") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.CreateOAuth2Client") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -506,9 +509,9 @@ func (a *OAuth2ApiService) CreateOAuth2ClientExecute(r ApiCreateOAuth2ClientRequ return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -525,6 +528,7 @@ func (a *OAuth2ApiService) CreateOAuth2ClientExecute(r ApiCreateOAuth2ClientRequ newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -534,6 +538,7 @@ func (a *OAuth2ApiService) CreateOAuth2ClientExecute(r ApiCreateOAuth2ClientRequ newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -552,7 +557,7 @@ func (a *OAuth2ApiService) CreateOAuth2ClientExecute(r ApiCreateOAuth2ClientRequ type ApiDeleteOAuth2ClientRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService id string } @@ -574,7 +579,7 @@ Make sure that this endpoint is well protected and only callable by first-party @param id The id of the OAuth 2.0 Client. @return ApiDeleteOAuth2ClientRequest */ -func (a *OAuth2ApiService) DeleteOAuth2Client(ctx context.Context, id string) ApiDeleteOAuth2ClientRequest { +func (a *OAuth2APIService) DeleteOAuth2Client(ctx context.Context, id string) ApiDeleteOAuth2ClientRequest { return ApiDeleteOAuth2ClientRequest{ ApiService: a, ctx: ctx, @@ -583,20 +588,20 @@ func (a *OAuth2ApiService) DeleteOAuth2Client(ctx context.Context, id string) Ap } // Execute executes the request -func (a *OAuth2ApiService) DeleteOAuth2ClientExecute(r ApiDeleteOAuth2ClientRequest) (*http.Response, error) { +func (a *OAuth2APIService) DeleteOAuth2ClientExecute(r ApiDeleteOAuth2ClientRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.DeleteOAuth2Client") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.DeleteOAuth2Client") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/clients/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -629,9 +634,9 @@ func (a *OAuth2ApiService) DeleteOAuth2ClientExecute(r ApiDeleteOAuth2ClientRequ return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -647,6 +652,7 @@ func (a *OAuth2ApiService) DeleteOAuth2ClientExecute(r ApiDeleteOAuth2ClientRequ newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -656,7 +662,7 @@ func (a *OAuth2ApiService) DeleteOAuth2ClientExecute(r ApiDeleteOAuth2ClientRequ type ApiDeleteOAuth2TokenRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService clientId *string } @@ -678,7 +684,7 @@ This endpoint deletes OAuth2 access tokens issued to an OAuth 2.0 Client from th @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiDeleteOAuth2TokenRequest */ -func (a *OAuth2ApiService) DeleteOAuth2Token(ctx context.Context) ApiDeleteOAuth2TokenRequest { +func (a *OAuth2APIService) DeleteOAuth2Token(ctx context.Context) ApiDeleteOAuth2TokenRequest { return ApiDeleteOAuth2TokenRequest{ ApiService: a, ctx: ctx, @@ -686,14 +692,14 @@ func (a *OAuth2ApiService) DeleteOAuth2Token(ctx context.Context) ApiDeleteOAuth } // Execute executes the request -func (a *OAuth2ApiService) DeleteOAuth2TokenExecute(r ApiDeleteOAuth2TokenRequest) (*http.Response, error) { +func (a *OAuth2APIService) DeleteOAuth2TokenExecute(r ApiDeleteOAuth2TokenRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.DeleteOAuth2Token") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.DeleteOAuth2Token") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } @@ -707,7 +713,7 @@ func (a *OAuth2ApiService) DeleteOAuth2TokenExecute(r ApiDeleteOAuth2TokenReques return nil, reportError("clientId is required and must be specified") } - localVarQueryParams.Add("client_id", parameterToString(*r.clientId, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "client_id", r.clientId, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -735,9 +741,9 @@ func (a *OAuth2ApiService) DeleteOAuth2TokenExecute(r ApiDeleteOAuth2TokenReques return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -753,6 +759,7 @@ func (a *OAuth2ApiService) DeleteOAuth2TokenExecute(r ApiDeleteOAuth2TokenReques newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -762,7 +769,7 @@ func (a *OAuth2ApiService) DeleteOAuth2TokenExecute(r ApiDeleteOAuth2TokenReques type ApiDeleteTrustedOAuth2JwtGrantIssuerRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService id string } @@ -783,7 +790,7 @@ for OAuth 2.0 Client Authentication and Authorization Grant. @param id The id of the desired grant @return ApiDeleteTrustedOAuth2JwtGrantIssuerRequest */ -func (a *OAuth2ApiService) DeleteTrustedOAuth2JwtGrantIssuer(ctx context.Context, id string) ApiDeleteTrustedOAuth2JwtGrantIssuerRequest { +func (a *OAuth2APIService) DeleteTrustedOAuth2JwtGrantIssuer(ctx context.Context, id string) ApiDeleteTrustedOAuth2JwtGrantIssuerRequest { return ApiDeleteTrustedOAuth2JwtGrantIssuerRequest{ ApiService: a, ctx: ctx, @@ -792,20 +799,20 @@ func (a *OAuth2ApiService) DeleteTrustedOAuth2JwtGrantIssuer(ctx context.Context } // Execute executes the request -func (a *OAuth2ApiService) DeleteTrustedOAuth2JwtGrantIssuerExecute(r ApiDeleteTrustedOAuth2JwtGrantIssuerRequest) (*http.Response, error) { +func (a *OAuth2APIService) DeleteTrustedOAuth2JwtGrantIssuerExecute(r ApiDeleteTrustedOAuth2JwtGrantIssuerRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.DeleteTrustedOAuth2JwtGrantIssuer") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.DeleteTrustedOAuth2JwtGrantIssuer") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/trust/grants/jwt-bearer/issuers/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -838,9 +845,9 @@ func (a *OAuth2ApiService) DeleteTrustedOAuth2JwtGrantIssuerExecute(r ApiDeleteT return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -856,6 +863,7 @@ func (a *OAuth2ApiService) DeleteTrustedOAuth2JwtGrantIssuerExecute(r ApiDeleteT newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -865,7 +873,7 @@ func (a *OAuth2ApiService) DeleteTrustedOAuth2JwtGrantIssuerExecute(r ApiDeleteT type ApiGetOAuth2ClientRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService id string } @@ -885,7 +893,7 @@ generated for applications which want to consume your OAuth 2.0 or OpenID Connec @param id The id of the OAuth 2.0 Client. @return ApiGetOAuth2ClientRequest */ -func (a *OAuth2ApiService) GetOAuth2Client(ctx context.Context, id string) ApiGetOAuth2ClientRequest { +func (a *OAuth2APIService) GetOAuth2Client(ctx context.Context, id string) ApiGetOAuth2ClientRequest { return ApiGetOAuth2ClientRequest{ ApiService: a, ctx: ctx, @@ -896,7 +904,7 @@ func (a *OAuth2ApiService) GetOAuth2Client(ctx context.Context, id string) ApiGe // Execute executes the request // // @return OAuth2Client -func (a *OAuth2ApiService) GetOAuth2ClientExecute(r ApiGetOAuth2ClientRequest) (*OAuth2Client, *http.Response, error) { +func (a *OAuth2APIService) GetOAuth2ClientExecute(r ApiGetOAuth2ClientRequest) (*OAuth2Client, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -904,13 +912,13 @@ func (a *OAuth2ApiService) GetOAuth2ClientExecute(r ApiGetOAuth2ClientRequest) ( localVarReturnValue *OAuth2Client ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.GetOAuth2Client") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.GetOAuth2Client") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/clients/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -943,9 +951,9 @@ func (a *OAuth2ApiService) GetOAuth2ClientExecute(r ApiGetOAuth2ClientRequest) ( return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -961,6 +969,7 @@ func (a *OAuth2ApiService) GetOAuth2ClientExecute(r ApiGetOAuth2ClientRequest) ( newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -979,7 +988,7 @@ func (a *OAuth2ApiService) GetOAuth2ClientExecute(r ApiGetOAuth2ClientRequest) ( type ApiGetOAuth2ConsentRequestRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService consentChallenge *string } @@ -1010,7 +1019,7 @@ head over to the OAuth 2.0 documentation. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiGetOAuth2ConsentRequestRequest */ -func (a *OAuth2ApiService) GetOAuth2ConsentRequest(ctx context.Context) ApiGetOAuth2ConsentRequestRequest { +func (a *OAuth2APIService) GetOAuth2ConsentRequest(ctx context.Context) ApiGetOAuth2ConsentRequestRequest { return ApiGetOAuth2ConsentRequestRequest{ ApiService: a, ctx: ctx, @@ -1020,7 +1029,7 @@ func (a *OAuth2ApiService) GetOAuth2ConsentRequest(ctx context.Context) ApiGetOA // Execute executes the request // // @return OAuth2ConsentRequest -func (a *OAuth2ApiService) GetOAuth2ConsentRequestExecute(r ApiGetOAuth2ConsentRequestRequest) (*OAuth2ConsentRequest, *http.Response, error) { +func (a *OAuth2APIService) GetOAuth2ConsentRequestExecute(r ApiGetOAuth2ConsentRequestRequest) (*OAuth2ConsentRequest, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -1028,7 +1037,7 @@ func (a *OAuth2ApiService) GetOAuth2ConsentRequestExecute(r ApiGetOAuth2ConsentR localVarReturnValue *OAuth2ConsentRequest ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.GetOAuth2ConsentRequest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.GetOAuth2ConsentRequest") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -1042,7 +1051,7 @@ func (a *OAuth2ApiService) GetOAuth2ConsentRequestExecute(r ApiGetOAuth2ConsentR return localVarReturnValue, nil, reportError("consentChallenge is required and must be specified") } - localVarQueryParams.Add("consent_challenge", parameterToString(*r.consentChallenge, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "consent_challenge", r.consentChallenge, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -1070,9 +1079,9 @@ func (a *OAuth2ApiService) GetOAuth2ConsentRequestExecute(r ApiGetOAuth2ConsentR return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -1089,6 +1098,7 @@ func (a *OAuth2ApiService) GetOAuth2ConsentRequestExecute(r ApiGetOAuth2ConsentR newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1098,6 +1108,7 @@ func (a *OAuth2ApiService) GetOAuth2ConsentRequestExecute(r ApiGetOAuth2ConsentR newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1116,7 +1127,7 @@ func (a *OAuth2ApiService) GetOAuth2ConsentRequestExecute(r ApiGetOAuth2ConsentR type ApiGetOAuth2LoginRequestRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService loginChallenge *string } @@ -1146,7 +1157,7 @@ provider uses that challenge to fetch information on the OAuth2 request and then @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiGetOAuth2LoginRequestRequest */ -func (a *OAuth2ApiService) GetOAuth2LoginRequest(ctx context.Context) ApiGetOAuth2LoginRequestRequest { +func (a *OAuth2APIService) GetOAuth2LoginRequest(ctx context.Context) ApiGetOAuth2LoginRequestRequest { return ApiGetOAuth2LoginRequestRequest{ ApiService: a, ctx: ctx, @@ -1156,7 +1167,7 @@ func (a *OAuth2ApiService) GetOAuth2LoginRequest(ctx context.Context) ApiGetOAut // Execute executes the request // // @return OAuth2LoginRequest -func (a *OAuth2ApiService) GetOAuth2LoginRequestExecute(r ApiGetOAuth2LoginRequestRequest) (*OAuth2LoginRequest, *http.Response, error) { +func (a *OAuth2APIService) GetOAuth2LoginRequestExecute(r ApiGetOAuth2LoginRequestRequest) (*OAuth2LoginRequest, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -1164,7 +1175,7 @@ func (a *OAuth2ApiService) GetOAuth2LoginRequestExecute(r ApiGetOAuth2LoginReque localVarReturnValue *OAuth2LoginRequest ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.GetOAuth2LoginRequest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.GetOAuth2LoginRequest") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -1178,7 +1189,7 @@ func (a *OAuth2ApiService) GetOAuth2LoginRequestExecute(r ApiGetOAuth2LoginReque return localVarReturnValue, nil, reportError("loginChallenge is required and must be specified") } - localVarQueryParams.Add("login_challenge", parameterToString(*r.loginChallenge, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "login_challenge", r.loginChallenge, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -1206,9 +1217,9 @@ func (a *OAuth2ApiService) GetOAuth2LoginRequestExecute(r ApiGetOAuth2LoginReque return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -1225,6 +1236,7 @@ func (a *OAuth2ApiService) GetOAuth2LoginRequestExecute(r ApiGetOAuth2LoginReque newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1234,6 +1246,7 @@ func (a *OAuth2ApiService) GetOAuth2LoginRequestExecute(r ApiGetOAuth2LoginReque newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1252,7 +1265,7 @@ func (a *OAuth2ApiService) GetOAuth2LoginRequestExecute(r ApiGetOAuth2LoginReque type ApiGetOAuth2LogoutRequestRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService logoutChallenge *string } @@ -1273,7 +1286,7 @@ Use this endpoint to fetch an Ory OAuth 2.0 logout request. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiGetOAuth2LogoutRequestRequest */ -func (a *OAuth2ApiService) GetOAuth2LogoutRequest(ctx context.Context) ApiGetOAuth2LogoutRequestRequest { +func (a *OAuth2APIService) GetOAuth2LogoutRequest(ctx context.Context) ApiGetOAuth2LogoutRequestRequest { return ApiGetOAuth2LogoutRequestRequest{ ApiService: a, ctx: ctx, @@ -1283,7 +1296,7 @@ func (a *OAuth2ApiService) GetOAuth2LogoutRequest(ctx context.Context) ApiGetOAu // Execute executes the request // // @return OAuth2LogoutRequest -func (a *OAuth2ApiService) GetOAuth2LogoutRequestExecute(r ApiGetOAuth2LogoutRequestRequest) (*OAuth2LogoutRequest, *http.Response, error) { +func (a *OAuth2APIService) GetOAuth2LogoutRequestExecute(r ApiGetOAuth2LogoutRequestRequest) (*OAuth2LogoutRequest, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -1291,7 +1304,7 @@ func (a *OAuth2ApiService) GetOAuth2LogoutRequestExecute(r ApiGetOAuth2LogoutReq localVarReturnValue *OAuth2LogoutRequest ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.GetOAuth2LogoutRequest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.GetOAuth2LogoutRequest") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -1305,7 +1318,7 @@ func (a *OAuth2ApiService) GetOAuth2LogoutRequestExecute(r ApiGetOAuth2LogoutReq return localVarReturnValue, nil, reportError("logoutChallenge is required and must be specified") } - localVarQueryParams.Add("logout_challenge", parameterToString(*r.logoutChallenge, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "logout_challenge", r.logoutChallenge, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -1333,9 +1346,9 @@ func (a *OAuth2ApiService) GetOAuth2LogoutRequestExecute(r ApiGetOAuth2LogoutReq return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -1352,6 +1365,7 @@ func (a *OAuth2ApiService) GetOAuth2LogoutRequestExecute(r ApiGetOAuth2LogoutReq newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1361,6 +1375,7 @@ func (a *OAuth2ApiService) GetOAuth2LogoutRequestExecute(r ApiGetOAuth2LogoutReq newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1379,7 +1394,7 @@ func (a *OAuth2ApiService) GetOAuth2LogoutRequestExecute(r ApiGetOAuth2LogoutReq type ApiGetTrustedOAuth2JwtGrantIssuerRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService id string } @@ -1397,7 +1412,7 @@ created the trust relationship. @param id The id of the desired grant @return ApiGetTrustedOAuth2JwtGrantIssuerRequest */ -func (a *OAuth2ApiService) GetTrustedOAuth2JwtGrantIssuer(ctx context.Context, id string) ApiGetTrustedOAuth2JwtGrantIssuerRequest { +func (a *OAuth2APIService) GetTrustedOAuth2JwtGrantIssuer(ctx context.Context, id string) ApiGetTrustedOAuth2JwtGrantIssuerRequest { return ApiGetTrustedOAuth2JwtGrantIssuerRequest{ ApiService: a, ctx: ctx, @@ -1408,7 +1423,7 @@ func (a *OAuth2ApiService) GetTrustedOAuth2JwtGrantIssuer(ctx context.Context, i // Execute executes the request // // @return TrustedOAuth2JwtGrantIssuer -func (a *OAuth2ApiService) GetTrustedOAuth2JwtGrantIssuerExecute(r ApiGetTrustedOAuth2JwtGrantIssuerRequest) (*TrustedOAuth2JwtGrantIssuer, *http.Response, error) { +func (a *OAuth2APIService) GetTrustedOAuth2JwtGrantIssuerExecute(r ApiGetTrustedOAuth2JwtGrantIssuerRequest) (*TrustedOAuth2JwtGrantIssuer, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -1416,13 +1431,13 @@ func (a *OAuth2ApiService) GetTrustedOAuth2JwtGrantIssuerExecute(r ApiGetTrusted localVarReturnValue *TrustedOAuth2JwtGrantIssuer ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.GetTrustedOAuth2JwtGrantIssuer") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.GetTrustedOAuth2JwtGrantIssuer") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/trust/grants/jwt-bearer/issuers/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -1455,9 +1470,9 @@ func (a *OAuth2ApiService) GetTrustedOAuth2JwtGrantIssuerExecute(r ApiGetTrusted return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -1473,6 +1488,7 @@ func (a *OAuth2ApiService) GetTrustedOAuth2JwtGrantIssuerExecute(r ApiGetTrusted newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1491,7 +1507,7 @@ func (a *OAuth2ApiService) GetTrustedOAuth2JwtGrantIssuerExecute(r ApiGetTrusted type ApiIntrospectOAuth2TokenRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService token *string scope *string } @@ -1522,7 +1538,7 @@ set additional data for a token by setting `session.access_token` during the con @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiIntrospectOAuth2TokenRequest */ -func (a *OAuth2ApiService) IntrospectOAuth2Token(ctx context.Context) ApiIntrospectOAuth2TokenRequest { +func (a *OAuth2APIService) IntrospectOAuth2Token(ctx context.Context) ApiIntrospectOAuth2TokenRequest { return ApiIntrospectOAuth2TokenRequest{ ApiService: a, ctx: ctx, @@ -1532,7 +1548,7 @@ func (a *OAuth2ApiService) IntrospectOAuth2Token(ctx context.Context) ApiIntrosp // Execute executes the request // // @return IntrospectedOAuth2Token -func (a *OAuth2ApiService) IntrospectOAuth2TokenExecute(r ApiIntrospectOAuth2TokenRequest) (*IntrospectedOAuth2Token, *http.Response, error) { +func (a *OAuth2APIService) IntrospectOAuth2TokenExecute(r ApiIntrospectOAuth2TokenRequest) (*IntrospectedOAuth2Token, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} @@ -1540,7 +1556,7 @@ func (a *OAuth2ApiService) IntrospectOAuth2TokenExecute(r ApiIntrospectOAuth2Tok localVarReturnValue *IntrospectedOAuth2Token ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.IntrospectOAuth2Token") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.IntrospectOAuth2Token") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -1572,9 +1588,9 @@ func (a *OAuth2ApiService) IntrospectOAuth2TokenExecute(r ApiIntrospectOAuth2Tok localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } if r.scope != nil { - localVarFormParams.Add("scope", parameterToString(*r.scope, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "scope", r.scope, "") } - localVarFormParams.Add("token", parameterToString(*r.token, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "token", r.token, "") req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) if err != nil { return localVarReturnValue, nil, err @@ -1585,9 +1601,9 @@ func (a *OAuth2ApiService) IntrospectOAuth2TokenExecute(r ApiIntrospectOAuth2Tok return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -1603,6 +1619,7 @@ func (a *OAuth2ApiService) IntrospectOAuth2TokenExecute(r ApiIntrospectOAuth2Tok newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1621,7 +1638,7 @@ func (a *OAuth2ApiService) IntrospectOAuth2TokenExecute(r ApiIntrospectOAuth2Tok type ApiListOAuth2ClientsRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService pageSize *int64 pageToken *string clientName *string @@ -1665,7 +1682,7 @@ As a default it lists the first 100 clients. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiListOAuth2ClientsRequest */ -func (a *OAuth2ApiService) ListOAuth2Clients(ctx context.Context) ApiListOAuth2ClientsRequest { +func (a *OAuth2APIService) ListOAuth2Clients(ctx context.Context) ApiListOAuth2ClientsRequest { return ApiListOAuth2ClientsRequest{ ApiService: a, ctx: ctx, @@ -1675,7 +1692,7 @@ func (a *OAuth2ApiService) ListOAuth2Clients(ctx context.Context) ApiListOAuth2C // Execute executes the request // // @return []OAuth2Client -func (a *OAuth2ApiService) ListOAuth2ClientsExecute(r ApiListOAuth2ClientsRequest) ([]OAuth2Client, *http.Response, error) { +func (a *OAuth2APIService) ListOAuth2ClientsExecute(r ApiListOAuth2ClientsRequest) ([]OAuth2Client, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -1683,7 +1700,7 @@ func (a *OAuth2ApiService) ListOAuth2ClientsExecute(r ApiListOAuth2ClientsReques localVarReturnValue []OAuth2Client ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.ListOAuth2Clients") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.ListOAuth2Clients") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -1695,16 +1712,22 @@ func (a *OAuth2ApiService) ListOAuth2ClientsExecute(r ApiListOAuth2ClientsReques localVarFormParams := url.Values{} if r.pageSize != nil { - localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "page_size", r.pageSize, "") + } else { + var defaultValue int64 = 250 + r.pageSize = &defaultValue } if r.pageToken != nil { - localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "page_token", r.pageToken, "") + } else { + var defaultValue string = "1" + r.pageToken = &defaultValue } if r.clientName != nil { - localVarQueryParams.Add("client_name", parameterToString(*r.clientName, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "client_name", r.clientName, "") } if r.owner != nil { - localVarQueryParams.Add("owner", parameterToString(*r.owner, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "owner", r.owner, "") } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -1733,9 +1756,9 @@ func (a *OAuth2ApiService) ListOAuth2ClientsExecute(r ApiListOAuth2ClientsReques return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -1751,6 +1774,7 @@ func (a *OAuth2ApiService) ListOAuth2ClientsExecute(r ApiListOAuth2ClientsReques newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1769,7 +1793,7 @@ func (a *OAuth2ApiService) ListOAuth2ClientsExecute(r ApiListOAuth2ClientsReques type ApiListOAuth2ConsentSessionsRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService subject *string pageSize *int64 pageToken *string @@ -1814,7 +1838,7 @@ empty JSON array with status code 200 OK. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiListOAuth2ConsentSessionsRequest */ -func (a *OAuth2ApiService) ListOAuth2ConsentSessions(ctx context.Context) ApiListOAuth2ConsentSessionsRequest { +func (a *OAuth2APIService) ListOAuth2ConsentSessions(ctx context.Context) ApiListOAuth2ConsentSessionsRequest { return ApiListOAuth2ConsentSessionsRequest{ ApiService: a, ctx: ctx, @@ -1824,7 +1848,7 @@ func (a *OAuth2ApiService) ListOAuth2ConsentSessions(ctx context.Context) ApiLis // Execute executes the request // // @return []OAuth2ConsentSession -func (a *OAuth2ApiService) ListOAuth2ConsentSessionsExecute(r ApiListOAuth2ConsentSessionsRequest) ([]OAuth2ConsentSession, *http.Response, error) { +func (a *OAuth2APIService) ListOAuth2ConsentSessionsExecute(r ApiListOAuth2ConsentSessionsRequest) ([]OAuth2ConsentSession, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -1832,7 +1856,7 @@ func (a *OAuth2ApiService) ListOAuth2ConsentSessionsExecute(r ApiListOAuth2Conse localVarReturnValue []OAuth2ConsentSession ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.ListOAuth2ConsentSessions") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.ListOAuth2ConsentSessions") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -1847,14 +1871,20 @@ func (a *OAuth2ApiService) ListOAuth2ConsentSessionsExecute(r ApiListOAuth2Conse } if r.pageSize != nil { - localVarQueryParams.Add("page_size", parameterToString(*r.pageSize, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "page_size", r.pageSize, "") + } else { + var defaultValue int64 = 250 + r.pageSize = &defaultValue } if r.pageToken != nil { - localVarQueryParams.Add("page_token", parameterToString(*r.pageToken, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "page_token", r.pageToken, "") + } else { + var defaultValue string = "1" + r.pageToken = &defaultValue } - localVarQueryParams.Add("subject", parameterToString(*r.subject, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "subject", r.subject, "") if r.loginSessionId != nil { - localVarQueryParams.Add("login_session_id", parameterToString(*r.loginSessionId, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "login_session_id", r.loginSessionId, "") } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -1883,9 +1913,9 @@ func (a *OAuth2ApiService) ListOAuth2ConsentSessionsExecute(r ApiListOAuth2Conse return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -1901,6 +1931,7 @@ func (a *OAuth2ApiService) ListOAuth2ConsentSessionsExecute(r ApiListOAuth2Conse newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -1919,7 +1950,7 @@ func (a *OAuth2ApiService) ListOAuth2ConsentSessionsExecute(r ApiListOAuth2Conse type ApiListTrustedOAuth2JwtGrantIssuersRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService maxItems *int64 defaultItems *int64 issuer *string @@ -1953,7 +1984,7 @@ Use this endpoint to list all trusted JWT Bearer Grant Type Issuers. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiListTrustedOAuth2JwtGrantIssuersRequest */ -func (a *OAuth2ApiService) ListTrustedOAuth2JwtGrantIssuers(ctx context.Context) ApiListTrustedOAuth2JwtGrantIssuersRequest { +func (a *OAuth2APIService) ListTrustedOAuth2JwtGrantIssuers(ctx context.Context) ApiListTrustedOAuth2JwtGrantIssuersRequest { return ApiListTrustedOAuth2JwtGrantIssuersRequest{ ApiService: a, ctx: ctx, @@ -1963,7 +1994,7 @@ func (a *OAuth2ApiService) ListTrustedOAuth2JwtGrantIssuers(ctx context.Context) // Execute executes the request // // @return []TrustedOAuth2JwtGrantIssuer -func (a *OAuth2ApiService) ListTrustedOAuth2JwtGrantIssuersExecute(r ApiListTrustedOAuth2JwtGrantIssuersRequest) ([]TrustedOAuth2JwtGrantIssuer, *http.Response, error) { +func (a *OAuth2APIService) ListTrustedOAuth2JwtGrantIssuersExecute(r ApiListTrustedOAuth2JwtGrantIssuersRequest) ([]TrustedOAuth2JwtGrantIssuer, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -1971,7 +2002,7 @@ func (a *OAuth2ApiService) ListTrustedOAuth2JwtGrantIssuersExecute(r ApiListTrus localVarReturnValue []TrustedOAuth2JwtGrantIssuer ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.ListTrustedOAuth2JwtGrantIssuers") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.ListTrustedOAuth2JwtGrantIssuers") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -1983,13 +2014,13 @@ func (a *OAuth2ApiService) ListTrustedOAuth2JwtGrantIssuersExecute(r ApiListTrus localVarFormParams := url.Values{} if r.maxItems != nil { - localVarQueryParams.Add("MaxItems", parameterToString(*r.maxItems, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "MaxItems", r.maxItems, "") } if r.defaultItems != nil { - localVarQueryParams.Add("DefaultItems", parameterToString(*r.defaultItems, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "DefaultItems", r.defaultItems, "") } if r.issuer != nil { - localVarQueryParams.Add("issuer", parameterToString(*r.issuer, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "issuer", r.issuer, "") } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -2018,9 +2049,9 @@ func (a *OAuth2ApiService) ListTrustedOAuth2JwtGrantIssuersExecute(r ApiListTrus return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -2036,6 +2067,7 @@ func (a *OAuth2ApiService) ListTrustedOAuth2JwtGrantIssuersExecute(r ApiListTrus newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -2054,7 +2086,7 @@ func (a *OAuth2ApiService) ListTrustedOAuth2JwtGrantIssuersExecute(r ApiListTrus type ApiOAuth2AuthorizeRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService } func (r ApiOAuth2AuthorizeRequest) Execute() (*ErrorOAuth2, *http.Response, error) { @@ -2067,12 +2099,13 @@ OAuth2Authorize OAuth 2.0 Authorize Endpoint Use open source libraries to perform OAuth 2.0 and OpenID Connect available for any programming language. You can find a list of libraries at https://oauth.net/code/ -The Ory SDK is not yet able to this endpoint properly. +This endpoint should not be used via the Ory SDK and is only included for technical reasons. +Instead, use one of the libraries linked above. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiOAuth2AuthorizeRequest */ -func (a *OAuth2ApiService) OAuth2Authorize(ctx context.Context) ApiOAuth2AuthorizeRequest { +func (a *OAuth2APIService) OAuth2Authorize(ctx context.Context) ApiOAuth2AuthorizeRequest { return ApiOAuth2AuthorizeRequest{ ApiService: a, ctx: ctx, @@ -2082,7 +2115,7 @@ func (a *OAuth2ApiService) OAuth2Authorize(ctx context.Context) ApiOAuth2Authori // Execute executes the request // // @return ErrorOAuth2 -func (a *OAuth2ApiService) OAuth2AuthorizeExecute(r ApiOAuth2AuthorizeRequest) (*ErrorOAuth2, *http.Response, error) { +func (a *OAuth2APIService) OAuth2AuthorizeExecute(r ApiOAuth2AuthorizeRequest) (*ErrorOAuth2, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -2090,7 +2123,7 @@ func (a *OAuth2ApiService) OAuth2AuthorizeExecute(r ApiOAuth2AuthorizeRequest) ( localVarReturnValue *ErrorOAuth2 ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.OAuth2Authorize") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.OAuth2Authorize") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -2128,9 +2161,9 @@ func (a *OAuth2ApiService) OAuth2AuthorizeExecute(r ApiOAuth2AuthorizeRequest) ( return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -2146,6 +2179,7 @@ func (a *OAuth2ApiService) OAuth2AuthorizeExecute(r ApiOAuth2AuthorizeRequest) ( newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -2164,7 +2198,7 @@ func (a *OAuth2ApiService) OAuth2AuthorizeExecute(r ApiOAuth2AuthorizeRequest) ( type ApiOauth2TokenExchangeRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService grantType *string clientId *string code *string @@ -2207,12 +2241,13 @@ Oauth2TokenExchange The OAuth 2.0 Token Endpoint Use open source libraries to perform OAuth 2.0 and OpenID Connect available for any programming language. You can find a list of libraries here https://oauth.net/code/ -The Ory SDK is not yet able to this endpoint properly. +This endpoint should not be used via the Ory SDK and is only included for technical reasons. +Instead, use one of the libraries linked above. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiOauth2TokenExchangeRequest */ -func (a *OAuth2ApiService) Oauth2TokenExchange(ctx context.Context) ApiOauth2TokenExchangeRequest { +func (a *OAuth2APIService) Oauth2TokenExchange(ctx context.Context) ApiOauth2TokenExchangeRequest { return ApiOauth2TokenExchangeRequest{ ApiService: a, ctx: ctx, @@ -2222,7 +2257,7 @@ func (a *OAuth2ApiService) Oauth2TokenExchange(ctx context.Context) ApiOauth2Tok // Execute executes the request // // @return OAuth2TokenExchange -func (a *OAuth2ApiService) Oauth2TokenExchangeExecute(r ApiOauth2TokenExchangeRequest) (*OAuth2TokenExchange, *http.Response, error) { +func (a *OAuth2APIService) Oauth2TokenExchangeExecute(r ApiOauth2TokenExchangeRequest) (*OAuth2TokenExchange, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} @@ -2230,7 +2265,7 @@ func (a *OAuth2ApiService) Oauth2TokenExchangeExecute(r ApiOauth2TokenExchangeRe localVarReturnValue *OAuth2TokenExchange ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.Oauth2TokenExchange") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.Oauth2TokenExchange") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -2262,17 +2297,17 @@ func (a *OAuth2ApiService) Oauth2TokenExchangeExecute(r ApiOauth2TokenExchangeRe localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } if r.clientId != nil { - localVarFormParams.Add("client_id", parameterToString(*r.clientId, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "client_id", r.clientId, "") } if r.code != nil { - localVarFormParams.Add("code", parameterToString(*r.code, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "code", r.code, "") } - localVarFormParams.Add("grant_type", parameterToString(*r.grantType, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "grant_type", r.grantType, "") if r.redirectUri != nil { - localVarFormParams.Add("redirect_uri", parameterToString(*r.redirectUri, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "redirect_uri", r.redirectUri, "") } if r.refreshToken != nil { - localVarFormParams.Add("refresh_token", parameterToString(*r.refreshToken, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "refresh_token", r.refreshToken, "") } req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) if err != nil { @@ -2284,9 +2319,9 @@ func (a *OAuth2ApiService) Oauth2TokenExchangeExecute(r ApiOauth2TokenExchangeRe return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -2302,6 +2337,7 @@ func (a *OAuth2ApiService) Oauth2TokenExchangeExecute(r ApiOauth2TokenExchangeRe newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -2320,7 +2356,7 @@ func (a *OAuth2ApiService) Oauth2TokenExchangeExecute(r ApiOauth2TokenExchangeRe type ApiPatchOAuth2ClientRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService id string jsonPatch *[]JsonPatch } @@ -2349,7 +2385,7 @@ generated for applications which want to consume your OAuth 2.0 or OpenID Connec @param id The id of the OAuth 2.0 Client. @return ApiPatchOAuth2ClientRequest */ -func (a *OAuth2ApiService) PatchOAuth2Client(ctx context.Context, id string) ApiPatchOAuth2ClientRequest { +func (a *OAuth2APIService) PatchOAuth2Client(ctx context.Context, id string) ApiPatchOAuth2ClientRequest { return ApiPatchOAuth2ClientRequest{ ApiService: a, ctx: ctx, @@ -2360,7 +2396,7 @@ func (a *OAuth2ApiService) PatchOAuth2Client(ctx context.Context, id string) Api // Execute executes the request // // @return OAuth2Client -func (a *OAuth2ApiService) PatchOAuth2ClientExecute(r ApiPatchOAuth2ClientRequest) (*OAuth2Client, *http.Response, error) { +func (a *OAuth2APIService) PatchOAuth2ClientExecute(r ApiPatchOAuth2ClientRequest) (*OAuth2Client, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPatch localVarPostBody interface{} @@ -2368,13 +2404,13 @@ func (a *OAuth2ApiService) PatchOAuth2ClientExecute(r ApiPatchOAuth2ClientReques localVarReturnValue *OAuth2Client ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.PatchOAuth2Client") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.PatchOAuth2Client") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/clients/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -2412,9 +2448,9 @@ func (a *OAuth2ApiService) PatchOAuth2ClientExecute(r ApiPatchOAuth2ClientReques return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -2431,6 +2467,7 @@ func (a *OAuth2ApiService) PatchOAuth2ClientExecute(r ApiPatchOAuth2ClientReques newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -2440,6 +2477,7 @@ func (a *OAuth2ApiService) PatchOAuth2ClientExecute(r ApiPatchOAuth2ClientReques newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -2458,7 +2496,7 @@ func (a *OAuth2ApiService) PatchOAuth2ClientExecute(r ApiPatchOAuth2ClientReques type ApiRejectOAuth2ConsentRequestRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService consentChallenge *string rejectOAuth2Request *RejectOAuth2Request } @@ -2500,7 +2538,7 @@ head over to the OAuth 2.0 documentation. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiRejectOAuth2ConsentRequestRequest */ -func (a *OAuth2ApiService) RejectOAuth2ConsentRequest(ctx context.Context) ApiRejectOAuth2ConsentRequestRequest { +func (a *OAuth2APIService) RejectOAuth2ConsentRequest(ctx context.Context) ApiRejectOAuth2ConsentRequestRequest { return ApiRejectOAuth2ConsentRequestRequest{ ApiService: a, ctx: ctx, @@ -2510,7 +2548,7 @@ func (a *OAuth2ApiService) RejectOAuth2ConsentRequest(ctx context.Context) ApiRe // Execute executes the request // // @return OAuth2RedirectTo -func (a *OAuth2ApiService) RejectOAuth2ConsentRequestExecute(r ApiRejectOAuth2ConsentRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { +func (a *OAuth2APIService) RejectOAuth2ConsentRequestExecute(r ApiRejectOAuth2ConsentRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -2518,7 +2556,7 @@ func (a *OAuth2ApiService) RejectOAuth2ConsentRequestExecute(r ApiRejectOAuth2Co localVarReturnValue *OAuth2RedirectTo ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.RejectOAuth2ConsentRequest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.RejectOAuth2ConsentRequest") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -2532,7 +2570,7 @@ func (a *OAuth2ApiService) RejectOAuth2ConsentRequestExecute(r ApiRejectOAuth2Co return localVarReturnValue, nil, reportError("consentChallenge is required and must be specified") } - localVarQueryParams.Add("consent_challenge", parameterToString(*r.consentChallenge, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "consent_challenge", r.consentChallenge, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{"application/json"} @@ -2562,9 +2600,9 @@ func (a *OAuth2ApiService) RejectOAuth2ConsentRequestExecute(r ApiRejectOAuth2Co return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -2580,6 +2618,7 @@ func (a *OAuth2ApiService) RejectOAuth2ConsentRequestExecute(r ApiRejectOAuth2Co newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -2598,7 +2637,7 @@ func (a *OAuth2ApiService) RejectOAuth2ConsentRequestExecute(r ApiRejectOAuth2Co type ApiRejectOAuth2LoginRequestRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService loginChallenge *string rejectOAuth2Request *RejectOAuth2Request } @@ -2635,7 +2674,7 @@ The response contains a redirect URL which the login provider should redirect th @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiRejectOAuth2LoginRequestRequest */ -func (a *OAuth2ApiService) RejectOAuth2LoginRequest(ctx context.Context) ApiRejectOAuth2LoginRequestRequest { +func (a *OAuth2APIService) RejectOAuth2LoginRequest(ctx context.Context) ApiRejectOAuth2LoginRequestRequest { return ApiRejectOAuth2LoginRequestRequest{ ApiService: a, ctx: ctx, @@ -2645,7 +2684,7 @@ func (a *OAuth2ApiService) RejectOAuth2LoginRequest(ctx context.Context) ApiReje // Execute executes the request // // @return OAuth2RedirectTo -func (a *OAuth2ApiService) RejectOAuth2LoginRequestExecute(r ApiRejectOAuth2LoginRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { +func (a *OAuth2APIService) RejectOAuth2LoginRequestExecute(r ApiRejectOAuth2LoginRequestRequest) (*OAuth2RedirectTo, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -2653,7 +2692,7 @@ func (a *OAuth2ApiService) RejectOAuth2LoginRequestExecute(r ApiRejectOAuth2Logi localVarReturnValue *OAuth2RedirectTo ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.RejectOAuth2LoginRequest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.RejectOAuth2LoginRequest") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -2667,7 +2706,7 @@ func (a *OAuth2ApiService) RejectOAuth2LoginRequestExecute(r ApiRejectOAuth2Logi return localVarReturnValue, nil, reportError("loginChallenge is required and must be specified") } - localVarQueryParams.Add("login_challenge", parameterToString(*r.loginChallenge, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "login_challenge", r.loginChallenge, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{"application/json"} @@ -2697,9 +2736,9 @@ func (a *OAuth2ApiService) RejectOAuth2LoginRequestExecute(r ApiRejectOAuth2Logi return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -2715,6 +2754,7 @@ func (a *OAuth2ApiService) RejectOAuth2LoginRequestExecute(r ApiRejectOAuth2Logi newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -2733,7 +2773,7 @@ func (a *OAuth2ApiService) RejectOAuth2LoginRequestExecute(r ApiRejectOAuth2Logi type ApiRejectOAuth2LogoutRequestRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService logoutChallenge *string } @@ -2757,7 +2797,7 @@ The response is empty as the logout provider has to chose what action to perform @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiRejectOAuth2LogoutRequestRequest */ -func (a *OAuth2ApiService) RejectOAuth2LogoutRequest(ctx context.Context) ApiRejectOAuth2LogoutRequestRequest { +func (a *OAuth2APIService) RejectOAuth2LogoutRequest(ctx context.Context) ApiRejectOAuth2LogoutRequestRequest { return ApiRejectOAuth2LogoutRequestRequest{ ApiService: a, ctx: ctx, @@ -2765,14 +2805,14 @@ func (a *OAuth2ApiService) RejectOAuth2LogoutRequest(ctx context.Context) ApiRej } // Execute executes the request -func (a *OAuth2ApiService) RejectOAuth2LogoutRequestExecute(r ApiRejectOAuth2LogoutRequestRequest) (*http.Response, error) { +func (a *OAuth2APIService) RejectOAuth2LogoutRequestExecute(r ApiRejectOAuth2LogoutRequestRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.RejectOAuth2LogoutRequest") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.RejectOAuth2LogoutRequest") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } @@ -2786,7 +2826,7 @@ func (a *OAuth2ApiService) RejectOAuth2LogoutRequestExecute(r ApiRejectOAuth2Log return nil, reportError("logoutChallenge is required and must be specified") } - localVarQueryParams.Add("logout_challenge", parameterToString(*r.logoutChallenge, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "logout_challenge", r.logoutChallenge, "") // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -2814,9 +2854,9 @@ func (a *OAuth2ApiService) RejectOAuth2LogoutRequestExecute(r ApiRejectOAuth2Log return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -2832,6 +2872,7 @@ func (a *OAuth2ApiService) RejectOAuth2LogoutRequestExecute(r ApiRejectOAuth2Log newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -2841,7 +2882,7 @@ func (a *OAuth2ApiService) RejectOAuth2LogoutRequestExecute(r ApiRejectOAuth2Log type ApiRevokeOAuth2ConsentSessionsRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService subject *string client *string all *bool @@ -2878,7 +2919,7 @@ associated OAuth 2.0 Access Tokens. You may also only revoke sessions for a spec @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiRevokeOAuth2ConsentSessionsRequest */ -func (a *OAuth2ApiService) RevokeOAuth2ConsentSessions(ctx context.Context) ApiRevokeOAuth2ConsentSessionsRequest { +func (a *OAuth2APIService) RevokeOAuth2ConsentSessions(ctx context.Context) ApiRevokeOAuth2ConsentSessionsRequest { return ApiRevokeOAuth2ConsentSessionsRequest{ ApiService: a, ctx: ctx, @@ -2886,14 +2927,14 @@ func (a *OAuth2ApiService) RevokeOAuth2ConsentSessions(ctx context.Context) ApiR } // Execute executes the request -func (a *OAuth2ApiService) RevokeOAuth2ConsentSessionsExecute(r ApiRevokeOAuth2ConsentSessionsRequest) (*http.Response, error) { +func (a *OAuth2APIService) RevokeOAuth2ConsentSessionsExecute(r ApiRevokeOAuth2ConsentSessionsRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.RevokeOAuth2ConsentSessions") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.RevokeOAuth2ConsentSessions") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } @@ -2907,12 +2948,12 @@ func (a *OAuth2ApiService) RevokeOAuth2ConsentSessionsExecute(r ApiRevokeOAuth2C return nil, reportError("subject is required and must be specified") } - localVarQueryParams.Add("subject", parameterToString(*r.subject, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "subject", r.subject, "") if r.client != nil { - localVarQueryParams.Add("client", parameterToString(*r.client, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "client", r.client, "") } if r.all != nil { - localVarQueryParams.Add("all", parameterToString(*r.all, "")) + parameterAddToHeaderOrQuery(localVarQueryParams, "all", r.all, "") } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -2941,9 +2982,9 @@ func (a *OAuth2ApiService) RevokeOAuth2ConsentSessionsExecute(r ApiRevokeOAuth2C return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -2959,6 +3000,7 @@ func (a *OAuth2ApiService) RevokeOAuth2ConsentSessionsExecute(r ApiRevokeOAuth2C newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -2968,8 +3010,9 @@ func (a *OAuth2ApiService) RevokeOAuth2ConsentSessionsExecute(r ApiRevokeOAuth2C type ApiRevokeOAuth2LoginSessionsRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService subject *string + sid *string } // OAuth 2.0 Subject The subject to revoke authentication sessions for. @@ -2978,21 +3021,32 @@ func (r ApiRevokeOAuth2LoginSessionsRequest) Subject(subject string) ApiRevokeOA return r } +// Login Session ID The login session to revoke. +func (r ApiRevokeOAuth2LoginSessionsRequest) Sid(sid string) ApiRevokeOAuth2LoginSessionsRequest { + r.sid = &sid + return r +} + func (r ApiRevokeOAuth2LoginSessionsRequest) Execute() (*http.Response, error) { return r.ApiService.RevokeOAuth2LoginSessionsExecute(r) } /* -RevokeOAuth2LoginSessions Revokes All OAuth 2.0 Login Sessions of a Subject +RevokeOAuth2LoginSessions Revokes OAuth 2.0 Login Sessions by either a Subject or a SessionID + +This endpoint invalidates authentication sessions. After revoking the authentication session(s), the subject +has to re-authenticate at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens. + +If you send the subject in a query param, all authentication sessions that belong to that subject are revoked. +No OpenID Connect Front- or Back-channel logout is performed in this case. -This endpoint invalidates a subject's authentication session. After revoking the authentication session, the subject -has to re-authenticate at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens and -does not work with OpenID Connect Front- or Back-channel logout. +Alternatively, you can send a SessionID via `sid` query param, in which case, only the session that is connected +to that SessionID is revoked. OpenID Connect Back-channel logout is performed in this case. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiRevokeOAuth2LoginSessionsRequest */ -func (a *OAuth2ApiService) RevokeOAuth2LoginSessions(ctx context.Context) ApiRevokeOAuth2LoginSessionsRequest { +func (a *OAuth2APIService) RevokeOAuth2LoginSessions(ctx context.Context) ApiRevokeOAuth2LoginSessionsRequest { return ApiRevokeOAuth2LoginSessionsRequest{ ApiService: a, ctx: ctx, @@ -3000,14 +3054,14 @@ func (a *OAuth2ApiService) RevokeOAuth2LoginSessions(ctx context.Context) ApiRev } // Execute executes the request -func (a *OAuth2ApiService) RevokeOAuth2LoginSessionsExecute(r ApiRevokeOAuth2LoginSessionsRequest) (*http.Response, error) { +func (a *OAuth2APIService) RevokeOAuth2LoginSessionsExecute(r ApiRevokeOAuth2LoginSessionsRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.RevokeOAuth2LoginSessions") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.RevokeOAuth2LoginSessions") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } @@ -3017,11 +3071,13 @@ func (a *OAuth2ApiService) RevokeOAuth2LoginSessionsExecute(r ApiRevokeOAuth2Log localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} localVarFormParams := url.Values{} - if r.subject == nil { - return nil, reportError("subject is required and must be specified") - } - localVarQueryParams.Add("subject", parameterToString(*r.subject, "")) + if r.subject != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "subject", r.subject, "") + } + if r.sid != nil { + parameterAddToHeaderOrQuery(localVarQueryParams, "sid", r.sid, "") + } // to determine the Content-Type header localVarHTTPContentTypes := []string{} @@ -3049,9 +3105,9 @@ func (a *OAuth2ApiService) RevokeOAuth2LoginSessionsExecute(r ApiRevokeOAuth2Log return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -3067,6 +3123,7 @@ func (a *OAuth2ApiService) RevokeOAuth2LoginSessionsExecute(r ApiRevokeOAuth2Log newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -3076,7 +3133,7 @@ func (a *OAuth2ApiService) RevokeOAuth2LoginSessionsExecute(r ApiRevokeOAuth2Log type ApiRevokeOAuth2TokenRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService token *string clientId *string clientSecret *string @@ -3112,7 +3169,7 @@ the client the token was generated for. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiRevokeOAuth2TokenRequest */ -func (a *OAuth2ApiService) RevokeOAuth2Token(ctx context.Context) ApiRevokeOAuth2TokenRequest { +func (a *OAuth2APIService) RevokeOAuth2Token(ctx context.Context) ApiRevokeOAuth2TokenRequest { return ApiRevokeOAuth2TokenRequest{ ApiService: a, ctx: ctx, @@ -3120,14 +3177,14 @@ func (a *OAuth2ApiService) RevokeOAuth2Token(ctx context.Context) ApiRevokeOAuth } // Execute executes the request -func (a *OAuth2ApiService) RevokeOAuth2TokenExecute(r ApiRevokeOAuth2TokenRequest) (*http.Response, error) { +func (a *OAuth2APIService) RevokeOAuth2TokenExecute(r ApiRevokeOAuth2TokenRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.RevokeOAuth2Token") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.RevokeOAuth2Token") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } @@ -3159,12 +3216,12 @@ func (a *OAuth2ApiService) RevokeOAuth2TokenExecute(r ApiRevokeOAuth2TokenReques localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept } if r.clientId != nil { - localVarFormParams.Add("client_id", parameterToString(*r.clientId, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "client_id", r.clientId, "") } if r.clientSecret != nil { - localVarFormParams.Add("client_secret", parameterToString(*r.clientSecret, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "client_secret", r.clientSecret, "") } - localVarFormParams.Add("token", parameterToString(*r.token, "")) + parameterAddToHeaderOrQuery(localVarFormParams, "token", r.token, "") req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) if err != nil { return nil, err @@ -3175,9 +3232,9 @@ func (a *OAuth2ApiService) RevokeOAuth2TokenExecute(r ApiRevokeOAuth2TokenReques return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -3193,6 +3250,7 @@ func (a *OAuth2ApiService) RevokeOAuth2TokenExecute(r ApiRevokeOAuth2TokenReques newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -3202,7 +3260,7 @@ func (a *OAuth2ApiService) RevokeOAuth2TokenExecute(r ApiRevokeOAuth2TokenReques type ApiSetOAuth2ClientRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService id string oAuth2Client *OAuth2Client } @@ -3232,7 +3290,7 @@ generated for applications which want to consume your OAuth 2.0 or OpenID Connec @param id OAuth 2.0 Client ID @return ApiSetOAuth2ClientRequest */ -func (a *OAuth2ApiService) SetOAuth2Client(ctx context.Context, id string) ApiSetOAuth2ClientRequest { +func (a *OAuth2APIService) SetOAuth2Client(ctx context.Context, id string) ApiSetOAuth2ClientRequest { return ApiSetOAuth2ClientRequest{ ApiService: a, ctx: ctx, @@ -3243,7 +3301,7 @@ func (a *OAuth2ApiService) SetOAuth2Client(ctx context.Context, id string) ApiSe // Execute executes the request // // @return OAuth2Client -func (a *OAuth2ApiService) SetOAuth2ClientExecute(r ApiSetOAuth2ClientRequest) (*OAuth2Client, *http.Response, error) { +func (a *OAuth2APIService) SetOAuth2ClientExecute(r ApiSetOAuth2ClientRequest) (*OAuth2Client, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -3251,13 +3309,13 @@ func (a *OAuth2ApiService) SetOAuth2ClientExecute(r ApiSetOAuth2ClientRequest) ( localVarReturnValue *OAuth2Client ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.SetOAuth2Client") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.SetOAuth2Client") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/clients/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3295,9 +3353,9 @@ func (a *OAuth2ApiService) SetOAuth2ClientExecute(r ApiSetOAuth2ClientRequest) ( return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -3314,6 +3372,7 @@ func (a *OAuth2ApiService) SetOAuth2ClientExecute(r ApiSetOAuth2ClientRequest) ( newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -3324,6 +3383,7 @@ func (a *OAuth2ApiService) SetOAuth2ClientExecute(r ApiSetOAuth2ClientRequest) ( newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -3333,6 +3393,7 @@ func (a *OAuth2ApiService) SetOAuth2ClientExecute(r ApiSetOAuth2ClientRequest) ( newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -3351,7 +3412,7 @@ func (a *OAuth2ApiService) SetOAuth2ClientExecute(r ApiSetOAuth2ClientRequest) ( type ApiSetOAuth2ClientLifespansRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService id string oAuth2ClientTokenLifespans *OAuth2ClientTokenLifespans } @@ -3374,7 +3435,7 @@ Set lifespans of different token types issued for this OAuth 2.0 client. Does no @param id OAuth 2.0 Client ID @return ApiSetOAuth2ClientLifespansRequest */ -func (a *OAuth2ApiService) SetOAuth2ClientLifespans(ctx context.Context, id string) ApiSetOAuth2ClientLifespansRequest { +func (a *OAuth2APIService) SetOAuth2ClientLifespans(ctx context.Context, id string) ApiSetOAuth2ClientLifespansRequest { return ApiSetOAuth2ClientLifespansRequest{ ApiService: a, ctx: ctx, @@ -3385,7 +3446,7 @@ func (a *OAuth2ApiService) SetOAuth2ClientLifespans(ctx context.Context, id stri // Execute executes the request // // @return OAuth2Client -func (a *OAuth2ApiService) SetOAuth2ClientLifespansExecute(r ApiSetOAuth2ClientLifespansRequest) (*OAuth2Client, *http.Response, error) { +func (a *OAuth2APIService) SetOAuth2ClientLifespansExecute(r ApiSetOAuth2ClientLifespansRequest) (*OAuth2Client, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -3393,13 +3454,13 @@ func (a *OAuth2ApiService) SetOAuth2ClientLifespansExecute(r ApiSetOAuth2ClientL localVarReturnValue *OAuth2Client ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.SetOAuth2ClientLifespans") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.SetOAuth2ClientLifespans") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/admin/clients/{id}/lifespans" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -3434,9 +3495,9 @@ func (a *OAuth2ApiService) SetOAuth2ClientLifespansExecute(r ApiSetOAuth2ClientL return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -3452,6 +3513,7 @@ func (a *OAuth2ApiService) SetOAuth2ClientLifespansExecute(r ApiSetOAuth2ClientL newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -3470,7 +3532,7 @@ func (a *OAuth2ApiService) SetOAuth2ClientLifespansExecute(r ApiSetOAuth2ClientL type ApiTrustOAuth2JwtGrantIssuerRequest struct { ctx context.Context - ApiService *OAuth2ApiService + ApiService *OAuth2APIService trustOAuth2JwtGrantIssuer *TrustOAuth2JwtGrantIssuer } @@ -3493,7 +3555,7 @@ and Authorization Grants [RFC7523](https://datatracker.ietf.org/doc/html/rfc7523 @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiTrustOAuth2JwtGrantIssuerRequest */ -func (a *OAuth2ApiService) TrustOAuth2JwtGrantIssuer(ctx context.Context) ApiTrustOAuth2JwtGrantIssuerRequest { +func (a *OAuth2APIService) TrustOAuth2JwtGrantIssuer(ctx context.Context) ApiTrustOAuth2JwtGrantIssuerRequest { return ApiTrustOAuth2JwtGrantIssuerRequest{ ApiService: a, ctx: ctx, @@ -3503,7 +3565,7 @@ func (a *OAuth2ApiService) TrustOAuth2JwtGrantIssuer(ctx context.Context) ApiTru // Execute executes the request // // @return TrustedOAuth2JwtGrantIssuer -func (a *OAuth2ApiService) TrustOAuth2JwtGrantIssuerExecute(r ApiTrustOAuth2JwtGrantIssuerRequest) (*TrustedOAuth2JwtGrantIssuer, *http.Response, error) { +func (a *OAuth2APIService) TrustOAuth2JwtGrantIssuerExecute(r ApiTrustOAuth2JwtGrantIssuerRequest) (*TrustedOAuth2JwtGrantIssuer, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} @@ -3511,7 +3573,7 @@ func (a *OAuth2ApiService) TrustOAuth2JwtGrantIssuerExecute(r ApiTrustOAuth2JwtG localVarReturnValue *TrustedOAuth2JwtGrantIssuer ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2ApiService.TrustOAuth2JwtGrantIssuer") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OAuth2APIService.TrustOAuth2JwtGrantIssuer") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -3551,9 +3613,9 @@ func (a *OAuth2ApiService) TrustOAuth2JwtGrantIssuerExecute(r ApiTrustOAuth2JwtG return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -3569,6 +3631,7 @@ func (a *OAuth2ApiService) TrustOAuth2JwtGrantIssuerExecute(r ApiTrustOAuth2JwtG newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } diff --git a/internal/httpclient/api_oidc.go b/internal/httpclient/api_oidc.go index 285774a2535..406711e3192 100644 --- a/internal/httpclient/api_oidc.go +++ b/internal/httpclient/api_oidc.go @@ -14,18 +14,18 @@ package openapi import ( "bytes" "context" - "io/ioutil" + "io" "net/http" "net/url" "strings" ) -// OidcApiService OidcApi service -type OidcApiService service +// OidcAPIService OidcAPI service +type OidcAPIService service type ApiCreateOidcDynamicClientRequest struct { ctx context.Context - ApiService *OidcApiService + ApiService *OidcAPIService oAuth2Client *OAuth2Client } @@ -57,7 +57,7 @@ Write the secret down and keep it somewhere safe. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiCreateOidcDynamicClientRequest */ -func (a *OidcApiService) CreateOidcDynamicClient(ctx context.Context) ApiCreateOidcDynamicClientRequest { +func (a *OidcAPIService) CreateOidcDynamicClient(ctx context.Context) ApiCreateOidcDynamicClientRequest { return ApiCreateOidcDynamicClientRequest{ ApiService: a, ctx: ctx, @@ -67,7 +67,7 @@ func (a *OidcApiService) CreateOidcDynamicClient(ctx context.Context) ApiCreateO // Execute executes the request // // @return OAuth2Client -func (a *OidcApiService) CreateOidcDynamicClientExecute(r ApiCreateOidcDynamicClientRequest) (*OAuth2Client, *http.Response, error) { +func (a *OidcAPIService) CreateOidcDynamicClientExecute(r ApiCreateOidcDynamicClientRequest) (*OAuth2Client, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPost localVarPostBody interface{} @@ -75,7 +75,7 @@ func (a *OidcApiService) CreateOidcDynamicClientExecute(r ApiCreateOidcDynamicCl localVarReturnValue *OAuth2Client ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcApiService.CreateOidcDynamicClient") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcAPIService.CreateOidcDynamicClient") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -118,9 +118,9 @@ func (a *OidcApiService) CreateOidcDynamicClientExecute(r ApiCreateOidcDynamicCl return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -137,6 +137,7 @@ func (a *OidcApiService) CreateOidcDynamicClientExecute(r ApiCreateOidcDynamicCl newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -146,6 +147,139 @@ func (a *OidcApiService) CreateOidcDynamicClientExecute(r ApiCreateOidcDynamicCl newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} + +type ApiCreateVerifiableCredentialRequest struct { + ctx context.Context + ApiService *OidcAPIService + createVerifiableCredentialRequestBody *CreateVerifiableCredentialRequestBody +} + +func (r ApiCreateVerifiableCredentialRequest) CreateVerifiableCredentialRequestBody(createVerifiableCredentialRequestBody CreateVerifiableCredentialRequestBody) ApiCreateVerifiableCredentialRequest { + r.createVerifiableCredentialRequestBody = &createVerifiableCredentialRequestBody + return r +} + +func (r ApiCreateVerifiableCredentialRequest) Execute() (*VerifiableCredentialResponse, *http.Response, error) { + return r.ApiService.CreateVerifiableCredentialExecute(r) +} + +/* +CreateVerifiableCredential Issues a Verifiable Credential + +This endpoint creates a verifiable credential that attests that the user +authenticated with the provided access token owns a certain public/private key +pair. + +More information can be found at +https://openid.net/specs/openid-connect-userinfo-vc-1_0.html. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @return ApiCreateVerifiableCredentialRequest +*/ +func (a *OidcAPIService) CreateVerifiableCredential(ctx context.Context) ApiCreateVerifiableCredentialRequest { + return ApiCreateVerifiableCredentialRequest{ + ApiService: a, + ctx: ctx, + } +} + +// Execute executes the request +// +// @return VerifiableCredentialResponse +func (a *OidcAPIService) CreateVerifiableCredentialExecute(r ApiCreateVerifiableCredentialRequest) (*VerifiableCredentialResponse, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *VerifiableCredentialResponse + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcAPIService.CreateVerifiableCredential") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/credentials" + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.createVerifiableCredentialRequestBody + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v VerifiableCredentialPrimingResponse + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + var v ErrorOAuth2 + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -164,7 +298,7 @@ func (a *OidcApiService) CreateOidcDynamicClientExecute(r ApiCreateOidcDynamicCl type ApiDeleteOidcDynamicClientRequest struct { ctx context.Context - ApiService *OidcApiService + ApiService *OidcAPIService id string } @@ -191,7 +325,7 @@ generated for applications which want to consume your OAuth 2.0 or OpenID Connec @param id The id of the OAuth 2.0 Client. @return ApiDeleteOidcDynamicClientRequest */ -func (a *OidcApiService) DeleteOidcDynamicClient(ctx context.Context, id string) ApiDeleteOidcDynamicClientRequest { +func (a *OidcAPIService) DeleteOidcDynamicClient(ctx context.Context, id string) ApiDeleteOidcDynamicClientRequest { return ApiDeleteOidcDynamicClientRequest{ ApiService: a, ctx: ctx, @@ -200,20 +334,20 @@ func (a *OidcApiService) DeleteOidcDynamicClient(ctx context.Context, id string) } // Execute executes the request -func (a *OidcApiService) DeleteOidcDynamicClientExecute(r ApiDeleteOidcDynamicClientRequest) (*http.Response, error) { +func (a *OidcAPIService) DeleteOidcDynamicClientExecute(r ApiDeleteOidcDynamicClientRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodDelete localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcApiService.DeleteOidcDynamicClient") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcAPIService.DeleteOidcDynamicClient") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/oauth2/register/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -246,9 +380,9 @@ func (a *OidcApiService) DeleteOidcDynamicClientExecute(r ApiDeleteOidcDynamicCl return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -264,6 +398,7 @@ func (a *OidcApiService) DeleteOidcDynamicClientExecute(r ApiDeleteOidcDynamicCl newErr.error = err.Error() return localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarHTTPResponse, newErr } @@ -273,7 +408,7 @@ func (a *OidcApiService) DeleteOidcDynamicClientExecute(r ApiDeleteOidcDynamicCl type ApiDiscoverOidcConfigurationRequest struct { ctx context.Context - ApiService *OidcApiService + ApiService *OidcAPIService } func (r ApiDiscoverOidcConfigurationRequest) Execute() (*OidcConfiguration, *http.Response, error) { @@ -291,7 +426,7 @@ For a full list of clients go here: https://openid.net/developers/certified/ @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiDiscoverOidcConfigurationRequest */ -func (a *OidcApiService) DiscoverOidcConfiguration(ctx context.Context) ApiDiscoverOidcConfigurationRequest { +func (a *OidcAPIService) DiscoverOidcConfiguration(ctx context.Context) ApiDiscoverOidcConfigurationRequest { return ApiDiscoverOidcConfigurationRequest{ ApiService: a, ctx: ctx, @@ -301,7 +436,7 @@ func (a *OidcApiService) DiscoverOidcConfiguration(ctx context.Context) ApiDisco // Execute executes the request // // @return OidcConfiguration -func (a *OidcApiService) DiscoverOidcConfigurationExecute(r ApiDiscoverOidcConfigurationRequest) (*OidcConfiguration, *http.Response, error) { +func (a *OidcAPIService) DiscoverOidcConfigurationExecute(r ApiDiscoverOidcConfigurationRequest) (*OidcConfiguration, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -309,7 +444,7 @@ func (a *OidcApiService) DiscoverOidcConfigurationExecute(r ApiDiscoverOidcConfi localVarReturnValue *OidcConfiguration ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcApiService.DiscoverOidcConfiguration") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcAPIService.DiscoverOidcConfiguration") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -347,9 +482,9 @@ func (a *OidcApiService) DiscoverOidcConfigurationExecute(r ApiDiscoverOidcConfi return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -365,6 +500,7 @@ func (a *OidcApiService) DiscoverOidcConfigurationExecute(r ApiDiscoverOidcConfi newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -383,7 +519,7 @@ func (a *OidcApiService) DiscoverOidcConfigurationExecute(r ApiDiscoverOidcConfi type ApiGetOidcDynamicClientRequest struct { ctx context.Context - ApiService *OidcApiService + ApiService *OidcAPIService id string } @@ -406,7 +542,7 @@ If it uses `client_secret_basic`, present the Client ID and the Client Secret in @param id The id of the OAuth 2.0 Client. @return ApiGetOidcDynamicClientRequest */ -func (a *OidcApiService) GetOidcDynamicClient(ctx context.Context, id string) ApiGetOidcDynamicClientRequest { +func (a *OidcAPIService) GetOidcDynamicClient(ctx context.Context, id string) ApiGetOidcDynamicClientRequest { return ApiGetOidcDynamicClientRequest{ ApiService: a, ctx: ctx, @@ -417,7 +553,7 @@ func (a *OidcApiService) GetOidcDynamicClient(ctx context.Context, id string) Ap // Execute executes the request // // @return OAuth2Client -func (a *OidcApiService) GetOidcDynamicClientExecute(r ApiGetOidcDynamicClientRequest) (*OAuth2Client, *http.Response, error) { +func (a *OidcAPIService) GetOidcDynamicClientExecute(r ApiGetOidcDynamicClientRequest) (*OAuth2Client, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -425,13 +561,13 @@ func (a *OidcApiService) GetOidcDynamicClientExecute(r ApiGetOidcDynamicClientRe localVarReturnValue *OAuth2Client ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcApiService.GetOidcDynamicClient") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcAPIService.GetOidcDynamicClient") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/oauth2/register/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -464,9 +600,9 @@ func (a *OidcApiService) GetOidcDynamicClientExecute(r ApiGetOidcDynamicClientRe return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -482,6 +618,7 @@ func (a *OidcApiService) GetOidcDynamicClientExecute(r ApiGetOidcDynamicClientRe newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -500,7 +637,7 @@ func (a *OidcApiService) GetOidcDynamicClientExecute(r ApiGetOidcDynamicClientRe type ApiGetOidcUserInfoRequest struct { ctx context.Context - ApiService *OidcApiService + ApiService *OidcAPIService } func (r ApiGetOidcUserInfoRequest) Execute() (*OidcUserInfo, *http.Response, error) { @@ -520,7 +657,7 @@ for more details about header format. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiGetOidcUserInfoRequest */ -func (a *OidcApiService) GetOidcUserInfo(ctx context.Context) ApiGetOidcUserInfoRequest { +func (a *OidcAPIService) GetOidcUserInfo(ctx context.Context) ApiGetOidcUserInfoRequest { return ApiGetOidcUserInfoRequest{ ApiService: a, ctx: ctx, @@ -530,7 +667,7 @@ func (a *OidcApiService) GetOidcUserInfo(ctx context.Context) ApiGetOidcUserInfo // Execute executes the request // // @return OidcUserInfo -func (a *OidcApiService) GetOidcUserInfoExecute(r ApiGetOidcUserInfoRequest) (*OidcUserInfo, *http.Response, error) { +func (a *OidcAPIService) GetOidcUserInfoExecute(r ApiGetOidcUserInfoRequest) (*OidcUserInfo, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -538,7 +675,7 @@ func (a *OidcApiService) GetOidcUserInfoExecute(r ApiGetOidcUserInfoRequest) (*O localVarReturnValue *OidcUserInfo ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcApiService.GetOidcUserInfo") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcAPIService.GetOidcUserInfo") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -576,9 +713,9 @@ func (a *OidcApiService) GetOidcUserInfoExecute(r ApiGetOidcUserInfoRequest) (*O return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -594,6 +731,7 @@ func (a *OidcApiService) GetOidcUserInfoExecute(r ApiGetOidcUserInfoRequest) (*O newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -612,7 +750,7 @@ func (a *OidcApiService) GetOidcUserInfoExecute(r ApiGetOidcUserInfoRequest) (*O type ApiRevokeOidcSessionRequest struct { ctx context.Context - ApiService *OidcApiService + ApiService *OidcAPIService } func (r ApiRevokeOidcSessionRequest) Execute() (*http.Response, error) { @@ -632,7 +770,7 @@ Back-channel logout is performed asynchronously and does not affect logout flow. @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiRevokeOidcSessionRequest */ -func (a *OidcApiService) RevokeOidcSession(ctx context.Context) ApiRevokeOidcSessionRequest { +func (a *OidcAPIService) RevokeOidcSession(ctx context.Context) ApiRevokeOidcSessionRequest { return ApiRevokeOidcSessionRequest{ ApiService: a, ctx: ctx, @@ -640,14 +778,14 @@ func (a *OidcApiService) RevokeOidcSession(ctx context.Context) ApiRevokeOidcSes } // Execute executes the request -func (a *OidcApiService) RevokeOidcSessionExecute(r ApiRevokeOidcSessionRequest) (*http.Response, error) { +func (a *OidcAPIService) RevokeOidcSessionExecute(r ApiRevokeOidcSessionRequest) (*http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} formFiles []formFile ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcApiService.RevokeOidcSession") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcAPIService.RevokeOidcSession") if err != nil { return nil, &GenericOpenAPIError{error: err.Error()} } @@ -685,9 +823,9 @@ func (a *OidcApiService) RevokeOidcSessionExecute(r ApiRevokeOidcSessionRequest) return localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarHTTPResponse, err } @@ -705,7 +843,7 @@ func (a *OidcApiService) RevokeOidcSessionExecute(r ApiRevokeOidcSessionRequest) type ApiSetOidcDynamicClientRequest struct { ctx context.Context - ApiService *OidcApiService + ApiService *OidcAPIService id string oAuth2Client *OAuth2Client } @@ -743,7 +881,7 @@ generated for applications which want to consume your OAuth 2.0 or OpenID Connec @param id OAuth 2.0 Client ID @return ApiSetOidcDynamicClientRequest */ -func (a *OidcApiService) SetOidcDynamicClient(ctx context.Context, id string) ApiSetOidcDynamicClientRequest { +func (a *OidcAPIService) SetOidcDynamicClient(ctx context.Context, id string) ApiSetOidcDynamicClientRequest { return ApiSetOidcDynamicClientRequest{ ApiService: a, ctx: ctx, @@ -754,7 +892,7 @@ func (a *OidcApiService) SetOidcDynamicClient(ctx context.Context, id string) Ap // Execute executes the request // // @return OAuth2Client -func (a *OidcApiService) SetOidcDynamicClientExecute(r ApiSetOidcDynamicClientRequest) (*OAuth2Client, *http.Response, error) { +func (a *OidcAPIService) SetOidcDynamicClientExecute(r ApiSetOidcDynamicClientRequest) (*OAuth2Client, *http.Response, error) { var ( localVarHTTPMethod = http.MethodPut localVarPostBody interface{} @@ -762,13 +900,13 @@ func (a *OidcApiService) SetOidcDynamicClientExecute(r ApiSetOidcDynamicClientRe localVarReturnValue *OAuth2Client ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcApiService.SetOidcDynamicClient") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "OidcAPIService.SetOidcDynamicClient") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } localVarPath := localBasePath + "/oauth2/register/{id}" - localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterToString(r.id, "")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) localVarHeaderParams := make(map[string]string) localVarQueryParams := url.Values{} @@ -806,9 +944,9 @@ func (a *OidcApiService) SetOidcDynamicClientExecute(r ApiSetOidcDynamicClientRe return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -825,6 +963,7 @@ func (a *OidcApiService) SetOidcDynamicClientExecute(r ApiSetOidcDynamicClientRe newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } @@ -834,6 +973,7 @@ func (a *OidcApiService) SetOidcDynamicClientExecute(r ApiSetOidcDynamicClientRe newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } diff --git a/internal/httpclient/api_wellknown.go b/internal/httpclient/api_wellknown.go index 2ba904fa4ef..ed51efc44b9 100644 --- a/internal/httpclient/api_wellknown.go +++ b/internal/httpclient/api_wellknown.go @@ -14,17 +14,17 @@ package openapi import ( "bytes" "context" - "io/ioutil" + "io" "net/http" "net/url" ) -// WellknownApiService WellknownApi service -type WellknownApiService service +// WellknownAPIService WellknownAPI service +type WellknownAPIService service type ApiDiscoverJsonWebKeysRequest struct { ctx context.Context - ApiService *WellknownApiService + ApiService *WellknownAPIService } func (r ApiDiscoverJsonWebKeysRequest) Execute() (*JsonWebKeySet, *http.Response, error) { @@ -38,10 +38,13 @@ This endpoint returns JSON Web Keys required to verifying OpenID Connect ID Toke if enabled, OAuth 2.0 JWT Access Tokens. This endpoint can be used with client libraries like [node-jwks-rsa](https://github.com/auth0/node-jwks-rsa) among others. +Adding custom keys requires first creating a keyset via the createJsonWebKeySet operation, +and then configuring the webfinger.jwks.broadcast_keys configuration value to include the keyset name. + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). @return ApiDiscoverJsonWebKeysRequest */ -func (a *WellknownApiService) DiscoverJsonWebKeys(ctx context.Context) ApiDiscoverJsonWebKeysRequest { +func (a *WellknownAPIService) DiscoverJsonWebKeys(ctx context.Context) ApiDiscoverJsonWebKeysRequest { return ApiDiscoverJsonWebKeysRequest{ ApiService: a, ctx: ctx, @@ -51,7 +54,7 @@ func (a *WellknownApiService) DiscoverJsonWebKeys(ctx context.Context) ApiDiscov // Execute executes the request // // @return JsonWebKeySet -func (a *WellknownApiService) DiscoverJsonWebKeysExecute(r ApiDiscoverJsonWebKeysRequest) (*JsonWebKeySet, *http.Response, error) { +func (a *WellknownAPIService) DiscoverJsonWebKeysExecute(r ApiDiscoverJsonWebKeysRequest) (*JsonWebKeySet, *http.Response, error) { var ( localVarHTTPMethod = http.MethodGet localVarPostBody interface{} @@ -59,7 +62,7 @@ func (a *WellknownApiService) DiscoverJsonWebKeysExecute(r ApiDiscoverJsonWebKey localVarReturnValue *JsonWebKeySet ) - localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WellknownApiService.DiscoverJsonWebKeys") + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WellknownAPIService.DiscoverJsonWebKeys") if err != nil { return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} } @@ -97,9 +100,9 @@ func (a *WellknownApiService) DiscoverJsonWebKeysExecute(r ApiDiscoverJsonWebKey return localVarReturnValue, localVarHTTPResponse, err } - localVarBody, err := ioutil.ReadAll(localVarHTTPResponse.Body) + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) localVarHTTPResponse.Body.Close() - localVarHTTPResponse.Body = ioutil.NopCloser(bytes.NewBuffer(localVarBody)) + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) if err != nil { return localVarReturnValue, localVarHTTPResponse, err } @@ -115,6 +118,7 @@ func (a *WellknownApiService) DiscoverJsonWebKeysExecute(r ApiDiscoverJsonWebKey newErr.error = err.Error() return localVarReturnValue, localVarHTTPResponse, newErr } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) newErr.model = v return localVarReturnValue, localVarHTTPResponse, newErr } diff --git a/internal/httpclient/client.go b/internal/httpclient/client.go index fe7ccccad0b..81e81275c1e 100644 --- a/internal/httpclient/client.go +++ b/internal/httpclient/client.go @@ -19,7 +19,6 @@ import ( "errors" "fmt" "io" - "io/ioutil" "log" "mime/multipart" "net/http" @@ -38,8 +37,10 @@ import ( ) var ( - jsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:vnd\.[^;]+\+)?json)`) - xmlCheck = regexp.MustCompile(`(?i:(?:application|text)/xml)`) + JsonCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:[^;]+\+)?json)`) + XmlCheck = regexp.MustCompile(`(?i:(?:application|text)/(?:[^;]+\+)?xml)`) + queryParamSplit = regexp.MustCompile(`(^|&)([^&]+)`) + queryDescape = strings.NewReplacer("%5B", "[", "%5D", "]") ) // APIClient manages communication with the Ory Hydra API API v @@ -50,15 +51,15 @@ type APIClient struct { // API Services - JwkApi *JwkApiService + JwkAPI *JwkAPIService - MetadataApi *MetadataApiService + MetadataAPI *MetadataAPIService - OAuth2Api *OAuth2ApiService + OAuth2API *OAuth2APIService - OidcApi *OidcApiService + OidcAPI *OidcAPIService - WellknownApi *WellknownApiService + WellknownAPI *WellknownAPIService } type service struct { @@ -77,11 +78,11 @@ func NewAPIClient(cfg *Configuration) *APIClient { c.common.client = c // API Services - c.JwkApi = (*JwkApiService)(&c.common) - c.MetadataApi = (*MetadataApiService)(&c.common) - c.OAuth2Api = (*OAuth2ApiService)(&c.common) - c.OidcApi = (*OidcApiService)(&c.common) - c.WellknownApi = (*WellknownApiService)(&c.common) + c.JwkAPI = (*JwkAPIService)(&c.common) + c.MetadataAPI = (*MetadataAPIService)(&c.common) + c.OAuth2API = (*OAuth2APIService)(&c.common) + c.OidcAPI = (*OidcAPIService)(&c.common) + c.WellknownAPI = (*WellknownAPIService)(&c.common) return c } @@ -133,33 +134,111 @@ func typeCheckParameter(obj interface{}, expected string, name string) error { // Check the type is as expected. if reflect.TypeOf(obj).String() != expected { - return fmt.Errorf("Expected %s to be of type %s but received %s.", name, expected, reflect.TypeOf(obj).String()) + return fmt.Errorf("expected %s to be of type %s but received %s", name, expected, reflect.TypeOf(obj).String()) } return nil } -// parameterToString convert interface{} parameters to string, using a delimiter if format is provided. -func parameterToString(obj interface{}, collectionFormat string) string { - var delimiter string - - switch collectionFormat { - case "pipes": - delimiter = "|" - case "ssv": - delimiter = " " - case "tsv": - delimiter = "\t" - case "csv": - delimiter = "," +func parameterValueToString(obj interface{}, key string) string { + if reflect.TypeOf(obj).Kind() != reflect.Ptr { + return fmt.Sprintf("%v", obj) + } + var param, ok = obj.(MappedNullable) + if !ok { + return "" + } + dataMap, err := param.ToMap() + if err != nil { + return "" } + return fmt.Sprintf("%v", dataMap[key]) +} + +// parameterAddToHeaderOrQuery adds the provided object to the request header or url query +// supporting deep object syntax +func parameterAddToHeaderOrQuery(headerOrQueryParams interface{}, keyPrefix string, obj interface{}, collectionType string) { + var v = reflect.ValueOf(obj) + var value = "" + if v == reflect.ValueOf(nil) { + value = "null" + } else { + switch v.Kind() { + case reflect.Invalid: + value = "invalid" + + case reflect.Struct: + if t, ok := obj.(MappedNullable); ok { + dataMap, err := t.ToMap() + if err != nil { + return + } + parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, dataMap, collectionType) + return + } + if t, ok := obj.(time.Time); ok { + parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, t.Format(time.RFC3339), collectionType) + return + } + value = v.Type().String() + " value" + case reflect.Slice: + var indValue = reflect.ValueOf(obj) + if indValue == reflect.ValueOf(nil) { + return + } + var lenIndValue = indValue.Len() + for i := 0; i < lenIndValue; i++ { + var arrayValue = indValue.Index(i) + parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, arrayValue.Interface(), collectionType) + } + return + + case reflect.Map: + var indValue = reflect.ValueOf(obj) + if indValue == reflect.ValueOf(nil) { + return + } + iter := indValue.MapRange() + for iter.Next() { + k, v := iter.Key(), iter.Value() + parameterAddToHeaderOrQuery(headerOrQueryParams, fmt.Sprintf("%s[%s]", keyPrefix, k.String()), v.Interface(), collectionType) + } + return + + case reflect.Interface: + fallthrough + case reflect.Ptr: + parameterAddToHeaderOrQuery(headerOrQueryParams, keyPrefix, v.Elem().Interface(), collectionType) + return - if reflect.TypeOf(obj).Kind() == reflect.Slice { - return strings.Trim(strings.Replace(fmt.Sprint(obj), " ", delimiter, -1), "[]") - } else if t, ok := obj.(time.Time); ok { - return t.Format(time.RFC3339) + case reflect.Int, reflect.Int8, reflect.Int16, + reflect.Int32, reflect.Int64: + value = strconv.FormatInt(v.Int(), 10) + case reflect.Uint, reflect.Uint8, reflect.Uint16, + reflect.Uint32, reflect.Uint64, reflect.Uintptr: + value = strconv.FormatUint(v.Uint(), 10) + case reflect.Float32, reflect.Float64: + value = strconv.FormatFloat(v.Float(), 'g', -1, 32) + case reflect.Bool: + value = strconv.FormatBool(v.Bool()) + case reflect.String: + value = v.String() + default: + value = v.Type().String() + " value" + } } - return fmt.Sprintf("%v", obj) + switch valuesMap := headerOrQueryParams.(type) { + case url.Values: + if collectionType == "csv" && valuesMap.Get(keyPrefix) != "" { + valuesMap.Set(keyPrefix, valuesMap.Get(keyPrefix)+","+value) + } else { + valuesMap.Add(keyPrefix, value) + } + break + case map[string]string: + valuesMap[keyPrefix] = value + break + } } // helper for converting interface{} parameters to json strings @@ -311,7 +390,11 @@ func (c *APIClient) prepareRequest( } // Encode the parameters. - url.RawQuery = query.Encode() + url.RawQuery = queryParamSplit.ReplaceAllStringFunc(query.Encode(), func(s string) string { + pieces := strings.Split(s, "=") + pieces[0] = queryDescape.Replace(pieces[0]) + return strings.Join(pieces, "=") + }) // Generate a new request if body != nil { @@ -378,8 +461,20 @@ func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err err *s = string(b) return nil } + if f, ok := v.(*os.File); ok { + f, err = os.CreateTemp("", "HttpClientFile") + if err != nil { + return + } + _, err = f.Write(b) + if err != nil { + return + } + _, err = f.Seek(0, io.SeekStart) + return + } if f, ok := v.(**os.File); ok { - *f, err = ioutil.TempFile("", "HttpClientFile") + *f, err = os.CreateTemp("", "HttpClientFile") if err != nil { return } @@ -390,13 +485,13 @@ func (c *APIClient) decode(v interface{}, b []byte, contentType string) (err err _, err = (*f).Seek(0, io.SeekStart) return } - if xmlCheck.MatchString(contentType) { + if XmlCheck.MatchString(contentType) { if err = xml.Unmarshal(b, v); err != nil { return err } return nil } - if jsonCheck.MatchString(contentType) { + if JsonCheck.MatchString(contentType) { if actualObj, ok := v.(interface{ GetActualInstance() interface{} }); ok { // oneOf, anyOf schemas if unmarshalObj, ok := actualObj.(interface{ UnmarshalJSON([]byte) error }); ok { // make sure it has UnmarshalJSON defined if err = unmarshalObj.UnmarshalJSON(b); err != nil { @@ -453,18 +548,22 @@ func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err e if reader, ok := body.(io.Reader); ok { _, err = bodyBuf.ReadFrom(reader) - } else if fp, ok := body.(**os.File); ok { - _, err = bodyBuf.ReadFrom(*fp) + } else if fp, ok := body.(*os.File); ok { + _, err = bodyBuf.ReadFrom(fp) } else if b, ok := body.([]byte); ok { _, err = bodyBuf.Write(b) } else if s, ok := body.(string); ok { _, err = bodyBuf.WriteString(s) } else if s, ok := body.(*string); ok { _, err = bodyBuf.WriteString(*s) - } else if jsonCheck.MatchString(contentType) { + } else if JsonCheck.MatchString(contentType) { err = json.NewEncoder(bodyBuf).Encode(body) - } else if xmlCheck.MatchString(contentType) { - err = xml.NewEncoder(bodyBuf).Encode(body) + } else if XmlCheck.MatchString(contentType) { + var bs []byte + bs, err = xml.Marshal(body) + if err == nil { + bodyBuf.Write(bs) + } } if err != nil { @@ -472,7 +571,7 @@ func setBody(body interface{}, contentType string) (bodyBuf *bytes.Buffer, err e } if bodyBuf.Len() == 0 { - err = fmt.Errorf("Invalid body type %s\n", contentType) + err = fmt.Errorf("invalid body type %s\n", contentType) return nil, err } return bodyBuf, nil @@ -574,3 +673,23 @@ func (e GenericOpenAPIError) Body() []byte { func (e GenericOpenAPIError) Model() interface{} { return e.model } + +// format error message using title and detail when model implements rfc7807 +func formatErrorMessage(status string, v interface{}) string { + str := "" + metaValue := reflect.ValueOf(v).Elem() + + if metaValue.Kind() == reflect.Struct { + field := metaValue.FieldByName("Title") + if field != (reflect.Value{}) { + str = fmt.Sprintf("%s", field.Interface()) + } + + field = metaValue.FieldByName("Detail") + if field != (reflect.Value{}) { + str = fmt.Sprintf("%s (%s)", str, field.Interface()) + } + } + + return strings.TrimSpace(fmt.Sprintf("%s %s", status, str)) +} diff --git a/internal/httpclient/configuration.go b/internal/httpclient/configuration.go index 548fdbb05c1..4a85bc09c1a 100644 --- a/internal/httpclient/configuration.go +++ b/internal/httpclient/configuration.go @@ -38,12 +38,6 @@ var ( // ContextAccessToken takes a string oauth2 access token as authentication for the request. ContextAccessToken = contextKey("accesstoken") - // ContextAPIKeys takes a string apikey as authentication for the request - ContextAPIKeys = contextKey("apiKeys") - - // ContextHttpSignatureAuth takes HttpSignatureAuth as authentication for the request. - ContextHttpSignatureAuth = contextKey("httpsignature") - // ContextServerIndex uses a server configuration from the index. ContextServerIndex = contextKey("serverIndex") @@ -123,7 +117,7 @@ func (c *Configuration) AddDefaultHeader(key string, value string) { // URL formats template on a index using given variables func (sc ServerConfigurations) URL(index int, variables map[string]string) (string, error) { if index < 0 || len(sc) <= index { - return "", fmt.Errorf("Index %v out of range %v", index, len(sc)-1) + return "", fmt.Errorf("index %v out of range %v", index, len(sc)-1) } server := sc[index] url := server.URL @@ -138,7 +132,7 @@ func (sc ServerConfigurations) URL(index int, variables map[string]string) (stri } } if !found { - return "", fmt.Errorf("The variable %s in the server URL has invalid value %v. Must be %v", name, value, variable.EnumValues) + return "", fmt.Errorf("the variable %s in the server URL has invalid value %v. Must be %v", name, value, variable.EnumValues) } url = strings.Replace(url, "{"+name+"}", value, -1) } else { diff --git a/internal/httpclient/docs/AcceptOAuth2ConsentRequest.md b/internal/httpclient/docs/AcceptOAuth2ConsentRequest.md index ec518b5d77d..c6284d0c66b 100644 --- a/internal/httpclient/docs/AcceptOAuth2ConsentRequest.md +++ b/internal/httpclient/docs/AcceptOAuth2ConsentRequest.md @@ -4,6 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**Context** | Pointer to **interface{}** | | [optional] **GrantAccessTokenAudience** | Pointer to **[]string** | | [optional] **GrantScope** | Pointer to **[]string** | | [optional] **HandledAt** | Pointer to **time.Time** | | [optional] @@ -30,6 +31,41 @@ NewAcceptOAuth2ConsentRequestWithDefaults instantiates a new AcceptOAuth2Consent This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set +### GetContext + +`func (o *AcceptOAuth2ConsentRequest) GetContext() interface{}` + +GetContext returns the Context field if non-nil, zero value otherwise. + +### GetContextOk + +`func (o *AcceptOAuth2ConsentRequest) GetContextOk() (*interface{}, bool)` + +GetContextOk returns a tuple with the Context field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetContext + +`func (o *AcceptOAuth2ConsentRequest) SetContext(v interface{})` + +SetContext sets Context field to given value. + +### HasContext + +`func (o *AcceptOAuth2ConsentRequest) HasContext() bool` + +HasContext returns a boolean if a field has been set. + +### SetContextNil + +`func (o *AcceptOAuth2ConsentRequest) SetContextNil(b bool)` + + SetContextNil sets the value for Context to be an explicit nil + +### UnsetContext +`func (o *AcceptOAuth2ConsentRequest) UnsetContext()` + +UnsetContext ensures that no value is present for Context, not even an explicit nil ### GetGrantAccessTokenAudience `func (o *AcceptOAuth2ConsentRequest) GetGrantAccessTokenAudience() []string` diff --git a/internal/httpclient/docs/AcceptOAuth2LoginRequest.md b/internal/httpclient/docs/AcceptOAuth2LoginRequest.md index 80bf2c5ef5e..e6f6d554546 100644 --- a/internal/httpclient/docs/AcceptOAuth2LoginRequest.md +++ b/internal/httpclient/docs/AcceptOAuth2LoginRequest.md @@ -7,7 +7,9 @@ Name | Type | Description | Notes **Acr** | Pointer to **string** | ACR sets the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it to express that, for example, a user authenticated using two factor authentication. | [optional] **Amr** | Pointer to **[]string** | | [optional] **Context** | Pointer to **interface{}** | | [optional] +**ExtendSessionLifespan** | Pointer to **bool** | Extend OAuth2 authentication session lifespan If set to `true`, the OAuth2 authentication cookie lifespan is extended. This is for example useful if you want the user to be able to use `prompt=none` continuously. This value can only be set to `true` if the user has an authentication, which is the case if the `skip` value is `true`. | [optional] **ForceSubjectIdentifier** | Pointer to **string** | ForceSubjectIdentifier forces the \"pairwise\" user ID of the end-user that authenticated. The \"pairwise\" user ID refers to the (Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg] of the OpenID Connect specification. It allows you to set an obfuscated subject (\"user\") identifier that is unique to the client. Please note that this changes the user ID on endpoint /userinfo and sub claim of the ID Token. It does not change the sub claim in the OAuth 2.0 Introspection. Per default, ORY Hydra handles this value with its own algorithm. In case you want to set this yourself you can use this field. Please note that setting this field has no effect if `pairwise` is not configured in ORY Hydra or the OAuth 2.0 Client does not expect a pairwise identifier (set via `subject_type` key in the client's configuration). Please also be aware that ORY Hydra is unable to properly compute this value during authentication. This implies that you have to compute this value on every authentication process (probably depending on the client ID or some other unique value). If you fail to compute the proper value, then authentication processes which have id_token_hint set might fail. | [optional] +**IdentityProviderSessionId** | Pointer to **string** | IdentityProviderSessionID is the session ID of the end-user that authenticated. If specified, we will use this value to propagate the logout. | [optional] **Remember** | Pointer to **bool** | Remember, if set to true, tells ORY Hydra to remember this user by telling the user agent (browser) to store a cookie with authentication data. If the same user performs another OAuth 2.0 Authorization Request, he/she will not be asked to log in again. | [optional] **RememberFor** | Pointer to **int64** | RememberFor sets how long the authentication should be remembered for in seconds. If set to `0`, the authorization will be remembered for the duration of the browser session (using a session cookie). | [optional] **Subject** | **string** | Subject is the user ID of the end-user that authenticated. | @@ -116,6 +118,31 @@ HasContext returns a boolean if a field has been set. `func (o *AcceptOAuth2LoginRequest) UnsetContext()` UnsetContext ensures that no value is present for Context, not even an explicit nil +### GetExtendSessionLifespan + +`func (o *AcceptOAuth2LoginRequest) GetExtendSessionLifespan() bool` + +GetExtendSessionLifespan returns the ExtendSessionLifespan field if non-nil, zero value otherwise. + +### GetExtendSessionLifespanOk + +`func (o *AcceptOAuth2LoginRequest) GetExtendSessionLifespanOk() (*bool, bool)` + +GetExtendSessionLifespanOk returns a tuple with the ExtendSessionLifespan field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetExtendSessionLifespan + +`func (o *AcceptOAuth2LoginRequest) SetExtendSessionLifespan(v bool)` + +SetExtendSessionLifespan sets ExtendSessionLifespan field to given value. + +### HasExtendSessionLifespan + +`func (o *AcceptOAuth2LoginRequest) HasExtendSessionLifespan() bool` + +HasExtendSessionLifespan returns a boolean if a field has been set. + ### GetForceSubjectIdentifier `func (o *AcceptOAuth2LoginRequest) GetForceSubjectIdentifier() string` @@ -141,6 +168,31 @@ SetForceSubjectIdentifier sets ForceSubjectIdentifier field to given value. HasForceSubjectIdentifier returns a boolean if a field has been set. +### GetIdentityProviderSessionId + +`func (o *AcceptOAuth2LoginRequest) GetIdentityProviderSessionId() string` + +GetIdentityProviderSessionId returns the IdentityProviderSessionId field if non-nil, zero value otherwise. + +### GetIdentityProviderSessionIdOk + +`func (o *AcceptOAuth2LoginRequest) GetIdentityProviderSessionIdOk() (*string, bool)` + +GetIdentityProviderSessionIdOk returns a tuple with the IdentityProviderSessionId field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetIdentityProviderSessionId + +`func (o *AcceptOAuth2LoginRequest) SetIdentityProviderSessionId(v string)` + +SetIdentityProviderSessionId sets IdentityProviderSessionId field to given value. + +### HasIdentityProviderSessionId + +`func (o *AcceptOAuth2LoginRequest) HasIdentityProviderSessionId() bool` + +HasIdentityProviderSessionId returns a boolean if a field has been set. + ### GetRemember `func (o *AcceptOAuth2LoginRequest) GetRemember() bool` diff --git a/internal/httpclient/docs/CreateVerifiableCredentialRequestBody.md b/internal/httpclient/docs/CreateVerifiableCredentialRequestBody.md new file mode 100644 index 00000000000..24a2834e86b --- /dev/null +++ b/internal/httpclient/docs/CreateVerifiableCredentialRequestBody.md @@ -0,0 +1,108 @@ +# CreateVerifiableCredentialRequestBody + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Format** | Pointer to **string** | | [optional] +**Proof** | Pointer to [**VerifiableCredentialProof**](VerifiableCredentialProof.md) | | [optional] +**Types** | Pointer to **[]string** | | [optional] + +## Methods + +### NewCreateVerifiableCredentialRequestBody + +`func NewCreateVerifiableCredentialRequestBody() *CreateVerifiableCredentialRequestBody` + +NewCreateVerifiableCredentialRequestBody instantiates a new CreateVerifiableCredentialRequestBody object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewCreateVerifiableCredentialRequestBodyWithDefaults + +`func NewCreateVerifiableCredentialRequestBodyWithDefaults() *CreateVerifiableCredentialRequestBody` + +NewCreateVerifiableCredentialRequestBodyWithDefaults instantiates a new CreateVerifiableCredentialRequestBody object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetFormat + +`func (o *CreateVerifiableCredentialRequestBody) GetFormat() string` + +GetFormat returns the Format field if non-nil, zero value otherwise. + +### GetFormatOk + +`func (o *CreateVerifiableCredentialRequestBody) GetFormatOk() (*string, bool)` + +GetFormatOk returns a tuple with the Format field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFormat + +`func (o *CreateVerifiableCredentialRequestBody) SetFormat(v string)` + +SetFormat sets Format field to given value. + +### HasFormat + +`func (o *CreateVerifiableCredentialRequestBody) HasFormat() bool` + +HasFormat returns a boolean if a field has been set. + +### GetProof + +`func (o *CreateVerifiableCredentialRequestBody) GetProof() VerifiableCredentialProof` + +GetProof returns the Proof field if non-nil, zero value otherwise. + +### GetProofOk + +`func (o *CreateVerifiableCredentialRequestBody) GetProofOk() (*VerifiableCredentialProof, bool)` + +GetProofOk returns a tuple with the Proof field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProof + +`func (o *CreateVerifiableCredentialRequestBody) SetProof(v VerifiableCredentialProof)` + +SetProof sets Proof field to given value. + +### HasProof + +`func (o *CreateVerifiableCredentialRequestBody) HasProof() bool` + +HasProof returns a boolean if a field has been set. + +### GetTypes + +`func (o *CreateVerifiableCredentialRequestBody) GetTypes() []string` + +GetTypes returns the Types field if non-nil, zero value otherwise. + +### GetTypesOk + +`func (o *CreateVerifiableCredentialRequestBody) GetTypesOk() (*[]string, bool)` + +GetTypesOk returns a tuple with the Types field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTypes + +`func (o *CreateVerifiableCredentialRequestBody) SetTypes(v []string)` + +SetTypes sets Types field to given value. + +### HasTypes + +`func (o *CreateVerifiableCredentialRequestBody) HasTypes() bool` + +HasTypes returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/CredentialSupportedDraft00.md b/internal/httpclient/docs/CredentialSupportedDraft00.md new file mode 100644 index 00000000000..1738f518fa8 --- /dev/null +++ b/internal/httpclient/docs/CredentialSupportedDraft00.md @@ -0,0 +1,134 @@ +# CredentialSupportedDraft00 + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**CryptographicBindingMethodsSupported** | Pointer to **[]string** | OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported Contains a list of cryptographic binding methods supported for signing the proof. | [optional] +**CryptographicSuitesSupported** | Pointer to **[]string** | OpenID Connect Verifiable Credentials Cryptographic Suites Supported Contains a list of cryptographic suites methods supported for signing the proof. | [optional] +**Format** | Pointer to **string** | OpenID Connect Verifiable Credentials Format Contains the format that is supported by this authorization server. | [optional] +**Types** | Pointer to **[]string** | OpenID Connect Verifiable Credentials Types Contains the types of verifiable credentials supported. | [optional] + +## Methods + +### NewCredentialSupportedDraft00 + +`func NewCredentialSupportedDraft00() *CredentialSupportedDraft00` + +NewCredentialSupportedDraft00 instantiates a new CredentialSupportedDraft00 object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewCredentialSupportedDraft00WithDefaults + +`func NewCredentialSupportedDraft00WithDefaults() *CredentialSupportedDraft00` + +NewCredentialSupportedDraft00WithDefaults instantiates a new CredentialSupportedDraft00 object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetCryptographicBindingMethodsSupported + +`func (o *CredentialSupportedDraft00) GetCryptographicBindingMethodsSupported() []string` + +GetCryptographicBindingMethodsSupported returns the CryptographicBindingMethodsSupported field if non-nil, zero value otherwise. + +### GetCryptographicBindingMethodsSupportedOk + +`func (o *CredentialSupportedDraft00) GetCryptographicBindingMethodsSupportedOk() (*[]string, bool)` + +GetCryptographicBindingMethodsSupportedOk returns a tuple with the CryptographicBindingMethodsSupported field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCryptographicBindingMethodsSupported + +`func (o *CredentialSupportedDraft00) SetCryptographicBindingMethodsSupported(v []string)` + +SetCryptographicBindingMethodsSupported sets CryptographicBindingMethodsSupported field to given value. + +### HasCryptographicBindingMethodsSupported + +`func (o *CredentialSupportedDraft00) HasCryptographicBindingMethodsSupported() bool` + +HasCryptographicBindingMethodsSupported returns a boolean if a field has been set. + +### GetCryptographicSuitesSupported + +`func (o *CredentialSupportedDraft00) GetCryptographicSuitesSupported() []string` + +GetCryptographicSuitesSupported returns the CryptographicSuitesSupported field if non-nil, zero value otherwise. + +### GetCryptographicSuitesSupportedOk + +`func (o *CredentialSupportedDraft00) GetCryptographicSuitesSupportedOk() (*[]string, bool)` + +GetCryptographicSuitesSupportedOk returns a tuple with the CryptographicSuitesSupported field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCryptographicSuitesSupported + +`func (o *CredentialSupportedDraft00) SetCryptographicSuitesSupported(v []string)` + +SetCryptographicSuitesSupported sets CryptographicSuitesSupported field to given value. + +### HasCryptographicSuitesSupported + +`func (o *CredentialSupportedDraft00) HasCryptographicSuitesSupported() bool` + +HasCryptographicSuitesSupported returns a boolean if a field has been set. + +### GetFormat + +`func (o *CredentialSupportedDraft00) GetFormat() string` + +GetFormat returns the Format field if non-nil, zero value otherwise. + +### GetFormatOk + +`func (o *CredentialSupportedDraft00) GetFormatOk() (*string, bool)` + +GetFormatOk returns a tuple with the Format field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFormat + +`func (o *CredentialSupportedDraft00) SetFormat(v string)` + +SetFormat sets Format field to given value. + +### HasFormat + +`func (o *CredentialSupportedDraft00) HasFormat() bool` + +HasFormat returns a boolean if a field has been set. + +### GetTypes + +`func (o *CredentialSupportedDraft00) GetTypes() []string` + +GetTypes returns the Types field if non-nil, zero value otherwise. + +### GetTypesOk + +`func (o *CredentialSupportedDraft00) GetTypesOk() (*[]string, bool)` + +GetTypesOk returns a tuple with the Types field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetTypes + +`func (o *CredentialSupportedDraft00) SetTypes(v []string)` + +SetTypes sets Types field to given value. + +### HasTypes + +`func (o *CredentialSupportedDraft00) HasTypes() bool` + +HasTypes returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/JwkApi.md b/internal/httpclient/docs/JwkAPI.md similarity index 61% rename from internal/httpclient/docs/JwkApi.md rename to internal/httpclient/docs/JwkAPI.md index 3527e0b9622..73db4fd70ee 100644 --- a/internal/httpclient/docs/JwkApi.md +++ b/internal/httpclient/docs/JwkAPI.md @@ -1,16 +1,16 @@ -# \JwkApi +# \JwkAPI All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- -[**CreateJsonWebKeySet**](JwkApi.md#CreateJsonWebKeySet) | **Post** /admin/keys/{set} | Create JSON Web Key -[**DeleteJsonWebKey**](JwkApi.md#DeleteJsonWebKey) | **Delete** /admin/keys/{set}/{kid} | Delete JSON Web Key -[**DeleteJsonWebKeySet**](JwkApi.md#DeleteJsonWebKeySet) | **Delete** /admin/keys/{set} | Delete JSON Web Key Set -[**GetJsonWebKey**](JwkApi.md#GetJsonWebKey) | **Get** /admin/keys/{set}/{kid} | Get JSON Web Key -[**GetJsonWebKeySet**](JwkApi.md#GetJsonWebKeySet) | **Get** /admin/keys/{set} | Retrieve a JSON Web Key Set -[**SetJsonWebKey**](JwkApi.md#SetJsonWebKey) | **Put** /admin/keys/{set}/{kid} | Set JSON Web Key -[**SetJsonWebKeySet**](JwkApi.md#SetJsonWebKeySet) | **Put** /admin/keys/{set} | Update a JSON Web Key Set +[**CreateJsonWebKeySet**](JwkAPI.md#CreateJsonWebKeySet) | **Post** /admin/keys/{set} | Create JSON Web Key +[**DeleteJsonWebKey**](JwkAPI.md#DeleteJsonWebKey) | **Delete** /admin/keys/{set}/{kid} | Delete JSON Web Key +[**DeleteJsonWebKeySet**](JwkAPI.md#DeleteJsonWebKeySet) | **Delete** /admin/keys/{set} | Delete JSON Web Key Set +[**GetJsonWebKey**](JwkAPI.md#GetJsonWebKey) | **Get** /admin/keys/{set}/{kid} | Get JSON Web Key +[**GetJsonWebKeySet**](JwkAPI.md#GetJsonWebKeySet) | **Get** /admin/keys/{set} | Retrieve a JSON Web Key Set +[**SetJsonWebKey**](JwkAPI.md#SetJsonWebKey) | **Put** /admin/keys/{set}/{kid} | Set JSON Web Key +[**SetJsonWebKeySet**](JwkAPI.md#SetJsonWebKeySet) | **Put** /admin/keys/{set} | Update a JSON Web Key Set @@ -28,25 +28,25 @@ Create JSON Web Key package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - set := "set_example" // string | The JSON Web Key Set ID - createJsonWebKeySet := *openapiclient.NewCreateJsonWebKeySet("Alg_example", "Kid_example", "Use_example") // CreateJsonWebKeySet | - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.JwkApi.CreateJsonWebKeySet(context.Background(), set).CreateJsonWebKeySet(createJsonWebKeySet).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `JwkApi.CreateJsonWebKeySet``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `CreateJsonWebKeySet`: JsonWebKeySet - fmt.Fprintf(os.Stdout, "Response from `JwkApi.CreateJsonWebKeySet`: %v\n", resp) + set := "set_example" // string | The JSON Web Key Set ID + createJsonWebKeySet := *openapiclient.NewCreateJsonWebKeySet("Alg_example", "Kid_example", "Use_example") // CreateJsonWebKeySet | + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.JwkAPI.CreateJsonWebKeySet(context.Background(), set).CreateJsonWebKeySet(createJsonWebKeySet).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `JwkAPI.CreateJsonWebKeySet``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `CreateJsonWebKeySet`: JsonWebKeySet + fmt.Fprintf(os.Stdout, "Response from `JwkAPI.CreateJsonWebKeySet`: %v\n", resp) } ``` @@ -100,23 +100,23 @@ Delete JSON Web Key package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - set := "set_example" // string | The JSON Web Key Set - kid := "kid_example" // string | The JSON Web Key ID (kid) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.JwkApi.DeleteJsonWebKey(context.Background(), set, kid).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `JwkApi.DeleteJsonWebKey``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + set := "set_example" // string | The JSON Web Key Set + kid := "kid_example" // string | The JSON Web Key ID (kid) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.JwkAPI.DeleteJsonWebKey(context.Background(), set, kid).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `JwkAPI.DeleteJsonWebKey``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -171,22 +171,22 @@ Delete JSON Web Key Set package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - set := "set_example" // string | The JSON Web Key Set - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.JwkApi.DeleteJsonWebKeySet(context.Background(), set).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `JwkApi.DeleteJsonWebKeySet``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + set := "set_example" // string | The JSON Web Key Set + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.JwkAPI.DeleteJsonWebKeySet(context.Background(), set).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `JwkAPI.DeleteJsonWebKeySet``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -239,25 +239,25 @@ Get JSON Web Key package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - set := "set_example" // string | JSON Web Key Set ID - kid := "kid_example" // string | JSON Web Key ID - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.JwkApi.GetJsonWebKey(context.Background(), set, kid).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `JwkApi.GetJsonWebKey``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetJsonWebKey`: JsonWebKeySet - fmt.Fprintf(os.Stdout, "Response from `JwkApi.GetJsonWebKey`: %v\n", resp) + set := "set_example" // string | JSON Web Key Set ID + kid := "kid_example" // string | JSON Web Key ID + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.JwkAPI.GetJsonWebKey(context.Background(), set, kid).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `JwkAPI.GetJsonWebKey``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetJsonWebKey`: JsonWebKeySet + fmt.Fprintf(os.Stdout, "Response from `JwkAPI.GetJsonWebKey`: %v\n", resp) } ``` @@ -312,24 +312,24 @@ Retrieve a JSON Web Key Set package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - set := "set_example" // string | JSON Web Key Set ID - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.JwkApi.GetJsonWebKeySet(context.Background(), set).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `JwkApi.GetJsonWebKeySet``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetJsonWebKeySet`: JsonWebKeySet - fmt.Fprintf(os.Stdout, "Response from `JwkApi.GetJsonWebKeySet`: %v\n", resp) + set := "set_example" // string | JSON Web Key Set ID + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.JwkAPI.GetJsonWebKeySet(context.Background(), set).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `JwkAPI.GetJsonWebKeySet``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetJsonWebKeySet`: JsonWebKeySet + fmt.Fprintf(os.Stdout, "Response from `JwkAPI.GetJsonWebKeySet`: %v\n", resp) } ``` @@ -382,26 +382,26 @@ Set JSON Web Key package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - set := "set_example" // string | The JSON Web Key Set ID - kid := "kid_example" // string | JSON Web Key ID - jsonWebKey := *openapiclient.NewJsonWebKey("RS256", "1603dfe0af8f4596", "RSA", "sig") // JsonWebKey | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.JwkApi.SetJsonWebKey(context.Background(), set, kid).JsonWebKey(jsonWebKey).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `JwkApi.SetJsonWebKey``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `SetJsonWebKey`: JsonWebKey - fmt.Fprintf(os.Stdout, "Response from `JwkApi.SetJsonWebKey`: %v\n", resp) + set := "set_example" // string | The JSON Web Key Set ID + kid := "kid_example" // string | JSON Web Key ID + jsonWebKey := *openapiclient.NewJsonWebKey("RS256", "1603dfe0af8f4596", "RSA", "sig") // JsonWebKey | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.JwkAPI.SetJsonWebKey(context.Background(), set, kid).JsonWebKey(jsonWebKey).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `JwkAPI.SetJsonWebKey``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `SetJsonWebKey`: JsonWebKey + fmt.Fprintf(os.Stdout, "Response from `JwkAPI.SetJsonWebKey`: %v\n", resp) } ``` @@ -457,25 +457,25 @@ Update a JSON Web Key Set package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - set := "set_example" // string | The JSON Web Key Set ID - jsonWebKeySet := *openapiclient.NewJsonWebKeySet() // JsonWebKeySet | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.JwkApi.SetJsonWebKeySet(context.Background(), set).JsonWebKeySet(jsonWebKeySet).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `JwkApi.SetJsonWebKeySet``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `SetJsonWebKeySet`: JsonWebKeySet - fmt.Fprintf(os.Stdout, "Response from `JwkApi.SetJsonWebKeySet`: %v\n", resp) + set := "set_example" // string | The JSON Web Key Set ID + jsonWebKeySet := *openapiclient.NewJsonWebKeySet() // JsonWebKeySet | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.JwkAPI.SetJsonWebKeySet(context.Background(), set).JsonWebKeySet(jsonWebKeySet).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `JwkAPI.SetJsonWebKeySet``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `SetJsonWebKeySet`: JsonWebKeySet + fmt.Fprintf(os.Stdout, "Response from `JwkAPI.SetJsonWebKeySet`: %v\n", resp) } ``` diff --git a/internal/httpclient/docs/MetadataApi.md b/internal/httpclient/docs/MetadataAPI.md similarity index 56% rename from internal/httpclient/docs/MetadataApi.md rename to internal/httpclient/docs/MetadataAPI.md index 064272fd09b..6280313b670 100644 --- a/internal/httpclient/docs/MetadataApi.md +++ b/internal/httpclient/docs/MetadataAPI.md @@ -1,12 +1,12 @@ -# \MetadataApi +# \MetadataAPI All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- -[**GetVersion**](MetadataApi.md#GetVersion) | **Get** /version | Return Running Software Version. -[**IsAlive**](MetadataApi.md#IsAlive) | **Get** /health/alive | Check HTTP Server Status -[**IsReady**](MetadataApi.md#IsReady) | **Get** /health/ready | Check HTTP Server and Database Status +[**GetVersion**](MetadataAPI.md#GetVersion) | **Get** /version | Return Running Software Version. +[**IsAlive**](MetadataAPI.md#IsAlive) | **Get** /health/alive | Check HTTP Server Status +[**IsReady**](MetadataAPI.md#IsReady) | **Get** /health/ready | Check HTTP Server and Database Status @@ -24,23 +24,23 @@ Return Running Software Version. package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.MetadataApi.GetVersion(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `MetadataApi.GetVersion``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetVersion`: GetVersion200Response - fmt.Fprintf(os.Stdout, "Response from `MetadataApi.GetVersion`: %v\n", resp) + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.MetadataAPI.GetVersion(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `MetadataAPI.GetVersion``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetVersion`: GetVersion200Response + fmt.Fprintf(os.Stdout, "Response from `MetadataAPI.GetVersion`: %v\n", resp) } ``` @@ -85,23 +85,23 @@ Check HTTP Server Status package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.MetadataApi.IsAlive(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `MetadataApi.IsAlive``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `IsAlive`: HealthStatus - fmt.Fprintf(os.Stdout, "Response from `MetadataApi.IsAlive`: %v\n", resp) + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.MetadataAPI.IsAlive(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `MetadataAPI.IsAlive``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `IsAlive`: HealthStatus + fmt.Fprintf(os.Stdout, "Response from `MetadataAPI.IsAlive`: %v\n", resp) } ``` @@ -146,23 +146,23 @@ Check HTTP Server and Database Status package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.MetadataApi.IsReady(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `MetadataApi.IsReady``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `IsReady`: IsReady200Response - fmt.Fprintf(os.Stdout, "Response from `MetadataApi.IsReady`: %v\n", resp) + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.MetadataAPI.IsReady(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `MetadataAPI.IsReady``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `IsReady`: IsReady200Response + fmt.Fprintf(os.Stdout, "Response from `MetadataAPI.IsReady`: %v\n", resp) } ``` diff --git a/internal/httpclient/docs/OAuth2Api.md b/internal/httpclient/docs/OAuth2API.md similarity index 57% rename from internal/httpclient/docs/OAuth2Api.md rename to internal/httpclient/docs/OAuth2API.md index bdee97d6a53..6f8c0aac527 100644 --- a/internal/httpclient/docs/OAuth2Api.md +++ b/internal/httpclient/docs/OAuth2API.md @@ -1,37 +1,37 @@ -# \OAuth2Api +# \OAuth2API All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- -[**AcceptOAuth2ConsentRequest**](OAuth2Api.md#AcceptOAuth2ConsentRequest) | **Put** /admin/oauth2/auth/requests/consent/accept | Accept OAuth 2.0 Consent Request -[**AcceptOAuth2LoginRequest**](OAuth2Api.md#AcceptOAuth2LoginRequest) | **Put** /admin/oauth2/auth/requests/login/accept | Accept OAuth 2.0 Login Request -[**AcceptOAuth2LogoutRequest**](OAuth2Api.md#AcceptOAuth2LogoutRequest) | **Put** /admin/oauth2/auth/requests/logout/accept | Accept OAuth 2.0 Session Logout Request -[**CreateOAuth2Client**](OAuth2Api.md#CreateOAuth2Client) | **Post** /admin/clients | Create OAuth 2.0 Client -[**DeleteOAuth2Client**](OAuth2Api.md#DeleteOAuth2Client) | **Delete** /admin/clients/{id} | Delete OAuth 2.0 Client -[**DeleteOAuth2Token**](OAuth2Api.md#DeleteOAuth2Token) | **Delete** /admin/oauth2/tokens | Delete OAuth 2.0 Access Tokens from specific OAuth 2.0 Client -[**DeleteTrustedOAuth2JwtGrantIssuer**](OAuth2Api.md#DeleteTrustedOAuth2JwtGrantIssuer) | **Delete** /admin/trust/grants/jwt-bearer/issuers/{id} | Delete Trusted OAuth2 JWT Bearer Grant Type Issuer -[**GetOAuth2Client**](OAuth2Api.md#GetOAuth2Client) | **Get** /admin/clients/{id} | Get an OAuth 2.0 Client -[**GetOAuth2ConsentRequest**](OAuth2Api.md#GetOAuth2ConsentRequest) | **Get** /admin/oauth2/auth/requests/consent | Get OAuth 2.0 Consent Request -[**GetOAuth2LoginRequest**](OAuth2Api.md#GetOAuth2LoginRequest) | **Get** /admin/oauth2/auth/requests/login | Get OAuth 2.0 Login Request -[**GetOAuth2LogoutRequest**](OAuth2Api.md#GetOAuth2LogoutRequest) | **Get** /admin/oauth2/auth/requests/logout | Get OAuth 2.0 Session Logout Request -[**GetTrustedOAuth2JwtGrantIssuer**](OAuth2Api.md#GetTrustedOAuth2JwtGrantIssuer) | **Get** /admin/trust/grants/jwt-bearer/issuers/{id} | Get Trusted OAuth2 JWT Bearer Grant Type Issuer -[**IntrospectOAuth2Token**](OAuth2Api.md#IntrospectOAuth2Token) | **Post** /admin/oauth2/introspect | Introspect OAuth2 Access and Refresh Tokens -[**ListOAuth2Clients**](OAuth2Api.md#ListOAuth2Clients) | **Get** /admin/clients | List OAuth 2.0 Clients -[**ListOAuth2ConsentSessions**](OAuth2Api.md#ListOAuth2ConsentSessions) | **Get** /admin/oauth2/auth/sessions/consent | List OAuth 2.0 Consent Sessions of a Subject -[**ListTrustedOAuth2JwtGrantIssuers**](OAuth2Api.md#ListTrustedOAuth2JwtGrantIssuers) | **Get** /admin/trust/grants/jwt-bearer/issuers | List Trusted OAuth2 JWT Bearer Grant Type Issuers -[**OAuth2Authorize**](OAuth2Api.md#OAuth2Authorize) | **Get** /oauth2/auth | OAuth 2.0 Authorize Endpoint -[**Oauth2TokenExchange**](OAuth2Api.md#Oauth2TokenExchange) | **Post** /oauth2/token | The OAuth 2.0 Token Endpoint -[**PatchOAuth2Client**](OAuth2Api.md#PatchOAuth2Client) | **Patch** /admin/clients/{id} | Patch OAuth 2.0 Client -[**RejectOAuth2ConsentRequest**](OAuth2Api.md#RejectOAuth2ConsentRequest) | **Put** /admin/oauth2/auth/requests/consent/reject | Reject OAuth 2.0 Consent Request -[**RejectOAuth2LoginRequest**](OAuth2Api.md#RejectOAuth2LoginRequest) | **Put** /admin/oauth2/auth/requests/login/reject | Reject OAuth 2.0 Login Request -[**RejectOAuth2LogoutRequest**](OAuth2Api.md#RejectOAuth2LogoutRequest) | **Put** /admin/oauth2/auth/requests/logout/reject | Reject OAuth 2.0 Session Logout Request -[**RevokeOAuth2ConsentSessions**](OAuth2Api.md#RevokeOAuth2ConsentSessions) | **Delete** /admin/oauth2/auth/sessions/consent | Revoke OAuth 2.0 Consent Sessions of a Subject -[**RevokeOAuth2LoginSessions**](OAuth2Api.md#RevokeOAuth2LoginSessions) | **Delete** /admin/oauth2/auth/sessions/login | Revokes All OAuth 2.0 Login Sessions of a Subject -[**RevokeOAuth2Token**](OAuth2Api.md#RevokeOAuth2Token) | **Post** /oauth2/revoke | Revoke OAuth 2.0 Access or Refresh Token -[**SetOAuth2Client**](OAuth2Api.md#SetOAuth2Client) | **Put** /admin/clients/{id} | Set OAuth 2.0 Client -[**SetOAuth2ClientLifespans**](OAuth2Api.md#SetOAuth2ClientLifespans) | **Put** /admin/clients/{id}/lifespans | Set OAuth2 Client Token Lifespans -[**TrustOAuth2JwtGrantIssuer**](OAuth2Api.md#TrustOAuth2JwtGrantIssuer) | **Post** /admin/trust/grants/jwt-bearer/issuers | Trust OAuth2 JWT Bearer Grant Type Issuer +[**AcceptOAuth2ConsentRequest**](OAuth2API.md#AcceptOAuth2ConsentRequest) | **Put** /admin/oauth2/auth/requests/consent/accept | Accept OAuth 2.0 Consent Request +[**AcceptOAuth2LoginRequest**](OAuth2API.md#AcceptOAuth2LoginRequest) | **Put** /admin/oauth2/auth/requests/login/accept | Accept OAuth 2.0 Login Request +[**AcceptOAuth2LogoutRequest**](OAuth2API.md#AcceptOAuth2LogoutRequest) | **Put** /admin/oauth2/auth/requests/logout/accept | Accept OAuth 2.0 Session Logout Request +[**CreateOAuth2Client**](OAuth2API.md#CreateOAuth2Client) | **Post** /admin/clients | Create OAuth 2.0 Client +[**DeleteOAuth2Client**](OAuth2API.md#DeleteOAuth2Client) | **Delete** /admin/clients/{id} | Delete OAuth 2.0 Client +[**DeleteOAuth2Token**](OAuth2API.md#DeleteOAuth2Token) | **Delete** /admin/oauth2/tokens | Delete OAuth 2.0 Access Tokens from specific OAuth 2.0 Client +[**DeleteTrustedOAuth2JwtGrantIssuer**](OAuth2API.md#DeleteTrustedOAuth2JwtGrantIssuer) | **Delete** /admin/trust/grants/jwt-bearer/issuers/{id} | Delete Trusted OAuth2 JWT Bearer Grant Type Issuer +[**GetOAuth2Client**](OAuth2API.md#GetOAuth2Client) | **Get** /admin/clients/{id} | Get an OAuth 2.0 Client +[**GetOAuth2ConsentRequest**](OAuth2API.md#GetOAuth2ConsentRequest) | **Get** /admin/oauth2/auth/requests/consent | Get OAuth 2.0 Consent Request +[**GetOAuth2LoginRequest**](OAuth2API.md#GetOAuth2LoginRequest) | **Get** /admin/oauth2/auth/requests/login | Get OAuth 2.0 Login Request +[**GetOAuth2LogoutRequest**](OAuth2API.md#GetOAuth2LogoutRequest) | **Get** /admin/oauth2/auth/requests/logout | Get OAuth 2.0 Session Logout Request +[**GetTrustedOAuth2JwtGrantIssuer**](OAuth2API.md#GetTrustedOAuth2JwtGrantIssuer) | **Get** /admin/trust/grants/jwt-bearer/issuers/{id} | Get Trusted OAuth2 JWT Bearer Grant Type Issuer +[**IntrospectOAuth2Token**](OAuth2API.md#IntrospectOAuth2Token) | **Post** /admin/oauth2/introspect | Introspect OAuth2 Access and Refresh Tokens +[**ListOAuth2Clients**](OAuth2API.md#ListOAuth2Clients) | **Get** /admin/clients | List OAuth 2.0 Clients +[**ListOAuth2ConsentSessions**](OAuth2API.md#ListOAuth2ConsentSessions) | **Get** /admin/oauth2/auth/sessions/consent | List OAuth 2.0 Consent Sessions of a Subject +[**ListTrustedOAuth2JwtGrantIssuers**](OAuth2API.md#ListTrustedOAuth2JwtGrantIssuers) | **Get** /admin/trust/grants/jwt-bearer/issuers | List Trusted OAuth2 JWT Bearer Grant Type Issuers +[**OAuth2Authorize**](OAuth2API.md#OAuth2Authorize) | **Get** /oauth2/auth | OAuth 2.0 Authorize Endpoint +[**Oauth2TokenExchange**](OAuth2API.md#Oauth2TokenExchange) | **Post** /oauth2/token | The OAuth 2.0 Token Endpoint +[**PatchOAuth2Client**](OAuth2API.md#PatchOAuth2Client) | **Patch** /admin/clients/{id} | Patch OAuth 2.0 Client +[**RejectOAuth2ConsentRequest**](OAuth2API.md#RejectOAuth2ConsentRequest) | **Put** /admin/oauth2/auth/requests/consent/reject | Reject OAuth 2.0 Consent Request +[**RejectOAuth2LoginRequest**](OAuth2API.md#RejectOAuth2LoginRequest) | **Put** /admin/oauth2/auth/requests/login/reject | Reject OAuth 2.0 Login Request +[**RejectOAuth2LogoutRequest**](OAuth2API.md#RejectOAuth2LogoutRequest) | **Put** /admin/oauth2/auth/requests/logout/reject | Reject OAuth 2.0 Session Logout Request +[**RevokeOAuth2ConsentSessions**](OAuth2API.md#RevokeOAuth2ConsentSessions) | **Delete** /admin/oauth2/auth/sessions/consent | Revoke OAuth 2.0 Consent Sessions of a Subject +[**RevokeOAuth2LoginSessions**](OAuth2API.md#RevokeOAuth2LoginSessions) | **Delete** /admin/oauth2/auth/sessions/login | Revokes OAuth 2.0 Login Sessions by either a Subject or a SessionID +[**RevokeOAuth2Token**](OAuth2API.md#RevokeOAuth2Token) | **Post** /oauth2/revoke | Revoke OAuth 2.0 Access or Refresh Token +[**SetOAuth2Client**](OAuth2API.md#SetOAuth2Client) | **Put** /admin/clients/{id} | Set OAuth 2.0 Client +[**SetOAuth2ClientLifespans**](OAuth2API.md#SetOAuth2ClientLifespans) | **Put** /admin/clients/{id}/lifespans | Set OAuth2 Client Token Lifespans +[**TrustOAuth2JwtGrantIssuer**](OAuth2API.md#TrustOAuth2JwtGrantIssuer) | **Post** /admin/trust/grants/jwt-bearer/issuers | Trust OAuth2 JWT Bearer Grant Type Issuer @@ -49,25 +49,25 @@ Accept OAuth 2.0 Consent Request package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - consentChallenge := "consentChallenge_example" // string | OAuth 2.0 Consent Request Challenge - acceptOAuth2ConsentRequest := *openapiclient.NewAcceptOAuth2ConsentRequest() // AcceptOAuth2ConsentRequest | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.AcceptOAuth2ConsentRequest(context.Background()).ConsentChallenge(consentChallenge).AcceptOAuth2ConsentRequest(acceptOAuth2ConsentRequest).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.AcceptOAuth2ConsentRequest``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `AcceptOAuth2ConsentRequest`: OAuth2RedirectTo - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.AcceptOAuth2ConsentRequest`: %v\n", resp) + consentChallenge := "consentChallenge_example" // string | OAuth 2.0 Consent Request Challenge + acceptOAuth2ConsentRequest := *openapiclient.NewAcceptOAuth2ConsentRequest() // AcceptOAuth2ConsentRequest | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.AcceptOAuth2ConsentRequest(context.Background()).ConsentChallenge(consentChallenge).AcceptOAuth2ConsentRequest(acceptOAuth2ConsentRequest).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.AcceptOAuth2ConsentRequest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `AcceptOAuth2ConsentRequest`: OAuth2RedirectTo + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.AcceptOAuth2ConsentRequest`: %v\n", resp) } ``` @@ -117,25 +117,25 @@ Accept OAuth 2.0 Login Request package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - loginChallenge := "loginChallenge_example" // string | OAuth 2.0 Login Request Challenge - acceptOAuth2LoginRequest := *openapiclient.NewAcceptOAuth2LoginRequest("Subject_example") // AcceptOAuth2LoginRequest | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()).LoginChallenge(loginChallenge).AcceptOAuth2LoginRequest(acceptOAuth2LoginRequest).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.AcceptOAuth2LoginRequest``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `AcceptOAuth2LoginRequest`: OAuth2RedirectTo - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.AcceptOAuth2LoginRequest`: %v\n", resp) + loginChallenge := "loginChallenge_example" // string | OAuth 2.0 Login Request Challenge + acceptOAuth2LoginRequest := *openapiclient.NewAcceptOAuth2LoginRequest("Subject_example") // AcceptOAuth2LoginRequest | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.AcceptOAuth2LoginRequest(context.Background()).LoginChallenge(loginChallenge).AcceptOAuth2LoginRequest(acceptOAuth2LoginRequest).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.AcceptOAuth2LoginRequest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `AcceptOAuth2LoginRequest`: OAuth2RedirectTo + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.AcceptOAuth2LoginRequest`: %v\n", resp) } ``` @@ -185,24 +185,24 @@ Accept OAuth 2.0 Session Logout Request package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - logoutChallenge := "logoutChallenge_example" // string | OAuth 2.0 Logout Request Challenge - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.AcceptOAuth2LogoutRequest(context.Background()).LogoutChallenge(logoutChallenge).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.AcceptOAuth2LogoutRequest``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `AcceptOAuth2LogoutRequest`: OAuth2RedirectTo - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.AcceptOAuth2LogoutRequest`: %v\n", resp) + logoutChallenge := "logoutChallenge_example" // string | OAuth 2.0 Logout Request Challenge + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.AcceptOAuth2LogoutRequest(context.Background()).LogoutChallenge(logoutChallenge).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.AcceptOAuth2LogoutRequest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `AcceptOAuth2LogoutRequest`: OAuth2RedirectTo + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.AcceptOAuth2LogoutRequest`: %v\n", resp) } ``` @@ -251,24 +251,24 @@ Create OAuth 2.0 Client package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - oAuth2Client := *openapiclient.NewOAuth2Client() // OAuth2Client | OAuth 2.0 Client Request Body - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.CreateOAuth2Client(context.Background()).OAuth2Client(oAuth2Client).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.CreateOAuth2Client``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `CreateOAuth2Client`: OAuth2Client - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.CreateOAuth2Client`: %v\n", resp) + oAuth2Client := *openapiclient.NewOAuth2Client() // OAuth2Client | OAuth 2.0 Client Request Body + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.CreateOAuth2Client(context.Background()).OAuth2Client(oAuth2Client).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.CreateOAuth2Client``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `CreateOAuth2Client`: OAuth2Client + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.CreateOAuth2Client`: %v\n", resp) } ``` @@ -317,22 +317,22 @@ Delete OAuth 2.0 Client package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | The id of the OAuth 2.0 Client. - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.DeleteOAuth2Client(context.Background(), id).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.DeleteOAuth2Client``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + id := "id_example" // string | The id of the OAuth 2.0 Client. + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.OAuth2API.DeleteOAuth2Client(context.Background(), id).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.DeleteOAuth2Client``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -385,22 +385,22 @@ Delete OAuth 2.0 Access Tokens from specific OAuth 2.0 Client package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - clientId := "clientId_example" // string | OAuth 2.0 Client ID - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.DeleteOAuth2Token(context.Background()).ClientId(clientId).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.DeleteOAuth2Token``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + clientId := "clientId_example" // string | OAuth 2.0 Client ID + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.OAuth2API.DeleteOAuth2Token(context.Background()).ClientId(clientId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.DeleteOAuth2Token``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -449,22 +449,22 @@ Delete Trusted OAuth2 JWT Bearer Grant Type Issuer package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | The id of the desired grant - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.DeleteTrustedOAuth2JwtGrantIssuer(context.Background(), id).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.DeleteTrustedOAuth2JwtGrantIssuer``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + id := "id_example" // string | The id of the desired grant + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.OAuth2API.DeleteTrustedOAuth2JwtGrantIssuer(context.Background(), id).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.DeleteTrustedOAuth2JwtGrantIssuer``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -517,24 +517,24 @@ Get an OAuth 2.0 Client package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | The id of the OAuth 2.0 Client. - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.GetOAuth2Client(context.Background(), id).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.GetOAuth2Client``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetOAuth2Client`: OAuth2Client - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.GetOAuth2Client`: %v\n", resp) + id := "id_example" // string | The id of the OAuth 2.0 Client. + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.GetOAuth2Client(context.Background(), id).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.GetOAuth2Client``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetOAuth2Client`: OAuth2Client + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.GetOAuth2Client`: %v\n", resp) } ``` @@ -587,24 +587,24 @@ Get OAuth 2.0 Consent Request package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - consentChallenge := "consentChallenge_example" // string | OAuth 2.0 Consent Request Challenge - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(consentChallenge).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.GetOAuth2ConsentRequest``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetOAuth2ConsentRequest`: OAuth2ConsentRequest - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.GetOAuth2ConsentRequest`: %v\n", resp) + consentChallenge := "consentChallenge_example" // string | OAuth 2.0 Consent Request Challenge + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(consentChallenge).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.GetOAuth2ConsentRequest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetOAuth2ConsentRequest`: OAuth2ConsentRequest + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.GetOAuth2ConsentRequest`: %v\n", resp) } ``` @@ -653,24 +653,24 @@ Get OAuth 2.0 Login Request package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - loginChallenge := "loginChallenge_example" // string | OAuth 2.0 Login Request Challenge - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.GetOAuth2LoginRequest(context.Background()).LoginChallenge(loginChallenge).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.GetOAuth2LoginRequest``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetOAuth2LoginRequest`: OAuth2LoginRequest - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.GetOAuth2LoginRequest`: %v\n", resp) + loginChallenge := "loginChallenge_example" // string | OAuth 2.0 Login Request Challenge + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.GetOAuth2LoginRequest(context.Background()).LoginChallenge(loginChallenge).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.GetOAuth2LoginRequest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetOAuth2LoginRequest`: OAuth2LoginRequest + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.GetOAuth2LoginRequest`: %v\n", resp) } ``` @@ -719,24 +719,24 @@ Get OAuth 2.0 Session Logout Request package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - logoutChallenge := "logoutChallenge_example" // string | - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.GetOAuth2LogoutRequest(context.Background()).LogoutChallenge(logoutChallenge).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.GetOAuth2LogoutRequest``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetOAuth2LogoutRequest`: OAuth2LogoutRequest - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.GetOAuth2LogoutRequest`: %v\n", resp) + logoutChallenge := "logoutChallenge_example" // string | + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.GetOAuth2LogoutRequest(context.Background()).LogoutChallenge(logoutChallenge).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.GetOAuth2LogoutRequest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetOAuth2LogoutRequest`: OAuth2LogoutRequest + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.GetOAuth2LogoutRequest`: %v\n", resp) } ``` @@ -785,24 +785,24 @@ Get Trusted OAuth2 JWT Bearer Grant Type Issuer package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | The id of the desired grant - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.GetTrustedOAuth2JwtGrantIssuer(context.Background(), id).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.GetTrustedOAuth2JwtGrantIssuer``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetTrustedOAuth2JwtGrantIssuer`: TrustedOAuth2JwtGrantIssuer - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.GetTrustedOAuth2JwtGrantIssuer`: %v\n", resp) + id := "id_example" // string | The id of the desired grant + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.GetTrustedOAuth2JwtGrantIssuer(context.Background(), id).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.GetTrustedOAuth2JwtGrantIssuer``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetTrustedOAuth2JwtGrantIssuer`: TrustedOAuth2JwtGrantIssuer + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.GetTrustedOAuth2JwtGrantIssuer`: %v\n", resp) } ``` @@ -855,25 +855,25 @@ Introspect OAuth2 Access and Refresh Tokens package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - token := "token_example" // string | The string value of the token. For access tokens, this is the \\\"access_token\\\" value returned from the token endpoint defined in OAuth 2.0. For refresh tokens, this is the \\\"refresh_token\\\" value returned. - scope := "scope_example" // string | An optional, space separated list of required scopes. If the access token was not granted one of the scopes, the result of active will be false. (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.IntrospectOAuth2Token(context.Background()).Token(token).Scope(scope).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.IntrospectOAuth2Token``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `IntrospectOAuth2Token`: IntrospectedOAuth2Token - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.IntrospectOAuth2Token`: %v\n", resp) + token := "token_example" // string | The string value of the token. For access tokens, this is the \\\"access_token\\\" value returned from the token endpoint defined in OAuth 2.0. For refresh tokens, this is the \\\"refresh_token\\\" value returned. + scope := "scope_example" // string | An optional, space separated list of required scopes. If the access token was not granted one of the scopes, the result of active will be false. (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.IntrospectOAuth2Token(context.Background()).Token(token).Scope(scope).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.IntrospectOAuth2Token``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `IntrospectOAuth2Token`: IntrospectedOAuth2Token + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.IntrospectOAuth2Token`: %v\n", resp) } ``` @@ -923,27 +923,27 @@ List OAuth 2.0 Clients package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - pageSize := int64(789) // int64 | Items per Page This is the number of items per page to return. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to 250) - pageToken := "pageToken_example" // string | Next Page Token The next page token. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to "1") - clientName := "clientName_example" // string | The name of the clients to filter by. (optional) - owner := "owner_example" // string | The owner of the clients to filter by. (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.ListOAuth2Clients(context.Background()).PageSize(pageSize).PageToken(pageToken).ClientName(clientName).Owner(owner).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.ListOAuth2Clients``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `ListOAuth2Clients`: []OAuth2Client - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.ListOAuth2Clients`: %v\n", resp) + pageSize := int64(789) // int64 | Items per Page This is the number of items per page to return. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to 250) + pageToken := "pageToken_example" // string | Next Page Token The next page token. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to "1") + clientName := "clientName_example" // string | The name of the clients to filter by. (optional) + owner := "owner_example" // string | The owner of the clients to filter by. (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.ListOAuth2Clients(context.Background()).PageSize(pageSize).PageToken(pageToken).ClientName(clientName).Owner(owner).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.ListOAuth2Clients``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListOAuth2Clients`: []OAuth2Client + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.ListOAuth2Clients`: %v\n", resp) } ``` @@ -995,27 +995,27 @@ List OAuth 2.0 Consent Sessions of a Subject package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - subject := "subject_example" // string | The subject to list the consent sessions for. - pageSize := int64(789) // int64 | Items per Page This is the number of items per page to return. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to 250) - pageToken := "pageToken_example" // string | Next Page Token The next page token. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to "1") - loginSessionId := "loginSessionId_example" // string | The login session id to list the consent sessions for. (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.ListOAuth2ConsentSessions(context.Background()).Subject(subject).PageSize(pageSize).PageToken(pageToken).LoginSessionId(loginSessionId).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.ListOAuth2ConsentSessions``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `ListOAuth2ConsentSessions`: []OAuth2ConsentSession - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.ListOAuth2ConsentSessions`: %v\n", resp) + subject := "subject_example" // string | The subject to list the consent sessions for. + pageSize := int64(789) // int64 | Items per Page This is the number of items per page to return. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to 250) + pageToken := "pageToken_example" // string | Next Page Token The next page token. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). (optional) (default to "1") + loginSessionId := "loginSessionId_example" // string | The login session id to list the consent sessions for. (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.ListOAuth2ConsentSessions(context.Background()).Subject(subject).PageSize(pageSize).PageToken(pageToken).LoginSessionId(loginSessionId).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.ListOAuth2ConsentSessions``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListOAuth2ConsentSessions`: []OAuth2ConsentSession + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.ListOAuth2ConsentSessions`: %v\n", resp) } ``` @@ -1067,26 +1067,26 @@ List Trusted OAuth2 JWT Bearer Grant Type Issuers package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - maxItems := int64(789) // int64 | (optional) - defaultItems := int64(789) // int64 | (optional) - issuer := "issuer_example" // string | If optional \"issuer\" is supplied, only jwt-bearer grants with this issuer will be returned. (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.ListTrustedOAuth2JwtGrantIssuers(context.Background()).MaxItems(maxItems).DefaultItems(defaultItems).Issuer(issuer).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.ListTrustedOAuth2JwtGrantIssuers``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `ListTrustedOAuth2JwtGrantIssuers`: []TrustedOAuth2JwtGrantIssuer - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.ListTrustedOAuth2JwtGrantIssuers`: %v\n", resp) + maxItems := int64(789) // int64 | (optional) + defaultItems := int64(789) // int64 | (optional) + issuer := "issuer_example" // string | If optional \"issuer\" is supplied, only jwt-bearer grants with this issuer will be returned. (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.ListTrustedOAuth2JwtGrantIssuers(context.Background()).MaxItems(maxItems).DefaultItems(defaultItems).Issuer(issuer).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.ListTrustedOAuth2JwtGrantIssuers``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `ListTrustedOAuth2JwtGrantIssuers`: []TrustedOAuth2JwtGrantIssuer + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.ListTrustedOAuth2JwtGrantIssuers`: %v\n", resp) } ``` @@ -1137,23 +1137,23 @@ OAuth 2.0 Authorize Endpoint package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.OAuth2Authorize(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.OAuth2Authorize``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `OAuth2Authorize`: ErrorOAuth2 - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.OAuth2Authorize`: %v\n", resp) + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.OAuth2Authorize(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.OAuth2Authorize``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `OAuth2Authorize`: ErrorOAuth2 + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.OAuth2Authorize`: %v\n", resp) } ``` @@ -1198,28 +1198,28 @@ The OAuth 2.0 Token Endpoint package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - grantType := "grantType_example" // string | - clientId := "clientId_example" // string | (optional) - code := "code_example" // string | (optional) - redirectUri := "redirectUri_example" // string | (optional) - refreshToken := "refreshToken_example" // string | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.Oauth2TokenExchange(context.Background()).GrantType(grantType).ClientId(clientId).Code(code).RedirectUri(redirectUri).RefreshToken(refreshToken).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.Oauth2TokenExchange``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `Oauth2TokenExchange`: OAuth2TokenExchange - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.Oauth2TokenExchange`: %v\n", resp) + grantType := "grantType_example" // string | + clientId := "clientId_example" // string | (optional) + code := "code_example" // string | (optional) + redirectUri := "redirectUri_example" // string | (optional) + refreshToken := "refreshToken_example" // string | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.Oauth2TokenExchange(context.Background()).GrantType(grantType).ClientId(clientId).Code(code).RedirectUri(redirectUri).RefreshToken(refreshToken).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.Oauth2TokenExchange``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `Oauth2TokenExchange`: OAuth2TokenExchange + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.Oauth2TokenExchange`: %v\n", resp) } ``` @@ -1272,25 +1272,25 @@ Patch OAuth 2.0 Client package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | The id of the OAuth 2.0 Client. - jsonPatch := []openapiclient.JsonPatch{*openapiclient.NewJsonPatch("replace", "/name")} // []JsonPatch | OAuth 2.0 Client JSON Patch Body - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.PatchOAuth2Client(context.Background(), id).JsonPatch(jsonPatch).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.PatchOAuth2Client``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `PatchOAuth2Client`: OAuth2Client - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.PatchOAuth2Client`: %v\n", resp) + id := "id_example" // string | The id of the OAuth 2.0 Client. + jsonPatch := []openapiclient.JsonPatch{*openapiclient.NewJsonPatch("replace", "/name")} // []JsonPatch | OAuth 2.0 Client JSON Patch Body + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.PatchOAuth2Client(context.Background(), id).JsonPatch(jsonPatch).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.PatchOAuth2Client``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `PatchOAuth2Client`: OAuth2Client + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.PatchOAuth2Client`: %v\n", resp) } ``` @@ -1344,25 +1344,25 @@ Reject OAuth 2.0 Consent Request package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - consentChallenge := "consentChallenge_example" // string | OAuth 2.0 Consent Request Challenge - rejectOAuth2Request := *openapiclient.NewRejectOAuth2Request() // RejectOAuth2Request | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.RejectOAuth2ConsentRequest(context.Background()).ConsentChallenge(consentChallenge).RejectOAuth2Request(rejectOAuth2Request).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.RejectOAuth2ConsentRequest``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `RejectOAuth2ConsentRequest`: OAuth2RedirectTo - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.RejectOAuth2ConsentRequest`: %v\n", resp) + consentChallenge := "consentChallenge_example" // string | OAuth 2.0 Consent Request Challenge + rejectOAuth2Request := *openapiclient.NewRejectOAuth2Request() // RejectOAuth2Request | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.RejectOAuth2ConsentRequest(context.Background()).ConsentChallenge(consentChallenge).RejectOAuth2Request(rejectOAuth2Request).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.RejectOAuth2ConsentRequest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `RejectOAuth2ConsentRequest`: OAuth2RedirectTo + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.RejectOAuth2ConsentRequest`: %v\n", resp) } ``` @@ -1412,25 +1412,25 @@ Reject OAuth 2.0 Login Request package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - loginChallenge := "loginChallenge_example" // string | OAuth 2.0 Login Request Challenge - rejectOAuth2Request := *openapiclient.NewRejectOAuth2Request() // RejectOAuth2Request | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.RejectOAuth2LoginRequest(context.Background()).LoginChallenge(loginChallenge).RejectOAuth2Request(rejectOAuth2Request).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.RejectOAuth2LoginRequest``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `RejectOAuth2LoginRequest`: OAuth2RedirectTo - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.RejectOAuth2LoginRequest`: %v\n", resp) + loginChallenge := "loginChallenge_example" // string | OAuth 2.0 Login Request Challenge + rejectOAuth2Request := *openapiclient.NewRejectOAuth2Request() // RejectOAuth2Request | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.RejectOAuth2LoginRequest(context.Background()).LoginChallenge(loginChallenge).RejectOAuth2Request(rejectOAuth2Request).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.RejectOAuth2LoginRequest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `RejectOAuth2LoginRequest`: OAuth2RedirectTo + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.RejectOAuth2LoginRequest`: %v\n", resp) } ``` @@ -1480,22 +1480,22 @@ Reject OAuth 2.0 Session Logout Request package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - logoutChallenge := "logoutChallenge_example" // string | - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.RejectOAuth2LogoutRequest(context.Background()).LogoutChallenge(logoutChallenge).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.RejectOAuth2LogoutRequest``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + logoutChallenge := "logoutChallenge_example" // string | + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.OAuth2API.RejectOAuth2LogoutRequest(context.Background()).LogoutChallenge(logoutChallenge).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.RejectOAuth2LogoutRequest``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -1544,24 +1544,24 @@ Revoke OAuth 2.0 Consent Sessions of a Subject package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - subject := "subject_example" // string | OAuth 2.0 Consent Subject The subject whose consent sessions should be deleted. - client := "client_example" // string | OAuth 2.0 Client ID If set, deletes only those consent sessions that have been granted to the specified OAuth 2.0 Client ID. (optional) - all := true // bool | Revoke All Consent Sessions If set to `true` deletes all consent sessions by the Subject that have been granted. (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.RevokeOAuth2ConsentSessions(context.Background()).Subject(subject).Client(client).All(all).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.RevokeOAuth2ConsentSessions``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + subject := "subject_example" // string | OAuth 2.0 Consent Subject The subject whose consent sessions should be deleted. + client := "client_example" // string | OAuth 2.0 Client ID If set, deletes only those consent sessions that have been granted to the specified OAuth 2.0 Client ID. (optional) + all := true // bool | Revoke All Consent Sessions If set to `true` deletes all consent sessions by the Subject that have been granted. (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.OAuth2API.RevokeOAuth2ConsentSessions(context.Background()).Subject(subject).Client(client).All(all).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.RevokeOAuth2ConsentSessions``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -1600,9 +1600,9 @@ No authorization required ## RevokeOAuth2LoginSessions -> RevokeOAuth2LoginSessions(ctx).Subject(subject).Execute() +> RevokeOAuth2LoginSessions(ctx).Subject(subject).Sid(sid).Execute() -Revokes All OAuth 2.0 Login Sessions of a Subject +Revokes OAuth 2.0 Login Sessions by either a Subject or a SessionID @@ -1612,22 +1612,23 @@ Revokes All OAuth 2.0 Login Sessions of a Subject package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - subject := "subject_example" // string | OAuth 2.0 Subject The subject to revoke authentication sessions for. - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.RevokeOAuth2LoginSessions(context.Background()).Subject(subject).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.RevokeOAuth2LoginSessions``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + subject := "subject_example" // string | OAuth 2.0 Subject The subject to revoke authentication sessions for. (optional) + sid := "sid_example" // string | Login Session ID The login session to revoke. (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.OAuth2API.RevokeOAuth2LoginSessions(context.Background()).Subject(subject).Sid(sid).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.RevokeOAuth2LoginSessions``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -1643,6 +1644,7 @@ Other parameters are passed through a pointer to a apiRevokeOAuth2LoginSessionsR Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **subject** | **string** | OAuth 2.0 Subject The subject to revoke authentication sessions for. | + **sid** | **string** | Login Session ID The login session to revoke. | ### Return type @@ -1676,24 +1678,24 @@ Revoke OAuth 2.0 Access or Refresh Token package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - token := "token_example" // string | - clientId := "clientId_example" // string | (optional) - clientSecret := "clientSecret_example" // string | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.RevokeOAuth2Token(context.Background()).Token(token).ClientId(clientId).ClientSecret(clientSecret).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.RevokeOAuth2Token``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + token := "token_example" // string | + clientId := "clientId_example" // string | (optional) + clientSecret := "clientSecret_example" // string | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.OAuth2API.RevokeOAuth2Token(context.Background()).Token(token).ClientId(clientId).ClientSecret(clientSecret).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.RevokeOAuth2Token``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -1744,25 +1746,25 @@ Set OAuth 2.0 Client package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | OAuth 2.0 Client ID - oAuth2Client := *openapiclient.NewOAuth2Client() // OAuth2Client | OAuth 2.0 Client Request Body - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.SetOAuth2Client(context.Background(), id).OAuth2Client(oAuth2Client).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.SetOAuth2Client``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `SetOAuth2Client`: OAuth2Client - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.SetOAuth2Client`: %v\n", resp) + id := "id_example" // string | OAuth 2.0 Client ID + oAuth2Client := *openapiclient.NewOAuth2Client() // OAuth2Client | OAuth 2.0 Client Request Body + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.SetOAuth2Client(context.Background(), id).OAuth2Client(oAuth2Client).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.SetOAuth2Client``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `SetOAuth2Client`: OAuth2Client + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.SetOAuth2Client`: %v\n", resp) } ``` @@ -1816,25 +1818,25 @@ Set OAuth2 Client Token Lifespans package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | OAuth 2.0 Client ID - oAuth2ClientTokenLifespans := *openapiclient.NewOAuth2ClientTokenLifespans() // OAuth2ClientTokenLifespans | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.SetOAuth2ClientLifespans(context.Background(), id).OAuth2ClientTokenLifespans(oAuth2ClientTokenLifespans).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.SetOAuth2ClientLifespans``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `SetOAuth2ClientLifespans`: OAuth2Client - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.SetOAuth2ClientLifespans`: %v\n", resp) + id := "id_example" // string | OAuth 2.0 Client ID + oAuth2ClientTokenLifespans := *openapiclient.NewOAuth2ClientTokenLifespans() // OAuth2ClientTokenLifespans | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.SetOAuth2ClientLifespans(context.Background(), id).OAuth2ClientTokenLifespans(oAuth2ClientTokenLifespans).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.SetOAuth2ClientLifespans``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `SetOAuth2ClientLifespans`: OAuth2Client + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.SetOAuth2ClientLifespans`: %v\n", resp) } ``` @@ -1888,25 +1890,25 @@ Trust OAuth2 JWT Bearer Grant Type Issuer package main import ( - "context" - "fmt" - "os" + "context" + "fmt" + "os" "time" - openapiclient "./openapi" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - trustOAuth2JwtGrantIssuer := *openapiclient.NewTrustOAuth2JwtGrantIssuer(time.Now(), "https://jwt-idp.example.com", *openapiclient.NewJsonWebKey("RS256", "1603dfe0af8f4596", "RSA", "sig"), []string{"Scope_example"}) // TrustOAuth2JwtGrantIssuer | (optional) - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(trustOAuth2JwtGrantIssuer).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OAuth2Api.TrustOAuth2JwtGrantIssuer``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `TrustOAuth2JwtGrantIssuer`: TrustedOAuth2JwtGrantIssuer - fmt.Fprintf(os.Stdout, "Response from `OAuth2Api.TrustOAuth2JwtGrantIssuer`: %v\n", resp) + trustOAuth2JwtGrantIssuer := *openapiclient.NewTrustOAuth2JwtGrantIssuer(time.Now(), "https://jwt-idp.example.com", *openapiclient.NewJsonWebKey("RS256", "1603dfe0af8f4596", "RSA", "sig"), []string{"Scope_example"}) // TrustOAuth2JwtGrantIssuer | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(trustOAuth2JwtGrantIssuer).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OAuth2API.TrustOAuth2JwtGrantIssuer``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `TrustOAuth2JwtGrantIssuer`: TrustedOAuth2JwtGrantIssuer + fmt.Fprintf(os.Stdout, "Response from `OAuth2API.TrustOAuth2JwtGrantIssuer`: %v\n", resp) } ``` diff --git a/internal/httpclient/docs/OAuth2Client.md b/internal/httpclient/docs/OAuth2Client.md index 9fc94fd071c..c9285372f9f 100644 --- a/internal/httpclient/docs/OAuth2Client.md +++ b/internal/httpclient/docs/OAuth2Client.md @@ -4,6 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- +**AccessTokenStrategy** | Pointer to **string** | OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`. | [optional] **AllowedCorsOrigins** | Pointer to **[]string** | | [optional] **Audience** | Pointer to **[]string** | | [optional] **AuthorizationCodeGrantAccessTokenLifespan** | Pointer to **string** | Specify a time duration in milliseconds, seconds, minutes, hours. | [optional] @@ -12,7 +13,7 @@ Name | Type | Description | Notes **BackchannelLogoutSessionRequired** | Pointer to **bool** | OpenID Connect Back-Channel Logout Session Required Boolean value specifying whether the RP requires that a sid (session ID) Claim be included in the Logout Token to identify the RP session with the OP when the backchannel_logout_uri is used. If omitted, the default value is false. | [optional] **BackchannelLogoutUri** | Pointer to **string** | OpenID Connect Back-Channel Logout URI RP URL that will cause the RP to log itself out when sent a Logout Token by the OP. | [optional] **ClientCredentialsGrantAccessTokenLifespan** | Pointer to **string** | Specify a time duration in milliseconds, seconds, minutes, hours. | [optional] -**ClientId** | Pointer to **string** | OAuth 2.0 Client ID The ID is autogenerated and immutable. | [optional] +**ClientId** | Pointer to **string** | OAuth 2.0 Client ID The ID is immutable. If no ID is provided, a UUID4 will be generated. | [optional] **ClientName** | Pointer to **string** | OAuth 2.0 Client Name The human-readable name of the client to be presented to the end-user during authorization. | [optional] **ClientSecret** | Pointer to **string** | OAuth 2.0 Client Secret The secret will be included in the create request as cleartext, and then never again. The secret is kept in hashed format and is not recoverable once lost. | [optional] **ClientSecretExpiresAt** | Pointer to **int64** | OAuth 2.0 Client Secret Expires At The field is currently not supported and its value is always 0. | [optional] @@ -43,8 +44,10 @@ Name | Type | Description | Notes **ResponseTypes** | Pointer to **[]string** | | [optional] **Scope** | Pointer to **string** | OAuth 2.0 Client Scope Scope is a string containing a space-separated list of scope values (as described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client can use when requesting access tokens. | [optional] **SectorIdentifierUri** | Pointer to **string** | OpenID Connect Sector Identifier URI URL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. The URL references a file with a single JSON array of redirect_uri values. | [optional] +**SkipConsent** | Pointer to **bool** | SkipConsent skips the consent screen for this client. This field can only be set from the admin API. | [optional] +**SkipLogoutConsent** | Pointer to **bool** | SkipLogoutConsent skips the logout consent screen for this client. This field can only be set from the admin API. | [optional] **SubjectType** | Pointer to **string** | OpenID Connect Subject Type The `subject_types_supported` Discovery parameter contains a list of the supported subject_type values for this server. Valid types include `pairwise` and `public`. | [optional] -**TokenEndpointAuthMethod** | Pointer to **string** | OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_post`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `client_secret_basic`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. | [optional] +**TokenEndpointAuthMethod** | Pointer to **string** | OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. | [optional] [default to "client_secret_basic"] **TokenEndpointAuthSigningAlg** | Pointer to **string** | OAuth 2.0 Token Endpoint Signing Algorithm Requested Client Authentication signing algorithm for the Token Endpoint. | [optional] **TosUri** | Pointer to **string** | OAuth 2.0 Client Terms of Service URI A URL string pointing to a human-readable terms of service document for the client that describes a contractual relationship between the end-user and the client that the end-user accepts when authorizing the client. | [optional] **UpdatedAt** | Pointer to **time.Time** | OAuth 2.0 Client Last Update Date UpdatedAt returns the timestamp of the last update. | [optional] @@ -69,6 +72,31 @@ NewOAuth2ClientWithDefaults instantiates a new OAuth2Client object This constructor will only assign default values to properties that have it defined, but it doesn't guarantee that properties required by API are set +### GetAccessTokenStrategy + +`func (o *OAuth2Client) GetAccessTokenStrategy() string` + +GetAccessTokenStrategy returns the AccessTokenStrategy field if non-nil, zero value otherwise. + +### GetAccessTokenStrategyOk + +`func (o *OAuth2Client) GetAccessTokenStrategyOk() (*string, bool)` + +GetAccessTokenStrategyOk returns a tuple with the AccessTokenStrategy field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetAccessTokenStrategy + +`func (o *OAuth2Client) SetAccessTokenStrategy(v string)` + +SetAccessTokenStrategy sets AccessTokenStrategy field to given value. + +### HasAccessTokenStrategy + +`func (o *OAuth2Client) HasAccessTokenStrategy() bool` + +HasAccessTokenStrategy returns a boolean if a field has been set. + ### GetAllowedCorsOrigins `func (o *OAuth2Client) GetAllowedCorsOrigins() []string` @@ -1064,6 +1092,56 @@ SetSectorIdentifierUri sets SectorIdentifierUri field to given value. HasSectorIdentifierUri returns a boolean if a field has been set. +### GetSkipConsent + +`func (o *OAuth2Client) GetSkipConsent() bool` + +GetSkipConsent returns the SkipConsent field if non-nil, zero value otherwise. + +### GetSkipConsentOk + +`func (o *OAuth2Client) GetSkipConsentOk() (*bool, bool)` + +GetSkipConsentOk returns a tuple with the SkipConsent field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSkipConsent + +`func (o *OAuth2Client) SetSkipConsent(v bool)` + +SetSkipConsent sets SkipConsent field to given value. + +### HasSkipConsent + +`func (o *OAuth2Client) HasSkipConsent() bool` + +HasSkipConsent returns a boolean if a field has been set. + +### GetSkipLogoutConsent + +`func (o *OAuth2Client) GetSkipLogoutConsent() bool` + +GetSkipLogoutConsent returns the SkipLogoutConsent field if non-nil, zero value otherwise. + +### GetSkipLogoutConsentOk + +`func (o *OAuth2Client) GetSkipLogoutConsentOk() (*bool, bool)` + +GetSkipLogoutConsentOk returns a tuple with the SkipLogoutConsent field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetSkipLogoutConsent + +`func (o *OAuth2Client) SetSkipLogoutConsent(v bool)` + +SetSkipLogoutConsent sets SkipLogoutConsent field to given value. + +### HasSkipLogoutConsent + +`func (o *OAuth2Client) HasSkipLogoutConsent() bool` + +HasSkipLogoutConsent returns a boolean if a field has been set. + ### GetSubjectType `func (o *OAuth2Client) GetSubjectType() string` diff --git a/internal/httpclient/docs/OAuth2ConsentSession.md b/internal/httpclient/docs/OAuth2ConsentSession.md index 732ecca2a3f..0399f2ab121 100644 --- a/internal/httpclient/docs/OAuth2ConsentSession.md +++ b/internal/httpclient/docs/OAuth2ConsentSession.md @@ -5,6 +5,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **ConsentRequest** | Pointer to [**OAuth2ConsentRequest**](OAuth2ConsentRequest.md) | | [optional] +**Context** | Pointer to **interface{}** | | [optional] **ExpiresAt** | Pointer to [**OAuth2ConsentSessionExpiresAt**](OAuth2ConsentSessionExpiresAt.md) | | [optional] **GrantAccessTokenAudience** | Pointer to **[]string** | | [optional] **GrantScope** | Pointer to **[]string** | | [optional] @@ -57,6 +58,41 @@ SetConsentRequest sets ConsentRequest field to given value. HasConsentRequest returns a boolean if a field has been set. +### GetContext + +`func (o *OAuth2ConsentSession) GetContext() interface{}` + +GetContext returns the Context field if non-nil, zero value otherwise. + +### GetContextOk + +`func (o *OAuth2ConsentSession) GetContextOk() (*interface{}, bool)` + +GetContextOk returns a tuple with the Context field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetContext + +`func (o *OAuth2ConsentSession) SetContext(v interface{})` + +SetContext sets Context field to given value. + +### HasContext + +`func (o *OAuth2ConsentSession) HasContext() bool` + +HasContext returns a boolean if a field has been set. + +### SetContextNil + +`func (o *OAuth2ConsentSession) SetContextNil(b bool)` + + SetContextNil sets the value for Context to be an explicit nil + +### UnsetContext +`func (o *OAuth2ConsentSession) UnsetContext()` + +UnsetContext ensures that no value is present for Context, not even an explicit nil ### GetExpiresAt `func (o *OAuth2ConsentSession) GetExpiresAt() OAuth2ConsentSessionExpiresAt` diff --git a/internal/httpclient/docs/OAuth2LoginRequest.md b/internal/httpclient/docs/OAuth2LoginRequest.md index aa34f248272..e70218c297d 100644 --- a/internal/httpclient/docs/OAuth2LoginRequest.md +++ b/internal/httpclient/docs/OAuth2LoginRequest.md @@ -8,8 +8,8 @@ Name | Type | Description | Notes **Client** | [**OAuth2Client**](OAuth2Client.md) | | **OidcContext** | Pointer to [**OAuth2ConsentRequestOpenIDConnectContext**](OAuth2ConsentRequestOpenIDConnectContext.md) | | [optional] **RequestUrl** | **string** | RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which initiates the OAuth 2.0 Authorization Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but might come in handy if you want to deal with additional request parameters. | -**RequestedAccessTokenAudience** | **[]string** | | -**RequestedScope** | **[]string** | | +**RequestedAccessTokenAudience** | Pointer to **[]string** | | [optional] +**RequestedScope** | Pointer to **[]string** | | [optional] **SessionId** | Pointer to **string** | SessionID is the login session ID. If the user-agent reuses a login session (via cookie / remember flag) this ID will remain the same. If the user-agent did not have an existing authentication session (e.g. remember is false) this will be a new random value. This value is used as the \"sid\" parameter in the ID Token and in OIDC Front-/Back- channel logout. It's value can generally be used to associate consecutive login requests by a certain user. | [optional] **Skip** | **bool** | Skip, if true, implies that the client has requested the same scopes from the same user previously. If true, you can skip asking the user to grant the requested scopes, and simply forward the user to the redirect URL. This feature allows you to update / set session information. | **Subject** | **string** | Subject is the user ID of the end-user that authenticated. Now, that end user needs to grant or deny the scope requested by the OAuth 2.0 client. If this value is set and `skip` is true, you MUST include this subject type when accepting the login request, or the request will fail. | @@ -18,7 +18,7 @@ Name | Type | Description | Notes ### NewOAuth2LoginRequest -`func NewOAuth2LoginRequest(challenge string, client OAuth2Client, requestUrl string, requestedAccessTokenAudience []string, requestedScope []string, skip bool, subject string, ) *OAuth2LoginRequest` +`func NewOAuth2LoginRequest(challenge string, client OAuth2Client, requestUrl string, skip bool, subject string, ) *OAuth2LoginRequest` NewOAuth2LoginRequest instantiates a new OAuth2LoginRequest object This constructor will assign default values to properties that have it defined, @@ -137,6 +137,11 @@ and a boolean to check if the value has been set. SetRequestedAccessTokenAudience sets RequestedAccessTokenAudience field to given value. +### HasRequestedAccessTokenAudience + +`func (o *OAuth2LoginRequest) HasRequestedAccessTokenAudience() bool` + +HasRequestedAccessTokenAudience returns a boolean if a field has been set. ### GetRequestedScope @@ -157,6 +162,11 @@ and a boolean to check if the value has been set. SetRequestedScope sets RequestedScope field to given value. +### HasRequestedScope + +`func (o *OAuth2LoginRequest) HasRequestedScope() bool` + +HasRequestedScope returns a boolean if a field has been set. ### GetSessionId diff --git a/internal/httpclient/docs/OAuth2TokenExchange.md b/internal/httpclient/docs/OAuth2TokenExchange.md index 8976c6ff0a6..cae2673e099 100644 --- a/internal/httpclient/docs/OAuth2TokenExchange.md +++ b/internal/httpclient/docs/OAuth2TokenExchange.md @@ -6,7 +6,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **AccessToken** | Pointer to **string** | The access token issued by the authorization server. | [optional] **ExpiresIn** | Pointer to **int64** | The lifetime in seconds of the access token. For example, the value \"3600\" denotes that the access token will expire in one hour from the time the response was generated. | [optional] -**IdToken** | Pointer to **int64** | To retrieve a refresh token request the id_token scope. | [optional] +**IdToken** | Pointer to **string** | To retrieve a refresh token request the id_token scope. | [optional] **RefreshToken** | Pointer to **string** | The refresh token, which can be used to obtain new access tokens. To retrieve it add the scope \"offline\" to your access token request. | [optional] **Scope** | Pointer to **string** | The scope of the access token | [optional] **TokenType** | Pointer to **string** | The type of the token issued | [optional] @@ -82,20 +82,20 @@ HasExpiresIn returns a boolean if a field has been set. ### GetIdToken -`func (o *OAuth2TokenExchange) GetIdToken() int64` +`func (o *OAuth2TokenExchange) GetIdToken() string` GetIdToken returns the IdToken field if non-nil, zero value otherwise. ### GetIdTokenOk -`func (o *OAuth2TokenExchange) GetIdTokenOk() (*int64, bool)` +`func (o *OAuth2TokenExchange) GetIdTokenOk() (*string, bool)` GetIdTokenOk returns a tuple with the IdToken field if it's non-nil, zero value otherwise and a boolean to check if the value has been set. ### SetIdToken -`func (o *OAuth2TokenExchange) SetIdToken(v int64)` +`func (o *OAuth2TokenExchange) SetIdToken(v string)` SetIdToken sets IdToken field to given value. diff --git a/internal/httpclient/docs/OidcApi.md b/internal/httpclient/docs/OidcAPI.md similarity index 52% rename from internal/httpclient/docs/OidcApi.md rename to internal/httpclient/docs/OidcAPI.md index 8087d0565df..7ec0f5b17a0 100644 --- a/internal/httpclient/docs/OidcApi.md +++ b/internal/httpclient/docs/OidcAPI.md @@ -1,16 +1,17 @@ -# \OidcApi +# \OidcAPI All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- -[**CreateOidcDynamicClient**](OidcApi.md#CreateOidcDynamicClient) | **Post** /oauth2/register | Register OAuth2 Client using OpenID Dynamic Client Registration -[**DeleteOidcDynamicClient**](OidcApi.md#DeleteOidcDynamicClient) | **Delete** /oauth2/register/{id} | Delete OAuth 2.0 Client using the OpenID Dynamic Client Registration Management Protocol -[**DiscoverOidcConfiguration**](OidcApi.md#DiscoverOidcConfiguration) | **Get** /.well-known/openid-configuration | OpenID Connect Discovery -[**GetOidcDynamicClient**](OidcApi.md#GetOidcDynamicClient) | **Get** /oauth2/register/{id} | Get OAuth2 Client using OpenID Dynamic Client Registration -[**GetOidcUserInfo**](OidcApi.md#GetOidcUserInfo) | **Get** /userinfo | OpenID Connect Userinfo -[**RevokeOidcSession**](OidcApi.md#RevokeOidcSession) | **Get** /oauth2/sessions/logout | OpenID Connect Front- and Back-channel Enabled Logout -[**SetOidcDynamicClient**](OidcApi.md#SetOidcDynamicClient) | **Put** /oauth2/register/{id} | Set OAuth2 Client using OpenID Dynamic Client Registration +[**CreateOidcDynamicClient**](OidcAPI.md#CreateOidcDynamicClient) | **Post** /oauth2/register | Register OAuth2 Client using OpenID Dynamic Client Registration +[**CreateVerifiableCredential**](OidcAPI.md#CreateVerifiableCredential) | **Post** /credentials | Issues a Verifiable Credential +[**DeleteOidcDynamicClient**](OidcAPI.md#DeleteOidcDynamicClient) | **Delete** /oauth2/register/{id} | Delete OAuth 2.0 Client using the OpenID Dynamic Client Registration Management Protocol +[**DiscoverOidcConfiguration**](OidcAPI.md#DiscoverOidcConfiguration) | **Get** /.well-known/openid-configuration | OpenID Connect Discovery +[**GetOidcDynamicClient**](OidcAPI.md#GetOidcDynamicClient) | **Get** /oauth2/register/{id} | Get OAuth2 Client using OpenID Dynamic Client Registration +[**GetOidcUserInfo**](OidcAPI.md#GetOidcUserInfo) | **Get** /userinfo | OpenID Connect Userinfo +[**RevokeOidcSession**](OidcAPI.md#RevokeOidcSession) | **Get** /oauth2/sessions/logout | OpenID Connect Front- and Back-channel Enabled Logout +[**SetOidcDynamicClient**](OidcAPI.md#SetOidcDynamicClient) | **Put** /oauth2/register/{id} | Set OAuth2 Client using OpenID Dynamic Client Registration @@ -28,24 +29,24 @@ Register OAuth2 Client using OpenID Dynamic Client Registration package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - oAuth2Client := *openapiclient.NewOAuth2Client() // OAuth2Client | Dynamic Client Registration Request Body - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OidcApi.CreateOidcDynamicClient(context.Background()).OAuth2Client(oAuth2Client).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OidcApi.CreateOidcDynamicClient``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `CreateOidcDynamicClient`: OAuth2Client - fmt.Fprintf(os.Stdout, "Response from `OidcApi.CreateOidcDynamicClient`: %v\n", resp) + oAuth2Client := *openapiclient.NewOAuth2Client() // OAuth2Client | Dynamic Client Registration Request Body + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OidcAPI.CreateOidcDynamicClient(context.Background()).OAuth2Client(oAuth2Client).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OidcAPI.CreateOidcDynamicClient``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `CreateOidcDynamicClient`: OAuth2Client + fmt.Fprintf(os.Stdout, "Response from `OidcAPI.CreateOidcDynamicClient`: %v\n", resp) } ``` @@ -80,6 +81,72 @@ No authorization required [[Back to README]](../README.md) +## CreateVerifiableCredential + +> VerifiableCredentialResponse CreateVerifiableCredential(ctx).CreateVerifiableCredentialRequestBody(createVerifiableCredentialRequestBody).Execute() + +Issues a Verifiable Credential + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" +) + +func main() { + createVerifiableCredentialRequestBody := *openapiclient.NewCreateVerifiableCredentialRequestBody() // CreateVerifiableCredentialRequestBody | (optional) + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OidcAPI.CreateVerifiableCredential(context.Background()).CreateVerifiableCredentialRequestBody(createVerifiableCredentialRequestBody).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OidcAPI.CreateVerifiableCredential``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `CreateVerifiableCredential`: VerifiableCredentialResponse + fmt.Fprintf(os.Stdout, "Response from `OidcAPI.CreateVerifiableCredential`: %v\n", resp) +} +``` + +### Path Parameters + + + +### Other Parameters + +Other parameters are passed through a pointer to a apiCreateVerifiableCredentialRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **createVerifiableCredentialRequestBody** | [**CreateVerifiableCredentialRequestBody**](CreateVerifiableCredentialRequestBody.md) | | + +### Return type + +[**VerifiableCredentialResponse**](VerifiableCredentialResponse.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: application/json +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## DeleteOidcDynamicClient > DeleteOidcDynamicClient(ctx, id).Execute() @@ -94,22 +161,22 @@ Delete OAuth 2.0 Client using the OpenID Dynamic Client Registration Management package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | The id of the OAuth 2.0 Client. - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OidcApi.DeleteOidcDynamicClient(context.Background(), id).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OidcApi.DeleteOidcDynamicClient``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + id := "id_example" // string | The id of the OAuth 2.0 Client. + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.OidcAPI.DeleteOidcDynamicClient(context.Background(), id).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OidcAPI.DeleteOidcDynamicClient``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -162,23 +229,23 @@ OpenID Connect Discovery package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OidcApi.DiscoverOidcConfiguration(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OidcApi.DiscoverOidcConfiguration``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `DiscoverOidcConfiguration`: OidcConfiguration - fmt.Fprintf(os.Stdout, "Response from `OidcApi.DiscoverOidcConfiguration`: %v\n", resp) + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OidcAPI.DiscoverOidcConfiguration(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OidcAPI.DiscoverOidcConfiguration``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `DiscoverOidcConfiguration`: OidcConfiguration + fmt.Fprintf(os.Stdout, "Response from `OidcAPI.DiscoverOidcConfiguration`: %v\n", resp) } ``` @@ -223,24 +290,24 @@ Get OAuth2 Client using OpenID Dynamic Client Registration package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | The id of the OAuth 2.0 Client. - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OidcApi.GetOidcDynamicClient(context.Background(), id).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OidcApi.GetOidcDynamicClient``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetOidcDynamicClient`: OAuth2Client - fmt.Fprintf(os.Stdout, "Response from `OidcApi.GetOidcDynamicClient`: %v\n", resp) + id := "id_example" // string | The id of the OAuth 2.0 Client. + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OidcAPI.GetOidcDynamicClient(context.Background(), id).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OidcAPI.GetOidcDynamicClient``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetOidcDynamicClient`: OAuth2Client + fmt.Fprintf(os.Stdout, "Response from `OidcAPI.GetOidcDynamicClient`: %v\n", resp) } ``` @@ -293,23 +360,23 @@ OpenID Connect Userinfo package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OidcApi.GetOidcUserInfo(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OidcApi.GetOidcUserInfo``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `GetOidcUserInfo`: OidcUserInfo - fmt.Fprintf(os.Stdout, "Response from `OidcApi.GetOidcUserInfo`: %v\n", resp) + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OidcAPI.GetOidcUserInfo(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OidcAPI.GetOidcUserInfo``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `GetOidcUserInfo`: OidcUserInfo + fmt.Fprintf(os.Stdout, "Response from `OidcAPI.GetOidcUserInfo`: %v\n", resp) } ``` @@ -354,21 +421,21 @@ OpenID Connect Front- and Back-channel Enabled Logout package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OidcApi.RevokeOidcSession(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OidcApi.RevokeOidcSession``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.OidcAPI.RevokeOidcSession(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OidcAPI.RevokeOidcSession``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } } ``` @@ -413,25 +480,25 @@ Set OAuth2 Client using OpenID Dynamic Client Registration package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - id := "id_example" // string | OAuth 2.0 Client ID - oAuth2Client := *openapiclient.NewOAuth2Client() // OAuth2Client | OAuth 2.0 Client Request Body - - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.OidcApi.SetOidcDynamicClient(context.Background(), id).OAuth2Client(oAuth2Client).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `OidcApi.SetOidcDynamicClient``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `SetOidcDynamicClient`: OAuth2Client - fmt.Fprintf(os.Stdout, "Response from `OidcApi.SetOidcDynamicClient`: %v\n", resp) + id := "id_example" // string | OAuth 2.0 Client ID + oAuth2Client := *openapiclient.NewOAuth2Client() // OAuth2Client | OAuth 2.0 Client Request Body + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.OidcAPI.SetOidcDynamicClient(context.Background(), id).OAuth2Client(oAuth2Client).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `OidcAPI.SetOidcDynamicClient``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `SetOidcDynamicClient`: OAuth2Client + fmt.Fprintf(os.Stdout, "Response from `OidcAPI.SetOidcDynamicClient`: %v\n", resp) } ``` diff --git a/internal/httpclient/docs/OidcConfiguration.md b/internal/httpclient/docs/OidcConfiguration.md index 723bd6a8b47..1b20c7d8733 100644 --- a/internal/httpclient/docs/OidcConfiguration.md +++ b/internal/httpclient/docs/OidcConfiguration.md @@ -10,6 +10,8 @@ Name | Type | Description | Notes **ClaimsParameterSupported** | Pointer to **bool** | OpenID Connect Claims Parameter Parameter Supported Boolean value specifying whether the OP supports use of the claims parameter, with true indicating support. | [optional] **ClaimsSupported** | Pointer to **[]string** | OpenID Connect Supported Claims JSON array containing a list of the Claim Names of the Claims that the OpenID Provider MAY be able to supply values for. Note that for privacy or other reasons, this might not be an exhaustive list. | [optional] **CodeChallengeMethodsSupported** | Pointer to **[]string** | OAuth 2.0 PKCE Supported Code Challenge Methods JSON array containing a list of Proof Key for Code Exchange (PKCE) [RFC7636] code challenge methods supported by this authorization server. | [optional] +**CredentialsEndpointDraft00** | Pointer to **string** | OpenID Connect Verifiable Credentials Endpoint Contains the URL of the Verifiable Credentials Endpoint. | [optional] +**CredentialsSupportedDraft00** | Pointer to [**[]CredentialSupportedDraft00**](CredentialSupportedDraft00.md) | OpenID Connect Verifiable Credentials Supported JSON array containing a list of the Verifiable Credentials supported by this authorization server. | [optional] **EndSessionEndpoint** | Pointer to **string** | OpenID Connect End-Session Endpoint URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP. | [optional] **FrontchannelLogoutSessionSupported** | Pointer to **bool** | OpenID Connect Front-Channel Logout Session Required Boolean value specifying whether the OP can pass iss (issuer) and sid (session ID) query parameters to identify the RP session with the OP when the frontchannel_logout_uri is used. If supported, the sid Claim is also included in ID Tokens issued by the OP. | [optional] **FrontchannelLogoutSupported** | Pointer to **bool** | OpenID Connect Front-Channel Logout Supported Boolean value specifying whether the OP supports HTTP-based logout, with true indicating support. | [optional] @@ -198,6 +200,56 @@ SetCodeChallengeMethodsSupported sets CodeChallengeMethodsSupported field to giv HasCodeChallengeMethodsSupported returns a boolean if a field has been set. +### GetCredentialsEndpointDraft00 + +`func (o *OidcConfiguration) GetCredentialsEndpointDraft00() string` + +GetCredentialsEndpointDraft00 returns the CredentialsEndpointDraft00 field if non-nil, zero value otherwise. + +### GetCredentialsEndpointDraft00Ok + +`func (o *OidcConfiguration) GetCredentialsEndpointDraft00Ok() (*string, bool)` + +GetCredentialsEndpointDraft00Ok returns a tuple with the CredentialsEndpointDraft00 field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCredentialsEndpointDraft00 + +`func (o *OidcConfiguration) SetCredentialsEndpointDraft00(v string)` + +SetCredentialsEndpointDraft00 sets CredentialsEndpointDraft00 field to given value. + +### HasCredentialsEndpointDraft00 + +`func (o *OidcConfiguration) HasCredentialsEndpointDraft00() bool` + +HasCredentialsEndpointDraft00 returns a boolean if a field has been set. + +### GetCredentialsSupportedDraft00 + +`func (o *OidcConfiguration) GetCredentialsSupportedDraft00() []CredentialSupportedDraft00` + +GetCredentialsSupportedDraft00 returns the CredentialsSupportedDraft00 field if non-nil, zero value otherwise. + +### GetCredentialsSupportedDraft00Ok + +`func (o *OidcConfiguration) GetCredentialsSupportedDraft00Ok() (*[]CredentialSupportedDraft00, bool)` + +GetCredentialsSupportedDraft00Ok returns a tuple with the CredentialsSupportedDraft00 field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCredentialsSupportedDraft00 + +`func (o *OidcConfiguration) SetCredentialsSupportedDraft00(v []CredentialSupportedDraft00)` + +SetCredentialsSupportedDraft00 sets CredentialsSupportedDraft00 field to given value. + +### HasCredentialsSupportedDraft00 + +`func (o *OidcConfiguration) HasCredentialsSupportedDraft00() bool` + +HasCredentialsSupportedDraft00 returns a boolean if a field has been set. + ### GetEndSessionEndpoint `func (o *OidcConfiguration) GetEndSessionEndpoint() string` diff --git a/internal/httpclient/docs/RFC6749ErrorJson.md b/internal/httpclient/docs/RFC6749ErrorJson.md new file mode 100644 index 00000000000..570e38c5a91 --- /dev/null +++ b/internal/httpclient/docs/RFC6749ErrorJson.md @@ -0,0 +1,160 @@ +# RFC6749ErrorJson + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Error** | Pointer to **string** | | [optional] +**ErrorDebug** | Pointer to **string** | | [optional] +**ErrorDescription** | Pointer to **string** | | [optional] +**ErrorHint** | Pointer to **string** | | [optional] +**StatusCode** | Pointer to **int64** | | [optional] + +## Methods + +### NewRFC6749ErrorJson + +`func NewRFC6749ErrorJson() *RFC6749ErrorJson` + +NewRFC6749ErrorJson instantiates a new RFC6749ErrorJson object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewRFC6749ErrorJsonWithDefaults + +`func NewRFC6749ErrorJsonWithDefaults() *RFC6749ErrorJson` + +NewRFC6749ErrorJsonWithDefaults instantiates a new RFC6749ErrorJson object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetError + +`func (o *RFC6749ErrorJson) GetError() string` + +GetError returns the Error field if non-nil, zero value otherwise. + +### GetErrorOk + +`func (o *RFC6749ErrorJson) GetErrorOk() (*string, bool)` + +GetErrorOk returns a tuple with the Error field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetError + +`func (o *RFC6749ErrorJson) SetError(v string)` + +SetError sets Error field to given value. + +### HasError + +`func (o *RFC6749ErrorJson) HasError() bool` + +HasError returns a boolean if a field has been set. + +### GetErrorDebug + +`func (o *RFC6749ErrorJson) GetErrorDebug() string` + +GetErrorDebug returns the ErrorDebug field if non-nil, zero value otherwise. + +### GetErrorDebugOk + +`func (o *RFC6749ErrorJson) GetErrorDebugOk() (*string, bool)` + +GetErrorDebugOk returns a tuple with the ErrorDebug field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorDebug + +`func (o *RFC6749ErrorJson) SetErrorDebug(v string)` + +SetErrorDebug sets ErrorDebug field to given value. + +### HasErrorDebug + +`func (o *RFC6749ErrorJson) HasErrorDebug() bool` + +HasErrorDebug returns a boolean if a field has been set. + +### GetErrorDescription + +`func (o *RFC6749ErrorJson) GetErrorDescription() string` + +GetErrorDescription returns the ErrorDescription field if non-nil, zero value otherwise. + +### GetErrorDescriptionOk + +`func (o *RFC6749ErrorJson) GetErrorDescriptionOk() (*string, bool)` + +GetErrorDescriptionOk returns a tuple with the ErrorDescription field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorDescription + +`func (o *RFC6749ErrorJson) SetErrorDescription(v string)` + +SetErrorDescription sets ErrorDescription field to given value. + +### HasErrorDescription + +`func (o *RFC6749ErrorJson) HasErrorDescription() bool` + +HasErrorDescription returns a boolean if a field has been set. + +### GetErrorHint + +`func (o *RFC6749ErrorJson) GetErrorHint() string` + +GetErrorHint returns the ErrorHint field if non-nil, zero value otherwise. + +### GetErrorHintOk + +`func (o *RFC6749ErrorJson) GetErrorHintOk() (*string, bool)` + +GetErrorHintOk returns a tuple with the ErrorHint field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorHint + +`func (o *RFC6749ErrorJson) SetErrorHint(v string)` + +SetErrorHint sets ErrorHint field to given value. + +### HasErrorHint + +`func (o *RFC6749ErrorJson) HasErrorHint() bool` + +HasErrorHint returns a boolean if a field has been set. + +### GetStatusCode + +`func (o *RFC6749ErrorJson) GetStatusCode() int64` + +GetStatusCode returns the StatusCode field if non-nil, zero value otherwise. + +### GetStatusCodeOk + +`func (o *RFC6749ErrorJson) GetStatusCodeOk() (*int64, bool)` + +GetStatusCodeOk returns a tuple with the StatusCode field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetStatusCode + +`func (o *RFC6749ErrorJson) SetStatusCode(v int64)` + +SetStatusCode sets StatusCode field to given value. + +### HasStatusCode + +`func (o *RFC6749ErrorJson) HasStatusCode() bool` + +HasStatusCode returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/VerifiableCredentialPrimingResponse.md b/internal/httpclient/docs/VerifiableCredentialPrimingResponse.md new file mode 100644 index 00000000000..5668ebf5a0b --- /dev/null +++ b/internal/httpclient/docs/VerifiableCredentialPrimingResponse.md @@ -0,0 +1,238 @@ +# VerifiableCredentialPrimingResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**CNonce** | Pointer to **string** | | [optional] +**CNonceExpiresIn** | Pointer to **int64** | | [optional] +**Error** | Pointer to **string** | | [optional] +**ErrorDebug** | Pointer to **string** | | [optional] +**ErrorDescription** | Pointer to **string** | | [optional] +**ErrorHint** | Pointer to **string** | | [optional] +**Format** | Pointer to **string** | | [optional] +**StatusCode** | Pointer to **int64** | | [optional] + +## Methods + +### NewVerifiableCredentialPrimingResponse + +`func NewVerifiableCredentialPrimingResponse() *VerifiableCredentialPrimingResponse` + +NewVerifiableCredentialPrimingResponse instantiates a new VerifiableCredentialPrimingResponse object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewVerifiableCredentialPrimingResponseWithDefaults + +`func NewVerifiableCredentialPrimingResponseWithDefaults() *VerifiableCredentialPrimingResponse` + +NewVerifiableCredentialPrimingResponseWithDefaults instantiates a new VerifiableCredentialPrimingResponse object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetCNonce + +`func (o *VerifiableCredentialPrimingResponse) GetCNonce() string` + +GetCNonce returns the CNonce field if non-nil, zero value otherwise. + +### GetCNonceOk + +`func (o *VerifiableCredentialPrimingResponse) GetCNonceOk() (*string, bool)` + +GetCNonceOk returns a tuple with the CNonce field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCNonce + +`func (o *VerifiableCredentialPrimingResponse) SetCNonce(v string)` + +SetCNonce sets CNonce field to given value. + +### HasCNonce + +`func (o *VerifiableCredentialPrimingResponse) HasCNonce() bool` + +HasCNonce returns a boolean if a field has been set. + +### GetCNonceExpiresIn + +`func (o *VerifiableCredentialPrimingResponse) GetCNonceExpiresIn() int64` + +GetCNonceExpiresIn returns the CNonceExpiresIn field if non-nil, zero value otherwise. + +### GetCNonceExpiresInOk + +`func (o *VerifiableCredentialPrimingResponse) GetCNonceExpiresInOk() (*int64, bool)` + +GetCNonceExpiresInOk returns a tuple with the CNonceExpiresIn field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCNonceExpiresIn + +`func (o *VerifiableCredentialPrimingResponse) SetCNonceExpiresIn(v int64)` + +SetCNonceExpiresIn sets CNonceExpiresIn field to given value. + +### HasCNonceExpiresIn + +`func (o *VerifiableCredentialPrimingResponse) HasCNonceExpiresIn() bool` + +HasCNonceExpiresIn returns a boolean if a field has been set. + +### GetError + +`func (o *VerifiableCredentialPrimingResponse) GetError() string` + +GetError returns the Error field if non-nil, zero value otherwise. + +### GetErrorOk + +`func (o *VerifiableCredentialPrimingResponse) GetErrorOk() (*string, bool)` + +GetErrorOk returns a tuple with the Error field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetError + +`func (o *VerifiableCredentialPrimingResponse) SetError(v string)` + +SetError sets Error field to given value. + +### HasError + +`func (o *VerifiableCredentialPrimingResponse) HasError() bool` + +HasError returns a boolean if a field has been set. + +### GetErrorDebug + +`func (o *VerifiableCredentialPrimingResponse) GetErrorDebug() string` + +GetErrorDebug returns the ErrorDebug field if non-nil, zero value otherwise. + +### GetErrorDebugOk + +`func (o *VerifiableCredentialPrimingResponse) GetErrorDebugOk() (*string, bool)` + +GetErrorDebugOk returns a tuple with the ErrorDebug field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorDebug + +`func (o *VerifiableCredentialPrimingResponse) SetErrorDebug(v string)` + +SetErrorDebug sets ErrorDebug field to given value. + +### HasErrorDebug + +`func (o *VerifiableCredentialPrimingResponse) HasErrorDebug() bool` + +HasErrorDebug returns a boolean if a field has been set. + +### GetErrorDescription + +`func (o *VerifiableCredentialPrimingResponse) GetErrorDescription() string` + +GetErrorDescription returns the ErrorDescription field if non-nil, zero value otherwise. + +### GetErrorDescriptionOk + +`func (o *VerifiableCredentialPrimingResponse) GetErrorDescriptionOk() (*string, bool)` + +GetErrorDescriptionOk returns a tuple with the ErrorDescription field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorDescription + +`func (o *VerifiableCredentialPrimingResponse) SetErrorDescription(v string)` + +SetErrorDescription sets ErrorDescription field to given value. + +### HasErrorDescription + +`func (o *VerifiableCredentialPrimingResponse) HasErrorDescription() bool` + +HasErrorDescription returns a boolean if a field has been set. + +### GetErrorHint + +`func (o *VerifiableCredentialPrimingResponse) GetErrorHint() string` + +GetErrorHint returns the ErrorHint field if non-nil, zero value otherwise. + +### GetErrorHintOk + +`func (o *VerifiableCredentialPrimingResponse) GetErrorHintOk() (*string, bool)` + +GetErrorHintOk returns a tuple with the ErrorHint field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetErrorHint + +`func (o *VerifiableCredentialPrimingResponse) SetErrorHint(v string)` + +SetErrorHint sets ErrorHint field to given value. + +### HasErrorHint + +`func (o *VerifiableCredentialPrimingResponse) HasErrorHint() bool` + +HasErrorHint returns a boolean if a field has been set. + +### GetFormat + +`func (o *VerifiableCredentialPrimingResponse) GetFormat() string` + +GetFormat returns the Format field if non-nil, zero value otherwise. + +### GetFormatOk + +`func (o *VerifiableCredentialPrimingResponse) GetFormatOk() (*string, bool)` + +GetFormatOk returns a tuple with the Format field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFormat + +`func (o *VerifiableCredentialPrimingResponse) SetFormat(v string)` + +SetFormat sets Format field to given value. + +### HasFormat + +`func (o *VerifiableCredentialPrimingResponse) HasFormat() bool` + +HasFormat returns a boolean if a field has been set. + +### GetStatusCode + +`func (o *VerifiableCredentialPrimingResponse) GetStatusCode() int64` + +GetStatusCode returns the StatusCode field if non-nil, zero value otherwise. + +### GetStatusCodeOk + +`func (o *VerifiableCredentialPrimingResponse) GetStatusCodeOk() (*int64, bool)` + +GetStatusCodeOk returns a tuple with the StatusCode field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetStatusCode + +`func (o *VerifiableCredentialPrimingResponse) SetStatusCode(v int64)` + +SetStatusCode sets StatusCode field to given value. + +### HasStatusCode + +`func (o *VerifiableCredentialPrimingResponse) HasStatusCode() bool` + +HasStatusCode returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/VerifiableCredentialProof.md b/internal/httpclient/docs/VerifiableCredentialProof.md new file mode 100644 index 00000000000..9412036cbb2 --- /dev/null +++ b/internal/httpclient/docs/VerifiableCredentialProof.md @@ -0,0 +1,82 @@ +# VerifiableCredentialProof + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Jwt** | Pointer to **string** | | [optional] +**ProofType** | Pointer to **string** | | [optional] + +## Methods + +### NewVerifiableCredentialProof + +`func NewVerifiableCredentialProof() *VerifiableCredentialProof` + +NewVerifiableCredentialProof instantiates a new VerifiableCredentialProof object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewVerifiableCredentialProofWithDefaults + +`func NewVerifiableCredentialProofWithDefaults() *VerifiableCredentialProof` + +NewVerifiableCredentialProofWithDefaults instantiates a new VerifiableCredentialProof object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetJwt + +`func (o *VerifiableCredentialProof) GetJwt() string` + +GetJwt returns the Jwt field if non-nil, zero value otherwise. + +### GetJwtOk + +`func (o *VerifiableCredentialProof) GetJwtOk() (*string, bool)` + +GetJwtOk returns a tuple with the Jwt field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetJwt + +`func (o *VerifiableCredentialProof) SetJwt(v string)` + +SetJwt sets Jwt field to given value. + +### HasJwt + +`func (o *VerifiableCredentialProof) HasJwt() bool` + +HasJwt returns a boolean if a field has been set. + +### GetProofType + +`func (o *VerifiableCredentialProof) GetProofType() string` + +GetProofType returns the ProofType field if non-nil, zero value otherwise. + +### GetProofTypeOk + +`func (o *VerifiableCredentialProof) GetProofTypeOk() (*string, bool)` + +GetProofTypeOk returns a tuple with the ProofType field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetProofType + +`func (o *VerifiableCredentialProof) SetProofType(v string)` + +SetProofType sets ProofType field to given value. + +### HasProofType + +`func (o *VerifiableCredentialProof) HasProofType() bool` + +HasProofType returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/VerifiableCredentialResponse.md b/internal/httpclient/docs/VerifiableCredentialResponse.md new file mode 100644 index 00000000000..aa594541c40 --- /dev/null +++ b/internal/httpclient/docs/VerifiableCredentialResponse.md @@ -0,0 +1,82 @@ +# VerifiableCredentialResponse + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**CredentialDraft00** | Pointer to **string** | | [optional] +**Format** | Pointer to **string** | | [optional] + +## Methods + +### NewVerifiableCredentialResponse + +`func NewVerifiableCredentialResponse() *VerifiableCredentialResponse` + +NewVerifiableCredentialResponse instantiates a new VerifiableCredentialResponse object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewVerifiableCredentialResponseWithDefaults + +`func NewVerifiableCredentialResponseWithDefaults() *VerifiableCredentialResponse` + +NewVerifiableCredentialResponseWithDefaults instantiates a new VerifiableCredentialResponse object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetCredentialDraft00 + +`func (o *VerifiableCredentialResponse) GetCredentialDraft00() string` + +GetCredentialDraft00 returns the CredentialDraft00 field if non-nil, zero value otherwise. + +### GetCredentialDraft00Ok + +`func (o *VerifiableCredentialResponse) GetCredentialDraft00Ok() (*string, bool)` + +GetCredentialDraft00Ok returns a tuple with the CredentialDraft00 field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetCredentialDraft00 + +`func (o *VerifiableCredentialResponse) SetCredentialDraft00(v string)` + +SetCredentialDraft00 sets CredentialDraft00 field to given value. + +### HasCredentialDraft00 + +`func (o *VerifiableCredentialResponse) HasCredentialDraft00() bool` + +HasCredentialDraft00 returns a boolean if a field has been set. + +### GetFormat + +`func (o *VerifiableCredentialResponse) GetFormat() string` + +GetFormat returns the Format field if non-nil, zero value otherwise. + +### GetFormatOk + +`func (o *VerifiableCredentialResponse) GetFormatOk() (*string, bool)` + +GetFormatOk returns a tuple with the Format field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetFormat + +`func (o *VerifiableCredentialResponse) SetFormat(v string)` + +SetFormat sets Format field to given value. + +### HasFormat + +`func (o *VerifiableCredentialResponse) HasFormat() bool` + +HasFormat returns a boolean if a field has been set. + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/internal/httpclient/docs/WellknownApi.md b/internal/httpclient/docs/WellknownAPI.md similarity index 58% rename from internal/httpclient/docs/WellknownApi.md rename to internal/httpclient/docs/WellknownAPI.md index 5f184777044..f61bbbc5186 100644 --- a/internal/httpclient/docs/WellknownApi.md +++ b/internal/httpclient/docs/WellknownAPI.md @@ -1,10 +1,10 @@ -# \WellknownApi +# \WellknownAPI All URIs are relative to *http://localhost* Method | HTTP request | Description ------------- | ------------- | ------------- -[**DiscoverJsonWebKeys**](WellknownApi.md#DiscoverJsonWebKeys) | **Get** /.well-known/jwks.json | Discover Well-Known JSON Web Keys +[**DiscoverJsonWebKeys**](WellknownAPI.md#DiscoverJsonWebKeys) | **Get** /.well-known/jwks.json | Discover Well-Known JSON Web Keys @@ -22,23 +22,23 @@ Discover Well-Known JSON Web Keys package main import ( - "context" - "fmt" - "os" - openapiclient "./openapi" + "context" + "fmt" + "os" + openapiclient "github.com/ory/hydra-client-go/v2" ) func main() { - configuration := openapiclient.NewConfiguration() - apiClient := openapiclient.NewAPIClient(configuration) - resp, r, err := apiClient.WellknownApi.DiscoverJsonWebKeys(context.Background()).Execute() - if err != nil { - fmt.Fprintf(os.Stderr, "Error when calling `WellknownApi.DiscoverJsonWebKeys``: %v\n", err) - fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) - } - // response from `DiscoverJsonWebKeys`: JsonWebKeySet - fmt.Fprintf(os.Stdout, "Response from `WellknownApi.DiscoverJsonWebKeys`: %v\n", resp) + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + resp, r, err := apiClient.WellknownAPI.DiscoverJsonWebKeys(context.Background()).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `WellknownAPI.DiscoverJsonWebKeys``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } + // response from `DiscoverJsonWebKeys`: JsonWebKeySet + fmt.Fprintf(os.Stdout, "Response from `WellknownAPI.DiscoverJsonWebKeys`: %v\n", resp) } ``` diff --git a/internal/httpclient/git_push.sh b/internal/httpclient/git_push.sh index cb3fc304a3a..c25540340a5 100644 --- a/internal/httpclient/git_push.sh +++ b/internal/httpclient/git_push.sh @@ -19,7 +19,7 @@ if [ "$git_user_id" = "" ]; then fi if [ "$git_repo_id" = "" ]; then - git_repo_id="hydra-client-go" + git_repo_id="hydra-client-go/v2" echo "[INFO] No command line input provided. Set \$git_repo_id to $git_repo_id" fi diff --git a/internal/httpclient/go.mod b/internal/httpclient/go.mod index b4d363e00c8..4a8378d605e 100644 --- a/internal/httpclient/go.mod +++ b/internal/httpclient/go.mod @@ -1,6 +1,6 @@ -module github.com/ory/hydra-client-go +module github.com/ory/hydra-client-go/v2 -go 1.13 +go 1.18 require ( golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558 diff --git a/internal/httpclient/go.sum b/internal/httpclient/go.sum index 734252e6815..3dee6d68163 100644 --- a/internal/httpclient/go.sum +++ b/internal/httpclient/go.sum @@ -1,13 +1,360 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4= +cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M= +cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= +cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= +cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= +cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= +cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= +cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= +cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= +cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= +cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= +github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= +github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= +github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= +golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20210323180902-22b0adad7558/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= +golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= +google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE= +google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM= +google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA= +google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= +google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= +google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= +google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= +rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= diff --git a/internal/httpclient/model_accept_o_auth2_consent_request.go b/internal/httpclient/model_accept_o_auth2_consent_request.go index 11d6459acfd..ff84659a399 100644 --- a/internal/httpclient/model_accept_o_auth2_consent_request.go +++ b/internal/httpclient/model_accept_o_auth2_consent_request.go @@ -16,11 +16,15 @@ import ( "time" ) +// checks if the AcceptOAuth2ConsentRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &AcceptOAuth2ConsentRequest{} + // AcceptOAuth2ConsentRequest struct for AcceptOAuth2ConsentRequest type AcceptOAuth2ConsentRequest struct { - GrantAccessTokenAudience []string `json:"grant_access_token_audience,omitempty"` - GrantScope []string `json:"grant_scope,omitempty"` - HandledAt *time.Time `json:"handled_at,omitempty"` + Context interface{} `json:"context,omitempty"` + GrantAccessTokenAudience []string `json:"grant_access_token_audience,omitempty"` + GrantScope []string `json:"grant_scope,omitempty"` + HandledAt *time.Time `json:"handled_at,omitempty"` // Remember, if set to true, tells ORY Hydra to remember this consent authorization and reuse it if the same client asks the same user for the same, or a subset of, scope. Remember *bool `json:"remember,omitempty"` // RememberFor sets how long the consent authorization should be remembered for in seconds. If set to `0`, the authorization will be remembered indefinitely. @@ -45,9 +49,42 @@ func NewAcceptOAuth2ConsentRequestWithDefaults() *AcceptOAuth2ConsentRequest { return &this } +// GetContext returns the Context field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *AcceptOAuth2ConsentRequest) GetContext() interface{} { + if o == nil { + var ret interface{} + return ret + } + return o.Context +} + +// GetContextOk returns a tuple with the Context field value if set, nil otherwise +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *AcceptOAuth2ConsentRequest) GetContextOk() (*interface{}, bool) { + if o == nil || IsNil(o.Context) { + return nil, false + } + return &o.Context, true +} + +// HasContext returns a boolean if a field has been set. +func (o *AcceptOAuth2ConsentRequest) HasContext() bool { + if o != nil && IsNil(o.Context) { + return true + } + + return false +} + +// SetContext gets a reference to the given interface{} and assigns it to the Context field. +func (o *AcceptOAuth2ConsentRequest) SetContext(v interface{}) { + o.Context = v +} + // GetGrantAccessTokenAudience returns the GrantAccessTokenAudience field value if set, zero value otherwise. func (o *AcceptOAuth2ConsentRequest) GetGrantAccessTokenAudience() []string { - if o == nil || o.GrantAccessTokenAudience == nil { + if o == nil || IsNil(o.GrantAccessTokenAudience) { var ret []string return ret } @@ -57,7 +94,7 @@ func (o *AcceptOAuth2ConsentRequest) GetGrantAccessTokenAudience() []string { // GetGrantAccessTokenAudienceOk returns a tuple with the GrantAccessTokenAudience field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2ConsentRequest) GetGrantAccessTokenAudienceOk() ([]string, bool) { - if o == nil || o.GrantAccessTokenAudience == nil { + if o == nil || IsNil(o.GrantAccessTokenAudience) { return nil, false } return o.GrantAccessTokenAudience, true @@ -65,7 +102,7 @@ func (o *AcceptOAuth2ConsentRequest) GetGrantAccessTokenAudienceOk() ([]string, // HasGrantAccessTokenAudience returns a boolean if a field has been set. func (o *AcceptOAuth2ConsentRequest) HasGrantAccessTokenAudience() bool { - if o != nil && o.GrantAccessTokenAudience != nil { + if o != nil && !IsNil(o.GrantAccessTokenAudience) { return true } @@ -79,7 +116,7 @@ func (o *AcceptOAuth2ConsentRequest) SetGrantAccessTokenAudience(v []string) { // GetGrantScope returns the GrantScope field value if set, zero value otherwise. func (o *AcceptOAuth2ConsentRequest) GetGrantScope() []string { - if o == nil || o.GrantScope == nil { + if o == nil || IsNil(o.GrantScope) { var ret []string return ret } @@ -89,7 +126,7 @@ func (o *AcceptOAuth2ConsentRequest) GetGrantScope() []string { // GetGrantScopeOk returns a tuple with the GrantScope field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2ConsentRequest) GetGrantScopeOk() ([]string, bool) { - if o == nil || o.GrantScope == nil { + if o == nil || IsNil(o.GrantScope) { return nil, false } return o.GrantScope, true @@ -97,7 +134,7 @@ func (o *AcceptOAuth2ConsentRequest) GetGrantScopeOk() ([]string, bool) { // HasGrantScope returns a boolean if a field has been set. func (o *AcceptOAuth2ConsentRequest) HasGrantScope() bool { - if o != nil && o.GrantScope != nil { + if o != nil && !IsNil(o.GrantScope) { return true } @@ -111,7 +148,7 @@ func (o *AcceptOAuth2ConsentRequest) SetGrantScope(v []string) { // GetHandledAt returns the HandledAt field value if set, zero value otherwise. func (o *AcceptOAuth2ConsentRequest) GetHandledAt() time.Time { - if o == nil || o.HandledAt == nil { + if o == nil || IsNil(o.HandledAt) { var ret time.Time return ret } @@ -121,7 +158,7 @@ func (o *AcceptOAuth2ConsentRequest) GetHandledAt() time.Time { // GetHandledAtOk returns a tuple with the HandledAt field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2ConsentRequest) GetHandledAtOk() (*time.Time, bool) { - if o == nil || o.HandledAt == nil { + if o == nil || IsNil(o.HandledAt) { return nil, false } return o.HandledAt, true @@ -129,7 +166,7 @@ func (o *AcceptOAuth2ConsentRequest) GetHandledAtOk() (*time.Time, bool) { // HasHandledAt returns a boolean if a field has been set. func (o *AcceptOAuth2ConsentRequest) HasHandledAt() bool { - if o != nil && o.HandledAt != nil { + if o != nil && !IsNil(o.HandledAt) { return true } @@ -143,7 +180,7 @@ func (o *AcceptOAuth2ConsentRequest) SetHandledAt(v time.Time) { // GetRemember returns the Remember field value if set, zero value otherwise. func (o *AcceptOAuth2ConsentRequest) GetRemember() bool { - if o == nil || o.Remember == nil { + if o == nil || IsNil(o.Remember) { var ret bool return ret } @@ -153,7 +190,7 @@ func (o *AcceptOAuth2ConsentRequest) GetRemember() bool { // GetRememberOk returns a tuple with the Remember field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2ConsentRequest) GetRememberOk() (*bool, bool) { - if o == nil || o.Remember == nil { + if o == nil || IsNil(o.Remember) { return nil, false } return o.Remember, true @@ -161,7 +198,7 @@ func (o *AcceptOAuth2ConsentRequest) GetRememberOk() (*bool, bool) { // HasRemember returns a boolean if a field has been set. func (o *AcceptOAuth2ConsentRequest) HasRemember() bool { - if o != nil && o.Remember != nil { + if o != nil && !IsNil(o.Remember) { return true } @@ -175,7 +212,7 @@ func (o *AcceptOAuth2ConsentRequest) SetRemember(v bool) { // GetRememberFor returns the RememberFor field value if set, zero value otherwise. func (o *AcceptOAuth2ConsentRequest) GetRememberFor() int64 { - if o == nil || o.RememberFor == nil { + if o == nil || IsNil(o.RememberFor) { var ret int64 return ret } @@ -185,7 +222,7 @@ func (o *AcceptOAuth2ConsentRequest) GetRememberFor() int64 { // GetRememberForOk returns a tuple with the RememberFor field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2ConsentRequest) GetRememberForOk() (*int64, bool) { - if o == nil || o.RememberFor == nil { + if o == nil || IsNil(o.RememberFor) { return nil, false } return o.RememberFor, true @@ -193,7 +230,7 @@ func (o *AcceptOAuth2ConsentRequest) GetRememberForOk() (*int64, bool) { // HasRememberFor returns a boolean if a field has been set. func (o *AcceptOAuth2ConsentRequest) HasRememberFor() bool { - if o != nil && o.RememberFor != nil { + if o != nil && !IsNil(o.RememberFor) { return true } @@ -207,7 +244,7 @@ func (o *AcceptOAuth2ConsentRequest) SetRememberFor(v int64) { // GetSession returns the Session field value if set, zero value otherwise. func (o *AcceptOAuth2ConsentRequest) GetSession() AcceptOAuth2ConsentRequestSession { - if o == nil || o.Session == nil { + if o == nil || IsNil(o.Session) { var ret AcceptOAuth2ConsentRequestSession return ret } @@ -217,7 +254,7 @@ func (o *AcceptOAuth2ConsentRequest) GetSession() AcceptOAuth2ConsentRequestSess // GetSessionOk returns a tuple with the Session field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2ConsentRequest) GetSessionOk() (*AcceptOAuth2ConsentRequestSession, bool) { - if o == nil || o.Session == nil { + if o == nil || IsNil(o.Session) { return nil, false } return o.Session, true @@ -225,7 +262,7 @@ func (o *AcceptOAuth2ConsentRequest) GetSessionOk() (*AcceptOAuth2ConsentRequest // HasSession returns a boolean if a field has been set. func (o *AcceptOAuth2ConsentRequest) HasSession() bool { - if o != nil && o.Session != nil { + if o != nil && !IsNil(o.Session) { return true } @@ -238,26 +275,37 @@ func (o *AcceptOAuth2ConsentRequest) SetSession(v AcceptOAuth2ConsentRequestSess } func (o AcceptOAuth2ConsentRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o AcceptOAuth2ConsentRequest) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.GrantAccessTokenAudience != nil { + if o.Context != nil { + toSerialize["context"] = o.Context + } + if !IsNil(o.GrantAccessTokenAudience) { toSerialize["grant_access_token_audience"] = o.GrantAccessTokenAudience } - if o.GrantScope != nil { + if !IsNil(o.GrantScope) { toSerialize["grant_scope"] = o.GrantScope } - if o.HandledAt != nil { + if !IsNil(o.HandledAt) { toSerialize["handled_at"] = o.HandledAt } - if o.Remember != nil { + if !IsNil(o.Remember) { toSerialize["remember"] = o.Remember } - if o.RememberFor != nil { + if !IsNil(o.RememberFor) { toSerialize["remember_for"] = o.RememberFor } - if o.Session != nil { + if !IsNil(o.Session) { toSerialize["session"] = o.Session } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableAcceptOAuth2ConsentRequest struct { diff --git a/internal/httpclient/model_accept_o_auth2_consent_request_session.go b/internal/httpclient/model_accept_o_auth2_consent_request_session.go index 33f78991a43..04f7d1356e0 100644 --- a/internal/httpclient/model_accept_o_auth2_consent_request_session.go +++ b/internal/httpclient/model_accept_o_auth2_consent_request_session.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the AcceptOAuth2ConsentRequestSession type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &AcceptOAuth2ConsentRequestSession{} + // AcceptOAuth2ConsentRequestSession struct for AcceptOAuth2ConsentRequestSession type AcceptOAuth2ConsentRequestSession struct { // AccessToken sets session data for the access and refresh token, as well as any future tokens issued by the refresh grant. Keep in mind that this data will be available to anyone performing OAuth 2.0 Challenge Introspection. If only your services can perform OAuth 2.0 Challenge Introspection, this is usually fine. But if third parties can access that endpoint as well, sensitive data from the session might be exposed to them. Use with care! @@ -53,7 +56,7 @@ func (o *AcceptOAuth2ConsentRequestSession) GetAccessToken() interface{} { // and a boolean to check if the value has been set. // NOTE: If the value is an explicit nil, `nil, true` will be returned func (o *AcceptOAuth2ConsentRequestSession) GetAccessTokenOk() (*interface{}, bool) { - if o == nil || o.AccessToken == nil { + if o == nil || IsNil(o.AccessToken) { return nil, false } return &o.AccessToken, true @@ -61,7 +64,7 @@ func (o *AcceptOAuth2ConsentRequestSession) GetAccessTokenOk() (*interface{}, bo // HasAccessToken returns a boolean if a field has been set. func (o *AcceptOAuth2ConsentRequestSession) HasAccessToken() bool { - if o != nil && o.AccessToken != nil { + if o != nil && IsNil(o.AccessToken) { return true } @@ -86,7 +89,7 @@ func (o *AcceptOAuth2ConsentRequestSession) GetIdToken() interface{} { // and a boolean to check if the value has been set. // NOTE: If the value is an explicit nil, `nil, true` will be returned func (o *AcceptOAuth2ConsentRequestSession) GetIdTokenOk() (*interface{}, bool) { - if o == nil || o.IdToken == nil { + if o == nil || IsNil(o.IdToken) { return nil, false } return &o.IdToken, true @@ -94,7 +97,7 @@ func (o *AcceptOAuth2ConsentRequestSession) GetIdTokenOk() (*interface{}, bool) // HasIdToken returns a boolean if a field has been set. func (o *AcceptOAuth2ConsentRequestSession) HasIdToken() bool { - if o != nil && o.IdToken != nil { + if o != nil && IsNil(o.IdToken) { return true } @@ -107,6 +110,14 @@ func (o *AcceptOAuth2ConsentRequestSession) SetIdToken(v interface{}) { } func (o AcceptOAuth2ConsentRequestSession) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o AcceptOAuth2ConsentRequestSession) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} if o.AccessToken != nil { toSerialize["access_token"] = o.AccessToken @@ -114,7 +125,7 @@ func (o AcceptOAuth2ConsentRequestSession) MarshalJSON() ([]byte, error) { if o.IdToken != nil { toSerialize["id_token"] = o.IdToken } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableAcceptOAuth2ConsentRequestSession struct { diff --git a/internal/httpclient/model_accept_o_auth2_login_request.go b/internal/httpclient/model_accept_o_auth2_login_request.go index 5ae383ad040..6b3538dbe41 100644 --- a/internal/httpclient/model_accept_o_auth2_login_request.go +++ b/internal/httpclient/model_accept_o_auth2_login_request.go @@ -12,17 +12,26 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the AcceptOAuth2LoginRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &AcceptOAuth2LoginRequest{} + // AcceptOAuth2LoginRequest struct for AcceptOAuth2LoginRequest type AcceptOAuth2LoginRequest struct { // ACR sets the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it to express that, for example, a user authenticated using two factor authentication. Acr *string `json:"acr,omitempty"` Amr []string `json:"amr,omitempty"` Context interface{} `json:"context,omitempty"` + // Extend OAuth2 authentication session lifespan If set to `true`, the OAuth2 authentication cookie lifespan is extended. This is for example useful if you want the user to be able to use `prompt=none` continuously. This value can only be set to `true` if the user has an authentication, which is the case if the `skip` value is `true`. + ExtendSessionLifespan *bool `json:"extend_session_lifespan,omitempty"` // ForceSubjectIdentifier forces the \"pairwise\" user ID of the end-user that authenticated. The \"pairwise\" user ID refers to the (Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg] of the OpenID Connect specification. It allows you to set an obfuscated subject (\"user\") identifier that is unique to the client. Please note that this changes the user ID on endpoint /userinfo and sub claim of the ID Token. It does not change the sub claim in the OAuth 2.0 Introspection. Per default, ORY Hydra handles this value with its own algorithm. In case you want to set this yourself you can use this field. Please note that setting this field has no effect if `pairwise` is not configured in ORY Hydra or the OAuth 2.0 Client does not expect a pairwise identifier (set via `subject_type` key in the client's configuration). Please also be aware that ORY Hydra is unable to properly compute this value during authentication. This implies that you have to compute this value on every authentication process (probably depending on the client ID or some other unique value). If you fail to compute the proper value, then authentication processes which have id_token_hint set might fail. ForceSubjectIdentifier *string `json:"force_subject_identifier,omitempty"` + // IdentityProviderSessionID is the session ID of the end-user that authenticated. If specified, we will use this value to propagate the logout. + IdentityProviderSessionId *string `json:"identity_provider_session_id,omitempty"` // Remember, if set to true, tells ORY Hydra to remember this user by telling the user agent (browser) to store a cookie with authentication data. If the same user performs another OAuth 2.0 Authorization Request, he/she will not be asked to log in again. Remember *bool `json:"remember,omitempty"` // RememberFor sets how long the authentication should be remembered for in seconds. If set to `0`, the authorization will be remembered for the duration of the browser session (using a session cookie). @@ -31,6 +40,8 @@ type AcceptOAuth2LoginRequest struct { Subject string `json:"subject"` } +type _AcceptOAuth2LoginRequest AcceptOAuth2LoginRequest + // NewAcceptOAuth2LoginRequest instantiates a new AcceptOAuth2LoginRequest object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -51,7 +62,7 @@ func NewAcceptOAuth2LoginRequestWithDefaults() *AcceptOAuth2LoginRequest { // GetAcr returns the Acr field value if set, zero value otherwise. func (o *AcceptOAuth2LoginRequest) GetAcr() string { - if o == nil || o.Acr == nil { + if o == nil || IsNil(o.Acr) { var ret string return ret } @@ -61,7 +72,7 @@ func (o *AcceptOAuth2LoginRequest) GetAcr() string { // GetAcrOk returns a tuple with the Acr field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2LoginRequest) GetAcrOk() (*string, bool) { - if o == nil || o.Acr == nil { + if o == nil || IsNil(o.Acr) { return nil, false } return o.Acr, true @@ -69,7 +80,7 @@ func (o *AcceptOAuth2LoginRequest) GetAcrOk() (*string, bool) { // HasAcr returns a boolean if a field has been set. func (o *AcceptOAuth2LoginRequest) HasAcr() bool { - if o != nil && o.Acr != nil { + if o != nil && !IsNil(o.Acr) { return true } @@ -83,7 +94,7 @@ func (o *AcceptOAuth2LoginRequest) SetAcr(v string) { // GetAmr returns the Amr field value if set, zero value otherwise. func (o *AcceptOAuth2LoginRequest) GetAmr() []string { - if o == nil || o.Amr == nil { + if o == nil || IsNil(o.Amr) { var ret []string return ret } @@ -93,7 +104,7 @@ func (o *AcceptOAuth2LoginRequest) GetAmr() []string { // GetAmrOk returns a tuple with the Amr field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2LoginRequest) GetAmrOk() ([]string, bool) { - if o == nil || o.Amr == nil { + if o == nil || IsNil(o.Amr) { return nil, false } return o.Amr, true @@ -101,7 +112,7 @@ func (o *AcceptOAuth2LoginRequest) GetAmrOk() ([]string, bool) { // HasAmr returns a boolean if a field has been set. func (o *AcceptOAuth2LoginRequest) HasAmr() bool { - if o != nil && o.Amr != nil { + if o != nil && !IsNil(o.Amr) { return true } @@ -126,7 +137,7 @@ func (o *AcceptOAuth2LoginRequest) GetContext() interface{} { // and a boolean to check if the value has been set. // NOTE: If the value is an explicit nil, `nil, true` will be returned func (o *AcceptOAuth2LoginRequest) GetContextOk() (*interface{}, bool) { - if o == nil || o.Context == nil { + if o == nil || IsNil(o.Context) { return nil, false } return &o.Context, true @@ -134,7 +145,7 @@ func (o *AcceptOAuth2LoginRequest) GetContextOk() (*interface{}, bool) { // HasContext returns a boolean if a field has been set. func (o *AcceptOAuth2LoginRequest) HasContext() bool { - if o != nil && o.Context != nil { + if o != nil && IsNil(o.Context) { return true } @@ -146,9 +157,41 @@ func (o *AcceptOAuth2LoginRequest) SetContext(v interface{}) { o.Context = v } +// GetExtendSessionLifespan returns the ExtendSessionLifespan field value if set, zero value otherwise. +func (o *AcceptOAuth2LoginRequest) GetExtendSessionLifespan() bool { + if o == nil || IsNil(o.ExtendSessionLifespan) { + var ret bool + return ret + } + return *o.ExtendSessionLifespan +} + +// GetExtendSessionLifespanOk returns a tuple with the ExtendSessionLifespan field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *AcceptOAuth2LoginRequest) GetExtendSessionLifespanOk() (*bool, bool) { + if o == nil || IsNil(o.ExtendSessionLifespan) { + return nil, false + } + return o.ExtendSessionLifespan, true +} + +// HasExtendSessionLifespan returns a boolean if a field has been set. +func (o *AcceptOAuth2LoginRequest) HasExtendSessionLifespan() bool { + if o != nil && !IsNil(o.ExtendSessionLifespan) { + return true + } + + return false +} + +// SetExtendSessionLifespan gets a reference to the given bool and assigns it to the ExtendSessionLifespan field. +func (o *AcceptOAuth2LoginRequest) SetExtendSessionLifespan(v bool) { + o.ExtendSessionLifespan = &v +} + // GetForceSubjectIdentifier returns the ForceSubjectIdentifier field value if set, zero value otherwise. func (o *AcceptOAuth2LoginRequest) GetForceSubjectIdentifier() string { - if o == nil || o.ForceSubjectIdentifier == nil { + if o == nil || IsNil(o.ForceSubjectIdentifier) { var ret string return ret } @@ -158,7 +201,7 @@ func (o *AcceptOAuth2LoginRequest) GetForceSubjectIdentifier() string { // GetForceSubjectIdentifierOk returns a tuple with the ForceSubjectIdentifier field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2LoginRequest) GetForceSubjectIdentifierOk() (*string, bool) { - if o == nil || o.ForceSubjectIdentifier == nil { + if o == nil || IsNil(o.ForceSubjectIdentifier) { return nil, false } return o.ForceSubjectIdentifier, true @@ -166,7 +209,7 @@ func (o *AcceptOAuth2LoginRequest) GetForceSubjectIdentifierOk() (*string, bool) // HasForceSubjectIdentifier returns a boolean if a field has been set. func (o *AcceptOAuth2LoginRequest) HasForceSubjectIdentifier() bool { - if o != nil && o.ForceSubjectIdentifier != nil { + if o != nil && !IsNil(o.ForceSubjectIdentifier) { return true } @@ -178,9 +221,41 @@ func (o *AcceptOAuth2LoginRequest) SetForceSubjectIdentifier(v string) { o.ForceSubjectIdentifier = &v } +// GetIdentityProviderSessionId returns the IdentityProviderSessionId field value if set, zero value otherwise. +func (o *AcceptOAuth2LoginRequest) GetIdentityProviderSessionId() string { + if o == nil || IsNil(o.IdentityProviderSessionId) { + var ret string + return ret + } + return *o.IdentityProviderSessionId +} + +// GetIdentityProviderSessionIdOk returns a tuple with the IdentityProviderSessionId field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *AcceptOAuth2LoginRequest) GetIdentityProviderSessionIdOk() (*string, bool) { + if o == nil || IsNil(o.IdentityProviderSessionId) { + return nil, false + } + return o.IdentityProviderSessionId, true +} + +// HasIdentityProviderSessionId returns a boolean if a field has been set. +func (o *AcceptOAuth2LoginRequest) HasIdentityProviderSessionId() bool { + if o != nil && !IsNil(o.IdentityProviderSessionId) { + return true + } + + return false +} + +// SetIdentityProviderSessionId gets a reference to the given string and assigns it to the IdentityProviderSessionId field. +func (o *AcceptOAuth2LoginRequest) SetIdentityProviderSessionId(v string) { + o.IdentityProviderSessionId = &v +} + // GetRemember returns the Remember field value if set, zero value otherwise. func (o *AcceptOAuth2LoginRequest) GetRemember() bool { - if o == nil || o.Remember == nil { + if o == nil || IsNil(o.Remember) { var ret bool return ret } @@ -190,7 +265,7 @@ func (o *AcceptOAuth2LoginRequest) GetRemember() bool { // GetRememberOk returns a tuple with the Remember field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2LoginRequest) GetRememberOk() (*bool, bool) { - if o == nil || o.Remember == nil { + if o == nil || IsNil(o.Remember) { return nil, false } return o.Remember, true @@ -198,7 +273,7 @@ func (o *AcceptOAuth2LoginRequest) GetRememberOk() (*bool, bool) { // HasRemember returns a boolean if a field has been set. func (o *AcceptOAuth2LoginRequest) HasRemember() bool { - if o != nil && o.Remember != nil { + if o != nil && !IsNil(o.Remember) { return true } @@ -212,7 +287,7 @@ func (o *AcceptOAuth2LoginRequest) SetRemember(v bool) { // GetRememberFor returns the RememberFor field value if set, zero value otherwise. func (o *AcceptOAuth2LoginRequest) GetRememberFor() int64 { - if o == nil || o.RememberFor == nil { + if o == nil || IsNil(o.RememberFor) { var ret int64 return ret } @@ -222,7 +297,7 @@ func (o *AcceptOAuth2LoginRequest) GetRememberFor() int64 { // GetRememberForOk returns a tuple with the RememberFor field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *AcceptOAuth2LoginRequest) GetRememberForOk() (*int64, bool) { - if o == nil || o.RememberFor == nil { + if o == nil || IsNil(o.RememberFor) { return nil, false } return o.RememberFor, true @@ -230,7 +305,7 @@ func (o *AcceptOAuth2LoginRequest) GetRememberForOk() (*int64, bool) { // HasRememberFor returns a boolean if a field has been set. func (o *AcceptOAuth2LoginRequest) HasRememberFor() bool { - if o != nil && o.RememberFor != nil { + if o != nil && !IsNil(o.RememberFor) { return true } @@ -267,29 +342,78 @@ func (o *AcceptOAuth2LoginRequest) SetSubject(v string) { } func (o AcceptOAuth2LoginRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o AcceptOAuth2LoginRequest) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Acr != nil { + if !IsNil(o.Acr) { toSerialize["acr"] = o.Acr } - if o.Amr != nil { + if !IsNil(o.Amr) { toSerialize["amr"] = o.Amr } if o.Context != nil { toSerialize["context"] = o.Context } - if o.ForceSubjectIdentifier != nil { + if !IsNil(o.ExtendSessionLifespan) { + toSerialize["extend_session_lifespan"] = o.ExtendSessionLifespan + } + if !IsNil(o.ForceSubjectIdentifier) { toSerialize["force_subject_identifier"] = o.ForceSubjectIdentifier } - if o.Remember != nil { + if !IsNil(o.IdentityProviderSessionId) { + toSerialize["identity_provider_session_id"] = o.IdentityProviderSessionId + } + if !IsNil(o.Remember) { toSerialize["remember"] = o.Remember } - if o.RememberFor != nil { + if !IsNil(o.RememberFor) { toSerialize["remember_for"] = o.RememberFor } - if true { - toSerialize["subject"] = o.Subject + toSerialize["subject"] = o.Subject + return toSerialize, nil +} + +func (o *AcceptOAuth2LoginRequest) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "subject", } - return json.Marshal(toSerialize) + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varAcceptOAuth2LoginRequest := _AcceptOAuth2LoginRequest{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varAcceptOAuth2LoginRequest) + + if err != nil { + return err + } + + *o = AcceptOAuth2LoginRequest(varAcceptOAuth2LoginRequest) + + return err } type NullableAcceptOAuth2LoginRequest struct { diff --git a/internal/httpclient/model_create_json_web_key_set.go b/internal/httpclient/model_create_json_web_key_set.go index 3c0f429b21b..4170214875e 100644 --- a/internal/httpclient/model_create_json_web_key_set.go +++ b/internal/httpclient/model_create_json_web_key_set.go @@ -12,9 +12,14 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the CreateJsonWebKeySet type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CreateJsonWebKeySet{} + // CreateJsonWebKeySet Create JSON Web Key Set Request Body type CreateJsonWebKeySet struct { // JSON Web Key Algorithm The algorithm to be used for creating the key. Supports `RS256`, `ES256`, `ES512`, `HS512`, and `HS256`. @@ -25,6 +30,8 @@ type CreateJsonWebKeySet struct { Use string `json:"use"` } +type _CreateJsonWebKeySet CreateJsonWebKeySet + // NewCreateJsonWebKeySet instantiates a new CreateJsonWebKeySet object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -118,17 +125,58 @@ func (o *CreateJsonWebKeySet) SetUse(v string) { } func (o CreateJsonWebKeySet) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o CreateJsonWebKeySet) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if true { - toSerialize["alg"] = o.Alg + toSerialize["alg"] = o.Alg + toSerialize["kid"] = o.Kid + toSerialize["use"] = o.Use + return toSerialize, nil +} + +func (o *CreateJsonWebKeySet) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "alg", + "kid", + "use", } - if true { - toSerialize["kid"] = o.Kid + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err } - if true { - toSerialize["use"] = o.Use + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } } - return json.Marshal(toSerialize) + + varCreateJsonWebKeySet := _CreateJsonWebKeySet{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varCreateJsonWebKeySet) + + if err != nil { + return err + } + + *o = CreateJsonWebKeySet(varCreateJsonWebKeySet) + + return err } type NullableCreateJsonWebKeySet struct { diff --git a/internal/httpclient/model_create_verifiable_credential_request_body.go b/internal/httpclient/model_create_verifiable_credential_request_body.go new file mode 100644 index 00000000000..463e4ac6501 --- /dev/null +++ b/internal/httpclient/model_create_verifiable_credential_request_body.go @@ -0,0 +1,197 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the CreateVerifiableCredentialRequestBody type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CreateVerifiableCredentialRequestBody{} + +// CreateVerifiableCredentialRequestBody struct for CreateVerifiableCredentialRequestBody +type CreateVerifiableCredentialRequestBody struct { + Format *string `json:"format,omitempty"` + Proof *VerifiableCredentialProof `json:"proof,omitempty"` + Types []string `json:"types,omitempty"` +} + +// NewCreateVerifiableCredentialRequestBody instantiates a new CreateVerifiableCredentialRequestBody object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewCreateVerifiableCredentialRequestBody() *CreateVerifiableCredentialRequestBody { + this := CreateVerifiableCredentialRequestBody{} + return &this +} + +// NewCreateVerifiableCredentialRequestBodyWithDefaults instantiates a new CreateVerifiableCredentialRequestBody object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewCreateVerifiableCredentialRequestBodyWithDefaults() *CreateVerifiableCredentialRequestBody { + this := CreateVerifiableCredentialRequestBody{} + return &this +} + +// GetFormat returns the Format field value if set, zero value otherwise. +func (o *CreateVerifiableCredentialRequestBody) GetFormat() string { + if o == nil || IsNil(o.Format) { + var ret string + return ret + } + return *o.Format +} + +// GetFormatOk returns a tuple with the Format field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateVerifiableCredentialRequestBody) GetFormatOk() (*string, bool) { + if o == nil || IsNil(o.Format) { + return nil, false + } + return o.Format, true +} + +// HasFormat returns a boolean if a field has been set. +func (o *CreateVerifiableCredentialRequestBody) HasFormat() bool { + if o != nil && !IsNil(o.Format) { + return true + } + + return false +} + +// SetFormat gets a reference to the given string and assigns it to the Format field. +func (o *CreateVerifiableCredentialRequestBody) SetFormat(v string) { + o.Format = &v +} + +// GetProof returns the Proof field value if set, zero value otherwise. +func (o *CreateVerifiableCredentialRequestBody) GetProof() VerifiableCredentialProof { + if o == nil || IsNil(o.Proof) { + var ret VerifiableCredentialProof + return ret + } + return *o.Proof +} + +// GetProofOk returns a tuple with the Proof field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateVerifiableCredentialRequestBody) GetProofOk() (*VerifiableCredentialProof, bool) { + if o == nil || IsNil(o.Proof) { + return nil, false + } + return o.Proof, true +} + +// HasProof returns a boolean if a field has been set. +func (o *CreateVerifiableCredentialRequestBody) HasProof() bool { + if o != nil && !IsNil(o.Proof) { + return true + } + + return false +} + +// SetProof gets a reference to the given VerifiableCredentialProof and assigns it to the Proof field. +func (o *CreateVerifiableCredentialRequestBody) SetProof(v VerifiableCredentialProof) { + o.Proof = &v +} + +// GetTypes returns the Types field value if set, zero value otherwise. +func (o *CreateVerifiableCredentialRequestBody) GetTypes() []string { + if o == nil || IsNil(o.Types) { + var ret []string + return ret + } + return o.Types +} + +// GetTypesOk returns a tuple with the Types field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CreateVerifiableCredentialRequestBody) GetTypesOk() ([]string, bool) { + if o == nil || IsNil(o.Types) { + return nil, false + } + return o.Types, true +} + +// HasTypes returns a boolean if a field has been set. +func (o *CreateVerifiableCredentialRequestBody) HasTypes() bool { + if o != nil && !IsNil(o.Types) { + return true + } + + return false +} + +// SetTypes gets a reference to the given []string and assigns it to the Types field. +func (o *CreateVerifiableCredentialRequestBody) SetTypes(v []string) { + o.Types = v +} + +func (o CreateVerifiableCredentialRequestBody) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o CreateVerifiableCredentialRequestBody) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Format) { + toSerialize["format"] = o.Format + } + if !IsNil(o.Proof) { + toSerialize["proof"] = o.Proof + } + if !IsNil(o.Types) { + toSerialize["types"] = o.Types + } + return toSerialize, nil +} + +type NullableCreateVerifiableCredentialRequestBody struct { + value *CreateVerifiableCredentialRequestBody + isSet bool +} + +func (v NullableCreateVerifiableCredentialRequestBody) Get() *CreateVerifiableCredentialRequestBody { + return v.value +} + +func (v *NullableCreateVerifiableCredentialRequestBody) Set(val *CreateVerifiableCredentialRequestBody) { + v.value = val + v.isSet = true +} + +func (v NullableCreateVerifiableCredentialRequestBody) IsSet() bool { + return v.isSet +} + +func (v *NullableCreateVerifiableCredentialRequestBody) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableCreateVerifiableCredentialRequestBody(val *CreateVerifiableCredentialRequestBody) *NullableCreateVerifiableCredentialRequestBody { + return &NullableCreateVerifiableCredentialRequestBody{value: val, isSet: true} +} + +func (v NullableCreateVerifiableCredentialRequestBody) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableCreateVerifiableCredentialRequestBody) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_credential_supported_draft00.go b/internal/httpclient/model_credential_supported_draft00.go new file mode 100644 index 00000000000..47d1c5198e7 --- /dev/null +++ b/internal/httpclient/model_credential_supported_draft00.go @@ -0,0 +1,237 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the CredentialSupportedDraft00 type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &CredentialSupportedDraft00{} + +// CredentialSupportedDraft00 Includes information about the supported verifiable credentials. +type CredentialSupportedDraft00 struct { + // OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported Contains a list of cryptographic binding methods supported for signing the proof. + CryptographicBindingMethodsSupported []string `json:"cryptographic_binding_methods_supported,omitempty"` + // OpenID Connect Verifiable Credentials Cryptographic Suites Supported Contains a list of cryptographic suites methods supported for signing the proof. + CryptographicSuitesSupported []string `json:"cryptographic_suites_supported,omitempty"` + // OpenID Connect Verifiable Credentials Format Contains the format that is supported by this authorization server. + Format *string `json:"format,omitempty"` + // OpenID Connect Verifiable Credentials Types Contains the types of verifiable credentials supported. + Types []string `json:"types,omitempty"` +} + +// NewCredentialSupportedDraft00 instantiates a new CredentialSupportedDraft00 object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewCredentialSupportedDraft00() *CredentialSupportedDraft00 { + this := CredentialSupportedDraft00{} + return &this +} + +// NewCredentialSupportedDraft00WithDefaults instantiates a new CredentialSupportedDraft00 object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewCredentialSupportedDraft00WithDefaults() *CredentialSupportedDraft00 { + this := CredentialSupportedDraft00{} + return &this +} + +// GetCryptographicBindingMethodsSupported returns the CryptographicBindingMethodsSupported field value if set, zero value otherwise. +func (o *CredentialSupportedDraft00) GetCryptographicBindingMethodsSupported() []string { + if o == nil || IsNil(o.CryptographicBindingMethodsSupported) { + var ret []string + return ret + } + return o.CryptographicBindingMethodsSupported +} + +// GetCryptographicBindingMethodsSupportedOk returns a tuple with the CryptographicBindingMethodsSupported field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CredentialSupportedDraft00) GetCryptographicBindingMethodsSupportedOk() ([]string, bool) { + if o == nil || IsNil(o.CryptographicBindingMethodsSupported) { + return nil, false + } + return o.CryptographicBindingMethodsSupported, true +} + +// HasCryptographicBindingMethodsSupported returns a boolean if a field has been set. +func (o *CredentialSupportedDraft00) HasCryptographicBindingMethodsSupported() bool { + if o != nil && !IsNil(o.CryptographicBindingMethodsSupported) { + return true + } + + return false +} + +// SetCryptographicBindingMethodsSupported gets a reference to the given []string and assigns it to the CryptographicBindingMethodsSupported field. +func (o *CredentialSupportedDraft00) SetCryptographicBindingMethodsSupported(v []string) { + o.CryptographicBindingMethodsSupported = v +} + +// GetCryptographicSuitesSupported returns the CryptographicSuitesSupported field value if set, zero value otherwise. +func (o *CredentialSupportedDraft00) GetCryptographicSuitesSupported() []string { + if o == nil || IsNil(o.CryptographicSuitesSupported) { + var ret []string + return ret + } + return o.CryptographicSuitesSupported +} + +// GetCryptographicSuitesSupportedOk returns a tuple with the CryptographicSuitesSupported field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CredentialSupportedDraft00) GetCryptographicSuitesSupportedOk() ([]string, bool) { + if o == nil || IsNil(o.CryptographicSuitesSupported) { + return nil, false + } + return o.CryptographicSuitesSupported, true +} + +// HasCryptographicSuitesSupported returns a boolean if a field has been set. +func (o *CredentialSupportedDraft00) HasCryptographicSuitesSupported() bool { + if o != nil && !IsNil(o.CryptographicSuitesSupported) { + return true + } + + return false +} + +// SetCryptographicSuitesSupported gets a reference to the given []string and assigns it to the CryptographicSuitesSupported field. +func (o *CredentialSupportedDraft00) SetCryptographicSuitesSupported(v []string) { + o.CryptographicSuitesSupported = v +} + +// GetFormat returns the Format field value if set, zero value otherwise. +func (o *CredentialSupportedDraft00) GetFormat() string { + if o == nil || IsNil(o.Format) { + var ret string + return ret + } + return *o.Format +} + +// GetFormatOk returns a tuple with the Format field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CredentialSupportedDraft00) GetFormatOk() (*string, bool) { + if o == nil || IsNil(o.Format) { + return nil, false + } + return o.Format, true +} + +// HasFormat returns a boolean if a field has been set. +func (o *CredentialSupportedDraft00) HasFormat() bool { + if o != nil && !IsNil(o.Format) { + return true + } + + return false +} + +// SetFormat gets a reference to the given string and assigns it to the Format field. +func (o *CredentialSupportedDraft00) SetFormat(v string) { + o.Format = &v +} + +// GetTypes returns the Types field value if set, zero value otherwise. +func (o *CredentialSupportedDraft00) GetTypes() []string { + if o == nil || IsNil(o.Types) { + var ret []string + return ret + } + return o.Types +} + +// GetTypesOk returns a tuple with the Types field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *CredentialSupportedDraft00) GetTypesOk() ([]string, bool) { + if o == nil || IsNil(o.Types) { + return nil, false + } + return o.Types, true +} + +// HasTypes returns a boolean if a field has been set. +func (o *CredentialSupportedDraft00) HasTypes() bool { + if o != nil && !IsNil(o.Types) { + return true + } + + return false +} + +// SetTypes gets a reference to the given []string and assigns it to the Types field. +func (o *CredentialSupportedDraft00) SetTypes(v []string) { + o.Types = v +} + +func (o CredentialSupportedDraft00) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o CredentialSupportedDraft00) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.CryptographicBindingMethodsSupported) { + toSerialize["cryptographic_binding_methods_supported"] = o.CryptographicBindingMethodsSupported + } + if !IsNil(o.CryptographicSuitesSupported) { + toSerialize["cryptographic_suites_supported"] = o.CryptographicSuitesSupported + } + if !IsNil(o.Format) { + toSerialize["format"] = o.Format + } + if !IsNil(o.Types) { + toSerialize["types"] = o.Types + } + return toSerialize, nil +} + +type NullableCredentialSupportedDraft00 struct { + value *CredentialSupportedDraft00 + isSet bool +} + +func (v NullableCredentialSupportedDraft00) Get() *CredentialSupportedDraft00 { + return v.value +} + +func (v *NullableCredentialSupportedDraft00) Set(val *CredentialSupportedDraft00) { + v.value = val + v.isSet = true +} + +func (v NullableCredentialSupportedDraft00) IsSet() bool { + return v.isSet +} + +func (v *NullableCredentialSupportedDraft00) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableCredentialSupportedDraft00(val *CredentialSupportedDraft00) *NullableCredentialSupportedDraft00 { + return &NullableCredentialSupportedDraft00{value: val, isSet: true} +} + +func (v NullableCredentialSupportedDraft00) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableCredentialSupportedDraft00) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_error_o_auth2.go b/internal/httpclient/model_error_o_auth2.go index 47b81b55881..f8be4fca180 100644 --- a/internal/httpclient/model_error_o_auth2.go +++ b/internal/httpclient/model_error_o_auth2.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the ErrorOAuth2 type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &ErrorOAuth2{} + // ErrorOAuth2 Error type ErrorOAuth2 struct { // Error @@ -48,7 +51,7 @@ func NewErrorOAuth2WithDefaults() *ErrorOAuth2 { // GetError returns the Error field value if set, zero value otherwise. func (o *ErrorOAuth2) GetError() string { - if o == nil || o.Error == nil { + if o == nil || IsNil(o.Error) { var ret string return ret } @@ -58,7 +61,7 @@ func (o *ErrorOAuth2) GetError() string { // GetErrorOk returns a tuple with the Error field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *ErrorOAuth2) GetErrorOk() (*string, bool) { - if o == nil || o.Error == nil { + if o == nil || IsNil(o.Error) { return nil, false } return o.Error, true @@ -66,7 +69,7 @@ func (o *ErrorOAuth2) GetErrorOk() (*string, bool) { // HasError returns a boolean if a field has been set. func (o *ErrorOAuth2) HasError() bool { - if o != nil && o.Error != nil { + if o != nil && !IsNil(o.Error) { return true } @@ -80,7 +83,7 @@ func (o *ErrorOAuth2) SetError(v string) { // GetErrorDebug returns the ErrorDebug field value if set, zero value otherwise. func (o *ErrorOAuth2) GetErrorDebug() string { - if o == nil || o.ErrorDebug == nil { + if o == nil || IsNil(o.ErrorDebug) { var ret string return ret } @@ -90,7 +93,7 @@ func (o *ErrorOAuth2) GetErrorDebug() string { // GetErrorDebugOk returns a tuple with the ErrorDebug field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *ErrorOAuth2) GetErrorDebugOk() (*string, bool) { - if o == nil || o.ErrorDebug == nil { + if o == nil || IsNil(o.ErrorDebug) { return nil, false } return o.ErrorDebug, true @@ -98,7 +101,7 @@ func (o *ErrorOAuth2) GetErrorDebugOk() (*string, bool) { // HasErrorDebug returns a boolean if a field has been set. func (o *ErrorOAuth2) HasErrorDebug() bool { - if o != nil && o.ErrorDebug != nil { + if o != nil && !IsNil(o.ErrorDebug) { return true } @@ -112,7 +115,7 @@ func (o *ErrorOAuth2) SetErrorDebug(v string) { // GetErrorDescription returns the ErrorDescription field value if set, zero value otherwise. func (o *ErrorOAuth2) GetErrorDescription() string { - if o == nil || o.ErrorDescription == nil { + if o == nil || IsNil(o.ErrorDescription) { var ret string return ret } @@ -122,7 +125,7 @@ func (o *ErrorOAuth2) GetErrorDescription() string { // GetErrorDescriptionOk returns a tuple with the ErrorDescription field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *ErrorOAuth2) GetErrorDescriptionOk() (*string, bool) { - if o == nil || o.ErrorDescription == nil { + if o == nil || IsNil(o.ErrorDescription) { return nil, false } return o.ErrorDescription, true @@ -130,7 +133,7 @@ func (o *ErrorOAuth2) GetErrorDescriptionOk() (*string, bool) { // HasErrorDescription returns a boolean if a field has been set. func (o *ErrorOAuth2) HasErrorDescription() bool { - if o != nil && o.ErrorDescription != nil { + if o != nil && !IsNil(o.ErrorDescription) { return true } @@ -144,7 +147,7 @@ func (o *ErrorOAuth2) SetErrorDescription(v string) { // GetErrorHint returns the ErrorHint field value if set, zero value otherwise. func (o *ErrorOAuth2) GetErrorHint() string { - if o == nil || o.ErrorHint == nil { + if o == nil || IsNil(o.ErrorHint) { var ret string return ret } @@ -154,7 +157,7 @@ func (o *ErrorOAuth2) GetErrorHint() string { // GetErrorHintOk returns a tuple with the ErrorHint field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *ErrorOAuth2) GetErrorHintOk() (*string, bool) { - if o == nil || o.ErrorHint == nil { + if o == nil || IsNil(o.ErrorHint) { return nil, false } return o.ErrorHint, true @@ -162,7 +165,7 @@ func (o *ErrorOAuth2) GetErrorHintOk() (*string, bool) { // HasErrorHint returns a boolean if a field has been set. func (o *ErrorOAuth2) HasErrorHint() bool { - if o != nil && o.ErrorHint != nil { + if o != nil && !IsNil(o.ErrorHint) { return true } @@ -176,7 +179,7 @@ func (o *ErrorOAuth2) SetErrorHint(v string) { // GetStatusCode returns the StatusCode field value if set, zero value otherwise. func (o *ErrorOAuth2) GetStatusCode() int64 { - if o == nil || o.StatusCode == nil { + if o == nil || IsNil(o.StatusCode) { var ret int64 return ret } @@ -186,7 +189,7 @@ func (o *ErrorOAuth2) GetStatusCode() int64 { // GetStatusCodeOk returns a tuple with the StatusCode field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *ErrorOAuth2) GetStatusCodeOk() (*int64, bool) { - if o == nil || o.StatusCode == nil { + if o == nil || IsNil(o.StatusCode) { return nil, false } return o.StatusCode, true @@ -194,7 +197,7 @@ func (o *ErrorOAuth2) GetStatusCodeOk() (*int64, bool) { // HasStatusCode returns a boolean if a field has been set. func (o *ErrorOAuth2) HasStatusCode() bool { - if o != nil && o.StatusCode != nil { + if o != nil && !IsNil(o.StatusCode) { return true } @@ -207,23 +210,31 @@ func (o *ErrorOAuth2) SetStatusCode(v int64) { } func (o ErrorOAuth2) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o ErrorOAuth2) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Error != nil { + if !IsNil(o.Error) { toSerialize["error"] = o.Error } - if o.ErrorDebug != nil { + if !IsNil(o.ErrorDebug) { toSerialize["error_debug"] = o.ErrorDebug } - if o.ErrorDescription != nil { + if !IsNil(o.ErrorDescription) { toSerialize["error_description"] = o.ErrorDescription } - if o.ErrorHint != nil { + if !IsNil(o.ErrorHint) { toSerialize["error_hint"] = o.ErrorHint } - if o.StatusCode != nil { + if !IsNil(o.StatusCode) { toSerialize["status_code"] = o.StatusCode } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableErrorOAuth2 struct { diff --git a/internal/httpclient/model_generic_error.go b/internal/httpclient/model_generic_error.go index ad78dc23583..18838178f7e 100644 --- a/internal/httpclient/model_generic_error.go +++ b/internal/httpclient/model_generic_error.go @@ -12,9 +12,14 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the GenericError type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &GenericError{} + // GenericError struct for GenericError type GenericError struct { // The status code @@ -35,6 +40,8 @@ type GenericError struct { Status *string `json:"status,omitempty"` } +type _GenericError GenericError + // NewGenericError instantiates a new GenericError object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -55,7 +62,7 @@ func NewGenericErrorWithDefaults() *GenericError { // GetCode returns the Code field value if set, zero value otherwise. func (o *GenericError) GetCode() int64 { - if o == nil || o.Code == nil { + if o == nil || IsNil(o.Code) { var ret int64 return ret } @@ -65,7 +72,7 @@ func (o *GenericError) GetCode() int64 { // GetCodeOk returns a tuple with the Code field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *GenericError) GetCodeOk() (*int64, bool) { - if o == nil || o.Code == nil { + if o == nil || IsNil(o.Code) { return nil, false } return o.Code, true @@ -73,7 +80,7 @@ func (o *GenericError) GetCodeOk() (*int64, bool) { // HasCode returns a boolean if a field has been set. func (o *GenericError) HasCode() bool { - if o != nil && o.Code != nil { + if o != nil && !IsNil(o.Code) { return true } @@ -87,7 +94,7 @@ func (o *GenericError) SetCode(v int64) { // GetDebug returns the Debug field value if set, zero value otherwise. func (o *GenericError) GetDebug() string { - if o == nil || o.Debug == nil { + if o == nil || IsNil(o.Debug) { var ret string return ret } @@ -97,7 +104,7 @@ func (o *GenericError) GetDebug() string { // GetDebugOk returns a tuple with the Debug field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *GenericError) GetDebugOk() (*string, bool) { - if o == nil || o.Debug == nil { + if o == nil || IsNil(o.Debug) { return nil, false } return o.Debug, true @@ -105,7 +112,7 @@ func (o *GenericError) GetDebugOk() (*string, bool) { // HasDebug returns a boolean if a field has been set. func (o *GenericError) HasDebug() bool { - if o != nil && o.Debug != nil { + if o != nil && !IsNil(o.Debug) { return true } @@ -130,7 +137,7 @@ func (o *GenericError) GetDetails() interface{} { // and a boolean to check if the value has been set. // NOTE: If the value is an explicit nil, `nil, true` will be returned func (o *GenericError) GetDetailsOk() (*interface{}, bool) { - if o == nil || o.Details == nil { + if o == nil || IsNil(o.Details) { return nil, false } return &o.Details, true @@ -138,7 +145,7 @@ func (o *GenericError) GetDetailsOk() (*interface{}, bool) { // HasDetails returns a boolean if a field has been set. func (o *GenericError) HasDetails() bool { - if o != nil && o.Details != nil { + if o != nil && IsNil(o.Details) { return true } @@ -152,7 +159,7 @@ func (o *GenericError) SetDetails(v interface{}) { // GetId returns the Id field value if set, zero value otherwise. func (o *GenericError) GetId() string { - if o == nil || o.Id == nil { + if o == nil || IsNil(o.Id) { var ret string return ret } @@ -162,7 +169,7 @@ func (o *GenericError) GetId() string { // GetIdOk returns a tuple with the Id field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *GenericError) GetIdOk() (*string, bool) { - if o == nil || o.Id == nil { + if o == nil || IsNil(o.Id) { return nil, false } return o.Id, true @@ -170,7 +177,7 @@ func (o *GenericError) GetIdOk() (*string, bool) { // HasId returns a boolean if a field has been set. func (o *GenericError) HasId() bool { - if o != nil && o.Id != nil { + if o != nil && !IsNil(o.Id) { return true } @@ -208,7 +215,7 @@ func (o *GenericError) SetMessage(v string) { // GetReason returns the Reason field value if set, zero value otherwise. func (o *GenericError) GetReason() string { - if o == nil || o.Reason == nil { + if o == nil || IsNil(o.Reason) { var ret string return ret } @@ -218,7 +225,7 @@ func (o *GenericError) GetReason() string { // GetReasonOk returns a tuple with the Reason field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *GenericError) GetReasonOk() (*string, bool) { - if o == nil || o.Reason == nil { + if o == nil || IsNil(o.Reason) { return nil, false } return o.Reason, true @@ -226,7 +233,7 @@ func (o *GenericError) GetReasonOk() (*string, bool) { // HasReason returns a boolean if a field has been set. func (o *GenericError) HasReason() bool { - if o != nil && o.Reason != nil { + if o != nil && !IsNil(o.Reason) { return true } @@ -240,7 +247,7 @@ func (o *GenericError) SetReason(v string) { // GetRequest returns the Request field value if set, zero value otherwise. func (o *GenericError) GetRequest() string { - if o == nil || o.Request == nil { + if o == nil || IsNil(o.Request) { var ret string return ret } @@ -250,7 +257,7 @@ func (o *GenericError) GetRequest() string { // GetRequestOk returns a tuple with the Request field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *GenericError) GetRequestOk() (*string, bool) { - if o == nil || o.Request == nil { + if o == nil || IsNil(o.Request) { return nil, false } return o.Request, true @@ -258,7 +265,7 @@ func (o *GenericError) GetRequestOk() (*string, bool) { // HasRequest returns a boolean if a field has been set. func (o *GenericError) HasRequest() bool { - if o != nil && o.Request != nil { + if o != nil && !IsNil(o.Request) { return true } @@ -272,7 +279,7 @@ func (o *GenericError) SetRequest(v string) { // GetStatus returns the Status field value if set, zero value otherwise. func (o *GenericError) GetStatus() string { - if o == nil || o.Status == nil { + if o == nil || IsNil(o.Status) { var ret string return ret } @@ -282,7 +289,7 @@ func (o *GenericError) GetStatus() string { // GetStatusOk returns a tuple with the Status field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *GenericError) GetStatusOk() (*string, bool) { - if o == nil || o.Status == nil { + if o == nil || IsNil(o.Status) { return nil, false } return o.Status, true @@ -290,7 +297,7 @@ func (o *GenericError) GetStatusOk() (*string, bool) { // HasStatus returns a boolean if a field has been set. func (o *GenericError) HasStatus() bool { - if o != nil && o.Status != nil { + if o != nil && !IsNil(o.Status) { return true } @@ -303,32 +310,75 @@ func (o *GenericError) SetStatus(v string) { } func (o GenericError) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o GenericError) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Code != nil { + if !IsNil(o.Code) { toSerialize["code"] = o.Code } - if o.Debug != nil { + if !IsNil(o.Debug) { toSerialize["debug"] = o.Debug } if o.Details != nil { toSerialize["details"] = o.Details } - if o.Id != nil { + if !IsNil(o.Id) { toSerialize["id"] = o.Id } - if true { - toSerialize["message"] = o.Message - } - if o.Reason != nil { + toSerialize["message"] = o.Message + if !IsNil(o.Reason) { toSerialize["reason"] = o.Reason } - if o.Request != nil { + if !IsNil(o.Request) { toSerialize["request"] = o.Request } - if o.Status != nil { + if !IsNil(o.Status) { toSerialize["status"] = o.Status } - return json.Marshal(toSerialize) + return toSerialize, nil +} + +func (o *GenericError) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "message", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varGenericError := _GenericError{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varGenericError) + + if err != nil { + return err + } + + *o = GenericError(varGenericError) + + return err } type NullableGenericError struct { diff --git a/internal/httpclient/model_get_version_200_response.go b/internal/httpclient/model_get_version_200_response.go index d53f4a72dcb..d4b885e3011 100644 --- a/internal/httpclient/model_get_version_200_response.go +++ b/internal/httpclient/model_get_version_200_response.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the GetVersion200Response type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &GetVersion200Response{} + // GetVersion200Response struct for GetVersion200Response type GetVersion200Response struct { // The version of Ory Hydra. @@ -40,7 +43,7 @@ func NewGetVersion200ResponseWithDefaults() *GetVersion200Response { // GetVersion returns the Version field value if set, zero value otherwise. func (o *GetVersion200Response) GetVersion() string { - if o == nil || o.Version == nil { + if o == nil || IsNil(o.Version) { var ret string return ret } @@ -50,7 +53,7 @@ func (o *GetVersion200Response) GetVersion() string { // GetVersionOk returns a tuple with the Version field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *GetVersion200Response) GetVersionOk() (*string, bool) { - if o == nil || o.Version == nil { + if o == nil || IsNil(o.Version) { return nil, false } return o.Version, true @@ -58,7 +61,7 @@ func (o *GetVersion200Response) GetVersionOk() (*string, bool) { // HasVersion returns a boolean if a field has been set. func (o *GetVersion200Response) HasVersion() bool { - if o != nil && o.Version != nil { + if o != nil && !IsNil(o.Version) { return true } @@ -71,11 +74,19 @@ func (o *GetVersion200Response) SetVersion(v string) { } func (o GetVersion200Response) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o GetVersion200Response) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Version != nil { + if !IsNil(o.Version) { toSerialize["version"] = o.Version } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableGetVersion200Response struct { diff --git a/internal/httpclient/model_health_not_ready_status.go b/internal/httpclient/model_health_not_ready_status.go index 97ac1e0b8fc..1fcf0b32667 100644 --- a/internal/httpclient/model_health_not_ready_status.go +++ b/internal/httpclient/model_health_not_ready_status.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the HealthNotReadyStatus type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &HealthNotReadyStatus{} + // HealthNotReadyStatus struct for HealthNotReadyStatus type HealthNotReadyStatus struct { // Errors contains a list of errors that caused the not ready status. @@ -40,7 +43,7 @@ func NewHealthNotReadyStatusWithDefaults() *HealthNotReadyStatus { // GetErrors returns the Errors field value if set, zero value otherwise. func (o *HealthNotReadyStatus) GetErrors() map[string]string { - if o == nil || o.Errors == nil { + if o == nil || IsNil(o.Errors) { var ret map[string]string return ret } @@ -50,7 +53,7 @@ func (o *HealthNotReadyStatus) GetErrors() map[string]string { // GetErrorsOk returns a tuple with the Errors field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *HealthNotReadyStatus) GetErrorsOk() (*map[string]string, bool) { - if o == nil || o.Errors == nil { + if o == nil || IsNil(o.Errors) { return nil, false } return o.Errors, true @@ -58,7 +61,7 @@ func (o *HealthNotReadyStatus) GetErrorsOk() (*map[string]string, bool) { // HasErrors returns a boolean if a field has been set. func (o *HealthNotReadyStatus) HasErrors() bool { - if o != nil && o.Errors != nil { + if o != nil && !IsNil(o.Errors) { return true } @@ -71,11 +74,19 @@ func (o *HealthNotReadyStatus) SetErrors(v map[string]string) { } func (o HealthNotReadyStatus) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o HealthNotReadyStatus) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Errors != nil { + if !IsNil(o.Errors) { toSerialize["errors"] = o.Errors } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableHealthNotReadyStatus struct { diff --git a/internal/httpclient/model_health_status.go b/internal/httpclient/model_health_status.go index 193dc526174..20d626d914a 100644 --- a/internal/httpclient/model_health_status.go +++ b/internal/httpclient/model_health_status.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the HealthStatus type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &HealthStatus{} + // HealthStatus struct for HealthStatus type HealthStatus struct { // Status always contains \"ok\". @@ -40,7 +43,7 @@ func NewHealthStatusWithDefaults() *HealthStatus { // GetStatus returns the Status field value if set, zero value otherwise. func (o *HealthStatus) GetStatus() string { - if o == nil || o.Status == nil { + if o == nil || IsNil(o.Status) { var ret string return ret } @@ -50,7 +53,7 @@ func (o *HealthStatus) GetStatus() string { // GetStatusOk returns a tuple with the Status field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *HealthStatus) GetStatusOk() (*string, bool) { - if o == nil || o.Status == nil { + if o == nil || IsNil(o.Status) { return nil, false } return o.Status, true @@ -58,7 +61,7 @@ func (o *HealthStatus) GetStatusOk() (*string, bool) { // HasStatus returns a boolean if a field has been set. func (o *HealthStatus) HasStatus() bool { - if o != nil && o.Status != nil { + if o != nil && !IsNil(o.Status) { return true } @@ -71,11 +74,19 @@ func (o *HealthStatus) SetStatus(v string) { } func (o HealthStatus) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o HealthStatus) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Status != nil { + if !IsNil(o.Status) { toSerialize["status"] = o.Status } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableHealthStatus struct { diff --git a/internal/httpclient/model_introspected_o_auth2_token.go b/internal/httpclient/model_introspected_o_auth2_token.go index a7d55aff1c0..18929106342 100644 --- a/internal/httpclient/model_introspected_o_auth2_token.go +++ b/internal/httpclient/model_introspected_o_auth2_token.go @@ -12,9 +12,14 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the IntrospectedOAuth2Token type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &IntrospectedOAuth2Token{} + // IntrospectedOAuth2Token Introspection contains an access token's session data as specified by [IETF RFC 7662](https://tools.ietf.org/html/rfc7662) type IntrospectedOAuth2Token struct { // Active is a boolean indicator of whether or not the presented token is currently active. The specifics of a token's \"active\" state will vary depending on the implementation of the authorization server and the information it keeps about its tokens, but a \"true\" value return for the \"active\" property will generally indicate that a given token has been issued by this authorization server, has not been revoked by the resource owner, and is within its given time window of validity (e.g., after its issuance time and before its expiration time). @@ -47,6 +52,8 @@ type IntrospectedOAuth2Token struct { Username *string `json:"username,omitempty"` } +type _IntrospectedOAuth2Token IntrospectedOAuth2Token + // NewIntrospectedOAuth2Token instantiates a new IntrospectedOAuth2Token object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -91,7 +98,7 @@ func (o *IntrospectedOAuth2Token) SetActive(v bool) { // GetAud returns the Aud field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetAud() []string { - if o == nil || o.Aud == nil { + if o == nil || IsNil(o.Aud) { var ret []string return ret } @@ -101,7 +108,7 @@ func (o *IntrospectedOAuth2Token) GetAud() []string { // GetAudOk returns a tuple with the Aud field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetAudOk() ([]string, bool) { - if o == nil || o.Aud == nil { + if o == nil || IsNil(o.Aud) { return nil, false } return o.Aud, true @@ -109,7 +116,7 @@ func (o *IntrospectedOAuth2Token) GetAudOk() ([]string, bool) { // HasAud returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasAud() bool { - if o != nil && o.Aud != nil { + if o != nil && !IsNil(o.Aud) { return true } @@ -123,7 +130,7 @@ func (o *IntrospectedOAuth2Token) SetAud(v []string) { // GetClientId returns the ClientId field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetClientId() string { - if o == nil || o.ClientId == nil { + if o == nil || IsNil(o.ClientId) { var ret string return ret } @@ -133,7 +140,7 @@ func (o *IntrospectedOAuth2Token) GetClientId() string { // GetClientIdOk returns a tuple with the ClientId field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetClientIdOk() (*string, bool) { - if o == nil || o.ClientId == nil { + if o == nil || IsNil(o.ClientId) { return nil, false } return o.ClientId, true @@ -141,7 +148,7 @@ func (o *IntrospectedOAuth2Token) GetClientIdOk() (*string, bool) { // HasClientId returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasClientId() bool { - if o != nil && o.ClientId != nil { + if o != nil && !IsNil(o.ClientId) { return true } @@ -155,7 +162,7 @@ func (o *IntrospectedOAuth2Token) SetClientId(v string) { // GetExp returns the Exp field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetExp() int64 { - if o == nil || o.Exp == nil { + if o == nil || IsNil(o.Exp) { var ret int64 return ret } @@ -165,7 +172,7 @@ func (o *IntrospectedOAuth2Token) GetExp() int64 { // GetExpOk returns a tuple with the Exp field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetExpOk() (*int64, bool) { - if o == nil || o.Exp == nil { + if o == nil || IsNil(o.Exp) { return nil, false } return o.Exp, true @@ -173,7 +180,7 @@ func (o *IntrospectedOAuth2Token) GetExpOk() (*int64, bool) { // HasExp returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasExp() bool { - if o != nil && o.Exp != nil { + if o != nil && !IsNil(o.Exp) { return true } @@ -187,7 +194,7 @@ func (o *IntrospectedOAuth2Token) SetExp(v int64) { // GetExt returns the Ext field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetExt() map[string]interface{} { - if o == nil || o.Ext == nil { + if o == nil || IsNil(o.Ext) { var ret map[string]interface{} return ret } @@ -197,15 +204,15 @@ func (o *IntrospectedOAuth2Token) GetExt() map[string]interface{} { // GetExtOk returns a tuple with the Ext field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetExtOk() (map[string]interface{}, bool) { - if o == nil || o.Ext == nil { - return nil, false + if o == nil || IsNil(o.Ext) { + return map[string]interface{}{}, false } return o.Ext, true } // HasExt returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasExt() bool { - if o != nil && o.Ext != nil { + if o != nil && !IsNil(o.Ext) { return true } @@ -219,7 +226,7 @@ func (o *IntrospectedOAuth2Token) SetExt(v map[string]interface{}) { // GetIat returns the Iat field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetIat() int64 { - if o == nil || o.Iat == nil { + if o == nil || IsNil(o.Iat) { var ret int64 return ret } @@ -229,7 +236,7 @@ func (o *IntrospectedOAuth2Token) GetIat() int64 { // GetIatOk returns a tuple with the Iat field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetIatOk() (*int64, bool) { - if o == nil || o.Iat == nil { + if o == nil || IsNil(o.Iat) { return nil, false } return o.Iat, true @@ -237,7 +244,7 @@ func (o *IntrospectedOAuth2Token) GetIatOk() (*int64, bool) { // HasIat returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasIat() bool { - if o != nil && o.Iat != nil { + if o != nil && !IsNil(o.Iat) { return true } @@ -251,7 +258,7 @@ func (o *IntrospectedOAuth2Token) SetIat(v int64) { // GetIss returns the Iss field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetIss() string { - if o == nil || o.Iss == nil { + if o == nil || IsNil(o.Iss) { var ret string return ret } @@ -261,7 +268,7 @@ func (o *IntrospectedOAuth2Token) GetIss() string { // GetIssOk returns a tuple with the Iss field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetIssOk() (*string, bool) { - if o == nil || o.Iss == nil { + if o == nil || IsNil(o.Iss) { return nil, false } return o.Iss, true @@ -269,7 +276,7 @@ func (o *IntrospectedOAuth2Token) GetIssOk() (*string, bool) { // HasIss returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasIss() bool { - if o != nil && o.Iss != nil { + if o != nil && !IsNil(o.Iss) { return true } @@ -283,7 +290,7 @@ func (o *IntrospectedOAuth2Token) SetIss(v string) { // GetNbf returns the Nbf field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetNbf() int64 { - if o == nil || o.Nbf == nil { + if o == nil || IsNil(o.Nbf) { var ret int64 return ret } @@ -293,7 +300,7 @@ func (o *IntrospectedOAuth2Token) GetNbf() int64 { // GetNbfOk returns a tuple with the Nbf field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetNbfOk() (*int64, bool) { - if o == nil || o.Nbf == nil { + if o == nil || IsNil(o.Nbf) { return nil, false } return o.Nbf, true @@ -301,7 +308,7 @@ func (o *IntrospectedOAuth2Token) GetNbfOk() (*int64, bool) { // HasNbf returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasNbf() bool { - if o != nil && o.Nbf != nil { + if o != nil && !IsNil(o.Nbf) { return true } @@ -315,7 +322,7 @@ func (o *IntrospectedOAuth2Token) SetNbf(v int64) { // GetObfuscatedSubject returns the ObfuscatedSubject field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetObfuscatedSubject() string { - if o == nil || o.ObfuscatedSubject == nil { + if o == nil || IsNil(o.ObfuscatedSubject) { var ret string return ret } @@ -325,7 +332,7 @@ func (o *IntrospectedOAuth2Token) GetObfuscatedSubject() string { // GetObfuscatedSubjectOk returns a tuple with the ObfuscatedSubject field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetObfuscatedSubjectOk() (*string, bool) { - if o == nil || o.ObfuscatedSubject == nil { + if o == nil || IsNil(o.ObfuscatedSubject) { return nil, false } return o.ObfuscatedSubject, true @@ -333,7 +340,7 @@ func (o *IntrospectedOAuth2Token) GetObfuscatedSubjectOk() (*string, bool) { // HasObfuscatedSubject returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasObfuscatedSubject() bool { - if o != nil && o.ObfuscatedSubject != nil { + if o != nil && !IsNil(o.ObfuscatedSubject) { return true } @@ -347,7 +354,7 @@ func (o *IntrospectedOAuth2Token) SetObfuscatedSubject(v string) { // GetScope returns the Scope field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetScope() string { - if o == nil || o.Scope == nil { + if o == nil || IsNil(o.Scope) { var ret string return ret } @@ -357,7 +364,7 @@ func (o *IntrospectedOAuth2Token) GetScope() string { // GetScopeOk returns a tuple with the Scope field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetScopeOk() (*string, bool) { - if o == nil || o.Scope == nil { + if o == nil || IsNil(o.Scope) { return nil, false } return o.Scope, true @@ -365,7 +372,7 @@ func (o *IntrospectedOAuth2Token) GetScopeOk() (*string, bool) { // HasScope returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasScope() bool { - if o != nil && o.Scope != nil { + if o != nil && !IsNil(o.Scope) { return true } @@ -379,7 +386,7 @@ func (o *IntrospectedOAuth2Token) SetScope(v string) { // GetSub returns the Sub field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetSub() string { - if o == nil || o.Sub == nil { + if o == nil || IsNil(o.Sub) { var ret string return ret } @@ -389,7 +396,7 @@ func (o *IntrospectedOAuth2Token) GetSub() string { // GetSubOk returns a tuple with the Sub field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetSubOk() (*string, bool) { - if o == nil || o.Sub == nil { + if o == nil || IsNil(o.Sub) { return nil, false } return o.Sub, true @@ -397,7 +404,7 @@ func (o *IntrospectedOAuth2Token) GetSubOk() (*string, bool) { // HasSub returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasSub() bool { - if o != nil && o.Sub != nil { + if o != nil && !IsNil(o.Sub) { return true } @@ -411,7 +418,7 @@ func (o *IntrospectedOAuth2Token) SetSub(v string) { // GetTokenType returns the TokenType field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetTokenType() string { - if o == nil || o.TokenType == nil { + if o == nil || IsNil(o.TokenType) { var ret string return ret } @@ -421,7 +428,7 @@ func (o *IntrospectedOAuth2Token) GetTokenType() string { // GetTokenTypeOk returns a tuple with the TokenType field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetTokenTypeOk() (*string, bool) { - if o == nil || o.TokenType == nil { + if o == nil || IsNil(o.TokenType) { return nil, false } return o.TokenType, true @@ -429,7 +436,7 @@ func (o *IntrospectedOAuth2Token) GetTokenTypeOk() (*string, bool) { // HasTokenType returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasTokenType() bool { - if o != nil && o.TokenType != nil { + if o != nil && !IsNil(o.TokenType) { return true } @@ -443,7 +450,7 @@ func (o *IntrospectedOAuth2Token) SetTokenType(v string) { // GetTokenUse returns the TokenUse field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetTokenUse() string { - if o == nil || o.TokenUse == nil { + if o == nil || IsNil(o.TokenUse) { var ret string return ret } @@ -453,7 +460,7 @@ func (o *IntrospectedOAuth2Token) GetTokenUse() string { // GetTokenUseOk returns a tuple with the TokenUse field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetTokenUseOk() (*string, bool) { - if o == nil || o.TokenUse == nil { + if o == nil || IsNil(o.TokenUse) { return nil, false } return o.TokenUse, true @@ -461,7 +468,7 @@ func (o *IntrospectedOAuth2Token) GetTokenUseOk() (*string, bool) { // HasTokenUse returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasTokenUse() bool { - if o != nil && o.TokenUse != nil { + if o != nil && !IsNil(o.TokenUse) { return true } @@ -475,7 +482,7 @@ func (o *IntrospectedOAuth2Token) SetTokenUse(v string) { // GetUsername returns the Username field value if set, zero value otherwise. func (o *IntrospectedOAuth2Token) GetUsername() string { - if o == nil || o.Username == nil { + if o == nil || IsNil(o.Username) { var ret string return ret } @@ -485,7 +492,7 @@ func (o *IntrospectedOAuth2Token) GetUsername() string { // GetUsernameOk returns a tuple with the Username field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IntrospectedOAuth2Token) GetUsernameOk() (*string, bool) { - if o == nil || o.Username == nil { + if o == nil || IsNil(o.Username) { return nil, false } return o.Username, true @@ -493,7 +500,7 @@ func (o *IntrospectedOAuth2Token) GetUsernameOk() (*string, bool) { // HasUsername returns a boolean if a field has been set. func (o *IntrospectedOAuth2Token) HasUsername() bool { - if o != nil && o.Username != nil { + if o != nil && !IsNil(o.Username) { return true } @@ -506,50 +513,93 @@ func (o *IntrospectedOAuth2Token) SetUsername(v string) { } func (o IntrospectedOAuth2Token) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["active"] = o.Active + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err } - if o.Aud != nil { + return json.Marshal(toSerialize) +} + +func (o IntrospectedOAuth2Token) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["active"] = o.Active + if !IsNil(o.Aud) { toSerialize["aud"] = o.Aud } - if o.ClientId != nil { + if !IsNil(o.ClientId) { toSerialize["client_id"] = o.ClientId } - if o.Exp != nil { + if !IsNil(o.Exp) { toSerialize["exp"] = o.Exp } - if o.Ext != nil { + if !IsNil(o.Ext) { toSerialize["ext"] = o.Ext } - if o.Iat != nil { + if !IsNil(o.Iat) { toSerialize["iat"] = o.Iat } - if o.Iss != nil { + if !IsNil(o.Iss) { toSerialize["iss"] = o.Iss } - if o.Nbf != nil { + if !IsNil(o.Nbf) { toSerialize["nbf"] = o.Nbf } - if o.ObfuscatedSubject != nil { + if !IsNil(o.ObfuscatedSubject) { toSerialize["obfuscated_subject"] = o.ObfuscatedSubject } - if o.Scope != nil { + if !IsNil(o.Scope) { toSerialize["scope"] = o.Scope } - if o.Sub != nil { + if !IsNil(o.Sub) { toSerialize["sub"] = o.Sub } - if o.TokenType != nil { + if !IsNil(o.TokenType) { toSerialize["token_type"] = o.TokenType } - if o.TokenUse != nil { + if !IsNil(o.TokenUse) { toSerialize["token_use"] = o.TokenUse } - if o.Username != nil { + if !IsNil(o.Username) { toSerialize["username"] = o.Username } - return json.Marshal(toSerialize) + return toSerialize, nil +} + +func (o *IntrospectedOAuth2Token) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "active", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varIntrospectedOAuth2Token := _IntrospectedOAuth2Token{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varIntrospectedOAuth2Token) + + if err != nil { + return err + } + + *o = IntrospectedOAuth2Token(varIntrospectedOAuth2Token) + + return err } type NullableIntrospectedOAuth2Token struct { diff --git a/internal/httpclient/model_is_ready_200_response.go b/internal/httpclient/model_is_ready_200_response.go index f7b8957c70f..8a44bacc885 100644 --- a/internal/httpclient/model_is_ready_200_response.go +++ b/internal/httpclient/model_is_ready_200_response.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the IsReady200Response type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &IsReady200Response{} + // IsReady200Response struct for IsReady200Response type IsReady200Response struct { // Always \"ok\". @@ -40,7 +43,7 @@ func NewIsReady200ResponseWithDefaults() *IsReady200Response { // GetStatus returns the Status field value if set, zero value otherwise. func (o *IsReady200Response) GetStatus() string { - if o == nil || o.Status == nil { + if o == nil || IsNil(o.Status) { var ret string return ret } @@ -50,7 +53,7 @@ func (o *IsReady200Response) GetStatus() string { // GetStatusOk returns a tuple with the Status field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IsReady200Response) GetStatusOk() (*string, bool) { - if o == nil || o.Status == nil { + if o == nil || IsNil(o.Status) { return nil, false } return o.Status, true @@ -58,7 +61,7 @@ func (o *IsReady200Response) GetStatusOk() (*string, bool) { // HasStatus returns a boolean if a field has been set. func (o *IsReady200Response) HasStatus() bool { - if o != nil && o.Status != nil { + if o != nil && !IsNil(o.Status) { return true } @@ -71,11 +74,19 @@ func (o *IsReady200Response) SetStatus(v string) { } func (o IsReady200Response) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o IsReady200Response) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Status != nil { + if !IsNil(o.Status) { toSerialize["status"] = o.Status } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableIsReady200Response struct { diff --git a/internal/httpclient/model_is_ready_503_response.go b/internal/httpclient/model_is_ready_503_response.go index 14788440b2b..f0696c01c6f 100644 --- a/internal/httpclient/model_is_ready_503_response.go +++ b/internal/httpclient/model_is_ready_503_response.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the IsReady503Response type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &IsReady503Response{} + // IsReady503Response struct for IsReady503Response type IsReady503Response struct { // Errors contains a list of errors that caused the not ready status. @@ -40,7 +43,7 @@ func NewIsReady503ResponseWithDefaults() *IsReady503Response { // GetErrors returns the Errors field value if set, zero value otherwise. func (o *IsReady503Response) GetErrors() map[string]string { - if o == nil || o.Errors == nil { + if o == nil || IsNil(o.Errors) { var ret map[string]string return ret } @@ -50,7 +53,7 @@ func (o *IsReady503Response) GetErrors() map[string]string { // GetErrorsOk returns a tuple with the Errors field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *IsReady503Response) GetErrorsOk() (*map[string]string, bool) { - if o == nil || o.Errors == nil { + if o == nil || IsNil(o.Errors) { return nil, false } return o.Errors, true @@ -58,7 +61,7 @@ func (o *IsReady503Response) GetErrorsOk() (*map[string]string, bool) { // HasErrors returns a boolean if a field has been set. func (o *IsReady503Response) HasErrors() bool { - if o != nil && o.Errors != nil { + if o != nil && !IsNil(o.Errors) { return true } @@ -71,11 +74,19 @@ func (o *IsReady503Response) SetErrors(v map[string]string) { } func (o IsReady503Response) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o IsReady503Response) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Errors != nil { + if !IsNil(o.Errors) { toSerialize["errors"] = o.Errors } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableIsReady503Response struct { diff --git a/internal/httpclient/model_json_patch.go b/internal/httpclient/model_json_patch.go index 4489698fd83..ec1b6786d0e 100644 --- a/internal/httpclient/model_json_patch.go +++ b/internal/httpclient/model_json_patch.go @@ -12,9 +12,14 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the JsonPatch type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &JsonPatch{} + // JsonPatch A JSONPatch document as defined by RFC 6902 type JsonPatch struct { // This field is used together with operation \"move\" and uses JSON Pointer notation. Learn more [about JSON Pointers](https://datatracker.ietf.org/doc/html/rfc6901#section-5). @@ -27,6 +32,8 @@ type JsonPatch struct { Value interface{} `json:"value,omitempty"` } +type _JsonPatch JsonPatch + // NewJsonPatch instantiates a new JsonPatch object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -48,7 +55,7 @@ func NewJsonPatchWithDefaults() *JsonPatch { // GetFrom returns the From field value if set, zero value otherwise. func (o *JsonPatch) GetFrom() string { - if o == nil || o.From == nil { + if o == nil || IsNil(o.From) { var ret string return ret } @@ -58,7 +65,7 @@ func (o *JsonPatch) GetFrom() string { // GetFromOk returns a tuple with the From field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonPatch) GetFromOk() (*string, bool) { - if o == nil || o.From == nil { + if o == nil || IsNil(o.From) { return nil, false } return o.From, true @@ -66,7 +73,7 @@ func (o *JsonPatch) GetFromOk() (*string, bool) { // HasFrom returns a boolean if a field has been set. func (o *JsonPatch) HasFrom() bool { - if o != nil && o.From != nil { + if o != nil && !IsNil(o.From) { return true } @@ -139,7 +146,7 @@ func (o *JsonPatch) GetValue() interface{} { // and a boolean to check if the value has been set. // NOTE: If the value is an explicit nil, `nil, true` will be returned func (o *JsonPatch) GetValueOk() (*interface{}, bool) { - if o == nil || o.Value == nil { + if o == nil || IsNil(o.Value) { return nil, false } return &o.Value, true @@ -147,7 +154,7 @@ func (o *JsonPatch) GetValueOk() (*interface{}, bool) { // HasValue returns a boolean if a field has been set. func (o *JsonPatch) HasValue() bool { - if o != nil && o.Value != nil { + if o != nil && IsNil(o.Value) { return true } @@ -160,20 +167,62 @@ func (o *JsonPatch) SetValue(v interface{}) { } func (o JsonPatch) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o JsonPatch) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.From != nil { + if !IsNil(o.From) { toSerialize["from"] = o.From } - if true { - toSerialize["op"] = o.Op - } - if true { - toSerialize["path"] = o.Path - } + toSerialize["op"] = o.Op + toSerialize["path"] = o.Path if o.Value != nil { toSerialize["value"] = o.Value } - return json.Marshal(toSerialize) + return toSerialize, nil +} + +func (o *JsonPatch) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "op", + "path", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varJsonPatch := _JsonPatch{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varJsonPatch) + + if err != nil { + return err + } + + *o = JsonPatch(varJsonPatch) + + return err } type NullableJsonPatch struct { diff --git a/internal/httpclient/model_json_web_key.go b/internal/httpclient/model_json_web_key.go index a56124b5ec1..c10a80c8fe9 100644 --- a/internal/httpclient/model_json_web_key.go +++ b/internal/httpclient/model_json_web_key.go @@ -12,9 +12,14 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the JsonWebKey type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &JsonWebKey{} + // JsonWebKey struct for JsonWebKey type JsonWebKey struct { // The \"alg\" (algorithm) parameter identifies the algorithm intended for use with the key. The values used should either be registered in the IANA \"JSON Web Signature and Encryption Algorithms\" registry established by [JWA] or be a value that contains a Collision- Resistant Name. @@ -41,6 +46,8 @@ type JsonWebKey struct { Y *string `json:"y,omitempty"` } +type _JsonWebKey JsonWebKey + // NewJsonWebKey instantiates a new JsonWebKey object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -88,7 +95,7 @@ func (o *JsonWebKey) SetAlg(v string) { // GetCrv returns the Crv field value if set, zero value otherwise. func (o *JsonWebKey) GetCrv() string { - if o == nil || o.Crv == nil { + if o == nil || IsNil(o.Crv) { var ret string return ret } @@ -98,7 +105,7 @@ func (o *JsonWebKey) GetCrv() string { // GetCrvOk returns a tuple with the Crv field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetCrvOk() (*string, bool) { - if o == nil || o.Crv == nil { + if o == nil || IsNil(o.Crv) { return nil, false } return o.Crv, true @@ -106,7 +113,7 @@ func (o *JsonWebKey) GetCrvOk() (*string, bool) { // HasCrv returns a boolean if a field has been set. func (o *JsonWebKey) HasCrv() bool { - if o != nil && o.Crv != nil { + if o != nil && !IsNil(o.Crv) { return true } @@ -120,7 +127,7 @@ func (o *JsonWebKey) SetCrv(v string) { // GetD returns the D field value if set, zero value otherwise. func (o *JsonWebKey) GetD() string { - if o == nil || o.D == nil { + if o == nil || IsNil(o.D) { var ret string return ret } @@ -130,7 +137,7 @@ func (o *JsonWebKey) GetD() string { // GetDOk returns a tuple with the D field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetDOk() (*string, bool) { - if o == nil || o.D == nil { + if o == nil || IsNil(o.D) { return nil, false } return o.D, true @@ -138,7 +145,7 @@ func (o *JsonWebKey) GetDOk() (*string, bool) { // HasD returns a boolean if a field has been set. func (o *JsonWebKey) HasD() bool { - if o != nil && o.D != nil { + if o != nil && !IsNil(o.D) { return true } @@ -152,7 +159,7 @@ func (o *JsonWebKey) SetD(v string) { // GetDp returns the Dp field value if set, zero value otherwise. func (o *JsonWebKey) GetDp() string { - if o == nil || o.Dp == nil { + if o == nil || IsNil(o.Dp) { var ret string return ret } @@ -162,7 +169,7 @@ func (o *JsonWebKey) GetDp() string { // GetDpOk returns a tuple with the Dp field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetDpOk() (*string, bool) { - if o == nil || o.Dp == nil { + if o == nil || IsNil(o.Dp) { return nil, false } return o.Dp, true @@ -170,7 +177,7 @@ func (o *JsonWebKey) GetDpOk() (*string, bool) { // HasDp returns a boolean if a field has been set. func (o *JsonWebKey) HasDp() bool { - if o != nil && o.Dp != nil { + if o != nil && !IsNil(o.Dp) { return true } @@ -184,7 +191,7 @@ func (o *JsonWebKey) SetDp(v string) { // GetDq returns the Dq field value if set, zero value otherwise. func (o *JsonWebKey) GetDq() string { - if o == nil || o.Dq == nil { + if o == nil || IsNil(o.Dq) { var ret string return ret } @@ -194,7 +201,7 @@ func (o *JsonWebKey) GetDq() string { // GetDqOk returns a tuple with the Dq field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetDqOk() (*string, bool) { - if o == nil || o.Dq == nil { + if o == nil || IsNil(o.Dq) { return nil, false } return o.Dq, true @@ -202,7 +209,7 @@ func (o *JsonWebKey) GetDqOk() (*string, bool) { // HasDq returns a boolean if a field has been set. func (o *JsonWebKey) HasDq() bool { - if o != nil && o.Dq != nil { + if o != nil && !IsNil(o.Dq) { return true } @@ -216,7 +223,7 @@ func (o *JsonWebKey) SetDq(v string) { // GetE returns the E field value if set, zero value otherwise. func (o *JsonWebKey) GetE() string { - if o == nil || o.E == nil { + if o == nil || IsNil(o.E) { var ret string return ret } @@ -226,7 +233,7 @@ func (o *JsonWebKey) GetE() string { // GetEOk returns a tuple with the E field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetEOk() (*string, bool) { - if o == nil || o.E == nil { + if o == nil || IsNil(o.E) { return nil, false } return o.E, true @@ -234,7 +241,7 @@ func (o *JsonWebKey) GetEOk() (*string, bool) { // HasE returns a boolean if a field has been set. func (o *JsonWebKey) HasE() bool { - if o != nil && o.E != nil { + if o != nil && !IsNil(o.E) { return true } @@ -248,7 +255,7 @@ func (o *JsonWebKey) SetE(v string) { // GetK returns the K field value if set, zero value otherwise. func (o *JsonWebKey) GetK() string { - if o == nil || o.K == nil { + if o == nil || IsNil(o.K) { var ret string return ret } @@ -258,7 +265,7 @@ func (o *JsonWebKey) GetK() string { // GetKOk returns a tuple with the K field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetKOk() (*string, bool) { - if o == nil || o.K == nil { + if o == nil || IsNil(o.K) { return nil, false } return o.K, true @@ -266,7 +273,7 @@ func (o *JsonWebKey) GetKOk() (*string, bool) { // HasK returns a boolean if a field has been set. func (o *JsonWebKey) HasK() bool { - if o != nil && o.K != nil { + if o != nil && !IsNil(o.K) { return true } @@ -328,7 +335,7 @@ func (o *JsonWebKey) SetKty(v string) { // GetN returns the N field value if set, zero value otherwise. func (o *JsonWebKey) GetN() string { - if o == nil || o.N == nil { + if o == nil || IsNil(o.N) { var ret string return ret } @@ -338,7 +345,7 @@ func (o *JsonWebKey) GetN() string { // GetNOk returns a tuple with the N field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetNOk() (*string, bool) { - if o == nil || o.N == nil { + if o == nil || IsNil(o.N) { return nil, false } return o.N, true @@ -346,7 +353,7 @@ func (o *JsonWebKey) GetNOk() (*string, bool) { // HasN returns a boolean if a field has been set. func (o *JsonWebKey) HasN() bool { - if o != nil && o.N != nil { + if o != nil && !IsNil(o.N) { return true } @@ -360,7 +367,7 @@ func (o *JsonWebKey) SetN(v string) { // GetP returns the P field value if set, zero value otherwise. func (o *JsonWebKey) GetP() string { - if o == nil || o.P == nil { + if o == nil || IsNil(o.P) { var ret string return ret } @@ -370,7 +377,7 @@ func (o *JsonWebKey) GetP() string { // GetPOk returns a tuple with the P field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetPOk() (*string, bool) { - if o == nil || o.P == nil { + if o == nil || IsNil(o.P) { return nil, false } return o.P, true @@ -378,7 +385,7 @@ func (o *JsonWebKey) GetPOk() (*string, bool) { // HasP returns a boolean if a field has been set. func (o *JsonWebKey) HasP() bool { - if o != nil && o.P != nil { + if o != nil && !IsNil(o.P) { return true } @@ -392,7 +399,7 @@ func (o *JsonWebKey) SetP(v string) { // GetQ returns the Q field value if set, zero value otherwise. func (o *JsonWebKey) GetQ() string { - if o == nil || o.Q == nil { + if o == nil || IsNil(o.Q) { var ret string return ret } @@ -402,7 +409,7 @@ func (o *JsonWebKey) GetQ() string { // GetQOk returns a tuple with the Q field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetQOk() (*string, bool) { - if o == nil || o.Q == nil { + if o == nil || IsNil(o.Q) { return nil, false } return o.Q, true @@ -410,7 +417,7 @@ func (o *JsonWebKey) GetQOk() (*string, bool) { // HasQ returns a boolean if a field has been set. func (o *JsonWebKey) HasQ() bool { - if o != nil && o.Q != nil { + if o != nil && !IsNil(o.Q) { return true } @@ -424,7 +431,7 @@ func (o *JsonWebKey) SetQ(v string) { // GetQi returns the Qi field value if set, zero value otherwise. func (o *JsonWebKey) GetQi() string { - if o == nil || o.Qi == nil { + if o == nil || IsNil(o.Qi) { var ret string return ret } @@ -434,7 +441,7 @@ func (o *JsonWebKey) GetQi() string { // GetQiOk returns a tuple with the Qi field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetQiOk() (*string, bool) { - if o == nil || o.Qi == nil { + if o == nil || IsNil(o.Qi) { return nil, false } return o.Qi, true @@ -442,7 +449,7 @@ func (o *JsonWebKey) GetQiOk() (*string, bool) { // HasQi returns a boolean if a field has been set. func (o *JsonWebKey) HasQi() bool { - if o != nil && o.Qi != nil { + if o != nil && !IsNil(o.Qi) { return true } @@ -480,7 +487,7 @@ func (o *JsonWebKey) SetUse(v string) { // GetX returns the X field value if set, zero value otherwise. func (o *JsonWebKey) GetX() string { - if o == nil || o.X == nil { + if o == nil || IsNil(o.X) { var ret string return ret } @@ -490,7 +497,7 @@ func (o *JsonWebKey) GetX() string { // GetXOk returns a tuple with the X field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetXOk() (*string, bool) { - if o == nil || o.X == nil { + if o == nil || IsNil(o.X) { return nil, false } return o.X, true @@ -498,7 +505,7 @@ func (o *JsonWebKey) GetXOk() (*string, bool) { // HasX returns a boolean if a field has been set. func (o *JsonWebKey) HasX() bool { - if o != nil && o.X != nil { + if o != nil && !IsNil(o.X) { return true } @@ -512,7 +519,7 @@ func (o *JsonWebKey) SetX(v string) { // GetX5c returns the X5c field value if set, zero value otherwise. func (o *JsonWebKey) GetX5c() []string { - if o == nil || o.X5c == nil { + if o == nil || IsNil(o.X5c) { var ret []string return ret } @@ -522,7 +529,7 @@ func (o *JsonWebKey) GetX5c() []string { // GetX5cOk returns a tuple with the X5c field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetX5cOk() ([]string, bool) { - if o == nil || o.X5c == nil { + if o == nil || IsNil(o.X5c) { return nil, false } return o.X5c, true @@ -530,7 +537,7 @@ func (o *JsonWebKey) GetX5cOk() ([]string, bool) { // HasX5c returns a boolean if a field has been set. func (o *JsonWebKey) HasX5c() bool { - if o != nil && o.X5c != nil { + if o != nil && !IsNil(o.X5c) { return true } @@ -544,7 +551,7 @@ func (o *JsonWebKey) SetX5c(v []string) { // GetY returns the Y field value if set, zero value otherwise. func (o *JsonWebKey) GetY() string { - if o == nil || o.Y == nil { + if o == nil || IsNil(o.Y) { var ret string return ret } @@ -554,7 +561,7 @@ func (o *JsonWebKey) GetY() string { // GetYOk returns a tuple with the Y field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKey) GetYOk() (*string, bool) { - if o == nil || o.Y == nil { + if o == nil || IsNil(o.Y) { return nil, false } return o.Y, true @@ -562,7 +569,7 @@ func (o *JsonWebKey) GetYOk() (*string, bool) { // HasY returns a boolean if a field has been set. func (o *JsonWebKey) HasY() bool { - if o != nil && o.Y != nil { + if o != nil && !IsNil(o.Y) { return true } @@ -575,59 +582,99 @@ func (o *JsonWebKey) SetY(v string) { } func (o JsonWebKey) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["alg"] = o.Alg + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err } - if o.Crv != nil { + return json.Marshal(toSerialize) +} + +func (o JsonWebKey) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["alg"] = o.Alg + if !IsNil(o.Crv) { toSerialize["crv"] = o.Crv } - if o.D != nil { + if !IsNil(o.D) { toSerialize["d"] = o.D } - if o.Dp != nil { + if !IsNil(o.Dp) { toSerialize["dp"] = o.Dp } - if o.Dq != nil { + if !IsNil(o.Dq) { toSerialize["dq"] = o.Dq } - if o.E != nil { + if !IsNil(o.E) { toSerialize["e"] = o.E } - if o.K != nil { + if !IsNil(o.K) { toSerialize["k"] = o.K } - if true { - toSerialize["kid"] = o.Kid - } - if true { - toSerialize["kty"] = o.Kty - } - if o.N != nil { + toSerialize["kid"] = o.Kid + toSerialize["kty"] = o.Kty + if !IsNil(o.N) { toSerialize["n"] = o.N } - if o.P != nil { + if !IsNil(o.P) { toSerialize["p"] = o.P } - if o.Q != nil { + if !IsNil(o.Q) { toSerialize["q"] = o.Q } - if o.Qi != nil { + if !IsNil(o.Qi) { toSerialize["qi"] = o.Qi } - if true { - toSerialize["use"] = o.Use - } - if o.X != nil { + toSerialize["use"] = o.Use + if !IsNil(o.X) { toSerialize["x"] = o.X } - if o.X5c != nil { + if !IsNil(o.X5c) { toSerialize["x5c"] = o.X5c } - if o.Y != nil { + if !IsNil(o.Y) { toSerialize["y"] = o.Y } - return json.Marshal(toSerialize) + return toSerialize, nil +} + +func (o *JsonWebKey) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "alg", + "kid", + "kty", + "use", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varJsonWebKey := _JsonWebKey{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varJsonWebKey) + + if err != nil { + return err + } + + *o = JsonWebKey(varJsonWebKey) + + return err } type NullableJsonWebKey struct { diff --git a/internal/httpclient/model_json_web_key_set.go b/internal/httpclient/model_json_web_key_set.go index 6d328f6615d..28820351167 100644 --- a/internal/httpclient/model_json_web_key_set.go +++ b/internal/httpclient/model_json_web_key_set.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the JsonWebKeySet type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &JsonWebKeySet{} + // JsonWebKeySet JSON Web Key Set type JsonWebKeySet struct { // List of JSON Web Keys The value of the \"keys\" parameter is an array of JSON Web Key (JWK) values. By default, the order of the JWK values within the array does not imply an order of preference among them, although applications of JWK Sets can choose to assign a meaning to the order for their purposes, if desired. @@ -40,7 +43,7 @@ func NewJsonWebKeySetWithDefaults() *JsonWebKeySet { // GetKeys returns the Keys field value if set, zero value otherwise. func (o *JsonWebKeySet) GetKeys() []JsonWebKey { - if o == nil || o.Keys == nil { + if o == nil || IsNil(o.Keys) { var ret []JsonWebKey return ret } @@ -50,7 +53,7 @@ func (o *JsonWebKeySet) GetKeys() []JsonWebKey { // GetKeysOk returns a tuple with the Keys field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *JsonWebKeySet) GetKeysOk() ([]JsonWebKey, bool) { - if o == nil || o.Keys == nil { + if o == nil || IsNil(o.Keys) { return nil, false } return o.Keys, true @@ -58,7 +61,7 @@ func (o *JsonWebKeySet) GetKeysOk() ([]JsonWebKey, bool) { // HasKeys returns a boolean if a field has been set. func (o *JsonWebKeySet) HasKeys() bool { - if o != nil && o.Keys != nil { + if o != nil && !IsNil(o.Keys) { return true } @@ -71,11 +74,19 @@ func (o *JsonWebKeySet) SetKeys(v []JsonWebKey) { } func (o JsonWebKeySet) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o JsonWebKeySet) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Keys != nil { + if !IsNil(o.Keys) { toSerialize["keys"] = o.Keys } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableJsonWebKeySet struct { diff --git a/internal/httpclient/model_o_auth2_client.go b/internal/httpclient/model_o_auth2_client.go index 976219bd5e4..96fc7da4003 100644 --- a/internal/httpclient/model_o_auth2_client.go +++ b/internal/httpclient/model_o_auth2_client.go @@ -16,10 +16,15 @@ import ( "time" ) +// checks if the OAuth2Client type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2Client{} + // OAuth2Client OAuth 2.0 Clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are generated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities. type OAuth2Client struct { - AllowedCorsOrigins []string `json:"allowed_cors_origins,omitempty"` - Audience []string `json:"audience,omitempty"` + // OAuth 2.0 Access Token Strategy AccessTokenStrategy is the strategy used to generate access tokens. Valid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens Setting the stragegy here overrides the global setting in `strategies.access_token`. + AccessTokenStrategy *string `json:"access_token_strategy,omitempty"` + AllowedCorsOrigins []string `json:"allowed_cors_origins,omitempty"` + Audience []string `json:"audience,omitempty"` // Specify a time duration in milliseconds, seconds, minutes, hours. AuthorizationCodeGrantAccessTokenLifespan *string `json:"authorization_code_grant_access_token_lifespan,omitempty"` // Specify a time duration in milliseconds, seconds, minutes, hours. @@ -32,7 +37,7 @@ type OAuth2Client struct { BackchannelLogoutUri *string `json:"backchannel_logout_uri,omitempty"` // Specify a time duration in milliseconds, seconds, minutes, hours. ClientCredentialsGrantAccessTokenLifespan *string `json:"client_credentials_grant_access_token_lifespan,omitempty"` - // OAuth 2.0 Client ID The ID is autogenerated and immutable. + // OAuth 2.0 Client ID The ID is immutable. If no ID is provided, a UUID4 will be generated. ClientId *string `json:"client_id,omitempty"` // OAuth 2.0 Client Name The human-readable name of the client to be presented to the end-user during authorization. ClientName *string `json:"client_name,omitempty"` @@ -87,9 +92,13 @@ type OAuth2Client struct { Scope *string `json:"scope,omitempty"` // OpenID Connect Sector Identifier URI URL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. The URL references a file with a single JSON array of redirect_uri values. SectorIdentifierUri *string `json:"sector_identifier_uri,omitempty"` + // SkipConsent skips the consent screen for this client. This field can only be set from the admin API. + SkipConsent *bool `json:"skip_consent,omitempty"` + // SkipLogoutConsent skips the logout consent screen for this client. This field can only be set from the admin API. + SkipLogoutConsent *bool `json:"skip_logout_consent,omitempty"` // OpenID Connect Subject Type The `subject_types_supported` Discovery parameter contains a list of the supported subject_type values for this server. Valid types include `pairwise` and `public`. SubjectType *string `json:"subject_type,omitempty"` - // OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_post`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `client_secret_basic`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. + // OAuth 2.0 Token Endpoint Authentication Method Requested Client Authentication method for the Token Endpoint. The options are: `client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header. `client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body. `private_key_jwt`: Use JSON Web Tokens to authenticate the client. `none`: Used for public clients (native apps, mobile apps) which can not have secrets. TokenEndpointAuthMethod *string `json:"token_endpoint_auth_method,omitempty"` // OAuth 2.0 Token Endpoint Signing Algorithm Requested Client Authentication signing algorithm for the Token Endpoint. TokenEndpointAuthSigningAlg *string `json:"token_endpoint_auth_signing_alg,omitempty"` @@ -107,6 +116,8 @@ type OAuth2Client struct { // will change when the set of required properties is changed func NewOAuth2Client() *OAuth2Client { this := OAuth2Client{} + var tokenEndpointAuthMethod string = "client_secret_basic" + this.TokenEndpointAuthMethod = &tokenEndpointAuthMethod return &this } @@ -115,12 +126,46 @@ func NewOAuth2Client() *OAuth2Client { // but it doesn't guarantee that properties required by API are set func NewOAuth2ClientWithDefaults() *OAuth2Client { this := OAuth2Client{} + var tokenEndpointAuthMethod string = "client_secret_basic" + this.TokenEndpointAuthMethod = &tokenEndpointAuthMethod return &this } +// GetAccessTokenStrategy returns the AccessTokenStrategy field value if set, zero value otherwise. +func (o *OAuth2Client) GetAccessTokenStrategy() string { + if o == nil || IsNil(o.AccessTokenStrategy) { + var ret string + return ret + } + return *o.AccessTokenStrategy +} + +// GetAccessTokenStrategyOk returns a tuple with the AccessTokenStrategy field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetAccessTokenStrategyOk() (*string, bool) { + if o == nil || IsNil(o.AccessTokenStrategy) { + return nil, false + } + return o.AccessTokenStrategy, true +} + +// HasAccessTokenStrategy returns a boolean if a field has been set. +func (o *OAuth2Client) HasAccessTokenStrategy() bool { + if o != nil && !IsNil(o.AccessTokenStrategy) { + return true + } + + return false +} + +// SetAccessTokenStrategy gets a reference to the given string and assigns it to the AccessTokenStrategy field. +func (o *OAuth2Client) SetAccessTokenStrategy(v string) { + o.AccessTokenStrategy = &v +} + // GetAllowedCorsOrigins returns the AllowedCorsOrigins field value if set, zero value otherwise. func (o *OAuth2Client) GetAllowedCorsOrigins() []string { - if o == nil || o.AllowedCorsOrigins == nil { + if o == nil || IsNil(o.AllowedCorsOrigins) { var ret []string return ret } @@ -130,7 +175,7 @@ func (o *OAuth2Client) GetAllowedCorsOrigins() []string { // GetAllowedCorsOriginsOk returns a tuple with the AllowedCorsOrigins field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetAllowedCorsOriginsOk() ([]string, bool) { - if o == nil || o.AllowedCorsOrigins == nil { + if o == nil || IsNil(o.AllowedCorsOrigins) { return nil, false } return o.AllowedCorsOrigins, true @@ -138,7 +183,7 @@ func (o *OAuth2Client) GetAllowedCorsOriginsOk() ([]string, bool) { // HasAllowedCorsOrigins returns a boolean if a field has been set. func (o *OAuth2Client) HasAllowedCorsOrigins() bool { - if o != nil && o.AllowedCorsOrigins != nil { + if o != nil && !IsNil(o.AllowedCorsOrigins) { return true } @@ -152,7 +197,7 @@ func (o *OAuth2Client) SetAllowedCorsOrigins(v []string) { // GetAudience returns the Audience field value if set, zero value otherwise. func (o *OAuth2Client) GetAudience() []string { - if o == nil || o.Audience == nil { + if o == nil || IsNil(o.Audience) { var ret []string return ret } @@ -162,7 +207,7 @@ func (o *OAuth2Client) GetAudience() []string { // GetAudienceOk returns a tuple with the Audience field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetAudienceOk() ([]string, bool) { - if o == nil || o.Audience == nil { + if o == nil || IsNil(o.Audience) { return nil, false } return o.Audience, true @@ -170,7 +215,7 @@ func (o *OAuth2Client) GetAudienceOk() ([]string, bool) { // HasAudience returns a boolean if a field has been set. func (o *OAuth2Client) HasAudience() bool { - if o != nil && o.Audience != nil { + if o != nil && !IsNil(o.Audience) { return true } @@ -184,7 +229,7 @@ func (o *OAuth2Client) SetAudience(v []string) { // GetAuthorizationCodeGrantAccessTokenLifespan returns the AuthorizationCodeGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetAuthorizationCodeGrantAccessTokenLifespan() string { - if o == nil || o.AuthorizationCodeGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantAccessTokenLifespan) { var ret string return ret } @@ -194,7 +239,7 @@ func (o *OAuth2Client) GetAuthorizationCodeGrantAccessTokenLifespan() string { // GetAuthorizationCodeGrantAccessTokenLifespanOk returns a tuple with the AuthorizationCodeGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetAuthorizationCodeGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.AuthorizationCodeGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantAccessTokenLifespan) { return nil, false } return o.AuthorizationCodeGrantAccessTokenLifespan, true @@ -202,7 +247,7 @@ func (o *OAuth2Client) GetAuthorizationCodeGrantAccessTokenLifespanOk() (*string // HasAuthorizationCodeGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasAuthorizationCodeGrantAccessTokenLifespan() bool { - if o != nil && o.AuthorizationCodeGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.AuthorizationCodeGrantAccessTokenLifespan) { return true } @@ -216,7 +261,7 @@ func (o *OAuth2Client) SetAuthorizationCodeGrantAccessTokenLifespan(v string) { // GetAuthorizationCodeGrantIdTokenLifespan returns the AuthorizationCodeGrantIdTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetAuthorizationCodeGrantIdTokenLifespan() string { - if o == nil || o.AuthorizationCodeGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantIdTokenLifespan) { var ret string return ret } @@ -226,7 +271,7 @@ func (o *OAuth2Client) GetAuthorizationCodeGrantIdTokenLifespan() string { // GetAuthorizationCodeGrantIdTokenLifespanOk returns a tuple with the AuthorizationCodeGrantIdTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetAuthorizationCodeGrantIdTokenLifespanOk() (*string, bool) { - if o == nil || o.AuthorizationCodeGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantIdTokenLifespan) { return nil, false } return o.AuthorizationCodeGrantIdTokenLifespan, true @@ -234,7 +279,7 @@ func (o *OAuth2Client) GetAuthorizationCodeGrantIdTokenLifespanOk() (*string, bo // HasAuthorizationCodeGrantIdTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasAuthorizationCodeGrantIdTokenLifespan() bool { - if o != nil && o.AuthorizationCodeGrantIdTokenLifespan != nil { + if o != nil && !IsNil(o.AuthorizationCodeGrantIdTokenLifespan) { return true } @@ -248,7 +293,7 @@ func (o *OAuth2Client) SetAuthorizationCodeGrantIdTokenLifespan(v string) { // GetAuthorizationCodeGrantRefreshTokenLifespan returns the AuthorizationCodeGrantRefreshTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetAuthorizationCodeGrantRefreshTokenLifespan() string { - if o == nil || o.AuthorizationCodeGrantRefreshTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantRefreshTokenLifespan) { var ret string return ret } @@ -258,7 +303,7 @@ func (o *OAuth2Client) GetAuthorizationCodeGrantRefreshTokenLifespan() string { // GetAuthorizationCodeGrantRefreshTokenLifespanOk returns a tuple with the AuthorizationCodeGrantRefreshTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetAuthorizationCodeGrantRefreshTokenLifespanOk() (*string, bool) { - if o == nil || o.AuthorizationCodeGrantRefreshTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantRefreshTokenLifespan) { return nil, false } return o.AuthorizationCodeGrantRefreshTokenLifespan, true @@ -266,7 +311,7 @@ func (o *OAuth2Client) GetAuthorizationCodeGrantRefreshTokenLifespanOk() (*strin // HasAuthorizationCodeGrantRefreshTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasAuthorizationCodeGrantRefreshTokenLifespan() bool { - if o != nil && o.AuthorizationCodeGrantRefreshTokenLifespan != nil { + if o != nil && !IsNil(o.AuthorizationCodeGrantRefreshTokenLifespan) { return true } @@ -280,7 +325,7 @@ func (o *OAuth2Client) SetAuthorizationCodeGrantRefreshTokenLifespan(v string) { // GetBackchannelLogoutSessionRequired returns the BackchannelLogoutSessionRequired field value if set, zero value otherwise. func (o *OAuth2Client) GetBackchannelLogoutSessionRequired() bool { - if o == nil || o.BackchannelLogoutSessionRequired == nil { + if o == nil || IsNil(o.BackchannelLogoutSessionRequired) { var ret bool return ret } @@ -290,7 +335,7 @@ func (o *OAuth2Client) GetBackchannelLogoutSessionRequired() bool { // GetBackchannelLogoutSessionRequiredOk returns a tuple with the BackchannelLogoutSessionRequired field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetBackchannelLogoutSessionRequiredOk() (*bool, bool) { - if o == nil || o.BackchannelLogoutSessionRequired == nil { + if o == nil || IsNil(o.BackchannelLogoutSessionRequired) { return nil, false } return o.BackchannelLogoutSessionRequired, true @@ -298,7 +343,7 @@ func (o *OAuth2Client) GetBackchannelLogoutSessionRequiredOk() (*bool, bool) { // HasBackchannelLogoutSessionRequired returns a boolean if a field has been set. func (o *OAuth2Client) HasBackchannelLogoutSessionRequired() bool { - if o != nil && o.BackchannelLogoutSessionRequired != nil { + if o != nil && !IsNil(o.BackchannelLogoutSessionRequired) { return true } @@ -312,7 +357,7 @@ func (o *OAuth2Client) SetBackchannelLogoutSessionRequired(v bool) { // GetBackchannelLogoutUri returns the BackchannelLogoutUri field value if set, zero value otherwise. func (o *OAuth2Client) GetBackchannelLogoutUri() string { - if o == nil || o.BackchannelLogoutUri == nil { + if o == nil || IsNil(o.BackchannelLogoutUri) { var ret string return ret } @@ -322,7 +367,7 @@ func (o *OAuth2Client) GetBackchannelLogoutUri() string { // GetBackchannelLogoutUriOk returns a tuple with the BackchannelLogoutUri field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetBackchannelLogoutUriOk() (*string, bool) { - if o == nil || o.BackchannelLogoutUri == nil { + if o == nil || IsNil(o.BackchannelLogoutUri) { return nil, false } return o.BackchannelLogoutUri, true @@ -330,7 +375,7 @@ func (o *OAuth2Client) GetBackchannelLogoutUriOk() (*string, bool) { // HasBackchannelLogoutUri returns a boolean if a field has been set. func (o *OAuth2Client) HasBackchannelLogoutUri() bool { - if o != nil && o.BackchannelLogoutUri != nil { + if o != nil && !IsNil(o.BackchannelLogoutUri) { return true } @@ -344,7 +389,7 @@ func (o *OAuth2Client) SetBackchannelLogoutUri(v string) { // GetClientCredentialsGrantAccessTokenLifespan returns the ClientCredentialsGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetClientCredentialsGrantAccessTokenLifespan() string { - if o == nil || o.ClientCredentialsGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.ClientCredentialsGrantAccessTokenLifespan) { var ret string return ret } @@ -354,7 +399,7 @@ func (o *OAuth2Client) GetClientCredentialsGrantAccessTokenLifespan() string { // GetClientCredentialsGrantAccessTokenLifespanOk returns a tuple with the ClientCredentialsGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetClientCredentialsGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.ClientCredentialsGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.ClientCredentialsGrantAccessTokenLifespan) { return nil, false } return o.ClientCredentialsGrantAccessTokenLifespan, true @@ -362,7 +407,7 @@ func (o *OAuth2Client) GetClientCredentialsGrantAccessTokenLifespanOk() (*string // HasClientCredentialsGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasClientCredentialsGrantAccessTokenLifespan() bool { - if o != nil && o.ClientCredentialsGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.ClientCredentialsGrantAccessTokenLifespan) { return true } @@ -376,7 +421,7 @@ func (o *OAuth2Client) SetClientCredentialsGrantAccessTokenLifespan(v string) { // GetClientId returns the ClientId field value if set, zero value otherwise. func (o *OAuth2Client) GetClientId() string { - if o == nil || o.ClientId == nil { + if o == nil || IsNil(o.ClientId) { var ret string return ret } @@ -386,7 +431,7 @@ func (o *OAuth2Client) GetClientId() string { // GetClientIdOk returns a tuple with the ClientId field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetClientIdOk() (*string, bool) { - if o == nil || o.ClientId == nil { + if o == nil || IsNil(o.ClientId) { return nil, false } return o.ClientId, true @@ -394,7 +439,7 @@ func (o *OAuth2Client) GetClientIdOk() (*string, bool) { // HasClientId returns a boolean if a field has been set. func (o *OAuth2Client) HasClientId() bool { - if o != nil && o.ClientId != nil { + if o != nil && !IsNil(o.ClientId) { return true } @@ -408,7 +453,7 @@ func (o *OAuth2Client) SetClientId(v string) { // GetClientName returns the ClientName field value if set, zero value otherwise. func (o *OAuth2Client) GetClientName() string { - if o == nil || o.ClientName == nil { + if o == nil || IsNil(o.ClientName) { var ret string return ret } @@ -418,7 +463,7 @@ func (o *OAuth2Client) GetClientName() string { // GetClientNameOk returns a tuple with the ClientName field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetClientNameOk() (*string, bool) { - if o == nil || o.ClientName == nil { + if o == nil || IsNil(o.ClientName) { return nil, false } return o.ClientName, true @@ -426,7 +471,7 @@ func (o *OAuth2Client) GetClientNameOk() (*string, bool) { // HasClientName returns a boolean if a field has been set. func (o *OAuth2Client) HasClientName() bool { - if o != nil && o.ClientName != nil { + if o != nil && !IsNil(o.ClientName) { return true } @@ -440,7 +485,7 @@ func (o *OAuth2Client) SetClientName(v string) { // GetClientSecret returns the ClientSecret field value if set, zero value otherwise. func (o *OAuth2Client) GetClientSecret() string { - if o == nil || o.ClientSecret == nil { + if o == nil || IsNil(o.ClientSecret) { var ret string return ret } @@ -450,7 +495,7 @@ func (o *OAuth2Client) GetClientSecret() string { // GetClientSecretOk returns a tuple with the ClientSecret field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetClientSecretOk() (*string, bool) { - if o == nil || o.ClientSecret == nil { + if o == nil || IsNil(o.ClientSecret) { return nil, false } return o.ClientSecret, true @@ -458,7 +503,7 @@ func (o *OAuth2Client) GetClientSecretOk() (*string, bool) { // HasClientSecret returns a boolean if a field has been set. func (o *OAuth2Client) HasClientSecret() bool { - if o != nil && o.ClientSecret != nil { + if o != nil && !IsNil(o.ClientSecret) { return true } @@ -472,7 +517,7 @@ func (o *OAuth2Client) SetClientSecret(v string) { // GetClientSecretExpiresAt returns the ClientSecretExpiresAt field value if set, zero value otherwise. func (o *OAuth2Client) GetClientSecretExpiresAt() int64 { - if o == nil || o.ClientSecretExpiresAt == nil { + if o == nil || IsNil(o.ClientSecretExpiresAt) { var ret int64 return ret } @@ -482,7 +527,7 @@ func (o *OAuth2Client) GetClientSecretExpiresAt() int64 { // GetClientSecretExpiresAtOk returns a tuple with the ClientSecretExpiresAt field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetClientSecretExpiresAtOk() (*int64, bool) { - if o == nil || o.ClientSecretExpiresAt == nil { + if o == nil || IsNil(o.ClientSecretExpiresAt) { return nil, false } return o.ClientSecretExpiresAt, true @@ -490,7 +535,7 @@ func (o *OAuth2Client) GetClientSecretExpiresAtOk() (*int64, bool) { // HasClientSecretExpiresAt returns a boolean if a field has been set. func (o *OAuth2Client) HasClientSecretExpiresAt() bool { - if o != nil && o.ClientSecretExpiresAt != nil { + if o != nil && !IsNil(o.ClientSecretExpiresAt) { return true } @@ -504,7 +549,7 @@ func (o *OAuth2Client) SetClientSecretExpiresAt(v int64) { // GetClientUri returns the ClientUri field value if set, zero value otherwise. func (o *OAuth2Client) GetClientUri() string { - if o == nil || o.ClientUri == nil { + if o == nil || IsNil(o.ClientUri) { var ret string return ret } @@ -514,7 +559,7 @@ func (o *OAuth2Client) GetClientUri() string { // GetClientUriOk returns a tuple with the ClientUri field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetClientUriOk() (*string, bool) { - if o == nil || o.ClientUri == nil { + if o == nil || IsNil(o.ClientUri) { return nil, false } return o.ClientUri, true @@ -522,7 +567,7 @@ func (o *OAuth2Client) GetClientUriOk() (*string, bool) { // HasClientUri returns a boolean if a field has been set. func (o *OAuth2Client) HasClientUri() bool { - if o != nil && o.ClientUri != nil { + if o != nil && !IsNil(o.ClientUri) { return true } @@ -536,7 +581,7 @@ func (o *OAuth2Client) SetClientUri(v string) { // GetContacts returns the Contacts field value if set, zero value otherwise. func (o *OAuth2Client) GetContacts() []string { - if o == nil || o.Contacts == nil { + if o == nil || IsNil(o.Contacts) { var ret []string return ret } @@ -546,7 +591,7 @@ func (o *OAuth2Client) GetContacts() []string { // GetContactsOk returns a tuple with the Contacts field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetContactsOk() ([]string, bool) { - if o == nil || o.Contacts == nil { + if o == nil || IsNil(o.Contacts) { return nil, false } return o.Contacts, true @@ -554,7 +599,7 @@ func (o *OAuth2Client) GetContactsOk() ([]string, bool) { // HasContacts returns a boolean if a field has been set. func (o *OAuth2Client) HasContacts() bool { - if o != nil && o.Contacts != nil { + if o != nil && !IsNil(o.Contacts) { return true } @@ -568,7 +613,7 @@ func (o *OAuth2Client) SetContacts(v []string) { // GetCreatedAt returns the CreatedAt field value if set, zero value otherwise. func (o *OAuth2Client) GetCreatedAt() time.Time { - if o == nil || o.CreatedAt == nil { + if o == nil || IsNil(o.CreatedAt) { var ret time.Time return ret } @@ -578,7 +623,7 @@ func (o *OAuth2Client) GetCreatedAt() time.Time { // GetCreatedAtOk returns a tuple with the CreatedAt field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetCreatedAtOk() (*time.Time, bool) { - if o == nil || o.CreatedAt == nil { + if o == nil || IsNil(o.CreatedAt) { return nil, false } return o.CreatedAt, true @@ -586,7 +631,7 @@ func (o *OAuth2Client) GetCreatedAtOk() (*time.Time, bool) { // HasCreatedAt returns a boolean if a field has been set. func (o *OAuth2Client) HasCreatedAt() bool { - if o != nil && o.CreatedAt != nil { + if o != nil && !IsNil(o.CreatedAt) { return true } @@ -600,7 +645,7 @@ func (o *OAuth2Client) SetCreatedAt(v time.Time) { // GetFrontchannelLogoutSessionRequired returns the FrontchannelLogoutSessionRequired field value if set, zero value otherwise. func (o *OAuth2Client) GetFrontchannelLogoutSessionRequired() bool { - if o == nil || o.FrontchannelLogoutSessionRequired == nil { + if o == nil || IsNil(o.FrontchannelLogoutSessionRequired) { var ret bool return ret } @@ -610,7 +655,7 @@ func (o *OAuth2Client) GetFrontchannelLogoutSessionRequired() bool { // GetFrontchannelLogoutSessionRequiredOk returns a tuple with the FrontchannelLogoutSessionRequired field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetFrontchannelLogoutSessionRequiredOk() (*bool, bool) { - if o == nil || o.FrontchannelLogoutSessionRequired == nil { + if o == nil || IsNil(o.FrontchannelLogoutSessionRequired) { return nil, false } return o.FrontchannelLogoutSessionRequired, true @@ -618,7 +663,7 @@ func (o *OAuth2Client) GetFrontchannelLogoutSessionRequiredOk() (*bool, bool) { // HasFrontchannelLogoutSessionRequired returns a boolean if a field has been set. func (o *OAuth2Client) HasFrontchannelLogoutSessionRequired() bool { - if o != nil && o.FrontchannelLogoutSessionRequired != nil { + if o != nil && !IsNil(o.FrontchannelLogoutSessionRequired) { return true } @@ -632,7 +677,7 @@ func (o *OAuth2Client) SetFrontchannelLogoutSessionRequired(v bool) { // GetFrontchannelLogoutUri returns the FrontchannelLogoutUri field value if set, zero value otherwise. func (o *OAuth2Client) GetFrontchannelLogoutUri() string { - if o == nil || o.FrontchannelLogoutUri == nil { + if o == nil || IsNil(o.FrontchannelLogoutUri) { var ret string return ret } @@ -642,7 +687,7 @@ func (o *OAuth2Client) GetFrontchannelLogoutUri() string { // GetFrontchannelLogoutUriOk returns a tuple with the FrontchannelLogoutUri field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetFrontchannelLogoutUriOk() (*string, bool) { - if o == nil || o.FrontchannelLogoutUri == nil { + if o == nil || IsNil(o.FrontchannelLogoutUri) { return nil, false } return o.FrontchannelLogoutUri, true @@ -650,7 +695,7 @@ func (o *OAuth2Client) GetFrontchannelLogoutUriOk() (*string, bool) { // HasFrontchannelLogoutUri returns a boolean if a field has been set. func (o *OAuth2Client) HasFrontchannelLogoutUri() bool { - if o != nil && o.FrontchannelLogoutUri != nil { + if o != nil && !IsNil(o.FrontchannelLogoutUri) { return true } @@ -664,7 +709,7 @@ func (o *OAuth2Client) SetFrontchannelLogoutUri(v string) { // GetGrantTypes returns the GrantTypes field value if set, zero value otherwise. func (o *OAuth2Client) GetGrantTypes() []string { - if o == nil || o.GrantTypes == nil { + if o == nil || IsNil(o.GrantTypes) { var ret []string return ret } @@ -674,7 +719,7 @@ func (o *OAuth2Client) GetGrantTypes() []string { // GetGrantTypesOk returns a tuple with the GrantTypes field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetGrantTypesOk() ([]string, bool) { - if o == nil || o.GrantTypes == nil { + if o == nil || IsNil(o.GrantTypes) { return nil, false } return o.GrantTypes, true @@ -682,7 +727,7 @@ func (o *OAuth2Client) GetGrantTypesOk() ([]string, bool) { // HasGrantTypes returns a boolean if a field has been set. func (o *OAuth2Client) HasGrantTypes() bool { - if o != nil && o.GrantTypes != nil { + if o != nil && !IsNil(o.GrantTypes) { return true } @@ -696,7 +741,7 @@ func (o *OAuth2Client) SetGrantTypes(v []string) { // GetImplicitGrantAccessTokenLifespan returns the ImplicitGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetImplicitGrantAccessTokenLifespan() string { - if o == nil || o.ImplicitGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.ImplicitGrantAccessTokenLifespan) { var ret string return ret } @@ -706,7 +751,7 @@ func (o *OAuth2Client) GetImplicitGrantAccessTokenLifespan() string { // GetImplicitGrantAccessTokenLifespanOk returns a tuple with the ImplicitGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetImplicitGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.ImplicitGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.ImplicitGrantAccessTokenLifespan) { return nil, false } return o.ImplicitGrantAccessTokenLifespan, true @@ -714,7 +759,7 @@ func (o *OAuth2Client) GetImplicitGrantAccessTokenLifespanOk() (*string, bool) { // HasImplicitGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasImplicitGrantAccessTokenLifespan() bool { - if o != nil && o.ImplicitGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.ImplicitGrantAccessTokenLifespan) { return true } @@ -728,7 +773,7 @@ func (o *OAuth2Client) SetImplicitGrantAccessTokenLifespan(v string) { // GetImplicitGrantIdTokenLifespan returns the ImplicitGrantIdTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetImplicitGrantIdTokenLifespan() string { - if o == nil || o.ImplicitGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.ImplicitGrantIdTokenLifespan) { var ret string return ret } @@ -738,7 +783,7 @@ func (o *OAuth2Client) GetImplicitGrantIdTokenLifespan() string { // GetImplicitGrantIdTokenLifespanOk returns a tuple with the ImplicitGrantIdTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetImplicitGrantIdTokenLifespanOk() (*string, bool) { - if o == nil || o.ImplicitGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.ImplicitGrantIdTokenLifespan) { return nil, false } return o.ImplicitGrantIdTokenLifespan, true @@ -746,7 +791,7 @@ func (o *OAuth2Client) GetImplicitGrantIdTokenLifespanOk() (*string, bool) { // HasImplicitGrantIdTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasImplicitGrantIdTokenLifespan() bool { - if o != nil && o.ImplicitGrantIdTokenLifespan != nil { + if o != nil && !IsNil(o.ImplicitGrantIdTokenLifespan) { return true } @@ -771,7 +816,7 @@ func (o *OAuth2Client) GetJwks() interface{} { // and a boolean to check if the value has been set. // NOTE: If the value is an explicit nil, `nil, true` will be returned func (o *OAuth2Client) GetJwksOk() (*interface{}, bool) { - if o == nil || o.Jwks == nil { + if o == nil || IsNil(o.Jwks) { return nil, false } return &o.Jwks, true @@ -779,7 +824,7 @@ func (o *OAuth2Client) GetJwksOk() (*interface{}, bool) { // HasJwks returns a boolean if a field has been set. func (o *OAuth2Client) HasJwks() bool { - if o != nil && o.Jwks != nil { + if o != nil && IsNil(o.Jwks) { return true } @@ -793,7 +838,7 @@ func (o *OAuth2Client) SetJwks(v interface{}) { // GetJwksUri returns the JwksUri field value if set, zero value otherwise. func (o *OAuth2Client) GetJwksUri() string { - if o == nil || o.JwksUri == nil { + if o == nil || IsNil(o.JwksUri) { var ret string return ret } @@ -803,7 +848,7 @@ func (o *OAuth2Client) GetJwksUri() string { // GetJwksUriOk returns a tuple with the JwksUri field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetJwksUriOk() (*string, bool) { - if o == nil || o.JwksUri == nil { + if o == nil || IsNil(o.JwksUri) { return nil, false } return o.JwksUri, true @@ -811,7 +856,7 @@ func (o *OAuth2Client) GetJwksUriOk() (*string, bool) { // HasJwksUri returns a boolean if a field has been set. func (o *OAuth2Client) HasJwksUri() bool { - if o != nil && o.JwksUri != nil { + if o != nil && !IsNil(o.JwksUri) { return true } @@ -825,7 +870,7 @@ func (o *OAuth2Client) SetJwksUri(v string) { // GetJwtBearerGrantAccessTokenLifespan returns the JwtBearerGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetJwtBearerGrantAccessTokenLifespan() string { - if o == nil || o.JwtBearerGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.JwtBearerGrantAccessTokenLifespan) { var ret string return ret } @@ -835,7 +880,7 @@ func (o *OAuth2Client) GetJwtBearerGrantAccessTokenLifespan() string { // GetJwtBearerGrantAccessTokenLifespanOk returns a tuple with the JwtBearerGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetJwtBearerGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.JwtBearerGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.JwtBearerGrantAccessTokenLifespan) { return nil, false } return o.JwtBearerGrantAccessTokenLifespan, true @@ -843,7 +888,7 @@ func (o *OAuth2Client) GetJwtBearerGrantAccessTokenLifespanOk() (*string, bool) // HasJwtBearerGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasJwtBearerGrantAccessTokenLifespan() bool { - if o != nil && o.JwtBearerGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.JwtBearerGrantAccessTokenLifespan) { return true } @@ -857,7 +902,7 @@ func (o *OAuth2Client) SetJwtBearerGrantAccessTokenLifespan(v string) { // GetLogoUri returns the LogoUri field value if set, zero value otherwise. func (o *OAuth2Client) GetLogoUri() string { - if o == nil || o.LogoUri == nil { + if o == nil || IsNil(o.LogoUri) { var ret string return ret } @@ -867,7 +912,7 @@ func (o *OAuth2Client) GetLogoUri() string { // GetLogoUriOk returns a tuple with the LogoUri field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetLogoUriOk() (*string, bool) { - if o == nil || o.LogoUri == nil { + if o == nil || IsNil(o.LogoUri) { return nil, false } return o.LogoUri, true @@ -875,7 +920,7 @@ func (o *OAuth2Client) GetLogoUriOk() (*string, bool) { // HasLogoUri returns a boolean if a field has been set. func (o *OAuth2Client) HasLogoUri() bool { - if o != nil && o.LogoUri != nil { + if o != nil && !IsNil(o.LogoUri) { return true } @@ -900,7 +945,7 @@ func (o *OAuth2Client) GetMetadata() interface{} { // and a boolean to check if the value has been set. // NOTE: If the value is an explicit nil, `nil, true` will be returned func (o *OAuth2Client) GetMetadataOk() (*interface{}, bool) { - if o == nil || o.Metadata == nil { + if o == nil || IsNil(o.Metadata) { return nil, false } return &o.Metadata, true @@ -908,7 +953,7 @@ func (o *OAuth2Client) GetMetadataOk() (*interface{}, bool) { // HasMetadata returns a boolean if a field has been set. func (o *OAuth2Client) HasMetadata() bool { - if o != nil && o.Metadata != nil { + if o != nil && IsNil(o.Metadata) { return true } @@ -922,7 +967,7 @@ func (o *OAuth2Client) SetMetadata(v interface{}) { // GetOwner returns the Owner field value if set, zero value otherwise. func (o *OAuth2Client) GetOwner() string { - if o == nil || o.Owner == nil { + if o == nil || IsNil(o.Owner) { var ret string return ret } @@ -932,7 +977,7 @@ func (o *OAuth2Client) GetOwner() string { // GetOwnerOk returns a tuple with the Owner field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetOwnerOk() (*string, bool) { - if o == nil || o.Owner == nil { + if o == nil || IsNil(o.Owner) { return nil, false } return o.Owner, true @@ -940,7 +985,7 @@ func (o *OAuth2Client) GetOwnerOk() (*string, bool) { // HasOwner returns a boolean if a field has been set. func (o *OAuth2Client) HasOwner() bool { - if o != nil && o.Owner != nil { + if o != nil && !IsNil(o.Owner) { return true } @@ -954,7 +999,7 @@ func (o *OAuth2Client) SetOwner(v string) { // GetPolicyUri returns the PolicyUri field value if set, zero value otherwise. func (o *OAuth2Client) GetPolicyUri() string { - if o == nil || o.PolicyUri == nil { + if o == nil || IsNil(o.PolicyUri) { var ret string return ret } @@ -964,7 +1009,7 @@ func (o *OAuth2Client) GetPolicyUri() string { // GetPolicyUriOk returns a tuple with the PolicyUri field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetPolicyUriOk() (*string, bool) { - if o == nil || o.PolicyUri == nil { + if o == nil || IsNil(o.PolicyUri) { return nil, false } return o.PolicyUri, true @@ -972,7 +1017,7 @@ func (o *OAuth2Client) GetPolicyUriOk() (*string, bool) { // HasPolicyUri returns a boolean if a field has been set. func (o *OAuth2Client) HasPolicyUri() bool { - if o != nil && o.PolicyUri != nil { + if o != nil && !IsNil(o.PolicyUri) { return true } @@ -986,7 +1031,7 @@ func (o *OAuth2Client) SetPolicyUri(v string) { // GetPostLogoutRedirectUris returns the PostLogoutRedirectUris field value if set, zero value otherwise. func (o *OAuth2Client) GetPostLogoutRedirectUris() []string { - if o == nil || o.PostLogoutRedirectUris == nil { + if o == nil || IsNil(o.PostLogoutRedirectUris) { var ret []string return ret } @@ -996,7 +1041,7 @@ func (o *OAuth2Client) GetPostLogoutRedirectUris() []string { // GetPostLogoutRedirectUrisOk returns a tuple with the PostLogoutRedirectUris field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetPostLogoutRedirectUrisOk() ([]string, bool) { - if o == nil || o.PostLogoutRedirectUris == nil { + if o == nil || IsNil(o.PostLogoutRedirectUris) { return nil, false } return o.PostLogoutRedirectUris, true @@ -1004,7 +1049,7 @@ func (o *OAuth2Client) GetPostLogoutRedirectUrisOk() ([]string, bool) { // HasPostLogoutRedirectUris returns a boolean if a field has been set. func (o *OAuth2Client) HasPostLogoutRedirectUris() bool { - if o != nil && o.PostLogoutRedirectUris != nil { + if o != nil && !IsNil(o.PostLogoutRedirectUris) { return true } @@ -1018,7 +1063,7 @@ func (o *OAuth2Client) SetPostLogoutRedirectUris(v []string) { // GetRedirectUris returns the RedirectUris field value if set, zero value otherwise. func (o *OAuth2Client) GetRedirectUris() []string { - if o == nil || o.RedirectUris == nil { + if o == nil || IsNil(o.RedirectUris) { var ret []string return ret } @@ -1028,7 +1073,7 @@ func (o *OAuth2Client) GetRedirectUris() []string { // GetRedirectUrisOk returns a tuple with the RedirectUris field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetRedirectUrisOk() ([]string, bool) { - if o == nil || o.RedirectUris == nil { + if o == nil || IsNil(o.RedirectUris) { return nil, false } return o.RedirectUris, true @@ -1036,7 +1081,7 @@ func (o *OAuth2Client) GetRedirectUrisOk() ([]string, bool) { // HasRedirectUris returns a boolean if a field has been set. func (o *OAuth2Client) HasRedirectUris() bool { - if o != nil && o.RedirectUris != nil { + if o != nil && !IsNil(o.RedirectUris) { return true } @@ -1050,7 +1095,7 @@ func (o *OAuth2Client) SetRedirectUris(v []string) { // GetRefreshTokenGrantAccessTokenLifespan returns the RefreshTokenGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetRefreshTokenGrantAccessTokenLifespan() string { - if o == nil || o.RefreshTokenGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantAccessTokenLifespan) { var ret string return ret } @@ -1060,7 +1105,7 @@ func (o *OAuth2Client) GetRefreshTokenGrantAccessTokenLifespan() string { // GetRefreshTokenGrantAccessTokenLifespanOk returns a tuple with the RefreshTokenGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetRefreshTokenGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.RefreshTokenGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantAccessTokenLifespan) { return nil, false } return o.RefreshTokenGrantAccessTokenLifespan, true @@ -1068,7 +1113,7 @@ func (o *OAuth2Client) GetRefreshTokenGrantAccessTokenLifespanOk() (*string, boo // HasRefreshTokenGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasRefreshTokenGrantAccessTokenLifespan() bool { - if o != nil && o.RefreshTokenGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.RefreshTokenGrantAccessTokenLifespan) { return true } @@ -1082,7 +1127,7 @@ func (o *OAuth2Client) SetRefreshTokenGrantAccessTokenLifespan(v string) { // GetRefreshTokenGrantIdTokenLifespan returns the RefreshTokenGrantIdTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetRefreshTokenGrantIdTokenLifespan() string { - if o == nil || o.RefreshTokenGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantIdTokenLifespan) { var ret string return ret } @@ -1092,7 +1137,7 @@ func (o *OAuth2Client) GetRefreshTokenGrantIdTokenLifespan() string { // GetRefreshTokenGrantIdTokenLifespanOk returns a tuple with the RefreshTokenGrantIdTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetRefreshTokenGrantIdTokenLifespanOk() (*string, bool) { - if o == nil || o.RefreshTokenGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantIdTokenLifespan) { return nil, false } return o.RefreshTokenGrantIdTokenLifespan, true @@ -1100,7 +1145,7 @@ func (o *OAuth2Client) GetRefreshTokenGrantIdTokenLifespanOk() (*string, bool) { // HasRefreshTokenGrantIdTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasRefreshTokenGrantIdTokenLifespan() bool { - if o != nil && o.RefreshTokenGrantIdTokenLifespan != nil { + if o != nil && !IsNil(o.RefreshTokenGrantIdTokenLifespan) { return true } @@ -1114,7 +1159,7 @@ func (o *OAuth2Client) SetRefreshTokenGrantIdTokenLifespan(v string) { // GetRefreshTokenGrantRefreshTokenLifespan returns the RefreshTokenGrantRefreshTokenLifespan field value if set, zero value otherwise. func (o *OAuth2Client) GetRefreshTokenGrantRefreshTokenLifespan() string { - if o == nil || o.RefreshTokenGrantRefreshTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantRefreshTokenLifespan) { var ret string return ret } @@ -1124,7 +1169,7 @@ func (o *OAuth2Client) GetRefreshTokenGrantRefreshTokenLifespan() string { // GetRefreshTokenGrantRefreshTokenLifespanOk returns a tuple with the RefreshTokenGrantRefreshTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetRefreshTokenGrantRefreshTokenLifespanOk() (*string, bool) { - if o == nil || o.RefreshTokenGrantRefreshTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantRefreshTokenLifespan) { return nil, false } return o.RefreshTokenGrantRefreshTokenLifespan, true @@ -1132,7 +1177,7 @@ func (o *OAuth2Client) GetRefreshTokenGrantRefreshTokenLifespanOk() (*string, bo // HasRefreshTokenGrantRefreshTokenLifespan returns a boolean if a field has been set. func (o *OAuth2Client) HasRefreshTokenGrantRefreshTokenLifespan() bool { - if o != nil && o.RefreshTokenGrantRefreshTokenLifespan != nil { + if o != nil && !IsNil(o.RefreshTokenGrantRefreshTokenLifespan) { return true } @@ -1146,7 +1191,7 @@ func (o *OAuth2Client) SetRefreshTokenGrantRefreshTokenLifespan(v string) { // GetRegistrationAccessToken returns the RegistrationAccessToken field value if set, zero value otherwise. func (o *OAuth2Client) GetRegistrationAccessToken() string { - if o == nil || o.RegistrationAccessToken == nil { + if o == nil || IsNil(o.RegistrationAccessToken) { var ret string return ret } @@ -1156,7 +1201,7 @@ func (o *OAuth2Client) GetRegistrationAccessToken() string { // GetRegistrationAccessTokenOk returns a tuple with the RegistrationAccessToken field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetRegistrationAccessTokenOk() (*string, bool) { - if o == nil || o.RegistrationAccessToken == nil { + if o == nil || IsNil(o.RegistrationAccessToken) { return nil, false } return o.RegistrationAccessToken, true @@ -1164,7 +1209,7 @@ func (o *OAuth2Client) GetRegistrationAccessTokenOk() (*string, bool) { // HasRegistrationAccessToken returns a boolean if a field has been set. func (o *OAuth2Client) HasRegistrationAccessToken() bool { - if o != nil && o.RegistrationAccessToken != nil { + if o != nil && !IsNil(o.RegistrationAccessToken) { return true } @@ -1178,7 +1223,7 @@ func (o *OAuth2Client) SetRegistrationAccessToken(v string) { // GetRegistrationClientUri returns the RegistrationClientUri field value if set, zero value otherwise. func (o *OAuth2Client) GetRegistrationClientUri() string { - if o == nil || o.RegistrationClientUri == nil { + if o == nil || IsNil(o.RegistrationClientUri) { var ret string return ret } @@ -1188,7 +1233,7 @@ func (o *OAuth2Client) GetRegistrationClientUri() string { // GetRegistrationClientUriOk returns a tuple with the RegistrationClientUri field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetRegistrationClientUriOk() (*string, bool) { - if o == nil || o.RegistrationClientUri == nil { + if o == nil || IsNil(o.RegistrationClientUri) { return nil, false } return o.RegistrationClientUri, true @@ -1196,7 +1241,7 @@ func (o *OAuth2Client) GetRegistrationClientUriOk() (*string, bool) { // HasRegistrationClientUri returns a boolean if a field has been set. func (o *OAuth2Client) HasRegistrationClientUri() bool { - if o != nil && o.RegistrationClientUri != nil { + if o != nil && !IsNil(o.RegistrationClientUri) { return true } @@ -1210,7 +1255,7 @@ func (o *OAuth2Client) SetRegistrationClientUri(v string) { // GetRequestObjectSigningAlg returns the RequestObjectSigningAlg field value if set, zero value otherwise. func (o *OAuth2Client) GetRequestObjectSigningAlg() string { - if o == nil || o.RequestObjectSigningAlg == nil { + if o == nil || IsNil(o.RequestObjectSigningAlg) { var ret string return ret } @@ -1220,7 +1265,7 @@ func (o *OAuth2Client) GetRequestObjectSigningAlg() string { // GetRequestObjectSigningAlgOk returns a tuple with the RequestObjectSigningAlg field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetRequestObjectSigningAlgOk() (*string, bool) { - if o == nil || o.RequestObjectSigningAlg == nil { + if o == nil || IsNil(o.RequestObjectSigningAlg) { return nil, false } return o.RequestObjectSigningAlg, true @@ -1228,7 +1273,7 @@ func (o *OAuth2Client) GetRequestObjectSigningAlgOk() (*string, bool) { // HasRequestObjectSigningAlg returns a boolean if a field has been set. func (o *OAuth2Client) HasRequestObjectSigningAlg() bool { - if o != nil && o.RequestObjectSigningAlg != nil { + if o != nil && !IsNil(o.RequestObjectSigningAlg) { return true } @@ -1242,7 +1287,7 @@ func (o *OAuth2Client) SetRequestObjectSigningAlg(v string) { // GetRequestUris returns the RequestUris field value if set, zero value otherwise. func (o *OAuth2Client) GetRequestUris() []string { - if o == nil || o.RequestUris == nil { + if o == nil || IsNil(o.RequestUris) { var ret []string return ret } @@ -1252,7 +1297,7 @@ func (o *OAuth2Client) GetRequestUris() []string { // GetRequestUrisOk returns a tuple with the RequestUris field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetRequestUrisOk() ([]string, bool) { - if o == nil || o.RequestUris == nil { + if o == nil || IsNil(o.RequestUris) { return nil, false } return o.RequestUris, true @@ -1260,7 +1305,7 @@ func (o *OAuth2Client) GetRequestUrisOk() ([]string, bool) { // HasRequestUris returns a boolean if a field has been set. func (o *OAuth2Client) HasRequestUris() bool { - if o != nil && o.RequestUris != nil { + if o != nil && !IsNil(o.RequestUris) { return true } @@ -1274,7 +1319,7 @@ func (o *OAuth2Client) SetRequestUris(v []string) { // GetResponseTypes returns the ResponseTypes field value if set, zero value otherwise. func (o *OAuth2Client) GetResponseTypes() []string { - if o == nil || o.ResponseTypes == nil { + if o == nil || IsNil(o.ResponseTypes) { var ret []string return ret } @@ -1284,7 +1329,7 @@ func (o *OAuth2Client) GetResponseTypes() []string { // GetResponseTypesOk returns a tuple with the ResponseTypes field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetResponseTypesOk() ([]string, bool) { - if o == nil || o.ResponseTypes == nil { + if o == nil || IsNil(o.ResponseTypes) { return nil, false } return o.ResponseTypes, true @@ -1292,7 +1337,7 @@ func (o *OAuth2Client) GetResponseTypesOk() ([]string, bool) { // HasResponseTypes returns a boolean if a field has been set. func (o *OAuth2Client) HasResponseTypes() bool { - if o != nil && o.ResponseTypes != nil { + if o != nil && !IsNil(o.ResponseTypes) { return true } @@ -1306,7 +1351,7 @@ func (o *OAuth2Client) SetResponseTypes(v []string) { // GetScope returns the Scope field value if set, zero value otherwise. func (o *OAuth2Client) GetScope() string { - if o == nil || o.Scope == nil { + if o == nil || IsNil(o.Scope) { var ret string return ret } @@ -1316,7 +1361,7 @@ func (o *OAuth2Client) GetScope() string { // GetScopeOk returns a tuple with the Scope field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetScopeOk() (*string, bool) { - if o == nil || o.Scope == nil { + if o == nil || IsNil(o.Scope) { return nil, false } return o.Scope, true @@ -1324,7 +1369,7 @@ func (o *OAuth2Client) GetScopeOk() (*string, bool) { // HasScope returns a boolean if a field has been set. func (o *OAuth2Client) HasScope() bool { - if o != nil && o.Scope != nil { + if o != nil && !IsNil(o.Scope) { return true } @@ -1338,7 +1383,7 @@ func (o *OAuth2Client) SetScope(v string) { // GetSectorIdentifierUri returns the SectorIdentifierUri field value if set, zero value otherwise. func (o *OAuth2Client) GetSectorIdentifierUri() string { - if o == nil || o.SectorIdentifierUri == nil { + if o == nil || IsNil(o.SectorIdentifierUri) { var ret string return ret } @@ -1348,7 +1393,7 @@ func (o *OAuth2Client) GetSectorIdentifierUri() string { // GetSectorIdentifierUriOk returns a tuple with the SectorIdentifierUri field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetSectorIdentifierUriOk() (*string, bool) { - if o == nil || o.SectorIdentifierUri == nil { + if o == nil || IsNil(o.SectorIdentifierUri) { return nil, false } return o.SectorIdentifierUri, true @@ -1356,7 +1401,7 @@ func (o *OAuth2Client) GetSectorIdentifierUriOk() (*string, bool) { // HasSectorIdentifierUri returns a boolean if a field has been set. func (o *OAuth2Client) HasSectorIdentifierUri() bool { - if o != nil && o.SectorIdentifierUri != nil { + if o != nil && !IsNil(o.SectorIdentifierUri) { return true } @@ -1368,9 +1413,73 @@ func (o *OAuth2Client) SetSectorIdentifierUri(v string) { o.SectorIdentifierUri = &v } +// GetSkipConsent returns the SkipConsent field value if set, zero value otherwise. +func (o *OAuth2Client) GetSkipConsent() bool { + if o == nil || IsNil(o.SkipConsent) { + var ret bool + return ret + } + return *o.SkipConsent +} + +// GetSkipConsentOk returns a tuple with the SkipConsent field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetSkipConsentOk() (*bool, bool) { + if o == nil || IsNil(o.SkipConsent) { + return nil, false + } + return o.SkipConsent, true +} + +// HasSkipConsent returns a boolean if a field has been set. +func (o *OAuth2Client) HasSkipConsent() bool { + if o != nil && !IsNil(o.SkipConsent) { + return true + } + + return false +} + +// SetSkipConsent gets a reference to the given bool and assigns it to the SkipConsent field. +func (o *OAuth2Client) SetSkipConsent(v bool) { + o.SkipConsent = &v +} + +// GetSkipLogoutConsent returns the SkipLogoutConsent field value if set, zero value otherwise. +func (o *OAuth2Client) GetSkipLogoutConsent() bool { + if o == nil || IsNil(o.SkipLogoutConsent) { + var ret bool + return ret + } + return *o.SkipLogoutConsent +} + +// GetSkipLogoutConsentOk returns a tuple with the SkipLogoutConsent field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OAuth2Client) GetSkipLogoutConsentOk() (*bool, bool) { + if o == nil || IsNil(o.SkipLogoutConsent) { + return nil, false + } + return o.SkipLogoutConsent, true +} + +// HasSkipLogoutConsent returns a boolean if a field has been set. +func (o *OAuth2Client) HasSkipLogoutConsent() bool { + if o != nil && !IsNil(o.SkipLogoutConsent) { + return true + } + + return false +} + +// SetSkipLogoutConsent gets a reference to the given bool and assigns it to the SkipLogoutConsent field. +func (o *OAuth2Client) SetSkipLogoutConsent(v bool) { + o.SkipLogoutConsent = &v +} + // GetSubjectType returns the SubjectType field value if set, zero value otherwise. func (o *OAuth2Client) GetSubjectType() string { - if o == nil || o.SubjectType == nil { + if o == nil || IsNil(o.SubjectType) { var ret string return ret } @@ -1380,7 +1489,7 @@ func (o *OAuth2Client) GetSubjectType() string { // GetSubjectTypeOk returns a tuple with the SubjectType field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetSubjectTypeOk() (*string, bool) { - if o == nil || o.SubjectType == nil { + if o == nil || IsNil(o.SubjectType) { return nil, false } return o.SubjectType, true @@ -1388,7 +1497,7 @@ func (o *OAuth2Client) GetSubjectTypeOk() (*string, bool) { // HasSubjectType returns a boolean if a field has been set. func (o *OAuth2Client) HasSubjectType() bool { - if o != nil && o.SubjectType != nil { + if o != nil && !IsNil(o.SubjectType) { return true } @@ -1402,7 +1511,7 @@ func (o *OAuth2Client) SetSubjectType(v string) { // GetTokenEndpointAuthMethod returns the TokenEndpointAuthMethod field value if set, zero value otherwise. func (o *OAuth2Client) GetTokenEndpointAuthMethod() string { - if o == nil || o.TokenEndpointAuthMethod == nil { + if o == nil || IsNil(o.TokenEndpointAuthMethod) { var ret string return ret } @@ -1412,7 +1521,7 @@ func (o *OAuth2Client) GetTokenEndpointAuthMethod() string { // GetTokenEndpointAuthMethodOk returns a tuple with the TokenEndpointAuthMethod field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetTokenEndpointAuthMethodOk() (*string, bool) { - if o == nil || o.TokenEndpointAuthMethod == nil { + if o == nil || IsNil(o.TokenEndpointAuthMethod) { return nil, false } return o.TokenEndpointAuthMethod, true @@ -1420,7 +1529,7 @@ func (o *OAuth2Client) GetTokenEndpointAuthMethodOk() (*string, bool) { // HasTokenEndpointAuthMethod returns a boolean if a field has been set. func (o *OAuth2Client) HasTokenEndpointAuthMethod() bool { - if o != nil && o.TokenEndpointAuthMethod != nil { + if o != nil && !IsNil(o.TokenEndpointAuthMethod) { return true } @@ -1434,7 +1543,7 @@ func (o *OAuth2Client) SetTokenEndpointAuthMethod(v string) { // GetTokenEndpointAuthSigningAlg returns the TokenEndpointAuthSigningAlg field value if set, zero value otherwise. func (o *OAuth2Client) GetTokenEndpointAuthSigningAlg() string { - if o == nil || o.TokenEndpointAuthSigningAlg == nil { + if o == nil || IsNil(o.TokenEndpointAuthSigningAlg) { var ret string return ret } @@ -1444,7 +1553,7 @@ func (o *OAuth2Client) GetTokenEndpointAuthSigningAlg() string { // GetTokenEndpointAuthSigningAlgOk returns a tuple with the TokenEndpointAuthSigningAlg field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetTokenEndpointAuthSigningAlgOk() (*string, bool) { - if o == nil || o.TokenEndpointAuthSigningAlg == nil { + if o == nil || IsNil(o.TokenEndpointAuthSigningAlg) { return nil, false } return o.TokenEndpointAuthSigningAlg, true @@ -1452,7 +1561,7 @@ func (o *OAuth2Client) GetTokenEndpointAuthSigningAlgOk() (*string, bool) { // HasTokenEndpointAuthSigningAlg returns a boolean if a field has been set. func (o *OAuth2Client) HasTokenEndpointAuthSigningAlg() bool { - if o != nil && o.TokenEndpointAuthSigningAlg != nil { + if o != nil && !IsNil(o.TokenEndpointAuthSigningAlg) { return true } @@ -1466,7 +1575,7 @@ func (o *OAuth2Client) SetTokenEndpointAuthSigningAlg(v string) { // GetTosUri returns the TosUri field value if set, zero value otherwise. func (o *OAuth2Client) GetTosUri() string { - if o == nil || o.TosUri == nil { + if o == nil || IsNil(o.TosUri) { var ret string return ret } @@ -1476,7 +1585,7 @@ func (o *OAuth2Client) GetTosUri() string { // GetTosUriOk returns a tuple with the TosUri field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetTosUriOk() (*string, bool) { - if o == nil || o.TosUri == nil { + if o == nil || IsNil(o.TosUri) { return nil, false } return o.TosUri, true @@ -1484,7 +1593,7 @@ func (o *OAuth2Client) GetTosUriOk() (*string, bool) { // HasTosUri returns a boolean if a field has been set. func (o *OAuth2Client) HasTosUri() bool { - if o != nil && o.TosUri != nil { + if o != nil && !IsNil(o.TosUri) { return true } @@ -1498,7 +1607,7 @@ func (o *OAuth2Client) SetTosUri(v string) { // GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise. func (o *OAuth2Client) GetUpdatedAt() time.Time { - if o == nil || o.UpdatedAt == nil { + if o == nil || IsNil(o.UpdatedAt) { var ret time.Time return ret } @@ -1508,7 +1617,7 @@ func (o *OAuth2Client) GetUpdatedAt() time.Time { // GetUpdatedAtOk returns a tuple with the UpdatedAt field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetUpdatedAtOk() (*time.Time, bool) { - if o == nil || o.UpdatedAt == nil { + if o == nil || IsNil(o.UpdatedAt) { return nil, false } return o.UpdatedAt, true @@ -1516,7 +1625,7 @@ func (o *OAuth2Client) GetUpdatedAtOk() (*time.Time, bool) { // HasUpdatedAt returns a boolean if a field has been set. func (o *OAuth2Client) HasUpdatedAt() bool { - if o != nil && o.UpdatedAt != nil { + if o != nil && !IsNil(o.UpdatedAt) { return true } @@ -1530,7 +1639,7 @@ func (o *OAuth2Client) SetUpdatedAt(v time.Time) { // GetUserinfoSignedResponseAlg returns the UserinfoSignedResponseAlg field value if set, zero value otherwise. func (o *OAuth2Client) GetUserinfoSignedResponseAlg() string { - if o == nil || o.UserinfoSignedResponseAlg == nil { + if o == nil || IsNil(o.UserinfoSignedResponseAlg) { var ret string return ret } @@ -1540,7 +1649,7 @@ func (o *OAuth2Client) GetUserinfoSignedResponseAlg() string { // GetUserinfoSignedResponseAlgOk returns a tuple with the UserinfoSignedResponseAlg field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2Client) GetUserinfoSignedResponseAlgOk() (*string, bool) { - if o == nil || o.UserinfoSignedResponseAlg == nil { + if o == nil || IsNil(o.UserinfoSignedResponseAlg) { return nil, false } return o.UserinfoSignedResponseAlg, true @@ -1548,7 +1657,7 @@ func (o *OAuth2Client) GetUserinfoSignedResponseAlgOk() (*string, bool) { // HasUserinfoSignedResponseAlg returns a boolean if a field has been set. func (o *OAuth2Client) HasUserinfoSignedResponseAlg() bool { - if o != nil && o.UserinfoSignedResponseAlg != nil { + if o != nil && !IsNil(o.UserinfoSignedResponseAlg) { return true } @@ -1561,143 +1670,160 @@ func (o *OAuth2Client) SetUserinfoSignedResponseAlg(v string) { } func (o OAuth2Client) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o OAuth2Client) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.AllowedCorsOrigins != nil { + if !IsNil(o.AccessTokenStrategy) { + toSerialize["access_token_strategy"] = o.AccessTokenStrategy + } + if !IsNil(o.AllowedCorsOrigins) { toSerialize["allowed_cors_origins"] = o.AllowedCorsOrigins } - if o.Audience != nil { + if !IsNil(o.Audience) { toSerialize["audience"] = o.Audience } - if o.AuthorizationCodeGrantAccessTokenLifespan != nil { + if !IsNil(o.AuthorizationCodeGrantAccessTokenLifespan) { toSerialize["authorization_code_grant_access_token_lifespan"] = o.AuthorizationCodeGrantAccessTokenLifespan } - if o.AuthorizationCodeGrantIdTokenLifespan != nil { + if !IsNil(o.AuthorizationCodeGrantIdTokenLifespan) { toSerialize["authorization_code_grant_id_token_lifespan"] = o.AuthorizationCodeGrantIdTokenLifespan } - if o.AuthorizationCodeGrantRefreshTokenLifespan != nil { + if !IsNil(o.AuthorizationCodeGrantRefreshTokenLifespan) { toSerialize["authorization_code_grant_refresh_token_lifespan"] = o.AuthorizationCodeGrantRefreshTokenLifespan } - if o.BackchannelLogoutSessionRequired != nil { + if !IsNil(o.BackchannelLogoutSessionRequired) { toSerialize["backchannel_logout_session_required"] = o.BackchannelLogoutSessionRequired } - if o.BackchannelLogoutUri != nil { + if !IsNil(o.BackchannelLogoutUri) { toSerialize["backchannel_logout_uri"] = o.BackchannelLogoutUri } - if o.ClientCredentialsGrantAccessTokenLifespan != nil { + if !IsNil(o.ClientCredentialsGrantAccessTokenLifespan) { toSerialize["client_credentials_grant_access_token_lifespan"] = o.ClientCredentialsGrantAccessTokenLifespan } - if o.ClientId != nil { + if !IsNil(o.ClientId) { toSerialize["client_id"] = o.ClientId } - if o.ClientName != nil { + if !IsNil(o.ClientName) { toSerialize["client_name"] = o.ClientName } - if o.ClientSecret != nil { + if !IsNil(o.ClientSecret) { toSerialize["client_secret"] = o.ClientSecret } - if o.ClientSecretExpiresAt != nil { + if !IsNil(o.ClientSecretExpiresAt) { toSerialize["client_secret_expires_at"] = o.ClientSecretExpiresAt } - if o.ClientUri != nil { + if !IsNil(o.ClientUri) { toSerialize["client_uri"] = o.ClientUri } - if o.Contacts != nil { + if !IsNil(o.Contacts) { toSerialize["contacts"] = o.Contacts } - if o.CreatedAt != nil { + if !IsNil(o.CreatedAt) { toSerialize["created_at"] = o.CreatedAt } - if o.FrontchannelLogoutSessionRequired != nil { + if !IsNil(o.FrontchannelLogoutSessionRequired) { toSerialize["frontchannel_logout_session_required"] = o.FrontchannelLogoutSessionRequired } - if o.FrontchannelLogoutUri != nil { + if !IsNil(o.FrontchannelLogoutUri) { toSerialize["frontchannel_logout_uri"] = o.FrontchannelLogoutUri } - if o.GrantTypes != nil { + if !IsNil(o.GrantTypes) { toSerialize["grant_types"] = o.GrantTypes } - if o.ImplicitGrantAccessTokenLifespan != nil { + if !IsNil(o.ImplicitGrantAccessTokenLifespan) { toSerialize["implicit_grant_access_token_lifespan"] = o.ImplicitGrantAccessTokenLifespan } - if o.ImplicitGrantIdTokenLifespan != nil { + if !IsNil(o.ImplicitGrantIdTokenLifespan) { toSerialize["implicit_grant_id_token_lifespan"] = o.ImplicitGrantIdTokenLifespan } if o.Jwks != nil { toSerialize["jwks"] = o.Jwks } - if o.JwksUri != nil { + if !IsNil(o.JwksUri) { toSerialize["jwks_uri"] = o.JwksUri } - if o.JwtBearerGrantAccessTokenLifespan != nil { + if !IsNil(o.JwtBearerGrantAccessTokenLifespan) { toSerialize["jwt_bearer_grant_access_token_lifespan"] = o.JwtBearerGrantAccessTokenLifespan } - if o.LogoUri != nil { + if !IsNil(o.LogoUri) { toSerialize["logo_uri"] = o.LogoUri } if o.Metadata != nil { toSerialize["metadata"] = o.Metadata } - if o.Owner != nil { + if !IsNil(o.Owner) { toSerialize["owner"] = o.Owner } - if o.PolicyUri != nil { + if !IsNil(o.PolicyUri) { toSerialize["policy_uri"] = o.PolicyUri } - if o.PostLogoutRedirectUris != nil { + if !IsNil(o.PostLogoutRedirectUris) { toSerialize["post_logout_redirect_uris"] = o.PostLogoutRedirectUris } - if o.RedirectUris != nil { + if !IsNil(o.RedirectUris) { toSerialize["redirect_uris"] = o.RedirectUris } - if o.RefreshTokenGrantAccessTokenLifespan != nil { + if !IsNil(o.RefreshTokenGrantAccessTokenLifespan) { toSerialize["refresh_token_grant_access_token_lifespan"] = o.RefreshTokenGrantAccessTokenLifespan } - if o.RefreshTokenGrantIdTokenLifespan != nil { + if !IsNil(o.RefreshTokenGrantIdTokenLifespan) { toSerialize["refresh_token_grant_id_token_lifespan"] = o.RefreshTokenGrantIdTokenLifespan } - if o.RefreshTokenGrantRefreshTokenLifespan != nil { + if !IsNil(o.RefreshTokenGrantRefreshTokenLifespan) { toSerialize["refresh_token_grant_refresh_token_lifespan"] = o.RefreshTokenGrantRefreshTokenLifespan } - if o.RegistrationAccessToken != nil { + if !IsNil(o.RegistrationAccessToken) { toSerialize["registration_access_token"] = o.RegistrationAccessToken } - if o.RegistrationClientUri != nil { + if !IsNil(o.RegistrationClientUri) { toSerialize["registration_client_uri"] = o.RegistrationClientUri } - if o.RequestObjectSigningAlg != nil { + if !IsNil(o.RequestObjectSigningAlg) { toSerialize["request_object_signing_alg"] = o.RequestObjectSigningAlg } - if o.RequestUris != nil { + if !IsNil(o.RequestUris) { toSerialize["request_uris"] = o.RequestUris } - if o.ResponseTypes != nil { + if !IsNil(o.ResponseTypes) { toSerialize["response_types"] = o.ResponseTypes } - if o.Scope != nil { + if !IsNil(o.Scope) { toSerialize["scope"] = o.Scope } - if o.SectorIdentifierUri != nil { + if !IsNil(o.SectorIdentifierUri) { toSerialize["sector_identifier_uri"] = o.SectorIdentifierUri } - if o.SubjectType != nil { + if !IsNil(o.SkipConsent) { + toSerialize["skip_consent"] = o.SkipConsent + } + if !IsNil(o.SkipLogoutConsent) { + toSerialize["skip_logout_consent"] = o.SkipLogoutConsent + } + if !IsNil(o.SubjectType) { toSerialize["subject_type"] = o.SubjectType } - if o.TokenEndpointAuthMethod != nil { + if !IsNil(o.TokenEndpointAuthMethod) { toSerialize["token_endpoint_auth_method"] = o.TokenEndpointAuthMethod } - if o.TokenEndpointAuthSigningAlg != nil { + if !IsNil(o.TokenEndpointAuthSigningAlg) { toSerialize["token_endpoint_auth_signing_alg"] = o.TokenEndpointAuthSigningAlg } - if o.TosUri != nil { + if !IsNil(o.TosUri) { toSerialize["tos_uri"] = o.TosUri } - if o.UpdatedAt != nil { + if !IsNil(o.UpdatedAt) { toSerialize["updated_at"] = o.UpdatedAt } - if o.UserinfoSignedResponseAlg != nil { + if !IsNil(o.UserinfoSignedResponseAlg) { toSerialize["userinfo_signed_response_alg"] = o.UserinfoSignedResponseAlg } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableOAuth2Client struct { diff --git a/internal/httpclient/model_o_auth2_client_token_lifespans.go b/internal/httpclient/model_o_auth2_client_token_lifespans.go index 27af7508496..2ed10b8508c 100644 --- a/internal/httpclient/model_o_auth2_client_token_lifespans.go +++ b/internal/httpclient/model_o_auth2_client_token_lifespans.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the OAuth2ClientTokenLifespans type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2ClientTokenLifespans{} + // OAuth2ClientTokenLifespans Lifespans of different token types issued for this OAuth 2.0 Client. type OAuth2ClientTokenLifespans struct { // Specify a time duration in milliseconds, seconds, minutes, hours. @@ -58,7 +61,7 @@ func NewOAuth2ClientTokenLifespansWithDefaults() *OAuth2ClientTokenLifespans { // GetAuthorizationCodeGrantAccessTokenLifespan returns the AuthorizationCodeGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantAccessTokenLifespan() string { - if o == nil || o.AuthorizationCodeGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantAccessTokenLifespan) { var ret string return ret } @@ -68,7 +71,7 @@ func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantAccessTokenLifespa // GetAuthorizationCodeGrantAccessTokenLifespanOk returns a tuple with the AuthorizationCodeGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.AuthorizationCodeGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantAccessTokenLifespan) { return nil, false } return o.AuthorizationCodeGrantAccessTokenLifespan, true @@ -76,7 +79,7 @@ func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantAccessTokenLifespa // HasAuthorizationCodeGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasAuthorizationCodeGrantAccessTokenLifespan() bool { - if o != nil && o.AuthorizationCodeGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.AuthorizationCodeGrantAccessTokenLifespan) { return true } @@ -90,7 +93,7 @@ func (o *OAuth2ClientTokenLifespans) SetAuthorizationCodeGrantAccessTokenLifespa // GetAuthorizationCodeGrantIdTokenLifespan returns the AuthorizationCodeGrantIdTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantIdTokenLifespan() string { - if o == nil || o.AuthorizationCodeGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantIdTokenLifespan) { var ret string return ret } @@ -100,7 +103,7 @@ func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantIdTokenLifespan() // GetAuthorizationCodeGrantIdTokenLifespanOk returns a tuple with the AuthorizationCodeGrantIdTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantIdTokenLifespanOk() (*string, bool) { - if o == nil || o.AuthorizationCodeGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantIdTokenLifespan) { return nil, false } return o.AuthorizationCodeGrantIdTokenLifespan, true @@ -108,7 +111,7 @@ func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantIdTokenLifespanOk( // HasAuthorizationCodeGrantIdTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasAuthorizationCodeGrantIdTokenLifespan() bool { - if o != nil && o.AuthorizationCodeGrantIdTokenLifespan != nil { + if o != nil && !IsNil(o.AuthorizationCodeGrantIdTokenLifespan) { return true } @@ -122,7 +125,7 @@ func (o *OAuth2ClientTokenLifespans) SetAuthorizationCodeGrantIdTokenLifespan(v // GetAuthorizationCodeGrantRefreshTokenLifespan returns the AuthorizationCodeGrantRefreshTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantRefreshTokenLifespan() string { - if o == nil || o.AuthorizationCodeGrantRefreshTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantRefreshTokenLifespan) { var ret string return ret } @@ -132,7 +135,7 @@ func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantRefreshTokenLifesp // GetAuthorizationCodeGrantRefreshTokenLifespanOk returns a tuple with the AuthorizationCodeGrantRefreshTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantRefreshTokenLifespanOk() (*string, bool) { - if o == nil || o.AuthorizationCodeGrantRefreshTokenLifespan == nil { + if o == nil || IsNil(o.AuthorizationCodeGrantRefreshTokenLifespan) { return nil, false } return o.AuthorizationCodeGrantRefreshTokenLifespan, true @@ -140,7 +143,7 @@ func (o *OAuth2ClientTokenLifespans) GetAuthorizationCodeGrantRefreshTokenLifesp // HasAuthorizationCodeGrantRefreshTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasAuthorizationCodeGrantRefreshTokenLifespan() bool { - if o != nil && o.AuthorizationCodeGrantRefreshTokenLifespan != nil { + if o != nil && !IsNil(o.AuthorizationCodeGrantRefreshTokenLifespan) { return true } @@ -154,7 +157,7 @@ func (o *OAuth2ClientTokenLifespans) SetAuthorizationCodeGrantRefreshTokenLifesp // GetClientCredentialsGrantAccessTokenLifespan returns the ClientCredentialsGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetClientCredentialsGrantAccessTokenLifespan() string { - if o == nil || o.ClientCredentialsGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.ClientCredentialsGrantAccessTokenLifespan) { var ret string return ret } @@ -164,7 +167,7 @@ func (o *OAuth2ClientTokenLifespans) GetClientCredentialsGrantAccessTokenLifespa // GetClientCredentialsGrantAccessTokenLifespanOk returns a tuple with the ClientCredentialsGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetClientCredentialsGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.ClientCredentialsGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.ClientCredentialsGrantAccessTokenLifespan) { return nil, false } return o.ClientCredentialsGrantAccessTokenLifespan, true @@ -172,7 +175,7 @@ func (o *OAuth2ClientTokenLifespans) GetClientCredentialsGrantAccessTokenLifespa // HasClientCredentialsGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasClientCredentialsGrantAccessTokenLifespan() bool { - if o != nil && o.ClientCredentialsGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.ClientCredentialsGrantAccessTokenLifespan) { return true } @@ -186,7 +189,7 @@ func (o *OAuth2ClientTokenLifespans) SetClientCredentialsGrantAccessTokenLifespa // GetImplicitGrantAccessTokenLifespan returns the ImplicitGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetImplicitGrantAccessTokenLifespan() string { - if o == nil || o.ImplicitGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.ImplicitGrantAccessTokenLifespan) { var ret string return ret } @@ -196,7 +199,7 @@ func (o *OAuth2ClientTokenLifespans) GetImplicitGrantAccessTokenLifespan() strin // GetImplicitGrantAccessTokenLifespanOk returns a tuple with the ImplicitGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetImplicitGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.ImplicitGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.ImplicitGrantAccessTokenLifespan) { return nil, false } return o.ImplicitGrantAccessTokenLifespan, true @@ -204,7 +207,7 @@ func (o *OAuth2ClientTokenLifespans) GetImplicitGrantAccessTokenLifespanOk() (*s // HasImplicitGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasImplicitGrantAccessTokenLifespan() bool { - if o != nil && o.ImplicitGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.ImplicitGrantAccessTokenLifespan) { return true } @@ -218,7 +221,7 @@ func (o *OAuth2ClientTokenLifespans) SetImplicitGrantAccessTokenLifespan(v strin // GetImplicitGrantIdTokenLifespan returns the ImplicitGrantIdTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetImplicitGrantIdTokenLifespan() string { - if o == nil || o.ImplicitGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.ImplicitGrantIdTokenLifespan) { var ret string return ret } @@ -228,7 +231,7 @@ func (o *OAuth2ClientTokenLifespans) GetImplicitGrantIdTokenLifespan() string { // GetImplicitGrantIdTokenLifespanOk returns a tuple with the ImplicitGrantIdTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetImplicitGrantIdTokenLifespanOk() (*string, bool) { - if o == nil || o.ImplicitGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.ImplicitGrantIdTokenLifespan) { return nil, false } return o.ImplicitGrantIdTokenLifespan, true @@ -236,7 +239,7 @@ func (o *OAuth2ClientTokenLifespans) GetImplicitGrantIdTokenLifespanOk() (*strin // HasImplicitGrantIdTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasImplicitGrantIdTokenLifespan() bool { - if o != nil && o.ImplicitGrantIdTokenLifespan != nil { + if o != nil && !IsNil(o.ImplicitGrantIdTokenLifespan) { return true } @@ -250,7 +253,7 @@ func (o *OAuth2ClientTokenLifespans) SetImplicitGrantIdTokenLifespan(v string) { // GetJwtBearerGrantAccessTokenLifespan returns the JwtBearerGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetJwtBearerGrantAccessTokenLifespan() string { - if o == nil || o.JwtBearerGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.JwtBearerGrantAccessTokenLifespan) { var ret string return ret } @@ -260,7 +263,7 @@ func (o *OAuth2ClientTokenLifespans) GetJwtBearerGrantAccessTokenLifespan() stri // GetJwtBearerGrantAccessTokenLifespanOk returns a tuple with the JwtBearerGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetJwtBearerGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.JwtBearerGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.JwtBearerGrantAccessTokenLifespan) { return nil, false } return o.JwtBearerGrantAccessTokenLifespan, true @@ -268,7 +271,7 @@ func (o *OAuth2ClientTokenLifespans) GetJwtBearerGrantAccessTokenLifespanOk() (* // HasJwtBearerGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasJwtBearerGrantAccessTokenLifespan() bool { - if o != nil && o.JwtBearerGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.JwtBearerGrantAccessTokenLifespan) { return true } @@ -282,7 +285,7 @@ func (o *OAuth2ClientTokenLifespans) SetJwtBearerGrantAccessTokenLifespan(v stri // GetRefreshTokenGrantAccessTokenLifespan returns the RefreshTokenGrantAccessTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantAccessTokenLifespan() string { - if o == nil || o.RefreshTokenGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantAccessTokenLifespan) { var ret string return ret } @@ -292,7 +295,7 @@ func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantAccessTokenLifespan() s // GetRefreshTokenGrantAccessTokenLifespanOk returns a tuple with the RefreshTokenGrantAccessTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantAccessTokenLifespanOk() (*string, bool) { - if o == nil || o.RefreshTokenGrantAccessTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantAccessTokenLifespan) { return nil, false } return o.RefreshTokenGrantAccessTokenLifespan, true @@ -300,7 +303,7 @@ func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantAccessTokenLifespanOk() // HasRefreshTokenGrantAccessTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasRefreshTokenGrantAccessTokenLifespan() bool { - if o != nil && o.RefreshTokenGrantAccessTokenLifespan != nil { + if o != nil && !IsNil(o.RefreshTokenGrantAccessTokenLifespan) { return true } @@ -314,7 +317,7 @@ func (o *OAuth2ClientTokenLifespans) SetRefreshTokenGrantAccessTokenLifespan(v s // GetRefreshTokenGrantIdTokenLifespan returns the RefreshTokenGrantIdTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantIdTokenLifespan() string { - if o == nil || o.RefreshTokenGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantIdTokenLifespan) { var ret string return ret } @@ -324,7 +327,7 @@ func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantIdTokenLifespan() strin // GetRefreshTokenGrantIdTokenLifespanOk returns a tuple with the RefreshTokenGrantIdTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantIdTokenLifespanOk() (*string, bool) { - if o == nil || o.RefreshTokenGrantIdTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantIdTokenLifespan) { return nil, false } return o.RefreshTokenGrantIdTokenLifespan, true @@ -332,7 +335,7 @@ func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantIdTokenLifespanOk() (*s // HasRefreshTokenGrantIdTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasRefreshTokenGrantIdTokenLifespan() bool { - if o != nil && o.RefreshTokenGrantIdTokenLifespan != nil { + if o != nil && !IsNil(o.RefreshTokenGrantIdTokenLifespan) { return true } @@ -346,7 +349,7 @@ func (o *OAuth2ClientTokenLifespans) SetRefreshTokenGrantIdTokenLifespan(v strin // GetRefreshTokenGrantRefreshTokenLifespan returns the RefreshTokenGrantRefreshTokenLifespan field value if set, zero value otherwise. func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantRefreshTokenLifespan() string { - if o == nil || o.RefreshTokenGrantRefreshTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantRefreshTokenLifespan) { var ret string return ret } @@ -356,7 +359,7 @@ func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantRefreshTokenLifespan() // GetRefreshTokenGrantRefreshTokenLifespanOk returns a tuple with the RefreshTokenGrantRefreshTokenLifespan field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantRefreshTokenLifespanOk() (*string, bool) { - if o == nil || o.RefreshTokenGrantRefreshTokenLifespan == nil { + if o == nil || IsNil(o.RefreshTokenGrantRefreshTokenLifespan) { return nil, false } return o.RefreshTokenGrantRefreshTokenLifespan, true @@ -364,7 +367,7 @@ func (o *OAuth2ClientTokenLifespans) GetRefreshTokenGrantRefreshTokenLifespanOk( // HasRefreshTokenGrantRefreshTokenLifespan returns a boolean if a field has been set. func (o *OAuth2ClientTokenLifespans) HasRefreshTokenGrantRefreshTokenLifespan() bool { - if o != nil && o.RefreshTokenGrantRefreshTokenLifespan != nil { + if o != nil && !IsNil(o.RefreshTokenGrantRefreshTokenLifespan) { return true } @@ -377,38 +380,46 @@ func (o *OAuth2ClientTokenLifespans) SetRefreshTokenGrantRefreshTokenLifespan(v } func (o OAuth2ClientTokenLifespans) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o OAuth2ClientTokenLifespans) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.AuthorizationCodeGrantAccessTokenLifespan != nil { + if !IsNil(o.AuthorizationCodeGrantAccessTokenLifespan) { toSerialize["authorization_code_grant_access_token_lifespan"] = o.AuthorizationCodeGrantAccessTokenLifespan } - if o.AuthorizationCodeGrantIdTokenLifespan != nil { + if !IsNil(o.AuthorizationCodeGrantIdTokenLifespan) { toSerialize["authorization_code_grant_id_token_lifespan"] = o.AuthorizationCodeGrantIdTokenLifespan } - if o.AuthorizationCodeGrantRefreshTokenLifespan != nil { + if !IsNil(o.AuthorizationCodeGrantRefreshTokenLifespan) { toSerialize["authorization_code_grant_refresh_token_lifespan"] = o.AuthorizationCodeGrantRefreshTokenLifespan } - if o.ClientCredentialsGrantAccessTokenLifespan != nil { + if !IsNil(o.ClientCredentialsGrantAccessTokenLifespan) { toSerialize["client_credentials_grant_access_token_lifespan"] = o.ClientCredentialsGrantAccessTokenLifespan } - if o.ImplicitGrantAccessTokenLifespan != nil { + if !IsNil(o.ImplicitGrantAccessTokenLifespan) { toSerialize["implicit_grant_access_token_lifespan"] = o.ImplicitGrantAccessTokenLifespan } - if o.ImplicitGrantIdTokenLifespan != nil { + if !IsNil(o.ImplicitGrantIdTokenLifespan) { toSerialize["implicit_grant_id_token_lifespan"] = o.ImplicitGrantIdTokenLifespan } - if o.JwtBearerGrantAccessTokenLifespan != nil { + if !IsNil(o.JwtBearerGrantAccessTokenLifespan) { toSerialize["jwt_bearer_grant_access_token_lifespan"] = o.JwtBearerGrantAccessTokenLifespan } - if o.RefreshTokenGrantAccessTokenLifespan != nil { + if !IsNil(o.RefreshTokenGrantAccessTokenLifespan) { toSerialize["refresh_token_grant_access_token_lifespan"] = o.RefreshTokenGrantAccessTokenLifespan } - if o.RefreshTokenGrantIdTokenLifespan != nil { + if !IsNil(o.RefreshTokenGrantIdTokenLifespan) { toSerialize["refresh_token_grant_id_token_lifespan"] = o.RefreshTokenGrantIdTokenLifespan } - if o.RefreshTokenGrantRefreshTokenLifespan != nil { + if !IsNil(o.RefreshTokenGrantRefreshTokenLifespan) { toSerialize["refresh_token_grant_refresh_token_lifespan"] = o.RefreshTokenGrantRefreshTokenLifespan } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableOAuth2ClientTokenLifespans struct { diff --git a/internal/httpclient/model_o_auth2_consent_request.go b/internal/httpclient/model_o_auth2_consent_request.go index a61e14d016e..78be5c543fa 100644 --- a/internal/httpclient/model_o_auth2_consent_request.go +++ b/internal/httpclient/model_o_auth2_consent_request.go @@ -12,9 +12,14 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the OAuth2ConsentRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2ConsentRequest{} + // OAuth2ConsentRequest struct for OAuth2ConsentRequest type OAuth2ConsentRequest struct { // ACR represents the Authentication AuthorizationContext Class Reference value for this authentication session. You can use it to express that, for example, a user authenticated using two factor authentication. @@ -39,6 +44,8 @@ type OAuth2ConsentRequest struct { Subject *string `json:"subject,omitempty"` } +type _OAuth2ConsentRequest OAuth2ConsentRequest + // NewOAuth2ConsentRequest instantiates a new OAuth2ConsentRequest object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -59,7 +66,7 @@ func NewOAuth2ConsentRequestWithDefaults() *OAuth2ConsentRequest { // GetAcr returns the Acr field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetAcr() string { - if o == nil || o.Acr == nil { + if o == nil || IsNil(o.Acr) { var ret string return ret } @@ -69,7 +76,7 @@ func (o *OAuth2ConsentRequest) GetAcr() string { // GetAcrOk returns a tuple with the Acr field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetAcrOk() (*string, bool) { - if o == nil || o.Acr == nil { + if o == nil || IsNil(o.Acr) { return nil, false } return o.Acr, true @@ -77,7 +84,7 @@ func (o *OAuth2ConsentRequest) GetAcrOk() (*string, bool) { // HasAcr returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasAcr() bool { - if o != nil && o.Acr != nil { + if o != nil && !IsNil(o.Acr) { return true } @@ -91,7 +98,7 @@ func (o *OAuth2ConsentRequest) SetAcr(v string) { // GetAmr returns the Amr field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetAmr() []string { - if o == nil || o.Amr == nil { + if o == nil || IsNil(o.Amr) { var ret []string return ret } @@ -101,7 +108,7 @@ func (o *OAuth2ConsentRequest) GetAmr() []string { // GetAmrOk returns a tuple with the Amr field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetAmrOk() ([]string, bool) { - if o == nil || o.Amr == nil { + if o == nil || IsNil(o.Amr) { return nil, false } return o.Amr, true @@ -109,7 +116,7 @@ func (o *OAuth2ConsentRequest) GetAmrOk() ([]string, bool) { // HasAmr returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasAmr() bool { - if o != nil && o.Amr != nil { + if o != nil && !IsNil(o.Amr) { return true } @@ -147,7 +154,7 @@ func (o *OAuth2ConsentRequest) SetChallenge(v string) { // GetClient returns the Client field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetClient() OAuth2Client { - if o == nil || o.Client == nil { + if o == nil || IsNil(o.Client) { var ret OAuth2Client return ret } @@ -157,7 +164,7 @@ func (o *OAuth2ConsentRequest) GetClient() OAuth2Client { // GetClientOk returns a tuple with the Client field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetClientOk() (*OAuth2Client, bool) { - if o == nil || o.Client == nil { + if o == nil || IsNil(o.Client) { return nil, false } return o.Client, true @@ -165,7 +172,7 @@ func (o *OAuth2ConsentRequest) GetClientOk() (*OAuth2Client, bool) { // HasClient returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasClient() bool { - if o != nil && o.Client != nil { + if o != nil && !IsNil(o.Client) { return true } @@ -190,7 +197,7 @@ func (o *OAuth2ConsentRequest) GetContext() interface{} { // and a boolean to check if the value has been set. // NOTE: If the value is an explicit nil, `nil, true` will be returned func (o *OAuth2ConsentRequest) GetContextOk() (*interface{}, bool) { - if o == nil || o.Context == nil { + if o == nil || IsNil(o.Context) { return nil, false } return &o.Context, true @@ -198,7 +205,7 @@ func (o *OAuth2ConsentRequest) GetContextOk() (*interface{}, bool) { // HasContext returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasContext() bool { - if o != nil && o.Context != nil { + if o != nil && IsNil(o.Context) { return true } @@ -212,7 +219,7 @@ func (o *OAuth2ConsentRequest) SetContext(v interface{}) { // GetLoginChallenge returns the LoginChallenge field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetLoginChallenge() string { - if o == nil || o.LoginChallenge == nil { + if o == nil || IsNil(o.LoginChallenge) { var ret string return ret } @@ -222,7 +229,7 @@ func (o *OAuth2ConsentRequest) GetLoginChallenge() string { // GetLoginChallengeOk returns a tuple with the LoginChallenge field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetLoginChallengeOk() (*string, bool) { - if o == nil || o.LoginChallenge == nil { + if o == nil || IsNil(o.LoginChallenge) { return nil, false } return o.LoginChallenge, true @@ -230,7 +237,7 @@ func (o *OAuth2ConsentRequest) GetLoginChallengeOk() (*string, bool) { // HasLoginChallenge returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasLoginChallenge() bool { - if o != nil && o.LoginChallenge != nil { + if o != nil && !IsNil(o.LoginChallenge) { return true } @@ -244,7 +251,7 @@ func (o *OAuth2ConsentRequest) SetLoginChallenge(v string) { // GetLoginSessionId returns the LoginSessionId field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetLoginSessionId() string { - if o == nil || o.LoginSessionId == nil { + if o == nil || IsNil(o.LoginSessionId) { var ret string return ret } @@ -254,7 +261,7 @@ func (o *OAuth2ConsentRequest) GetLoginSessionId() string { // GetLoginSessionIdOk returns a tuple with the LoginSessionId field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetLoginSessionIdOk() (*string, bool) { - if o == nil || o.LoginSessionId == nil { + if o == nil || IsNil(o.LoginSessionId) { return nil, false } return o.LoginSessionId, true @@ -262,7 +269,7 @@ func (o *OAuth2ConsentRequest) GetLoginSessionIdOk() (*string, bool) { // HasLoginSessionId returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasLoginSessionId() bool { - if o != nil && o.LoginSessionId != nil { + if o != nil && !IsNil(o.LoginSessionId) { return true } @@ -276,7 +283,7 @@ func (o *OAuth2ConsentRequest) SetLoginSessionId(v string) { // GetOidcContext returns the OidcContext field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetOidcContext() OAuth2ConsentRequestOpenIDConnectContext { - if o == nil || o.OidcContext == nil { + if o == nil || IsNil(o.OidcContext) { var ret OAuth2ConsentRequestOpenIDConnectContext return ret } @@ -286,7 +293,7 @@ func (o *OAuth2ConsentRequest) GetOidcContext() OAuth2ConsentRequestOpenIDConnec // GetOidcContextOk returns a tuple with the OidcContext field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetOidcContextOk() (*OAuth2ConsentRequestOpenIDConnectContext, bool) { - if o == nil || o.OidcContext == nil { + if o == nil || IsNil(o.OidcContext) { return nil, false } return o.OidcContext, true @@ -294,7 +301,7 @@ func (o *OAuth2ConsentRequest) GetOidcContextOk() (*OAuth2ConsentRequestOpenIDCo // HasOidcContext returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasOidcContext() bool { - if o != nil && o.OidcContext != nil { + if o != nil && !IsNil(o.OidcContext) { return true } @@ -308,7 +315,7 @@ func (o *OAuth2ConsentRequest) SetOidcContext(v OAuth2ConsentRequestOpenIDConnec // GetRequestUrl returns the RequestUrl field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetRequestUrl() string { - if o == nil || o.RequestUrl == nil { + if o == nil || IsNil(o.RequestUrl) { var ret string return ret } @@ -318,7 +325,7 @@ func (o *OAuth2ConsentRequest) GetRequestUrl() string { // GetRequestUrlOk returns a tuple with the RequestUrl field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetRequestUrlOk() (*string, bool) { - if o == nil || o.RequestUrl == nil { + if o == nil || IsNil(o.RequestUrl) { return nil, false } return o.RequestUrl, true @@ -326,7 +333,7 @@ func (o *OAuth2ConsentRequest) GetRequestUrlOk() (*string, bool) { // HasRequestUrl returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasRequestUrl() bool { - if o != nil && o.RequestUrl != nil { + if o != nil && !IsNil(o.RequestUrl) { return true } @@ -340,7 +347,7 @@ func (o *OAuth2ConsentRequest) SetRequestUrl(v string) { // GetRequestedAccessTokenAudience returns the RequestedAccessTokenAudience field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetRequestedAccessTokenAudience() []string { - if o == nil || o.RequestedAccessTokenAudience == nil { + if o == nil || IsNil(o.RequestedAccessTokenAudience) { var ret []string return ret } @@ -350,7 +357,7 @@ func (o *OAuth2ConsentRequest) GetRequestedAccessTokenAudience() []string { // GetRequestedAccessTokenAudienceOk returns a tuple with the RequestedAccessTokenAudience field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetRequestedAccessTokenAudienceOk() ([]string, bool) { - if o == nil || o.RequestedAccessTokenAudience == nil { + if o == nil || IsNil(o.RequestedAccessTokenAudience) { return nil, false } return o.RequestedAccessTokenAudience, true @@ -358,7 +365,7 @@ func (o *OAuth2ConsentRequest) GetRequestedAccessTokenAudienceOk() ([]string, bo // HasRequestedAccessTokenAudience returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasRequestedAccessTokenAudience() bool { - if o != nil && o.RequestedAccessTokenAudience != nil { + if o != nil && !IsNil(o.RequestedAccessTokenAudience) { return true } @@ -372,7 +379,7 @@ func (o *OAuth2ConsentRequest) SetRequestedAccessTokenAudience(v []string) { // GetRequestedScope returns the RequestedScope field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetRequestedScope() []string { - if o == nil || o.RequestedScope == nil { + if o == nil || IsNil(o.RequestedScope) { var ret []string return ret } @@ -382,7 +389,7 @@ func (o *OAuth2ConsentRequest) GetRequestedScope() []string { // GetRequestedScopeOk returns a tuple with the RequestedScope field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetRequestedScopeOk() ([]string, bool) { - if o == nil || o.RequestedScope == nil { + if o == nil || IsNil(o.RequestedScope) { return nil, false } return o.RequestedScope, true @@ -390,7 +397,7 @@ func (o *OAuth2ConsentRequest) GetRequestedScopeOk() ([]string, bool) { // HasRequestedScope returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasRequestedScope() bool { - if o != nil && o.RequestedScope != nil { + if o != nil && !IsNil(o.RequestedScope) { return true } @@ -404,7 +411,7 @@ func (o *OAuth2ConsentRequest) SetRequestedScope(v []string) { // GetSkip returns the Skip field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetSkip() bool { - if o == nil || o.Skip == nil { + if o == nil || IsNil(o.Skip) { var ret bool return ret } @@ -414,7 +421,7 @@ func (o *OAuth2ConsentRequest) GetSkip() bool { // GetSkipOk returns a tuple with the Skip field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetSkipOk() (*bool, bool) { - if o == nil || o.Skip == nil { + if o == nil || IsNil(o.Skip) { return nil, false } return o.Skip, true @@ -422,7 +429,7 @@ func (o *OAuth2ConsentRequest) GetSkipOk() (*bool, bool) { // HasSkip returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasSkip() bool { - if o != nil && o.Skip != nil { + if o != nil && !IsNil(o.Skip) { return true } @@ -436,7 +443,7 @@ func (o *OAuth2ConsentRequest) SetSkip(v bool) { // GetSubject returns the Subject field value if set, zero value otherwise. func (o *OAuth2ConsentRequest) GetSubject() string { - if o == nil || o.Subject == nil { + if o == nil || IsNil(o.Subject) { var ret string return ret } @@ -446,7 +453,7 @@ func (o *OAuth2ConsentRequest) GetSubject() string { // GetSubjectOk returns a tuple with the Subject field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequest) GetSubjectOk() (*string, bool) { - if o == nil || o.Subject == nil { + if o == nil || IsNil(o.Subject) { return nil, false } return o.Subject, true @@ -454,7 +461,7 @@ func (o *OAuth2ConsentRequest) GetSubjectOk() (*string, bool) { // HasSubject returns a boolean if a field has been set. func (o *OAuth2ConsentRequest) HasSubject() bool { - if o != nil && o.Subject != nil { + if o != nil && !IsNil(o.Subject) { return true } @@ -467,47 +474,90 @@ func (o *OAuth2ConsentRequest) SetSubject(v string) { } func (o OAuth2ConsentRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o OAuth2ConsentRequest) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Acr != nil { + if !IsNil(o.Acr) { toSerialize["acr"] = o.Acr } - if o.Amr != nil { + if !IsNil(o.Amr) { toSerialize["amr"] = o.Amr } - if true { - toSerialize["challenge"] = o.Challenge - } - if o.Client != nil { + toSerialize["challenge"] = o.Challenge + if !IsNil(o.Client) { toSerialize["client"] = o.Client } if o.Context != nil { toSerialize["context"] = o.Context } - if o.LoginChallenge != nil { + if !IsNil(o.LoginChallenge) { toSerialize["login_challenge"] = o.LoginChallenge } - if o.LoginSessionId != nil { + if !IsNil(o.LoginSessionId) { toSerialize["login_session_id"] = o.LoginSessionId } - if o.OidcContext != nil { + if !IsNil(o.OidcContext) { toSerialize["oidc_context"] = o.OidcContext } - if o.RequestUrl != nil { + if !IsNil(o.RequestUrl) { toSerialize["request_url"] = o.RequestUrl } - if o.RequestedAccessTokenAudience != nil { + if !IsNil(o.RequestedAccessTokenAudience) { toSerialize["requested_access_token_audience"] = o.RequestedAccessTokenAudience } - if o.RequestedScope != nil { + if !IsNil(o.RequestedScope) { toSerialize["requested_scope"] = o.RequestedScope } - if o.Skip != nil { + if !IsNil(o.Skip) { toSerialize["skip"] = o.Skip } - if o.Subject != nil { + if !IsNil(o.Subject) { toSerialize["subject"] = o.Subject } - return json.Marshal(toSerialize) + return toSerialize, nil +} + +func (o *OAuth2ConsentRequest) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "challenge", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varOAuth2ConsentRequest := _OAuth2ConsentRequest{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varOAuth2ConsentRequest) + + if err != nil { + return err + } + + *o = OAuth2ConsentRequest(varOAuth2ConsentRequest) + + return err } type NullableOAuth2ConsentRequest struct { diff --git a/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go b/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go index 8bc15fafe33..962ab736c66 100644 --- a/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go +++ b/internal/httpclient/model_o_auth2_consent_request_open_id_connect_context.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the OAuth2ConsentRequestOpenIDConnectContext type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2ConsentRequestOpenIDConnectContext{} + // OAuth2ConsentRequestOpenIDConnectContext struct for OAuth2ConsentRequestOpenIDConnectContext type OAuth2ConsentRequestOpenIDConnectContext struct { // ACRValues is the Authentication AuthorizationContext Class Reference requested in the OAuth 2.0 Authorization request. It is a parameter defined by OpenID Connect and expresses which level of authentication (e.g. 2FA) is required. OpenID Connect defines it as follows: > Requested Authentication AuthorizationContext Class Reference values. Space-separated string that specifies the acr values that the Authorization Server is being requested to use for processing this Authentication Request, with the values appearing in order of preference. The Authentication AuthorizationContext Class satisfied by the authentication performed is returned as the acr Claim Value, as specified in Section 2. The acr Claim is requested as a Voluntary Claim by this parameter. @@ -48,7 +51,7 @@ func NewOAuth2ConsentRequestOpenIDConnectContextWithDefaults() *OAuth2ConsentReq // GetAcrValues returns the AcrValues field value if set, zero value otherwise. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAcrValues() []string { - if o == nil || o.AcrValues == nil { + if o == nil || IsNil(o.AcrValues) { var ret []string return ret } @@ -58,7 +61,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAcrValues() []string { // GetAcrValuesOk returns a tuple with the AcrValues field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAcrValuesOk() ([]string, bool) { - if o == nil || o.AcrValues == nil { + if o == nil || IsNil(o.AcrValues) { return nil, false } return o.AcrValues, true @@ -66,7 +69,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) GetAcrValuesOk() ([]string, b // HasAcrValues returns a boolean if a field has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) HasAcrValues() bool { - if o != nil && o.AcrValues != nil { + if o != nil && !IsNil(o.AcrValues) { return true } @@ -80,7 +83,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) SetAcrValues(v []string) { // GetDisplay returns the Display field value if set, zero value otherwise. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetDisplay() string { - if o == nil || o.Display == nil { + if o == nil || IsNil(o.Display) { var ret string return ret } @@ -90,7 +93,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) GetDisplay() string { // GetDisplayOk returns a tuple with the Display field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetDisplayOk() (*string, bool) { - if o == nil || o.Display == nil { + if o == nil || IsNil(o.Display) { return nil, false } return o.Display, true @@ -98,7 +101,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) GetDisplayOk() (*string, bool // HasDisplay returns a boolean if a field has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) HasDisplay() bool { - if o != nil && o.Display != nil { + if o != nil && !IsNil(o.Display) { return true } @@ -112,7 +115,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) SetDisplay(v string) { // GetIdTokenHintClaims returns the IdTokenHintClaims field value if set, zero value otherwise. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetIdTokenHintClaims() map[string]interface{} { - if o == nil || o.IdTokenHintClaims == nil { + if o == nil || IsNil(o.IdTokenHintClaims) { var ret map[string]interface{} return ret } @@ -122,15 +125,15 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) GetIdTokenHintClaims() map[st // GetIdTokenHintClaimsOk returns a tuple with the IdTokenHintClaims field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetIdTokenHintClaimsOk() (map[string]interface{}, bool) { - if o == nil || o.IdTokenHintClaims == nil { - return nil, false + if o == nil || IsNil(o.IdTokenHintClaims) { + return map[string]interface{}{}, false } return o.IdTokenHintClaims, true } // HasIdTokenHintClaims returns a boolean if a field has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) HasIdTokenHintClaims() bool { - if o != nil && o.IdTokenHintClaims != nil { + if o != nil && !IsNil(o.IdTokenHintClaims) { return true } @@ -144,7 +147,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) SetIdTokenHintClaims(v map[st // GetLoginHint returns the LoginHint field value if set, zero value otherwise. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetLoginHint() string { - if o == nil || o.LoginHint == nil { + if o == nil || IsNil(o.LoginHint) { var ret string return ret } @@ -154,7 +157,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) GetLoginHint() string { // GetLoginHintOk returns a tuple with the LoginHint field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetLoginHintOk() (*string, bool) { - if o == nil || o.LoginHint == nil { + if o == nil || IsNil(o.LoginHint) { return nil, false } return o.LoginHint, true @@ -162,7 +165,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) GetLoginHintOk() (*string, bo // HasLoginHint returns a boolean if a field has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) HasLoginHint() bool { - if o != nil && o.LoginHint != nil { + if o != nil && !IsNil(o.LoginHint) { return true } @@ -176,7 +179,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) SetLoginHint(v string) { // GetUiLocales returns the UiLocales field value if set, zero value otherwise. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetUiLocales() []string { - if o == nil || o.UiLocales == nil { + if o == nil || IsNil(o.UiLocales) { var ret []string return ret } @@ -186,7 +189,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) GetUiLocales() []string { // GetUiLocalesOk returns a tuple with the UiLocales field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) GetUiLocalesOk() ([]string, bool) { - if o == nil || o.UiLocales == nil { + if o == nil || IsNil(o.UiLocales) { return nil, false } return o.UiLocales, true @@ -194,7 +197,7 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) GetUiLocalesOk() ([]string, b // HasUiLocales returns a boolean if a field has been set. func (o *OAuth2ConsentRequestOpenIDConnectContext) HasUiLocales() bool { - if o != nil && o.UiLocales != nil { + if o != nil && !IsNil(o.UiLocales) { return true } @@ -207,23 +210,31 @@ func (o *OAuth2ConsentRequestOpenIDConnectContext) SetUiLocales(v []string) { } func (o OAuth2ConsentRequestOpenIDConnectContext) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o OAuth2ConsentRequestOpenIDConnectContext) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.AcrValues != nil { + if !IsNil(o.AcrValues) { toSerialize["acr_values"] = o.AcrValues } - if o.Display != nil { + if !IsNil(o.Display) { toSerialize["display"] = o.Display } - if o.IdTokenHintClaims != nil { + if !IsNil(o.IdTokenHintClaims) { toSerialize["id_token_hint_claims"] = o.IdTokenHintClaims } - if o.LoginHint != nil { + if !IsNil(o.LoginHint) { toSerialize["login_hint"] = o.LoginHint } - if o.UiLocales != nil { + if !IsNil(o.UiLocales) { toSerialize["ui_locales"] = o.UiLocales } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableOAuth2ConsentRequestOpenIDConnectContext struct { diff --git a/internal/httpclient/model_o_auth2_consent_session.go b/internal/httpclient/model_o_auth2_consent_session.go index 10d5e797cc5..92772ab891f 100644 --- a/internal/httpclient/model_o_auth2_consent_session.go +++ b/internal/httpclient/model_o_auth2_consent_session.go @@ -16,9 +16,13 @@ import ( "time" ) +// checks if the OAuth2ConsentSession type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2ConsentSession{} + // OAuth2ConsentSession A completed OAuth 2.0 Consent Session. type OAuth2ConsentSession struct { ConsentRequest *OAuth2ConsentRequest `json:"consent_request,omitempty"` + Context interface{} `json:"context,omitempty"` ExpiresAt *OAuth2ConsentSessionExpiresAt `json:"expires_at,omitempty"` GrantAccessTokenAudience []string `json:"grant_access_token_audience,omitempty"` GrantScope []string `json:"grant_scope,omitempty"` @@ -49,7 +53,7 @@ func NewOAuth2ConsentSessionWithDefaults() *OAuth2ConsentSession { // GetConsentRequest returns the ConsentRequest field value if set, zero value otherwise. func (o *OAuth2ConsentSession) GetConsentRequest() OAuth2ConsentRequest { - if o == nil || o.ConsentRequest == nil { + if o == nil || IsNil(o.ConsentRequest) { var ret OAuth2ConsentRequest return ret } @@ -59,7 +63,7 @@ func (o *OAuth2ConsentSession) GetConsentRequest() OAuth2ConsentRequest { // GetConsentRequestOk returns a tuple with the ConsentRequest field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSession) GetConsentRequestOk() (*OAuth2ConsentRequest, bool) { - if o == nil || o.ConsentRequest == nil { + if o == nil || IsNil(o.ConsentRequest) { return nil, false } return o.ConsentRequest, true @@ -67,7 +71,7 @@ func (o *OAuth2ConsentSession) GetConsentRequestOk() (*OAuth2ConsentRequest, boo // HasConsentRequest returns a boolean if a field has been set. func (o *OAuth2ConsentSession) HasConsentRequest() bool { - if o != nil && o.ConsentRequest != nil { + if o != nil && !IsNil(o.ConsentRequest) { return true } @@ -79,9 +83,42 @@ func (o *OAuth2ConsentSession) SetConsentRequest(v OAuth2ConsentRequest) { o.ConsentRequest = &v } +// GetContext returns the Context field value if set, zero value otherwise (both if not set or set to explicit null). +func (o *OAuth2ConsentSession) GetContext() interface{} { + if o == nil { + var ret interface{} + return ret + } + return o.Context +} + +// GetContextOk returns a tuple with the Context field value if set, nil otherwise +// and a boolean to check if the value has been set. +// NOTE: If the value is an explicit nil, `nil, true` will be returned +func (o *OAuth2ConsentSession) GetContextOk() (*interface{}, bool) { + if o == nil || IsNil(o.Context) { + return nil, false + } + return &o.Context, true +} + +// HasContext returns a boolean if a field has been set. +func (o *OAuth2ConsentSession) HasContext() bool { + if o != nil && IsNil(o.Context) { + return true + } + + return false +} + +// SetContext gets a reference to the given interface{} and assigns it to the Context field. +func (o *OAuth2ConsentSession) SetContext(v interface{}) { + o.Context = v +} + // GetExpiresAt returns the ExpiresAt field value if set, zero value otherwise. func (o *OAuth2ConsentSession) GetExpiresAt() OAuth2ConsentSessionExpiresAt { - if o == nil || o.ExpiresAt == nil { + if o == nil || IsNil(o.ExpiresAt) { var ret OAuth2ConsentSessionExpiresAt return ret } @@ -91,7 +128,7 @@ func (o *OAuth2ConsentSession) GetExpiresAt() OAuth2ConsentSessionExpiresAt { // GetExpiresAtOk returns a tuple with the ExpiresAt field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSession) GetExpiresAtOk() (*OAuth2ConsentSessionExpiresAt, bool) { - if o == nil || o.ExpiresAt == nil { + if o == nil || IsNil(o.ExpiresAt) { return nil, false } return o.ExpiresAt, true @@ -99,7 +136,7 @@ func (o *OAuth2ConsentSession) GetExpiresAtOk() (*OAuth2ConsentSessionExpiresAt, // HasExpiresAt returns a boolean if a field has been set. func (o *OAuth2ConsentSession) HasExpiresAt() bool { - if o != nil && o.ExpiresAt != nil { + if o != nil && !IsNil(o.ExpiresAt) { return true } @@ -113,7 +150,7 @@ func (o *OAuth2ConsentSession) SetExpiresAt(v OAuth2ConsentSessionExpiresAt) { // GetGrantAccessTokenAudience returns the GrantAccessTokenAudience field value if set, zero value otherwise. func (o *OAuth2ConsentSession) GetGrantAccessTokenAudience() []string { - if o == nil || o.GrantAccessTokenAudience == nil { + if o == nil || IsNil(o.GrantAccessTokenAudience) { var ret []string return ret } @@ -123,7 +160,7 @@ func (o *OAuth2ConsentSession) GetGrantAccessTokenAudience() []string { // GetGrantAccessTokenAudienceOk returns a tuple with the GrantAccessTokenAudience field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSession) GetGrantAccessTokenAudienceOk() ([]string, bool) { - if o == nil || o.GrantAccessTokenAudience == nil { + if o == nil || IsNil(o.GrantAccessTokenAudience) { return nil, false } return o.GrantAccessTokenAudience, true @@ -131,7 +168,7 @@ func (o *OAuth2ConsentSession) GetGrantAccessTokenAudienceOk() ([]string, bool) // HasGrantAccessTokenAudience returns a boolean if a field has been set. func (o *OAuth2ConsentSession) HasGrantAccessTokenAudience() bool { - if o != nil && o.GrantAccessTokenAudience != nil { + if o != nil && !IsNil(o.GrantAccessTokenAudience) { return true } @@ -145,7 +182,7 @@ func (o *OAuth2ConsentSession) SetGrantAccessTokenAudience(v []string) { // GetGrantScope returns the GrantScope field value if set, zero value otherwise. func (o *OAuth2ConsentSession) GetGrantScope() []string { - if o == nil || o.GrantScope == nil { + if o == nil || IsNil(o.GrantScope) { var ret []string return ret } @@ -155,7 +192,7 @@ func (o *OAuth2ConsentSession) GetGrantScope() []string { // GetGrantScopeOk returns a tuple with the GrantScope field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSession) GetGrantScopeOk() ([]string, bool) { - if o == nil || o.GrantScope == nil { + if o == nil || IsNil(o.GrantScope) { return nil, false } return o.GrantScope, true @@ -163,7 +200,7 @@ func (o *OAuth2ConsentSession) GetGrantScopeOk() ([]string, bool) { // HasGrantScope returns a boolean if a field has been set. func (o *OAuth2ConsentSession) HasGrantScope() bool { - if o != nil && o.GrantScope != nil { + if o != nil && !IsNil(o.GrantScope) { return true } @@ -177,7 +214,7 @@ func (o *OAuth2ConsentSession) SetGrantScope(v []string) { // GetHandledAt returns the HandledAt field value if set, zero value otherwise. func (o *OAuth2ConsentSession) GetHandledAt() time.Time { - if o == nil || o.HandledAt == nil { + if o == nil || IsNil(o.HandledAt) { var ret time.Time return ret } @@ -187,7 +224,7 @@ func (o *OAuth2ConsentSession) GetHandledAt() time.Time { // GetHandledAtOk returns a tuple with the HandledAt field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSession) GetHandledAtOk() (*time.Time, bool) { - if o == nil || o.HandledAt == nil { + if o == nil || IsNil(o.HandledAt) { return nil, false } return o.HandledAt, true @@ -195,7 +232,7 @@ func (o *OAuth2ConsentSession) GetHandledAtOk() (*time.Time, bool) { // HasHandledAt returns a boolean if a field has been set. func (o *OAuth2ConsentSession) HasHandledAt() bool { - if o != nil && o.HandledAt != nil { + if o != nil && !IsNil(o.HandledAt) { return true } @@ -209,7 +246,7 @@ func (o *OAuth2ConsentSession) SetHandledAt(v time.Time) { // GetRemember returns the Remember field value if set, zero value otherwise. func (o *OAuth2ConsentSession) GetRemember() bool { - if o == nil || o.Remember == nil { + if o == nil || IsNil(o.Remember) { var ret bool return ret } @@ -219,7 +256,7 @@ func (o *OAuth2ConsentSession) GetRemember() bool { // GetRememberOk returns a tuple with the Remember field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSession) GetRememberOk() (*bool, bool) { - if o == nil || o.Remember == nil { + if o == nil || IsNil(o.Remember) { return nil, false } return o.Remember, true @@ -227,7 +264,7 @@ func (o *OAuth2ConsentSession) GetRememberOk() (*bool, bool) { // HasRemember returns a boolean if a field has been set. func (o *OAuth2ConsentSession) HasRemember() bool { - if o != nil && o.Remember != nil { + if o != nil && !IsNil(o.Remember) { return true } @@ -241,7 +278,7 @@ func (o *OAuth2ConsentSession) SetRemember(v bool) { // GetRememberFor returns the RememberFor field value if set, zero value otherwise. func (o *OAuth2ConsentSession) GetRememberFor() int64 { - if o == nil || o.RememberFor == nil { + if o == nil || IsNil(o.RememberFor) { var ret int64 return ret } @@ -251,7 +288,7 @@ func (o *OAuth2ConsentSession) GetRememberFor() int64 { // GetRememberForOk returns a tuple with the RememberFor field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSession) GetRememberForOk() (*int64, bool) { - if o == nil || o.RememberFor == nil { + if o == nil || IsNil(o.RememberFor) { return nil, false } return o.RememberFor, true @@ -259,7 +296,7 @@ func (o *OAuth2ConsentSession) GetRememberForOk() (*int64, bool) { // HasRememberFor returns a boolean if a field has been set. func (o *OAuth2ConsentSession) HasRememberFor() bool { - if o != nil && o.RememberFor != nil { + if o != nil && !IsNil(o.RememberFor) { return true } @@ -273,7 +310,7 @@ func (o *OAuth2ConsentSession) SetRememberFor(v int64) { // GetSession returns the Session field value if set, zero value otherwise. func (o *OAuth2ConsentSession) GetSession() AcceptOAuth2ConsentRequestSession { - if o == nil || o.Session == nil { + if o == nil || IsNil(o.Session) { var ret AcceptOAuth2ConsentRequestSession return ret } @@ -283,7 +320,7 @@ func (o *OAuth2ConsentSession) GetSession() AcceptOAuth2ConsentRequestSession { // GetSessionOk returns a tuple with the Session field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSession) GetSessionOk() (*AcceptOAuth2ConsentRequestSession, bool) { - if o == nil || o.Session == nil { + if o == nil || IsNil(o.Session) { return nil, false } return o.Session, true @@ -291,7 +328,7 @@ func (o *OAuth2ConsentSession) GetSessionOk() (*AcceptOAuth2ConsentRequestSessio // HasSession returns a boolean if a field has been set. func (o *OAuth2ConsentSession) HasSession() bool { - if o != nil && o.Session != nil { + if o != nil && !IsNil(o.Session) { return true } @@ -304,32 +341,43 @@ func (o *OAuth2ConsentSession) SetSession(v AcceptOAuth2ConsentRequestSession) { } func (o OAuth2ConsentSession) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o OAuth2ConsentSession) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.ConsentRequest != nil { + if !IsNil(o.ConsentRequest) { toSerialize["consent_request"] = o.ConsentRequest } - if o.ExpiresAt != nil { + if o.Context != nil { + toSerialize["context"] = o.Context + } + if !IsNil(o.ExpiresAt) { toSerialize["expires_at"] = o.ExpiresAt } - if o.GrantAccessTokenAudience != nil { + if !IsNil(o.GrantAccessTokenAudience) { toSerialize["grant_access_token_audience"] = o.GrantAccessTokenAudience } - if o.GrantScope != nil { + if !IsNil(o.GrantScope) { toSerialize["grant_scope"] = o.GrantScope } - if o.HandledAt != nil { + if !IsNil(o.HandledAt) { toSerialize["handled_at"] = o.HandledAt } - if o.Remember != nil { + if !IsNil(o.Remember) { toSerialize["remember"] = o.Remember } - if o.RememberFor != nil { + if !IsNil(o.RememberFor) { toSerialize["remember_for"] = o.RememberFor } - if o.Session != nil { + if !IsNil(o.Session) { toSerialize["session"] = o.Session } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableOAuth2ConsentSession struct { diff --git a/internal/httpclient/model_o_auth2_consent_session_expires_at.go b/internal/httpclient/model_o_auth2_consent_session_expires_at.go index a0a752b99bb..20be47a9a88 100644 --- a/internal/httpclient/model_o_auth2_consent_session_expires_at.go +++ b/internal/httpclient/model_o_auth2_consent_session_expires_at.go @@ -16,6 +16,9 @@ import ( "time" ) +// checks if the OAuth2ConsentSessionExpiresAt type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2ConsentSessionExpiresAt{} + // OAuth2ConsentSessionExpiresAt struct for OAuth2ConsentSessionExpiresAt type OAuth2ConsentSessionExpiresAt struct { AccessToken *time.Time `json:"access_token,omitempty"` @@ -44,7 +47,7 @@ func NewOAuth2ConsentSessionExpiresAtWithDefaults() *OAuth2ConsentSessionExpires // GetAccessToken returns the AccessToken field value if set, zero value otherwise. func (o *OAuth2ConsentSessionExpiresAt) GetAccessToken() time.Time { - if o == nil || o.AccessToken == nil { + if o == nil || IsNil(o.AccessToken) { var ret time.Time return ret } @@ -54,7 +57,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetAccessToken() time.Time { // GetAccessTokenOk returns a tuple with the AccessToken field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSessionExpiresAt) GetAccessTokenOk() (*time.Time, bool) { - if o == nil || o.AccessToken == nil { + if o == nil || IsNil(o.AccessToken) { return nil, false } return o.AccessToken, true @@ -62,7 +65,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetAccessTokenOk() (*time.Time, bool) { // HasAccessToken returns a boolean if a field has been set. func (o *OAuth2ConsentSessionExpiresAt) HasAccessToken() bool { - if o != nil && o.AccessToken != nil { + if o != nil && !IsNil(o.AccessToken) { return true } @@ -76,7 +79,7 @@ func (o *OAuth2ConsentSessionExpiresAt) SetAccessToken(v time.Time) { // GetAuthorizeCode returns the AuthorizeCode field value if set, zero value otherwise. func (o *OAuth2ConsentSessionExpiresAt) GetAuthorizeCode() time.Time { - if o == nil || o.AuthorizeCode == nil { + if o == nil || IsNil(o.AuthorizeCode) { var ret time.Time return ret } @@ -86,7 +89,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetAuthorizeCode() time.Time { // GetAuthorizeCodeOk returns a tuple with the AuthorizeCode field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSessionExpiresAt) GetAuthorizeCodeOk() (*time.Time, bool) { - if o == nil || o.AuthorizeCode == nil { + if o == nil || IsNil(o.AuthorizeCode) { return nil, false } return o.AuthorizeCode, true @@ -94,7 +97,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetAuthorizeCodeOk() (*time.Time, bool) // HasAuthorizeCode returns a boolean if a field has been set. func (o *OAuth2ConsentSessionExpiresAt) HasAuthorizeCode() bool { - if o != nil && o.AuthorizeCode != nil { + if o != nil && !IsNil(o.AuthorizeCode) { return true } @@ -108,7 +111,7 @@ func (o *OAuth2ConsentSessionExpiresAt) SetAuthorizeCode(v time.Time) { // GetIdToken returns the IdToken field value if set, zero value otherwise. func (o *OAuth2ConsentSessionExpiresAt) GetIdToken() time.Time { - if o == nil || o.IdToken == nil { + if o == nil || IsNil(o.IdToken) { var ret time.Time return ret } @@ -118,7 +121,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetIdToken() time.Time { // GetIdTokenOk returns a tuple with the IdToken field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSessionExpiresAt) GetIdTokenOk() (*time.Time, bool) { - if o == nil || o.IdToken == nil { + if o == nil || IsNil(o.IdToken) { return nil, false } return o.IdToken, true @@ -126,7 +129,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetIdTokenOk() (*time.Time, bool) { // HasIdToken returns a boolean if a field has been set. func (o *OAuth2ConsentSessionExpiresAt) HasIdToken() bool { - if o != nil && o.IdToken != nil { + if o != nil && !IsNil(o.IdToken) { return true } @@ -140,7 +143,7 @@ func (o *OAuth2ConsentSessionExpiresAt) SetIdToken(v time.Time) { // GetParContext returns the ParContext field value if set, zero value otherwise. func (o *OAuth2ConsentSessionExpiresAt) GetParContext() time.Time { - if o == nil || o.ParContext == nil { + if o == nil || IsNil(o.ParContext) { var ret time.Time return ret } @@ -150,7 +153,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetParContext() time.Time { // GetParContextOk returns a tuple with the ParContext field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSessionExpiresAt) GetParContextOk() (*time.Time, bool) { - if o == nil || o.ParContext == nil { + if o == nil || IsNil(o.ParContext) { return nil, false } return o.ParContext, true @@ -158,7 +161,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetParContextOk() (*time.Time, bool) { // HasParContext returns a boolean if a field has been set. func (o *OAuth2ConsentSessionExpiresAt) HasParContext() bool { - if o != nil && o.ParContext != nil { + if o != nil && !IsNil(o.ParContext) { return true } @@ -172,7 +175,7 @@ func (o *OAuth2ConsentSessionExpiresAt) SetParContext(v time.Time) { // GetRefreshToken returns the RefreshToken field value if set, zero value otherwise. func (o *OAuth2ConsentSessionExpiresAt) GetRefreshToken() time.Time { - if o == nil || o.RefreshToken == nil { + if o == nil || IsNil(o.RefreshToken) { var ret time.Time return ret } @@ -182,7 +185,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetRefreshToken() time.Time { // GetRefreshTokenOk returns a tuple with the RefreshToken field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2ConsentSessionExpiresAt) GetRefreshTokenOk() (*time.Time, bool) { - if o == nil || o.RefreshToken == nil { + if o == nil || IsNil(o.RefreshToken) { return nil, false } return o.RefreshToken, true @@ -190,7 +193,7 @@ func (o *OAuth2ConsentSessionExpiresAt) GetRefreshTokenOk() (*time.Time, bool) { // HasRefreshToken returns a boolean if a field has been set. func (o *OAuth2ConsentSessionExpiresAt) HasRefreshToken() bool { - if o != nil && o.RefreshToken != nil { + if o != nil && !IsNil(o.RefreshToken) { return true } @@ -203,23 +206,31 @@ func (o *OAuth2ConsentSessionExpiresAt) SetRefreshToken(v time.Time) { } func (o OAuth2ConsentSessionExpiresAt) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o OAuth2ConsentSessionExpiresAt) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.AccessToken != nil { + if !IsNil(o.AccessToken) { toSerialize["access_token"] = o.AccessToken } - if o.AuthorizeCode != nil { + if !IsNil(o.AuthorizeCode) { toSerialize["authorize_code"] = o.AuthorizeCode } - if o.IdToken != nil { + if !IsNil(o.IdToken) { toSerialize["id_token"] = o.IdToken } - if o.ParContext != nil { + if !IsNil(o.ParContext) { toSerialize["par_context"] = o.ParContext } - if o.RefreshToken != nil { + if !IsNil(o.RefreshToken) { toSerialize["refresh_token"] = o.RefreshToken } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableOAuth2ConsentSessionExpiresAt struct { diff --git a/internal/httpclient/model_o_auth2_login_request.go b/internal/httpclient/model_o_auth2_login_request.go index cf29c2a47d0..2ddac3113c8 100644 --- a/internal/httpclient/model_o_auth2_login_request.go +++ b/internal/httpclient/model_o_auth2_login_request.go @@ -12,9 +12,14 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the OAuth2LoginRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2LoginRequest{} + // OAuth2LoginRequest struct for OAuth2LoginRequest type OAuth2LoginRequest struct { // ID is the identifier (\"login challenge\") of the login request. It is used to identify the session. @@ -23,8 +28,8 @@ type OAuth2LoginRequest struct { OidcContext *OAuth2ConsentRequestOpenIDConnectContext `json:"oidc_context,omitempty"` // RequestURL is the original OAuth 2.0 Authorization URL requested by the OAuth 2.0 client. It is the URL which initiates the OAuth 2.0 Authorization Code or OAuth 2.0 Implicit flow. This URL is typically not needed, but might come in handy if you want to deal with additional request parameters. RequestUrl string `json:"request_url"` - RequestedAccessTokenAudience []string `json:"requested_access_token_audience"` - RequestedScope []string `json:"requested_scope"` + RequestedAccessTokenAudience []string `json:"requested_access_token_audience,omitempty"` + RequestedScope []string `json:"requested_scope,omitempty"` // SessionID is the login session ID. If the user-agent reuses a login session (via cookie / remember flag) this ID will remain the same. If the user-agent did not have an existing authentication session (e.g. remember is false) this will be a new random value. This value is used as the \"sid\" parameter in the ID Token and in OIDC Front-/Back- channel logout. It's value can generally be used to associate consecutive login requests by a certain user. SessionId *string `json:"session_id,omitempty"` // Skip, if true, implies that the client has requested the same scopes from the same user previously. If true, you can skip asking the user to grant the requested scopes, and simply forward the user to the redirect URL. This feature allows you to update / set session information. @@ -33,17 +38,17 @@ type OAuth2LoginRequest struct { Subject string `json:"subject"` } +type _OAuth2LoginRequest OAuth2LoginRequest + // NewOAuth2LoginRequest instantiates a new OAuth2LoginRequest object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments // will change when the set of required properties is changed -func NewOAuth2LoginRequest(challenge string, client OAuth2Client, requestUrl string, requestedAccessTokenAudience []string, requestedScope []string, skip bool, subject string) *OAuth2LoginRequest { +func NewOAuth2LoginRequest(challenge string, client OAuth2Client, requestUrl string, skip bool, subject string) *OAuth2LoginRequest { this := OAuth2LoginRequest{} this.Challenge = challenge this.Client = client this.RequestUrl = requestUrl - this.RequestedAccessTokenAudience = requestedAccessTokenAudience - this.RequestedScope = requestedScope this.Skip = skip this.Subject = subject return &this @@ -107,7 +112,7 @@ func (o *OAuth2LoginRequest) SetClient(v OAuth2Client) { // GetOidcContext returns the OidcContext field value if set, zero value otherwise. func (o *OAuth2LoginRequest) GetOidcContext() OAuth2ConsentRequestOpenIDConnectContext { - if o == nil || o.OidcContext == nil { + if o == nil || IsNil(o.OidcContext) { var ret OAuth2ConsentRequestOpenIDConnectContext return ret } @@ -117,7 +122,7 @@ func (o *OAuth2LoginRequest) GetOidcContext() OAuth2ConsentRequestOpenIDConnectC // GetOidcContextOk returns a tuple with the OidcContext field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LoginRequest) GetOidcContextOk() (*OAuth2ConsentRequestOpenIDConnectContext, bool) { - if o == nil || o.OidcContext == nil { + if o == nil || IsNil(o.OidcContext) { return nil, false } return o.OidcContext, true @@ -125,7 +130,7 @@ func (o *OAuth2LoginRequest) GetOidcContextOk() (*OAuth2ConsentRequestOpenIDConn // HasOidcContext returns a boolean if a field has been set. func (o *OAuth2LoginRequest) HasOidcContext() bool { - if o != nil && o.OidcContext != nil { + if o != nil && !IsNil(o.OidcContext) { return true } @@ -161,57 +166,73 @@ func (o *OAuth2LoginRequest) SetRequestUrl(v string) { o.RequestUrl = v } -// GetRequestedAccessTokenAudience returns the RequestedAccessTokenAudience field value +// GetRequestedAccessTokenAudience returns the RequestedAccessTokenAudience field value if set, zero value otherwise. func (o *OAuth2LoginRequest) GetRequestedAccessTokenAudience() []string { - if o == nil { + if o == nil || IsNil(o.RequestedAccessTokenAudience) { var ret []string return ret } - return o.RequestedAccessTokenAudience } -// GetRequestedAccessTokenAudienceOk returns a tuple with the RequestedAccessTokenAudience field value +// GetRequestedAccessTokenAudienceOk returns a tuple with the RequestedAccessTokenAudience field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LoginRequest) GetRequestedAccessTokenAudienceOk() ([]string, bool) { - if o == nil { + if o == nil || IsNil(o.RequestedAccessTokenAudience) { return nil, false } return o.RequestedAccessTokenAudience, true } -// SetRequestedAccessTokenAudience sets field value +// HasRequestedAccessTokenAudience returns a boolean if a field has been set. +func (o *OAuth2LoginRequest) HasRequestedAccessTokenAudience() bool { + if o != nil && !IsNil(o.RequestedAccessTokenAudience) { + return true + } + + return false +} + +// SetRequestedAccessTokenAudience gets a reference to the given []string and assigns it to the RequestedAccessTokenAudience field. func (o *OAuth2LoginRequest) SetRequestedAccessTokenAudience(v []string) { o.RequestedAccessTokenAudience = v } -// GetRequestedScope returns the RequestedScope field value +// GetRequestedScope returns the RequestedScope field value if set, zero value otherwise. func (o *OAuth2LoginRequest) GetRequestedScope() []string { - if o == nil { + if o == nil || IsNil(o.RequestedScope) { var ret []string return ret } - return o.RequestedScope } -// GetRequestedScopeOk returns a tuple with the RequestedScope field value +// GetRequestedScopeOk returns a tuple with the RequestedScope field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LoginRequest) GetRequestedScopeOk() ([]string, bool) { - if o == nil { + if o == nil || IsNil(o.RequestedScope) { return nil, false } return o.RequestedScope, true } -// SetRequestedScope sets field value +// HasRequestedScope returns a boolean if a field has been set. +func (o *OAuth2LoginRequest) HasRequestedScope() bool { + if o != nil && !IsNil(o.RequestedScope) { + return true + } + + return false +} + +// SetRequestedScope gets a reference to the given []string and assigns it to the RequestedScope field. func (o *OAuth2LoginRequest) SetRequestedScope(v []string) { o.RequestedScope = v } // GetSessionId returns the SessionId field value if set, zero value otherwise. func (o *OAuth2LoginRequest) GetSessionId() string { - if o == nil || o.SessionId == nil { + if o == nil || IsNil(o.SessionId) { var ret string return ret } @@ -221,7 +242,7 @@ func (o *OAuth2LoginRequest) GetSessionId() string { // GetSessionIdOk returns a tuple with the SessionId field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LoginRequest) GetSessionIdOk() (*string, bool) { - if o == nil || o.SessionId == nil { + if o == nil || IsNil(o.SessionId) { return nil, false } return o.SessionId, true @@ -229,7 +250,7 @@ func (o *OAuth2LoginRequest) GetSessionIdOk() (*string, bool) { // HasSessionId returns a boolean if a field has been set. func (o *OAuth2LoginRequest) HasSessionId() bool { - if o != nil && o.SessionId != nil { + if o != nil && !IsNil(o.SessionId) { return true } @@ -290,35 +311,74 @@ func (o *OAuth2LoginRequest) SetSubject(v string) { } func (o OAuth2LoginRequest) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["challenge"] = o.Challenge - } - if true { - toSerialize["client"] = o.Client + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err } - if o.OidcContext != nil { + return json.Marshal(toSerialize) +} + +func (o OAuth2LoginRequest) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["challenge"] = o.Challenge + toSerialize["client"] = o.Client + if !IsNil(o.OidcContext) { toSerialize["oidc_context"] = o.OidcContext } - if true { - toSerialize["request_url"] = o.RequestUrl - } - if true { + toSerialize["request_url"] = o.RequestUrl + if !IsNil(o.RequestedAccessTokenAudience) { toSerialize["requested_access_token_audience"] = o.RequestedAccessTokenAudience } - if true { + if !IsNil(o.RequestedScope) { toSerialize["requested_scope"] = o.RequestedScope } - if o.SessionId != nil { + if !IsNil(o.SessionId) { toSerialize["session_id"] = o.SessionId } - if true { - toSerialize["skip"] = o.Skip + toSerialize["skip"] = o.Skip + toSerialize["subject"] = o.Subject + return toSerialize, nil +} + +func (o *OAuth2LoginRequest) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "challenge", + "client", + "request_url", + "skip", + "subject", } - if true { - toSerialize["subject"] = o.Subject + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err } - return json.Marshal(toSerialize) + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varOAuth2LoginRequest := _OAuth2LoginRequest{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varOAuth2LoginRequest) + + if err != nil { + return err + } + + *o = OAuth2LoginRequest(varOAuth2LoginRequest) + + return err } type NullableOAuth2LoginRequest struct { diff --git a/internal/httpclient/model_o_auth2_logout_request.go b/internal/httpclient/model_o_auth2_logout_request.go index 4a2ef7c0bc7..517ed65cf56 100644 --- a/internal/httpclient/model_o_auth2_logout_request.go +++ b/internal/httpclient/model_o_auth2_logout_request.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the OAuth2LogoutRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2LogoutRequest{} + // OAuth2LogoutRequest struct for OAuth2LogoutRequest type OAuth2LogoutRequest struct { // Challenge is the identifier (\"logout challenge\") of the logout authentication request. It is used to identify the session. @@ -49,7 +52,7 @@ func NewOAuth2LogoutRequestWithDefaults() *OAuth2LogoutRequest { // GetChallenge returns the Challenge field value if set, zero value otherwise. func (o *OAuth2LogoutRequest) GetChallenge() string { - if o == nil || o.Challenge == nil { + if o == nil || IsNil(o.Challenge) { var ret string return ret } @@ -59,7 +62,7 @@ func (o *OAuth2LogoutRequest) GetChallenge() string { // GetChallengeOk returns a tuple with the Challenge field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LogoutRequest) GetChallengeOk() (*string, bool) { - if o == nil || o.Challenge == nil { + if o == nil || IsNil(o.Challenge) { return nil, false } return o.Challenge, true @@ -67,7 +70,7 @@ func (o *OAuth2LogoutRequest) GetChallengeOk() (*string, bool) { // HasChallenge returns a boolean if a field has been set. func (o *OAuth2LogoutRequest) HasChallenge() bool { - if o != nil && o.Challenge != nil { + if o != nil && !IsNil(o.Challenge) { return true } @@ -81,7 +84,7 @@ func (o *OAuth2LogoutRequest) SetChallenge(v string) { // GetClient returns the Client field value if set, zero value otherwise. func (o *OAuth2LogoutRequest) GetClient() OAuth2Client { - if o == nil || o.Client == nil { + if o == nil || IsNil(o.Client) { var ret OAuth2Client return ret } @@ -91,7 +94,7 @@ func (o *OAuth2LogoutRequest) GetClient() OAuth2Client { // GetClientOk returns a tuple with the Client field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LogoutRequest) GetClientOk() (*OAuth2Client, bool) { - if o == nil || o.Client == nil { + if o == nil || IsNil(o.Client) { return nil, false } return o.Client, true @@ -99,7 +102,7 @@ func (o *OAuth2LogoutRequest) GetClientOk() (*OAuth2Client, bool) { // HasClient returns a boolean if a field has been set. func (o *OAuth2LogoutRequest) HasClient() bool { - if o != nil && o.Client != nil { + if o != nil && !IsNil(o.Client) { return true } @@ -113,7 +116,7 @@ func (o *OAuth2LogoutRequest) SetClient(v OAuth2Client) { // GetRequestUrl returns the RequestUrl field value if set, zero value otherwise. func (o *OAuth2LogoutRequest) GetRequestUrl() string { - if o == nil || o.RequestUrl == nil { + if o == nil || IsNil(o.RequestUrl) { var ret string return ret } @@ -123,7 +126,7 @@ func (o *OAuth2LogoutRequest) GetRequestUrl() string { // GetRequestUrlOk returns a tuple with the RequestUrl field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LogoutRequest) GetRequestUrlOk() (*string, bool) { - if o == nil || o.RequestUrl == nil { + if o == nil || IsNil(o.RequestUrl) { return nil, false } return o.RequestUrl, true @@ -131,7 +134,7 @@ func (o *OAuth2LogoutRequest) GetRequestUrlOk() (*string, bool) { // HasRequestUrl returns a boolean if a field has been set. func (o *OAuth2LogoutRequest) HasRequestUrl() bool { - if o != nil && o.RequestUrl != nil { + if o != nil && !IsNil(o.RequestUrl) { return true } @@ -145,7 +148,7 @@ func (o *OAuth2LogoutRequest) SetRequestUrl(v string) { // GetRpInitiated returns the RpInitiated field value if set, zero value otherwise. func (o *OAuth2LogoutRequest) GetRpInitiated() bool { - if o == nil || o.RpInitiated == nil { + if o == nil || IsNil(o.RpInitiated) { var ret bool return ret } @@ -155,7 +158,7 @@ func (o *OAuth2LogoutRequest) GetRpInitiated() bool { // GetRpInitiatedOk returns a tuple with the RpInitiated field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LogoutRequest) GetRpInitiatedOk() (*bool, bool) { - if o == nil || o.RpInitiated == nil { + if o == nil || IsNil(o.RpInitiated) { return nil, false } return o.RpInitiated, true @@ -163,7 +166,7 @@ func (o *OAuth2LogoutRequest) GetRpInitiatedOk() (*bool, bool) { // HasRpInitiated returns a boolean if a field has been set. func (o *OAuth2LogoutRequest) HasRpInitiated() bool { - if o != nil && o.RpInitiated != nil { + if o != nil && !IsNil(o.RpInitiated) { return true } @@ -177,7 +180,7 @@ func (o *OAuth2LogoutRequest) SetRpInitiated(v bool) { // GetSid returns the Sid field value if set, zero value otherwise. func (o *OAuth2LogoutRequest) GetSid() string { - if o == nil || o.Sid == nil { + if o == nil || IsNil(o.Sid) { var ret string return ret } @@ -187,7 +190,7 @@ func (o *OAuth2LogoutRequest) GetSid() string { // GetSidOk returns a tuple with the Sid field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LogoutRequest) GetSidOk() (*string, bool) { - if o == nil || o.Sid == nil { + if o == nil || IsNil(o.Sid) { return nil, false } return o.Sid, true @@ -195,7 +198,7 @@ func (o *OAuth2LogoutRequest) GetSidOk() (*string, bool) { // HasSid returns a boolean if a field has been set. func (o *OAuth2LogoutRequest) HasSid() bool { - if o != nil && o.Sid != nil { + if o != nil && !IsNil(o.Sid) { return true } @@ -209,7 +212,7 @@ func (o *OAuth2LogoutRequest) SetSid(v string) { // GetSubject returns the Subject field value if set, zero value otherwise. func (o *OAuth2LogoutRequest) GetSubject() string { - if o == nil || o.Subject == nil { + if o == nil || IsNil(o.Subject) { var ret string return ret } @@ -219,7 +222,7 @@ func (o *OAuth2LogoutRequest) GetSubject() string { // GetSubjectOk returns a tuple with the Subject field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2LogoutRequest) GetSubjectOk() (*string, bool) { - if o == nil || o.Subject == nil { + if o == nil || IsNil(o.Subject) { return nil, false } return o.Subject, true @@ -227,7 +230,7 @@ func (o *OAuth2LogoutRequest) GetSubjectOk() (*string, bool) { // HasSubject returns a boolean if a field has been set. func (o *OAuth2LogoutRequest) HasSubject() bool { - if o != nil && o.Subject != nil { + if o != nil && !IsNil(o.Subject) { return true } @@ -240,26 +243,34 @@ func (o *OAuth2LogoutRequest) SetSubject(v string) { } func (o OAuth2LogoutRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o OAuth2LogoutRequest) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Challenge != nil { + if !IsNil(o.Challenge) { toSerialize["challenge"] = o.Challenge } - if o.Client != nil { + if !IsNil(o.Client) { toSerialize["client"] = o.Client } - if o.RequestUrl != nil { + if !IsNil(o.RequestUrl) { toSerialize["request_url"] = o.RequestUrl } - if o.RpInitiated != nil { + if !IsNil(o.RpInitiated) { toSerialize["rp_initiated"] = o.RpInitiated } - if o.Sid != nil { + if !IsNil(o.Sid) { toSerialize["sid"] = o.Sid } - if o.Subject != nil { + if !IsNil(o.Subject) { toSerialize["subject"] = o.Subject } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableOAuth2LogoutRequest struct { diff --git a/internal/httpclient/model_o_auth2_redirect_to.go b/internal/httpclient/model_o_auth2_redirect_to.go index 5abf9d4f250..e2ff2035357 100644 --- a/internal/httpclient/model_o_auth2_redirect_to.go +++ b/internal/httpclient/model_o_auth2_redirect_to.go @@ -12,15 +12,22 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the OAuth2RedirectTo type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2RedirectTo{} + // OAuth2RedirectTo Contains a redirect URL used to complete a login, consent, or logout request. type OAuth2RedirectTo struct { // RedirectURL is the URL which you should redirect the user's browser to once the authentication process is completed. RedirectTo string `json:"redirect_to"` } +type _OAuth2RedirectTo OAuth2RedirectTo + // NewOAuth2RedirectTo instantiates a new OAuth2RedirectTo object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -64,13 +71,56 @@ func (o *OAuth2RedirectTo) SetRedirectTo(v string) { } func (o OAuth2RedirectTo) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["redirect_to"] = o.RedirectTo + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err } return json.Marshal(toSerialize) } +func (o OAuth2RedirectTo) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["redirect_to"] = o.RedirectTo + return toSerialize, nil +} + +func (o *OAuth2RedirectTo) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "redirect_to", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varOAuth2RedirectTo := _OAuth2RedirectTo{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varOAuth2RedirectTo) + + if err != nil { + return err + } + + *o = OAuth2RedirectTo(varOAuth2RedirectTo) + + return err +} + type NullableOAuth2RedirectTo struct { value *OAuth2RedirectTo isSet bool diff --git a/internal/httpclient/model_o_auth2_token_exchange.go b/internal/httpclient/model_o_auth2_token_exchange.go index 6db3a25cb8f..f2997682d5d 100644 --- a/internal/httpclient/model_o_auth2_token_exchange.go +++ b/internal/httpclient/model_o_auth2_token_exchange.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the OAuth2TokenExchange type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OAuth2TokenExchange{} + // OAuth2TokenExchange OAuth2 Token Exchange Result type OAuth2TokenExchange struct { // The access token issued by the authorization server. @@ -22,7 +25,7 @@ type OAuth2TokenExchange struct { // The lifetime in seconds of the access token. For example, the value \"3600\" denotes that the access token will expire in one hour from the time the response was generated. ExpiresIn *int64 `json:"expires_in,omitempty"` // To retrieve a refresh token request the id_token scope. - IdToken *int64 `json:"id_token,omitempty"` + IdToken *string `json:"id_token,omitempty"` // The refresh token, which can be used to obtain new access tokens. To retrieve it add the scope \"offline\" to your access token request. RefreshToken *string `json:"refresh_token,omitempty"` // The scope of the access token @@ -50,7 +53,7 @@ func NewOAuth2TokenExchangeWithDefaults() *OAuth2TokenExchange { // GetAccessToken returns the AccessToken field value if set, zero value otherwise. func (o *OAuth2TokenExchange) GetAccessToken() string { - if o == nil || o.AccessToken == nil { + if o == nil || IsNil(o.AccessToken) { var ret string return ret } @@ -60,7 +63,7 @@ func (o *OAuth2TokenExchange) GetAccessToken() string { // GetAccessTokenOk returns a tuple with the AccessToken field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2TokenExchange) GetAccessTokenOk() (*string, bool) { - if o == nil || o.AccessToken == nil { + if o == nil || IsNil(o.AccessToken) { return nil, false } return o.AccessToken, true @@ -68,7 +71,7 @@ func (o *OAuth2TokenExchange) GetAccessTokenOk() (*string, bool) { // HasAccessToken returns a boolean if a field has been set. func (o *OAuth2TokenExchange) HasAccessToken() bool { - if o != nil && o.AccessToken != nil { + if o != nil && !IsNil(o.AccessToken) { return true } @@ -82,7 +85,7 @@ func (o *OAuth2TokenExchange) SetAccessToken(v string) { // GetExpiresIn returns the ExpiresIn field value if set, zero value otherwise. func (o *OAuth2TokenExchange) GetExpiresIn() int64 { - if o == nil || o.ExpiresIn == nil { + if o == nil || IsNil(o.ExpiresIn) { var ret int64 return ret } @@ -92,7 +95,7 @@ func (o *OAuth2TokenExchange) GetExpiresIn() int64 { // GetExpiresInOk returns a tuple with the ExpiresIn field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2TokenExchange) GetExpiresInOk() (*int64, bool) { - if o == nil || o.ExpiresIn == nil { + if o == nil || IsNil(o.ExpiresIn) { return nil, false } return o.ExpiresIn, true @@ -100,7 +103,7 @@ func (o *OAuth2TokenExchange) GetExpiresInOk() (*int64, bool) { // HasExpiresIn returns a boolean if a field has been set. func (o *OAuth2TokenExchange) HasExpiresIn() bool { - if o != nil && o.ExpiresIn != nil { + if o != nil && !IsNil(o.ExpiresIn) { return true } @@ -113,9 +116,9 @@ func (o *OAuth2TokenExchange) SetExpiresIn(v int64) { } // GetIdToken returns the IdToken field value if set, zero value otherwise. -func (o *OAuth2TokenExchange) GetIdToken() int64 { - if o == nil || o.IdToken == nil { - var ret int64 +func (o *OAuth2TokenExchange) GetIdToken() string { + if o == nil || IsNil(o.IdToken) { + var ret string return ret } return *o.IdToken @@ -123,8 +126,8 @@ func (o *OAuth2TokenExchange) GetIdToken() int64 { // GetIdTokenOk returns a tuple with the IdToken field value if set, nil otherwise // and a boolean to check if the value has been set. -func (o *OAuth2TokenExchange) GetIdTokenOk() (*int64, bool) { - if o == nil || o.IdToken == nil { +func (o *OAuth2TokenExchange) GetIdTokenOk() (*string, bool) { + if o == nil || IsNil(o.IdToken) { return nil, false } return o.IdToken, true @@ -132,21 +135,21 @@ func (o *OAuth2TokenExchange) GetIdTokenOk() (*int64, bool) { // HasIdToken returns a boolean if a field has been set. func (o *OAuth2TokenExchange) HasIdToken() bool { - if o != nil && o.IdToken != nil { + if o != nil && !IsNil(o.IdToken) { return true } return false } -// SetIdToken gets a reference to the given int64 and assigns it to the IdToken field. -func (o *OAuth2TokenExchange) SetIdToken(v int64) { +// SetIdToken gets a reference to the given string and assigns it to the IdToken field. +func (o *OAuth2TokenExchange) SetIdToken(v string) { o.IdToken = &v } // GetRefreshToken returns the RefreshToken field value if set, zero value otherwise. func (o *OAuth2TokenExchange) GetRefreshToken() string { - if o == nil || o.RefreshToken == nil { + if o == nil || IsNil(o.RefreshToken) { var ret string return ret } @@ -156,7 +159,7 @@ func (o *OAuth2TokenExchange) GetRefreshToken() string { // GetRefreshTokenOk returns a tuple with the RefreshToken field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2TokenExchange) GetRefreshTokenOk() (*string, bool) { - if o == nil || o.RefreshToken == nil { + if o == nil || IsNil(o.RefreshToken) { return nil, false } return o.RefreshToken, true @@ -164,7 +167,7 @@ func (o *OAuth2TokenExchange) GetRefreshTokenOk() (*string, bool) { // HasRefreshToken returns a boolean if a field has been set. func (o *OAuth2TokenExchange) HasRefreshToken() bool { - if o != nil && o.RefreshToken != nil { + if o != nil && !IsNil(o.RefreshToken) { return true } @@ -178,7 +181,7 @@ func (o *OAuth2TokenExchange) SetRefreshToken(v string) { // GetScope returns the Scope field value if set, zero value otherwise. func (o *OAuth2TokenExchange) GetScope() string { - if o == nil || o.Scope == nil { + if o == nil || IsNil(o.Scope) { var ret string return ret } @@ -188,7 +191,7 @@ func (o *OAuth2TokenExchange) GetScope() string { // GetScopeOk returns a tuple with the Scope field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2TokenExchange) GetScopeOk() (*string, bool) { - if o == nil || o.Scope == nil { + if o == nil || IsNil(o.Scope) { return nil, false } return o.Scope, true @@ -196,7 +199,7 @@ func (o *OAuth2TokenExchange) GetScopeOk() (*string, bool) { // HasScope returns a boolean if a field has been set. func (o *OAuth2TokenExchange) HasScope() bool { - if o != nil && o.Scope != nil { + if o != nil && !IsNil(o.Scope) { return true } @@ -210,7 +213,7 @@ func (o *OAuth2TokenExchange) SetScope(v string) { // GetTokenType returns the TokenType field value if set, zero value otherwise. func (o *OAuth2TokenExchange) GetTokenType() string { - if o == nil || o.TokenType == nil { + if o == nil || IsNil(o.TokenType) { var ret string return ret } @@ -220,7 +223,7 @@ func (o *OAuth2TokenExchange) GetTokenType() string { // GetTokenTypeOk returns a tuple with the TokenType field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OAuth2TokenExchange) GetTokenTypeOk() (*string, bool) { - if o == nil || o.TokenType == nil { + if o == nil || IsNil(o.TokenType) { return nil, false } return o.TokenType, true @@ -228,7 +231,7 @@ func (o *OAuth2TokenExchange) GetTokenTypeOk() (*string, bool) { // HasTokenType returns a boolean if a field has been set. func (o *OAuth2TokenExchange) HasTokenType() bool { - if o != nil && o.TokenType != nil { + if o != nil && !IsNil(o.TokenType) { return true } @@ -241,26 +244,34 @@ func (o *OAuth2TokenExchange) SetTokenType(v string) { } func (o OAuth2TokenExchange) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o OAuth2TokenExchange) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.AccessToken != nil { + if !IsNil(o.AccessToken) { toSerialize["access_token"] = o.AccessToken } - if o.ExpiresIn != nil { + if !IsNil(o.ExpiresIn) { toSerialize["expires_in"] = o.ExpiresIn } - if o.IdToken != nil { + if !IsNil(o.IdToken) { toSerialize["id_token"] = o.IdToken } - if o.RefreshToken != nil { + if !IsNil(o.RefreshToken) { toSerialize["refresh_token"] = o.RefreshToken } - if o.Scope != nil { + if !IsNil(o.Scope) { toSerialize["scope"] = o.Scope } - if o.TokenType != nil { + if !IsNil(o.TokenType) { toSerialize["token_type"] = o.TokenType } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableOAuth2TokenExchange struct { diff --git a/internal/httpclient/model_oidc_configuration.go b/internal/httpclient/model_oidc_configuration.go index 78411e52b75..240e40b307f 100644 --- a/internal/httpclient/model_oidc_configuration.go +++ b/internal/httpclient/model_oidc_configuration.go @@ -12,9 +12,14 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" ) +// checks if the OidcConfiguration type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OidcConfiguration{} + // OidcConfiguration Includes links to several endpoints (for example `/oauth2/token`) and exposes information on supported signature algorithms among others. type OidcConfiguration struct { // OAuth 2.0 Authorization Endpoint URL @@ -29,6 +34,10 @@ type OidcConfiguration struct { ClaimsSupported []string `json:"claims_supported,omitempty"` // OAuth 2.0 PKCE Supported Code Challenge Methods JSON array containing a list of Proof Key for Code Exchange (PKCE) [RFC7636] code challenge methods supported by this authorization server. CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported,omitempty"` + // OpenID Connect Verifiable Credentials Endpoint Contains the URL of the Verifiable Credentials Endpoint. + CredentialsEndpointDraft00 *string `json:"credentials_endpoint_draft_00,omitempty"` + // OpenID Connect Verifiable Credentials Supported JSON array containing a list of the Verifiable Credentials supported by this authorization server. + CredentialsSupportedDraft00 []CredentialSupportedDraft00 `json:"credentials_supported_draft_00,omitempty"` // OpenID Connect End-Session Endpoint URL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP. EndSessionEndpoint *string `json:"end_session_endpoint,omitempty"` // OpenID Connect Front-Channel Logout Session Required Boolean value specifying whether the OP can pass iss (issuer) and sid (session ID) query parameters to identify the RP session with the OP when the frontchannel_logout_uri is used. If supported, the sid Claim is also included in ID Tokens issued by the OP. @@ -77,6 +86,8 @@ type OidcConfiguration struct { UserinfoSigningAlgValuesSupported []string `json:"userinfo_signing_alg_values_supported,omitempty"` } +type _OidcConfiguration OidcConfiguration + // NewOidcConfiguration instantiates a new OidcConfiguration object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -129,7 +140,7 @@ func (o *OidcConfiguration) SetAuthorizationEndpoint(v string) { // GetBackchannelLogoutSessionSupported returns the BackchannelLogoutSessionSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetBackchannelLogoutSessionSupported() bool { - if o == nil || o.BackchannelLogoutSessionSupported == nil { + if o == nil || IsNil(o.BackchannelLogoutSessionSupported) { var ret bool return ret } @@ -139,7 +150,7 @@ func (o *OidcConfiguration) GetBackchannelLogoutSessionSupported() bool { // GetBackchannelLogoutSessionSupportedOk returns a tuple with the BackchannelLogoutSessionSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetBackchannelLogoutSessionSupportedOk() (*bool, bool) { - if o == nil || o.BackchannelLogoutSessionSupported == nil { + if o == nil || IsNil(o.BackchannelLogoutSessionSupported) { return nil, false } return o.BackchannelLogoutSessionSupported, true @@ -147,7 +158,7 @@ func (o *OidcConfiguration) GetBackchannelLogoutSessionSupportedOk() (*bool, boo // HasBackchannelLogoutSessionSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasBackchannelLogoutSessionSupported() bool { - if o != nil && o.BackchannelLogoutSessionSupported != nil { + if o != nil && !IsNil(o.BackchannelLogoutSessionSupported) { return true } @@ -161,7 +172,7 @@ func (o *OidcConfiguration) SetBackchannelLogoutSessionSupported(v bool) { // GetBackchannelLogoutSupported returns the BackchannelLogoutSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetBackchannelLogoutSupported() bool { - if o == nil || o.BackchannelLogoutSupported == nil { + if o == nil || IsNil(o.BackchannelLogoutSupported) { var ret bool return ret } @@ -171,7 +182,7 @@ func (o *OidcConfiguration) GetBackchannelLogoutSupported() bool { // GetBackchannelLogoutSupportedOk returns a tuple with the BackchannelLogoutSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetBackchannelLogoutSupportedOk() (*bool, bool) { - if o == nil || o.BackchannelLogoutSupported == nil { + if o == nil || IsNil(o.BackchannelLogoutSupported) { return nil, false } return o.BackchannelLogoutSupported, true @@ -179,7 +190,7 @@ func (o *OidcConfiguration) GetBackchannelLogoutSupportedOk() (*bool, bool) { // HasBackchannelLogoutSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasBackchannelLogoutSupported() bool { - if o != nil && o.BackchannelLogoutSupported != nil { + if o != nil && !IsNil(o.BackchannelLogoutSupported) { return true } @@ -193,7 +204,7 @@ func (o *OidcConfiguration) SetBackchannelLogoutSupported(v bool) { // GetClaimsParameterSupported returns the ClaimsParameterSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetClaimsParameterSupported() bool { - if o == nil || o.ClaimsParameterSupported == nil { + if o == nil || IsNil(o.ClaimsParameterSupported) { var ret bool return ret } @@ -203,7 +214,7 @@ func (o *OidcConfiguration) GetClaimsParameterSupported() bool { // GetClaimsParameterSupportedOk returns a tuple with the ClaimsParameterSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetClaimsParameterSupportedOk() (*bool, bool) { - if o == nil || o.ClaimsParameterSupported == nil { + if o == nil || IsNil(o.ClaimsParameterSupported) { return nil, false } return o.ClaimsParameterSupported, true @@ -211,7 +222,7 @@ func (o *OidcConfiguration) GetClaimsParameterSupportedOk() (*bool, bool) { // HasClaimsParameterSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasClaimsParameterSupported() bool { - if o != nil && o.ClaimsParameterSupported != nil { + if o != nil && !IsNil(o.ClaimsParameterSupported) { return true } @@ -225,7 +236,7 @@ func (o *OidcConfiguration) SetClaimsParameterSupported(v bool) { // GetClaimsSupported returns the ClaimsSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetClaimsSupported() []string { - if o == nil || o.ClaimsSupported == nil { + if o == nil || IsNil(o.ClaimsSupported) { var ret []string return ret } @@ -235,7 +246,7 @@ func (o *OidcConfiguration) GetClaimsSupported() []string { // GetClaimsSupportedOk returns a tuple with the ClaimsSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetClaimsSupportedOk() ([]string, bool) { - if o == nil || o.ClaimsSupported == nil { + if o == nil || IsNil(o.ClaimsSupported) { return nil, false } return o.ClaimsSupported, true @@ -243,7 +254,7 @@ func (o *OidcConfiguration) GetClaimsSupportedOk() ([]string, bool) { // HasClaimsSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasClaimsSupported() bool { - if o != nil && o.ClaimsSupported != nil { + if o != nil && !IsNil(o.ClaimsSupported) { return true } @@ -257,7 +268,7 @@ func (o *OidcConfiguration) SetClaimsSupported(v []string) { // GetCodeChallengeMethodsSupported returns the CodeChallengeMethodsSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetCodeChallengeMethodsSupported() []string { - if o == nil || o.CodeChallengeMethodsSupported == nil { + if o == nil || IsNil(o.CodeChallengeMethodsSupported) { var ret []string return ret } @@ -267,7 +278,7 @@ func (o *OidcConfiguration) GetCodeChallengeMethodsSupported() []string { // GetCodeChallengeMethodsSupportedOk returns a tuple with the CodeChallengeMethodsSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetCodeChallengeMethodsSupportedOk() ([]string, bool) { - if o == nil || o.CodeChallengeMethodsSupported == nil { + if o == nil || IsNil(o.CodeChallengeMethodsSupported) { return nil, false } return o.CodeChallengeMethodsSupported, true @@ -275,7 +286,7 @@ func (o *OidcConfiguration) GetCodeChallengeMethodsSupportedOk() ([]string, bool // HasCodeChallengeMethodsSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasCodeChallengeMethodsSupported() bool { - if o != nil && o.CodeChallengeMethodsSupported != nil { + if o != nil && !IsNil(o.CodeChallengeMethodsSupported) { return true } @@ -287,9 +298,73 @@ func (o *OidcConfiguration) SetCodeChallengeMethodsSupported(v []string) { o.CodeChallengeMethodsSupported = v } +// GetCredentialsEndpointDraft00 returns the CredentialsEndpointDraft00 field value if set, zero value otherwise. +func (o *OidcConfiguration) GetCredentialsEndpointDraft00() string { + if o == nil || IsNil(o.CredentialsEndpointDraft00) { + var ret string + return ret + } + return *o.CredentialsEndpointDraft00 +} + +// GetCredentialsEndpointDraft00Ok returns a tuple with the CredentialsEndpointDraft00 field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OidcConfiguration) GetCredentialsEndpointDraft00Ok() (*string, bool) { + if o == nil || IsNil(o.CredentialsEndpointDraft00) { + return nil, false + } + return o.CredentialsEndpointDraft00, true +} + +// HasCredentialsEndpointDraft00 returns a boolean if a field has been set. +func (o *OidcConfiguration) HasCredentialsEndpointDraft00() bool { + if o != nil && !IsNil(o.CredentialsEndpointDraft00) { + return true + } + + return false +} + +// SetCredentialsEndpointDraft00 gets a reference to the given string and assigns it to the CredentialsEndpointDraft00 field. +func (o *OidcConfiguration) SetCredentialsEndpointDraft00(v string) { + o.CredentialsEndpointDraft00 = &v +} + +// GetCredentialsSupportedDraft00 returns the CredentialsSupportedDraft00 field value if set, zero value otherwise. +func (o *OidcConfiguration) GetCredentialsSupportedDraft00() []CredentialSupportedDraft00 { + if o == nil || IsNil(o.CredentialsSupportedDraft00) { + var ret []CredentialSupportedDraft00 + return ret + } + return o.CredentialsSupportedDraft00 +} + +// GetCredentialsSupportedDraft00Ok returns a tuple with the CredentialsSupportedDraft00 field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *OidcConfiguration) GetCredentialsSupportedDraft00Ok() ([]CredentialSupportedDraft00, bool) { + if o == nil || IsNil(o.CredentialsSupportedDraft00) { + return nil, false + } + return o.CredentialsSupportedDraft00, true +} + +// HasCredentialsSupportedDraft00 returns a boolean if a field has been set. +func (o *OidcConfiguration) HasCredentialsSupportedDraft00() bool { + if o != nil && !IsNil(o.CredentialsSupportedDraft00) { + return true + } + + return false +} + +// SetCredentialsSupportedDraft00 gets a reference to the given []CredentialSupportedDraft00 and assigns it to the CredentialsSupportedDraft00 field. +func (o *OidcConfiguration) SetCredentialsSupportedDraft00(v []CredentialSupportedDraft00) { + o.CredentialsSupportedDraft00 = v +} + // GetEndSessionEndpoint returns the EndSessionEndpoint field value if set, zero value otherwise. func (o *OidcConfiguration) GetEndSessionEndpoint() string { - if o == nil || o.EndSessionEndpoint == nil { + if o == nil || IsNil(o.EndSessionEndpoint) { var ret string return ret } @@ -299,7 +374,7 @@ func (o *OidcConfiguration) GetEndSessionEndpoint() string { // GetEndSessionEndpointOk returns a tuple with the EndSessionEndpoint field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetEndSessionEndpointOk() (*string, bool) { - if o == nil || o.EndSessionEndpoint == nil { + if o == nil || IsNil(o.EndSessionEndpoint) { return nil, false } return o.EndSessionEndpoint, true @@ -307,7 +382,7 @@ func (o *OidcConfiguration) GetEndSessionEndpointOk() (*string, bool) { // HasEndSessionEndpoint returns a boolean if a field has been set. func (o *OidcConfiguration) HasEndSessionEndpoint() bool { - if o != nil && o.EndSessionEndpoint != nil { + if o != nil && !IsNil(o.EndSessionEndpoint) { return true } @@ -321,7 +396,7 @@ func (o *OidcConfiguration) SetEndSessionEndpoint(v string) { // GetFrontchannelLogoutSessionSupported returns the FrontchannelLogoutSessionSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetFrontchannelLogoutSessionSupported() bool { - if o == nil || o.FrontchannelLogoutSessionSupported == nil { + if o == nil || IsNil(o.FrontchannelLogoutSessionSupported) { var ret bool return ret } @@ -331,7 +406,7 @@ func (o *OidcConfiguration) GetFrontchannelLogoutSessionSupported() bool { // GetFrontchannelLogoutSessionSupportedOk returns a tuple with the FrontchannelLogoutSessionSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetFrontchannelLogoutSessionSupportedOk() (*bool, bool) { - if o == nil || o.FrontchannelLogoutSessionSupported == nil { + if o == nil || IsNil(o.FrontchannelLogoutSessionSupported) { return nil, false } return o.FrontchannelLogoutSessionSupported, true @@ -339,7 +414,7 @@ func (o *OidcConfiguration) GetFrontchannelLogoutSessionSupportedOk() (*bool, bo // HasFrontchannelLogoutSessionSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasFrontchannelLogoutSessionSupported() bool { - if o != nil && o.FrontchannelLogoutSessionSupported != nil { + if o != nil && !IsNil(o.FrontchannelLogoutSessionSupported) { return true } @@ -353,7 +428,7 @@ func (o *OidcConfiguration) SetFrontchannelLogoutSessionSupported(v bool) { // GetFrontchannelLogoutSupported returns the FrontchannelLogoutSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetFrontchannelLogoutSupported() bool { - if o == nil || o.FrontchannelLogoutSupported == nil { + if o == nil || IsNil(o.FrontchannelLogoutSupported) { var ret bool return ret } @@ -363,7 +438,7 @@ func (o *OidcConfiguration) GetFrontchannelLogoutSupported() bool { // GetFrontchannelLogoutSupportedOk returns a tuple with the FrontchannelLogoutSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetFrontchannelLogoutSupportedOk() (*bool, bool) { - if o == nil || o.FrontchannelLogoutSupported == nil { + if o == nil || IsNil(o.FrontchannelLogoutSupported) { return nil, false } return o.FrontchannelLogoutSupported, true @@ -371,7 +446,7 @@ func (o *OidcConfiguration) GetFrontchannelLogoutSupportedOk() (*bool, bool) { // HasFrontchannelLogoutSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasFrontchannelLogoutSupported() bool { - if o != nil && o.FrontchannelLogoutSupported != nil { + if o != nil && !IsNil(o.FrontchannelLogoutSupported) { return true } @@ -385,7 +460,7 @@ func (o *OidcConfiguration) SetFrontchannelLogoutSupported(v bool) { // GetGrantTypesSupported returns the GrantTypesSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetGrantTypesSupported() []string { - if o == nil || o.GrantTypesSupported == nil { + if o == nil || IsNil(o.GrantTypesSupported) { var ret []string return ret } @@ -395,7 +470,7 @@ func (o *OidcConfiguration) GetGrantTypesSupported() []string { // GetGrantTypesSupportedOk returns a tuple with the GrantTypesSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetGrantTypesSupportedOk() ([]string, bool) { - if o == nil || o.GrantTypesSupported == nil { + if o == nil || IsNil(o.GrantTypesSupported) { return nil, false } return o.GrantTypesSupported, true @@ -403,7 +478,7 @@ func (o *OidcConfiguration) GetGrantTypesSupportedOk() ([]string, bool) { // HasGrantTypesSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasGrantTypesSupported() bool { - if o != nil && o.GrantTypesSupported != nil { + if o != nil && !IsNil(o.GrantTypesSupported) { return true } @@ -513,7 +588,7 @@ func (o *OidcConfiguration) SetJwksUri(v string) { // GetRegistrationEndpoint returns the RegistrationEndpoint field value if set, zero value otherwise. func (o *OidcConfiguration) GetRegistrationEndpoint() string { - if o == nil || o.RegistrationEndpoint == nil { + if o == nil || IsNil(o.RegistrationEndpoint) { var ret string return ret } @@ -523,7 +598,7 @@ func (o *OidcConfiguration) GetRegistrationEndpoint() string { // GetRegistrationEndpointOk returns a tuple with the RegistrationEndpoint field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetRegistrationEndpointOk() (*string, bool) { - if o == nil || o.RegistrationEndpoint == nil { + if o == nil || IsNil(o.RegistrationEndpoint) { return nil, false } return o.RegistrationEndpoint, true @@ -531,7 +606,7 @@ func (o *OidcConfiguration) GetRegistrationEndpointOk() (*string, bool) { // HasRegistrationEndpoint returns a boolean if a field has been set. func (o *OidcConfiguration) HasRegistrationEndpoint() bool { - if o != nil && o.RegistrationEndpoint != nil { + if o != nil && !IsNil(o.RegistrationEndpoint) { return true } @@ -545,7 +620,7 @@ func (o *OidcConfiguration) SetRegistrationEndpoint(v string) { // GetRequestObjectSigningAlgValuesSupported returns the RequestObjectSigningAlgValuesSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetRequestObjectSigningAlgValuesSupported() []string { - if o == nil || o.RequestObjectSigningAlgValuesSupported == nil { + if o == nil || IsNil(o.RequestObjectSigningAlgValuesSupported) { var ret []string return ret } @@ -555,7 +630,7 @@ func (o *OidcConfiguration) GetRequestObjectSigningAlgValuesSupported() []string // GetRequestObjectSigningAlgValuesSupportedOk returns a tuple with the RequestObjectSigningAlgValuesSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetRequestObjectSigningAlgValuesSupportedOk() ([]string, bool) { - if o == nil || o.RequestObjectSigningAlgValuesSupported == nil { + if o == nil || IsNil(o.RequestObjectSigningAlgValuesSupported) { return nil, false } return o.RequestObjectSigningAlgValuesSupported, true @@ -563,7 +638,7 @@ func (o *OidcConfiguration) GetRequestObjectSigningAlgValuesSupportedOk() ([]str // HasRequestObjectSigningAlgValuesSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasRequestObjectSigningAlgValuesSupported() bool { - if o != nil && o.RequestObjectSigningAlgValuesSupported != nil { + if o != nil && !IsNil(o.RequestObjectSigningAlgValuesSupported) { return true } @@ -577,7 +652,7 @@ func (o *OidcConfiguration) SetRequestObjectSigningAlgValuesSupported(v []string // GetRequestParameterSupported returns the RequestParameterSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetRequestParameterSupported() bool { - if o == nil || o.RequestParameterSupported == nil { + if o == nil || IsNil(o.RequestParameterSupported) { var ret bool return ret } @@ -587,7 +662,7 @@ func (o *OidcConfiguration) GetRequestParameterSupported() bool { // GetRequestParameterSupportedOk returns a tuple with the RequestParameterSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetRequestParameterSupportedOk() (*bool, bool) { - if o == nil || o.RequestParameterSupported == nil { + if o == nil || IsNil(o.RequestParameterSupported) { return nil, false } return o.RequestParameterSupported, true @@ -595,7 +670,7 @@ func (o *OidcConfiguration) GetRequestParameterSupportedOk() (*bool, bool) { // HasRequestParameterSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasRequestParameterSupported() bool { - if o != nil && o.RequestParameterSupported != nil { + if o != nil && !IsNil(o.RequestParameterSupported) { return true } @@ -609,7 +684,7 @@ func (o *OidcConfiguration) SetRequestParameterSupported(v bool) { // GetRequestUriParameterSupported returns the RequestUriParameterSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetRequestUriParameterSupported() bool { - if o == nil || o.RequestUriParameterSupported == nil { + if o == nil || IsNil(o.RequestUriParameterSupported) { var ret bool return ret } @@ -619,7 +694,7 @@ func (o *OidcConfiguration) GetRequestUriParameterSupported() bool { // GetRequestUriParameterSupportedOk returns a tuple with the RequestUriParameterSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetRequestUriParameterSupportedOk() (*bool, bool) { - if o == nil || o.RequestUriParameterSupported == nil { + if o == nil || IsNil(o.RequestUriParameterSupported) { return nil, false } return o.RequestUriParameterSupported, true @@ -627,7 +702,7 @@ func (o *OidcConfiguration) GetRequestUriParameterSupportedOk() (*bool, bool) { // HasRequestUriParameterSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasRequestUriParameterSupported() bool { - if o != nil && o.RequestUriParameterSupported != nil { + if o != nil && !IsNil(o.RequestUriParameterSupported) { return true } @@ -641,7 +716,7 @@ func (o *OidcConfiguration) SetRequestUriParameterSupported(v bool) { // GetRequireRequestUriRegistration returns the RequireRequestUriRegistration field value if set, zero value otherwise. func (o *OidcConfiguration) GetRequireRequestUriRegistration() bool { - if o == nil || o.RequireRequestUriRegistration == nil { + if o == nil || IsNil(o.RequireRequestUriRegistration) { var ret bool return ret } @@ -651,7 +726,7 @@ func (o *OidcConfiguration) GetRequireRequestUriRegistration() bool { // GetRequireRequestUriRegistrationOk returns a tuple with the RequireRequestUriRegistration field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetRequireRequestUriRegistrationOk() (*bool, bool) { - if o == nil || o.RequireRequestUriRegistration == nil { + if o == nil || IsNil(o.RequireRequestUriRegistration) { return nil, false } return o.RequireRequestUriRegistration, true @@ -659,7 +734,7 @@ func (o *OidcConfiguration) GetRequireRequestUriRegistrationOk() (*bool, bool) { // HasRequireRequestUriRegistration returns a boolean if a field has been set. func (o *OidcConfiguration) HasRequireRequestUriRegistration() bool { - if o != nil && o.RequireRequestUriRegistration != nil { + if o != nil && !IsNil(o.RequireRequestUriRegistration) { return true } @@ -673,7 +748,7 @@ func (o *OidcConfiguration) SetRequireRequestUriRegistration(v bool) { // GetResponseModesSupported returns the ResponseModesSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetResponseModesSupported() []string { - if o == nil || o.ResponseModesSupported == nil { + if o == nil || IsNil(o.ResponseModesSupported) { var ret []string return ret } @@ -683,7 +758,7 @@ func (o *OidcConfiguration) GetResponseModesSupported() []string { // GetResponseModesSupportedOk returns a tuple with the ResponseModesSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetResponseModesSupportedOk() ([]string, bool) { - if o == nil || o.ResponseModesSupported == nil { + if o == nil || IsNil(o.ResponseModesSupported) { return nil, false } return o.ResponseModesSupported, true @@ -691,7 +766,7 @@ func (o *OidcConfiguration) GetResponseModesSupportedOk() ([]string, bool) { // HasResponseModesSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasResponseModesSupported() bool { - if o != nil && o.ResponseModesSupported != nil { + if o != nil && !IsNil(o.ResponseModesSupported) { return true } @@ -729,7 +804,7 @@ func (o *OidcConfiguration) SetResponseTypesSupported(v []string) { // GetRevocationEndpoint returns the RevocationEndpoint field value if set, zero value otherwise. func (o *OidcConfiguration) GetRevocationEndpoint() string { - if o == nil || o.RevocationEndpoint == nil { + if o == nil || IsNil(o.RevocationEndpoint) { var ret string return ret } @@ -739,7 +814,7 @@ func (o *OidcConfiguration) GetRevocationEndpoint() string { // GetRevocationEndpointOk returns a tuple with the RevocationEndpoint field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetRevocationEndpointOk() (*string, bool) { - if o == nil || o.RevocationEndpoint == nil { + if o == nil || IsNil(o.RevocationEndpoint) { return nil, false } return o.RevocationEndpoint, true @@ -747,7 +822,7 @@ func (o *OidcConfiguration) GetRevocationEndpointOk() (*string, bool) { // HasRevocationEndpoint returns a boolean if a field has been set. func (o *OidcConfiguration) HasRevocationEndpoint() bool { - if o != nil && o.RevocationEndpoint != nil { + if o != nil && !IsNil(o.RevocationEndpoint) { return true } @@ -761,7 +836,7 @@ func (o *OidcConfiguration) SetRevocationEndpoint(v string) { // GetScopesSupported returns the ScopesSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetScopesSupported() []string { - if o == nil || o.ScopesSupported == nil { + if o == nil || IsNil(o.ScopesSupported) { var ret []string return ret } @@ -771,7 +846,7 @@ func (o *OidcConfiguration) GetScopesSupported() []string { // GetScopesSupportedOk returns a tuple with the ScopesSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetScopesSupportedOk() ([]string, bool) { - if o == nil || o.ScopesSupported == nil { + if o == nil || IsNil(o.ScopesSupported) { return nil, false } return o.ScopesSupported, true @@ -779,7 +854,7 @@ func (o *OidcConfiguration) GetScopesSupportedOk() ([]string, bool) { // HasScopesSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasScopesSupported() bool { - if o != nil && o.ScopesSupported != nil { + if o != nil && !IsNil(o.ScopesSupported) { return true } @@ -841,7 +916,7 @@ func (o *OidcConfiguration) SetTokenEndpoint(v string) { // GetTokenEndpointAuthMethodsSupported returns the TokenEndpointAuthMethodsSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetTokenEndpointAuthMethodsSupported() []string { - if o == nil || o.TokenEndpointAuthMethodsSupported == nil { + if o == nil || IsNil(o.TokenEndpointAuthMethodsSupported) { var ret []string return ret } @@ -851,7 +926,7 @@ func (o *OidcConfiguration) GetTokenEndpointAuthMethodsSupported() []string { // GetTokenEndpointAuthMethodsSupportedOk returns a tuple with the TokenEndpointAuthMethodsSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetTokenEndpointAuthMethodsSupportedOk() ([]string, bool) { - if o == nil || o.TokenEndpointAuthMethodsSupported == nil { + if o == nil || IsNil(o.TokenEndpointAuthMethodsSupported) { return nil, false } return o.TokenEndpointAuthMethodsSupported, true @@ -859,7 +934,7 @@ func (o *OidcConfiguration) GetTokenEndpointAuthMethodsSupportedOk() ([]string, // HasTokenEndpointAuthMethodsSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasTokenEndpointAuthMethodsSupported() bool { - if o != nil && o.TokenEndpointAuthMethodsSupported != nil { + if o != nil && !IsNil(o.TokenEndpointAuthMethodsSupported) { return true } @@ -873,7 +948,7 @@ func (o *OidcConfiguration) SetTokenEndpointAuthMethodsSupported(v []string) { // GetUserinfoEndpoint returns the UserinfoEndpoint field value if set, zero value otherwise. func (o *OidcConfiguration) GetUserinfoEndpoint() string { - if o == nil || o.UserinfoEndpoint == nil { + if o == nil || IsNil(o.UserinfoEndpoint) { var ret string return ret } @@ -883,7 +958,7 @@ func (o *OidcConfiguration) GetUserinfoEndpoint() string { // GetUserinfoEndpointOk returns a tuple with the UserinfoEndpoint field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetUserinfoEndpointOk() (*string, bool) { - if o == nil || o.UserinfoEndpoint == nil { + if o == nil || IsNil(o.UserinfoEndpoint) { return nil, false } return o.UserinfoEndpoint, true @@ -891,7 +966,7 @@ func (o *OidcConfiguration) GetUserinfoEndpointOk() (*string, bool) { // HasUserinfoEndpoint returns a boolean if a field has been set. func (o *OidcConfiguration) HasUserinfoEndpoint() bool { - if o != nil && o.UserinfoEndpoint != nil { + if o != nil && !IsNil(o.UserinfoEndpoint) { return true } @@ -929,7 +1004,7 @@ func (o *OidcConfiguration) SetUserinfoSignedResponseAlg(v []string) { // GetUserinfoSigningAlgValuesSupported returns the UserinfoSigningAlgValuesSupported field value if set, zero value otherwise. func (o *OidcConfiguration) GetUserinfoSigningAlgValuesSupported() []string { - if o == nil || o.UserinfoSigningAlgValuesSupported == nil { + if o == nil || IsNil(o.UserinfoSigningAlgValuesSupported) { var ret []string return ret } @@ -939,7 +1014,7 @@ func (o *OidcConfiguration) GetUserinfoSigningAlgValuesSupported() []string { // GetUserinfoSigningAlgValuesSupportedOk returns a tuple with the UserinfoSigningAlgValuesSupported field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcConfiguration) GetUserinfoSigningAlgValuesSupportedOk() ([]string, bool) { - if o == nil || o.UserinfoSigningAlgValuesSupported == nil { + if o == nil || IsNil(o.UserinfoSigningAlgValuesSupported) { return nil, false } return o.UserinfoSigningAlgValuesSupported, true @@ -947,7 +1022,7 @@ func (o *OidcConfiguration) GetUserinfoSigningAlgValuesSupportedOk() ([]string, // HasUserinfoSigningAlgValuesSupported returns a boolean if a field has been set. func (o *OidcConfiguration) HasUserinfoSigningAlgValuesSupported() bool { - if o != nil && o.UserinfoSigningAlgValuesSupported != nil { + if o != nil && !IsNil(o.UserinfoSigningAlgValuesSupported) { return true } @@ -960,95 +1035,136 @@ func (o *OidcConfiguration) SetUserinfoSigningAlgValuesSupported(v []string) { } func (o OidcConfiguration) MarshalJSON() ([]byte, error) { - toSerialize := map[string]interface{}{} - if true { - toSerialize["authorization_endpoint"] = o.AuthorizationEndpoint + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err } - if o.BackchannelLogoutSessionSupported != nil { + return json.Marshal(toSerialize) +} + +func (o OidcConfiguration) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["authorization_endpoint"] = o.AuthorizationEndpoint + if !IsNil(o.BackchannelLogoutSessionSupported) { toSerialize["backchannel_logout_session_supported"] = o.BackchannelLogoutSessionSupported } - if o.BackchannelLogoutSupported != nil { + if !IsNil(o.BackchannelLogoutSupported) { toSerialize["backchannel_logout_supported"] = o.BackchannelLogoutSupported } - if o.ClaimsParameterSupported != nil { + if !IsNil(o.ClaimsParameterSupported) { toSerialize["claims_parameter_supported"] = o.ClaimsParameterSupported } - if o.ClaimsSupported != nil { + if !IsNil(o.ClaimsSupported) { toSerialize["claims_supported"] = o.ClaimsSupported } - if o.CodeChallengeMethodsSupported != nil { + if !IsNil(o.CodeChallengeMethodsSupported) { toSerialize["code_challenge_methods_supported"] = o.CodeChallengeMethodsSupported } - if o.EndSessionEndpoint != nil { + if !IsNil(o.CredentialsEndpointDraft00) { + toSerialize["credentials_endpoint_draft_00"] = o.CredentialsEndpointDraft00 + } + if !IsNil(o.CredentialsSupportedDraft00) { + toSerialize["credentials_supported_draft_00"] = o.CredentialsSupportedDraft00 + } + if !IsNil(o.EndSessionEndpoint) { toSerialize["end_session_endpoint"] = o.EndSessionEndpoint } - if o.FrontchannelLogoutSessionSupported != nil { + if !IsNil(o.FrontchannelLogoutSessionSupported) { toSerialize["frontchannel_logout_session_supported"] = o.FrontchannelLogoutSessionSupported } - if o.FrontchannelLogoutSupported != nil { + if !IsNil(o.FrontchannelLogoutSupported) { toSerialize["frontchannel_logout_supported"] = o.FrontchannelLogoutSupported } - if o.GrantTypesSupported != nil { + if !IsNil(o.GrantTypesSupported) { toSerialize["grant_types_supported"] = o.GrantTypesSupported } - if true { - toSerialize["id_token_signed_response_alg"] = o.IdTokenSignedResponseAlg - } - if true { - toSerialize["id_token_signing_alg_values_supported"] = o.IdTokenSigningAlgValuesSupported - } - if true { - toSerialize["issuer"] = o.Issuer - } - if true { - toSerialize["jwks_uri"] = o.JwksUri - } - if o.RegistrationEndpoint != nil { + toSerialize["id_token_signed_response_alg"] = o.IdTokenSignedResponseAlg + toSerialize["id_token_signing_alg_values_supported"] = o.IdTokenSigningAlgValuesSupported + toSerialize["issuer"] = o.Issuer + toSerialize["jwks_uri"] = o.JwksUri + if !IsNil(o.RegistrationEndpoint) { toSerialize["registration_endpoint"] = o.RegistrationEndpoint } - if o.RequestObjectSigningAlgValuesSupported != nil { + if !IsNil(o.RequestObjectSigningAlgValuesSupported) { toSerialize["request_object_signing_alg_values_supported"] = o.RequestObjectSigningAlgValuesSupported } - if o.RequestParameterSupported != nil { + if !IsNil(o.RequestParameterSupported) { toSerialize["request_parameter_supported"] = o.RequestParameterSupported } - if o.RequestUriParameterSupported != nil { + if !IsNil(o.RequestUriParameterSupported) { toSerialize["request_uri_parameter_supported"] = o.RequestUriParameterSupported } - if o.RequireRequestUriRegistration != nil { + if !IsNil(o.RequireRequestUriRegistration) { toSerialize["require_request_uri_registration"] = o.RequireRequestUriRegistration } - if o.ResponseModesSupported != nil { + if !IsNil(o.ResponseModesSupported) { toSerialize["response_modes_supported"] = o.ResponseModesSupported } - if true { - toSerialize["response_types_supported"] = o.ResponseTypesSupported - } - if o.RevocationEndpoint != nil { + toSerialize["response_types_supported"] = o.ResponseTypesSupported + if !IsNil(o.RevocationEndpoint) { toSerialize["revocation_endpoint"] = o.RevocationEndpoint } - if o.ScopesSupported != nil { + if !IsNil(o.ScopesSupported) { toSerialize["scopes_supported"] = o.ScopesSupported } - if true { - toSerialize["subject_types_supported"] = o.SubjectTypesSupported - } - if true { - toSerialize["token_endpoint"] = o.TokenEndpoint - } - if o.TokenEndpointAuthMethodsSupported != nil { + toSerialize["subject_types_supported"] = o.SubjectTypesSupported + toSerialize["token_endpoint"] = o.TokenEndpoint + if !IsNil(o.TokenEndpointAuthMethodsSupported) { toSerialize["token_endpoint_auth_methods_supported"] = o.TokenEndpointAuthMethodsSupported } - if o.UserinfoEndpoint != nil { + if !IsNil(o.UserinfoEndpoint) { toSerialize["userinfo_endpoint"] = o.UserinfoEndpoint } - if true { - toSerialize["userinfo_signed_response_alg"] = o.UserinfoSignedResponseAlg - } - if o.UserinfoSigningAlgValuesSupported != nil { + toSerialize["userinfo_signed_response_alg"] = o.UserinfoSignedResponseAlg + if !IsNil(o.UserinfoSigningAlgValuesSupported) { toSerialize["userinfo_signing_alg_values_supported"] = o.UserinfoSigningAlgValuesSupported } - return json.Marshal(toSerialize) + return toSerialize, nil +} + +func (o *OidcConfiguration) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "authorization_endpoint", + "id_token_signed_response_alg", + "id_token_signing_alg_values_supported", + "issuer", + "jwks_uri", + "response_types_supported", + "subject_types_supported", + "token_endpoint", + "userinfo_signed_response_alg", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varOidcConfiguration := _OidcConfiguration{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varOidcConfiguration) + + if err != nil { + return err + } + + *o = OidcConfiguration(varOidcConfiguration) + + return err } type NullableOidcConfiguration struct { diff --git a/internal/httpclient/model_oidc_user_info.go b/internal/httpclient/model_oidc_user_info.go index f1b942a7b6e..d6a08aedfe8 100644 --- a/internal/httpclient/model_oidc_user_info.go +++ b/internal/httpclient/model_oidc_user_info.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the OidcUserInfo type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &OidcUserInfo{} + // OidcUserInfo OpenID Connect Userinfo type OidcUserInfo struct { // End-User's birthday, represented as an ISO 8601:2004 [ISO8601‑2004] YYYY-MM-DD format. The year MAY be 0000, indicating that it is omitted. To represent only the year, YYYY format is allowed. Note that depending on the underlying platform's date related function, providing just year can result in varying month and day, so the implementers need to take this factor into account to correctly process the dates. @@ -76,7 +79,7 @@ func NewOidcUserInfoWithDefaults() *OidcUserInfo { // GetBirthdate returns the Birthdate field value if set, zero value otherwise. func (o *OidcUserInfo) GetBirthdate() string { - if o == nil || o.Birthdate == nil { + if o == nil || IsNil(o.Birthdate) { var ret string return ret } @@ -86,7 +89,7 @@ func (o *OidcUserInfo) GetBirthdate() string { // GetBirthdateOk returns a tuple with the Birthdate field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetBirthdateOk() (*string, bool) { - if o == nil || o.Birthdate == nil { + if o == nil || IsNil(o.Birthdate) { return nil, false } return o.Birthdate, true @@ -94,7 +97,7 @@ func (o *OidcUserInfo) GetBirthdateOk() (*string, bool) { // HasBirthdate returns a boolean if a field has been set. func (o *OidcUserInfo) HasBirthdate() bool { - if o != nil && o.Birthdate != nil { + if o != nil && !IsNil(o.Birthdate) { return true } @@ -108,7 +111,7 @@ func (o *OidcUserInfo) SetBirthdate(v string) { // GetEmail returns the Email field value if set, zero value otherwise. func (o *OidcUserInfo) GetEmail() string { - if o == nil || o.Email == nil { + if o == nil || IsNil(o.Email) { var ret string return ret } @@ -118,7 +121,7 @@ func (o *OidcUserInfo) GetEmail() string { // GetEmailOk returns a tuple with the Email field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetEmailOk() (*string, bool) { - if o == nil || o.Email == nil { + if o == nil || IsNil(o.Email) { return nil, false } return o.Email, true @@ -126,7 +129,7 @@ func (o *OidcUserInfo) GetEmailOk() (*string, bool) { // HasEmail returns a boolean if a field has been set. func (o *OidcUserInfo) HasEmail() bool { - if o != nil && o.Email != nil { + if o != nil && !IsNil(o.Email) { return true } @@ -140,7 +143,7 @@ func (o *OidcUserInfo) SetEmail(v string) { // GetEmailVerified returns the EmailVerified field value if set, zero value otherwise. func (o *OidcUserInfo) GetEmailVerified() bool { - if o == nil || o.EmailVerified == nil { + if o == nil || IsNil(o.EmailVerified) { var ret bool return ret } @@ -150,7 +153,7 @@ func (o *OidcUserInfo) GetEmailVerified() bool { // GetEmailVerifiedOk returns a tuple with the EmailVerified field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetEmailVerifiedOk() (*bool, bool) { - if o == nil || o.EmailVerified == nil { + if o == nil || IsNil(o.EmailVerified) { return nil, false } return o.EmailVerified, true @@ -158,7 +161,7 @@ func (o *OidcUserInfo) GetEmailVerifiedOk() (*bool, bool) { // HasEmailVerified returns a boolean if a field has been set. func (o *OidcUserInfo) HasEmailVerified() bool { - if o != nil && o.EmailVerified != nil { + if o != nil && !IsNil(o.EmailVerified) { return true } @@ -172,7 +175,7 @@ func (o *OidcUserInfo) SetEmailVerified(v bool) { // GetFamilyName returns the FamilyName field value if set, zero value otherwise. func (o *OidcUserInfo) GetFamilyName() string { - if o == nil || o.FamilyName == nil { + if o == nil || IsNil(o.FamilyName) { var ret string return ret } @@ -182,7 +185,7 @@ func (o *OidcUserInfo) GetFamilyName() string { // GetFamilyNameOk returns a tuple with the FamilyName field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetFamilyNameOk() (*string, bool) { - if o == nil || o.FamilyName == nil { + if o == nil || IsNil(o.FamilyName) { return nil, false } return o.FamilyName, true @@ -190,7 +193,7 @@ func (o *OidcUserInfo) GetFamilyNameOk() (*string, bool) { // HasFamilyName returns a boolean if a field has been set. func (o *OidcUserInfo) HasFamilyName() bool { - if o != nil && o.FamilyName != nil { + if o != nil && !IsNil(o.FamilyName) { return true } @@ -204,7 +207,7 @@ func (o *OidcUserInfo) SetFamilyName(v string) { // GetGender returns the Gender field value if set, zero value otherwise. func (o *OidcUserInfo) GetGender() string { - if o == nil || o.Gender == nil { + if o == nil || IsNil(o.Gender) { var ret string return ret } @@ -214,7 +217,7 @@ func (o *OidcUserInfo) GetGender() string { // GetGenderOk returns a tuple with the Gender field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetGenderOk() (*string, bool) { - if o == nil || o.Gender == nil { + if o == nil || IsNil(o.Gender) { return nil, false } return o.Gender, true @@ -222,7 +225,7 @@ func (o *OidcUserInfo) GetGenderOk() (*string, bool) { // HasGender returns a boolean if a field has been set. func (o *OidcUserInfo) HasGender() bool { - if o != nil && o.Gender != nil { + if o != nil && !IsNil(o.Gender) { return true } @@ -236,7 +239,7 @@ func (o *OidcUserInfo) SetGender(v string) { // GetGivenName returns the GivenName field value if set, zero value otherwise. func (o *OidcUserInfo) GetGivenName() string { - if o == nil || o.GivenName == nil { + if o == nil || IsNil(o.GivenName) { var ret string return ret } @@ -246,7 +249,7 @@ func (o *OidcUserInfo) GetGivenName() string { // GetGivenNameOk returns a tuple with the GivenName field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetGivenNameOk() (*string, bool) { - if o == nil || o.GivenName == nil { + if o == nil || IsNil(o.GivenName) { return nil, false } return o.GivenName, true @@ -254,7 +257,7 @@ func (o *OidcUserInfo) GetGivenNameOk() (*string, bool) { // HasGivenName returns a boolean if a field has been set. func (o *OidcUserInfo) HasGivenName() bool { - if o != nil && o.GivenName != nil { + if o != nil && !IsNil(o.GivenName) { return true } @@ -268,7 +271,7 @@ func (o *OidcUserInfo) SetGivenName(v string) { // GetLocale returns the Locale field value if set, zero value otherwise. func (o *OidcUserInfo) GetLocale() string { - if o == nil || o.Locale == nil { + if o == nil || IsNil(o.Locale) { var ret string return ret } @@ -278,7 +281,7 @@ func (o *OidcUserInfo) GetLocale() string { // GetLocaleOk returns a tuple with the Locale field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetLocaleOk() (*string, bool) { - if o == nil || o.Locale == nil { + if o == nil || IsNil(o.Locale) { return nil, false } return o.Locale, true @@ -286,7 +289,7 @@ func (o *OidcUserInfo) GetLocaleOk() (*string, bool) { // HasLocale returns a boolean if a field has been set. func (o *OidcUserInfo) HasLocale() bool { - if o != nil && o.Locale != nil { + if o != nil && !IsNil(o.Locale) { return true } @@ -300,7 +303,7 @@ func (o *OidcUserInfo) SetLocale(v string) { // GetMiddleName returns the MiddleName field value if set, zero value otherwise. func (o *OidcUserInfo) GetMiddleName() string { - if o == nil || o.MiddleName == nil { + if o == nil || IsNil(o.MiddleName) { var ret string return ret } @@ -310,7 +313,7 @@ func (o *OidcUserInfo) GetMiddleName() string { // GetMiddleNameOk returns a tuple with the MiddleName field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetMiddleNameOk() (*string, bool) { - if o == nil || o.MiddleName == nil { + if o == nil || IsNil(o.MiddleName) { return nil, false } return o.MiddleName, true @@ -318,7 +321,7 @@ func (o *OidcUserInfo) GetMiddleNameOk() (*string, bool) { // HasMiddleName returns a boolean if a field has been set. func (o *OidcUserInfo) HasMiddleName() bool { - if o != nil && o.MiddleName != nil { + if o != nil && !IsNil(o.MiddleName) { return true } @@ -332,7 +335,7 @@ func (o *OidcUserInfo) SetMiddleName(v string) { // GetName returns the Name field value if set, zero value otherwise. func (o *OidcUserInfo) GetName() string { - if o == nil || o.Name == nil { + if o == nil || IsNil(o.Name) { var ret string return ret } @@ -342,7 +345,7 @@ func (o *OidcUserInfo) GetName() string { // GetNameOk returns a tuple with the Name field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetNameOk() (*string, bool) { - if o == nil || o.Name == nil { + if o == nil || IsNil(o.Name) { return nil, false } return o.Name, true @@ -350,7 +353,7 @@ func (o *OidcUserInfo) GetNameOk() (*string, bool) { // HasName returns a boolean if a field has been set. func (o *OidcUserInfo) HasName() bool { - if o != nil && o.Name != nil { + if o != nil && !IsNil(o.Name) { return true } @@ -364,7 +367,7 @@ func (o *OidcUserInfo) SetName(v string) { // GetNickname returns the Nickname field value if set, zero value otherwise. func (o *OidcUserInfo) GetNickname() string { - if o == nil || o.Nickname == nil { + if o == nil || IsNil(o.Nickname) { var ret string return ret } @@ -374,7 +377,7 @@ func (o *OidcUserInfo) GetNickname() string { // GetNicknameOk returns a tuple with the Nickname field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetNicknameOk() (*string, bool) { - if o == nil || o.Nickname == nil { + if o == nil || IsNil(o.Nickname) { return nil, false } return o.Nickname, true @@ -382,7 +385,7 @@ func (o *OidcUserInfo) GetNicknameOk() (*string, bool) { // HasNickname returns a boolean if a field has been set. func (o *OidcUserInfo) HasNickname() bool { - if o != nil && o.Nickname != nil { + if o != nil && !IsNil(o.Nickname) { return true } @@ -396,7 +399,7 @@ func (o *OidcUserInfo) SetNickname(v string) { // GetPhoneNumber returns the PhoneNumber field value if set, zero value otherwise. func (o *OidcUserInfo) GetPhoneNumber() string { - if o == nil || o.PhoneNumber == nil { + if o == nil || IsNil(o.PhoneNumber) { var ret string return ret } @@ -406,7 +409,7 @@ func (o *OidcUserInfo) GetPhoneNumber() string { // GetPhoneNumberOk returns a tuple with the PhoneNumber field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetPhoneNumberOk() (*string, bool) { - if o == nil || o.PhoneNumber == nil { + if o == nil || IsNil(o.PhoneNumber) { return nil, false } return o.PhoneNumber, true @@ -414,7 +417,7 @@ func (o *OidcUserInfo) GetPhoneNumberOk() (*string, bool) { // HasPhoneNumber returns a boolean if a field has been set. func (o *OidcUserInfo) HasPhoneNumber() bool { - if o != nil && o.PhoneNumber != nil { + if o != nil && !IsNil(o.PhoneNumber) { return true } @@ -428,7 +431,7 @@ func (o *OidcUserInfo) SetPhoneNumber(v string) { // GetPhoneNumberVerified returns the PhoneNumberVerified field value if set, zero value otherwise. func (o *OidcUserInfo) GetPhoneNumberVerified() bool { - if o == nil || o.PhoneNumberVerified == nil { + if o == nil || IsNil(o.PhoneNumberVerified) { var ret bool return ret } @@ -438,7 +441,7 @@ func (o *OidcUserInfo) GetPhoneNumberVerified() bool { // GetPhoneNumberVerifiedOk returns a tuple with the PhoneNumberVerified field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetPhoneNumberVerifiedOk() (*bool, bool) { - if o == nil || o.PhoneNumberVerified == nil { + if o == nil || IsNil(o.PhoneNumberVerified) { return nil, false } return o.PhoneNumberVerified, true @@ -446,7 +449,7 @@ func (o *OidcUserInfo) GetPhoneNumberVerifiedOk() (*bool, bool) { // HasPhoneNumberVerified returns a boolean if a field has been set. func (o *OidcUserInfo) HasPhoneNumberVerified() bool { - if o != nil && o.PhoneNumberVerified != nil { + if o != nil && !IsNil(o.PhoneNumberVerified) { return true } @@ -460,7 +463,7 @@ func (o *OidcUserInfo) SetPhoneNumberVerified(v bool) { // GetPicture returns the Picture field value if set, zero value otherwise. func (o *OidcUserInfo) GetPicture() string { - if o == nil || o.Picture == nil { + if o == nil || IsNil(o.Picture) { var ret string return ret } @@ -470,7 +473,7 @@ func (o *OidcUserInfo) GetPicture() string { // GetPictureOk returns a tuple with the Picture field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetPictureOk() (*string, bool) { - if o == nil || o.Picture == nil { + if o == nil || IsNil(o.Picture) { return nil, false } return o.Picture, true @@ -478,7 +481,7 @@ func (o *OidcUserInfo) GetPictureOk() (*string, bool) { // HasPicture returns a boolean if a field has been set. func (o *OidcUserInfo) HasPicture() bool { - if o != nil && o.Picture != nil { + if o != nil && !IsNil(o.Picture) { return true } @@ -492,7 +495,7 @@ func (o *OidcUserInfo) SetPicture(v string) { // GetPreferredUsername returns the PreferredUsername field value if set, zero value otherwise. func (o *OidcUserInfo) GetPreferredUsername() string { - if o == nil || o.PreferredUsername == nil { + if o == nil || IsNil(o.PreferredUsername) { var ret string return ret } @@ -502,7 +505,7 @@ func (o *OidcUserInfo) GetPreferredUsername() string { // GetPreferredUsernameOk returns a tuple with the PreferredUsername field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetPreferredUsernameOk() (*string, bool) { - if o == nil || o.PreferredUsername == nil { + if o == nil || IsNil(o.PreferredUsername) { return nil, false } return o.PreferredUsername, true @@ -510,7 +513,7 @@ func (o *OidcUserInfo) GetPreferredUsernameOk() (*string, bool) { // HasPreferredUsername returns a boolean if a field has been set. func (o *OidcUserInfo) HasPreferredUsername() bool { - if o != nil && o.PreferredUsername != nil { + if o != nil && !IsNil(o.PreferredUsername) { return true } @@ -524,7 +527,7 @@ func (o *OidcUserInfo) SetPreferredUsername(v string) { // GetProfile returns the Profile field value if set, zero value otherwise. func (o *OidcUserInfo) GetProfile() string { - if o == nil || o.Profile == nil { + if o == nil || IsNil(o.Profile) { var ret string return ret } @@ -534,7 +537,7 @@ func (o *OidcUserInfo) GetProfile() string { // GetProfileOk returns a tuple with the Profile field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetProfileOk() (*string, bool) { - if o == nil || o.Profile == nil { + if o == nil || IsNil(o.Profile) { return nil, false } return o.Profile, true @@ -542,7 +545,7 @@ func (o *OidcUserInfo) GetProfileOk() (*string, bool) { // HasProfile returns a boolean if a field has been set. func (o *OidcUserInfo) HasProfile() bool { - if o != nil && o.Profile != nil { + if o != nil && !IsNil(o.Profile) { return true } @@ -556,7 +559,7 @@ func (o *OidcUserInfo) SetProfile(v string) { // GetSub returns the Sub field value if set, zero value otherwise. func (o *OidcUserInfo) GetSub() string { - if o == nil || o.Sub == nil { + if o == nil || IsNil(o.Sub) { var ret string return ret } @@ -566,7 +569,7 @@ func (o *OidcUserInfo) GetSub() string { // GetSubOk returns a tuple with the Sub field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetSubOk() (*string, bool) { - if o == nil || o.Sub == nil { + if o == nil || IsNil(o.Sub) { return nil, false } return o.Sub, true @@ -574,7 +577,7 @@ func (o *OidcUserInfo) GetSubOk() (*string, bool) { // HasSub returns a boolean if a field has been set. func (o *OidcUserInfo) HasSub() bool { - if o != nil && o.Sub != nil { + if o != nil && !IsNil(o.Sub) { return true } @@ -588,7 +591,7 @@ func (o *OidcUserInfo) SetSub(v string) { // GetUpdatedAt returns the UpdatedAt field value if set, zero value otherwise. func (o *OidcUserInfo) GetUpdatedAt() int64 { - if o == nil || o.UpdatedAt == nil { + if o == nil || IsNil(o.UpdatedAt) { var ret int64 return ret } @@ -598,7 +601,7 @@ func (o *OidcUserInfo) GetUpdatedAt() int64 { // GetUpdatedAtOk returns a tuple with the UpdatedAt field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetUpdatedAtOk() (*int64, bool) { - if o == nil || o.UpdatedAt == nil { + if o == nil || IsNil(o.UpdatedAt) { return nil, false } return o.UpdatedAt, true @@ -606,7 +609,7 @@ func (o *OidcUserInfo) GetUpdatedAtOk() (*int64, bool) { // HasUpdatedAt returns a boolean if a field has been set. func (o *OidcUserInfo) HasUpdatedAt() bool { - if o != nil && o.UpdatedAt != nil { + if o != nil && !IsNil(o.UpdatedAt) { return true } @@ -620,7 +623,7 @@ func (o *OidcUserInfo) SetUpdatedAt(v int64) { // GetWebsite returns the Website field value if set, zero value otherwise. func (o *OidcUserInfo) GetWebsite() string { - if o == nil || o.Website == nil { + if o == nil || IsNil(o.Website) { var ret string return ret } @@ -630,7 +633,7 @@ func (o *OidcUserInfo) GetWebsite() string { // GetWebsiteOk returns a tuple with the Website field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetWebsiteOk() (*string, bool) { - if o == nil || o.Website == nil { + if o == nil || IsNil(o.Website) { return nil, false } return o.Website, true @@ -638,7 +641,7 @@ func (o *OidcUserInfo) GetWebsiteOk() (*string, bool) { // HasWebsite returns a boolean if a field has been set. func (o *OidcUserInfo) HasWebsite() bool { - if o != nil && o.Website != nil { + if o != nil && !IsNil(o.Website) { return true } @@ -652,7 +655,7 @@ func (o *OidcUserInfo) SetWebsite(v string) { // GetZoneinfo returns the Zoneinfo field value if set, zero value otherwise. func (o *OidcUserInfo) GetZoneinfo() string { - if o == nil || o.Zoneinfo == nil { + if o == nil || IsNil(o.Zoneinfo) { var ret string return ret } @@ -662,7 +665,7 @@ func (o *OidcUserInfo) GetZoneinfo() string { // GetZoneinfoOk returns a tuple with the Zoneinfo field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *OidcUserInfo) GetZoneinfoOk() (*string, bool) { - if o == nil || o.Zoneinfo == nil { + if o == nil || IsNil(o.Zoneinfo) { return nil, false } return o.Zoneinfo, true @@ -670,7 +673,7 @@ func (o *OidcUserInfo) GetZoneinfoOk() (*string, bool) { // HasZoneinfo returns a boolean if a field has been set. func (o *OidcUserInfo) HasZoneinfo() bool { - if o != nil && o.Zoneinfo != nil { + if o != nil && !IsNil(o.Zoneinfo) { return true } @@ -683,65 +686,73 @@ func (o *OidcUserInfo) SetZoneinfo(v string) { } func (o OidcUserInfo) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o OidcUserInfo) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Birthdate != nil { + if !IsNil(o.Birthdate) { toSerialize["birthdate"] = o.Birthdate } - if o.Email != nil { + if !IsNil(o.Email) { toSerialize["email"] = o.Email } - if o.EmailVerified != nil { + if !IsNil(o.EmailVerified) { toSerialize["email_verified"] = o.EmailVerified } - if o.FamilyName != nil { + if !IsNil(o.FamilyName) { toSerialize["family_name"] = o.FamilyName } - if o.Gender != nil { + if !IsNil(o.Gender) { toSerialize["gender"] = o.Gender } - if o.GivenName != nil { + if !IsNil(o.GivenName) { toSerialize["given_name"] = o.GivenName } - if o.Locale != nil { + if !IsNil(o.Locale) { toSerialize["locale"] = o.Locale } - if o.MiddleName != nil { + if !IsNil(o.MiddleName) { toSerialize["middle_name"] = o.MiddleName } - if o.Name != nil { + if !IsNil(o.Name) { toSerialize["name"] = o.Name } - if o.Nickname != nil { + if !IsNil(o.Nickname) { toSerialize["nickname"] = o.Nickname } - if o.PhoneNumber != nil { + if !IsNil(o.PhoneNumber) { toSerialize["phone_number"] = o.PhoneNumber } - if o.PhoneNumberVerified != nil { + if !IsNil(o.PhoneNumberVerified) { toSerialize["phone_number_verified"] = o.PhoneNumberVerified } - if o.Picture != nil { + if !IsNil(o.Picture) { toSerialize["picture"] = o.Picture } - if o.PreferredUsername != nil { + if !IsNil(o.PreferredUsername) { toSerialize["preferred_username"] = o.PreferredUsername } - if o.Profile != nil { + if !IsNil(o.Profile) { toSerialize["profile"] = o.Profile } - if o.Sub != nil { + if !IsNil(o.Sub) { toSerialize["sub"] = o.Sub } - if o.UpdatedAt != nil { + if !IsNil(o.UpdatedAt) { toSerialize["updated_at"] = o.UpdatedAt } - if o.Website != nil { + if !IsNil(o.Website) { toSerialize["website"] = o.Website } - if o.Zoneinfo != nil { + if !IsNil(o.Zoneinfo) { toSerialize["zoneinfo"] = o.Zoneinfo } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableOidcUserInfo struct { diff --git a/internal/httpclient/model_pagination.go b/internal/httpclient/model_pagination.go index 66402865828..3c8fb123987 100644 --- a/internal/httpclient/model_pagination.go +++ b/internal/httpclient/model_pagination.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the Pagination type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &Pagination{} + // Pagination struct for Pagination type Pagination struct { // Items per page This is the number of items per page to return. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). @@ -50,7 +53,7 @@ func NewPaginationWithDefaults() *Pagination { // GetPageSize returns the PageSize field value if set, zero value otherwise. func (o *Pagination) GetPageSize() int64 { - if o == nil || o.PageSize == nil { + if o == nil || IsNil(o.PageSize) { var ret int64 return ret } @@ -60,7 +63,7 @@ func (o *Pagination) GetPageSize() int64 { // GetPageSizeOk returns a tuple with the PageSize field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *Pagination) GetPageSizeOk() (*int64, bool) { - if o == nil || o.PageSize == nil { + if o == nil || IsNil(o.PageSize) { return nil, false } return o.PageSize, true @@ -68,7 +71,7 @@ func (o *Pagination) GetPageSizeOk() (*int64, bool) { // HasPageSize returns a boolean if a field has been set. func (o *Pagination) HasPageSize() bool { - if o != nil && o.PageSize != nil { + if o != nil && !IsNil(o.PageSize) { return true } @@ -82,7 +85,7 @@ func (o *Pagination) SetPageSize(v int64) { // GetPageToken returns the PageToken field value if set, zero value otherwise. func (o *Pagination) GetPageToken() string { - if o == nil || o.PageToken == nil { + if o == nil || IsNil(o.PageToken) { var ret string return ret } @@ -92,7 +95,7 @@ func (o *Pagination) GetPageToken() string { // GetPageTokenOk returns a tuple with the PageToken field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *Pagination) GetPageTokenOk() (*string, bool) { - if o == nil || o.PageToken == nil { + if o == nil || IsNil(o.PageToken) { return nil, false } return o.PageToken, true @@ -100,7 +103,7 @@ func (o *Pagination) GetPageTokenOk() (*string, bool) { // HasPageToken returns a boolean if a field has been set. func (o *Pagination) HasPageToken() bool { - if o != nil && o.PageToken != nil { + if o != nil && !IsNil(o.PageToken) { return true } @@ -113,14 +116,22 @@ func (o *Pagination) SetPageToken(v string) { } func (o Pagination) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o Pagination) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.PageSize != nil { + if !IsNil(o.PageSize) { toSerialize["page_size"] = o.PageSize } - if o.PageToken != nil { + if !IsNil(o.PageToken) { toSerialize["page_token"] = o.PageToken } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullablePagination struct { diff --git a/internal/httpclient/model_pagination_headers.go b/internal/httpclient/model_pagination_headers.go index 803a8119b4e..acb56f21978 100644 --- a/internal/httpclient/model_pagination_headers.go +++ b/internal/httpclient/model_pagination_headers.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the PaginationHeaders type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &PaginationHeaders{} + // PaginationHeaders struct for PaginationHeaders type PaginationHeaders struct { // The link header contains pagination links. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). in: header @@ -42,7 +45,7 @@ func NewPaginationHeadersWithDefaults() *PaginationHeaders { // GetLink returns the Link field value if set, zero value otherwise. func (o *PaginationHeaders) GetLink() string { - if o == nil || o.Link == nil { + if o == nil || IsNil(o.Link) { var ret string return ret } @@ -52,7 +55,7 @@ func (o *PaginationHeaders) GetLink() string { // GetLinkOk returns a tuple with the Link field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *PaginationHeaders) GetLinkOk() (*string, bool) { - if o == nil || o.Link == nil { + if o == nil || IsNil(o.Link) { return nil, false } return o.Link, true @@ -60,7 +63,7 @@ func (o *PaginationHeaders) GetLinkOk() (*string, bool) { // HasLink returns a boolean if a field has been set. func (o *PaginationHeaders) HasLink() bool { - if o != nil && o.Link != nil { + if o != nil && !IsNil(o.Link) { return true } @@ -74,7 +77,7 @@ func (o *PaginationHeaders) SetLink(v string) { // GetXTotalCount returns the XTotalCount field value if set, zero value otherwise. func (o *PaginationHeaders) GetXTotalCount() string { - if o == nil || o.XTotalCount == nil { + if o == nil || IsNil(o.XTotalCount) { var ret string return ret } @@ -84,7 +87,7 @@ func (o *PaginationHeaders) GetXTotalCount() string { // GetXTotalCountOk returns a tuple with the XTotalCount field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *PaginationHeaders) GetXTotalCountOk() (*string, bool) { - if o == nil || o.XTotalCount == nil { + if o == nil || IsNil(o.XTotalCount) { return nil, false } return o.XTotalCount, true @@ -92,7 +95,7 @@ func (o *PaginationHeaders) GetXTotalCountOk() (*string, bool) { // HasXTotalCount returns a boolean if a field has been set. func (o *PaginationHeaders) HasXTotalCount() bool { - if o != nil && o.XTotalCount != nil { + if o != nil && !IsNil(o.XTotalCount) { return true } @@ -105,14 +108,22 @@ func (o *PaginationHeaders) SetXTotalCount(v string) { } func (o PaginationHeaders) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o PaginationHeaders) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Link != nil { + if !IsNil(o.Link) { toSerialize["link"] = o.Link } - if o.XTotalCount != nil { + if !IsNil(o.XTotalCount) { toSerialize["x-total-count"] = o.XTotalCount } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullablePaginationHeaders struct { diff --git a/internal/httpclient/model_reject_o_auth2_request.go b/internal/httpclient/model_reject_o_auth2_request.go index 4b6817491a5..8d0a178a3fb 100644 --- a/internal/httpclient/model_reject_o_auth2_request.go +++ b/internal/httpclient/model_reject_o_auth2_request.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the RejectOAuth2Request type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &RejectOAuth2Request{} + // RejectOAuth2Request struct for RejectOAuth2Request type RejectOAuth2Request struct { // The error should follow the OAuth2 error format (e.g. `invalid_request`, `login_required`). Defaults to `request_denied`. @@ -48,7 +51,7 @@ func NewRejectOAuth2RequestWithDefaults() *RejectOAuth2Request { // GetError returns the Error field value if set, zero value otherwise. func (o *RejectOAuth2Request) GetError() string { - if o == nil || o.Error == nil { + if o == nil || IsNil(o.Error) { var ret string return ret } @@ -58,7 +61,7 @@ func (o *RejectOAuth2Request) GetError() string { // GetErrorOk returns a tuple with the Error field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *RejectOAuth2Request) GetErrorOk() (*string, bool) { - if o == nil || o.Error == nil { + if o == nil || IsNil(o.Error) { return nil, false } return o.Error, true @@ -66,7 +69,7 @@ func (o *RejectOAuth2Request) GetErrorOk() (*string, bool) { // HasError returns a boolean if a field has been set. func (o *RejectOAuth2Request) HasError() bool { - if o != nil && o.Error != nil { + if o != nil && !IsNil(o.Error) { return true } @@ -80,7 +83,7 @@ func (o *RejectOAuth2Request) SetError(v string) { // GetErrorDebug returns the ErrorDebug field value if set, zero value otherwise. func (o *RejectOAuth2Request) GetErrorDebug() string { - if o == nil || o.ErrorDebug == nil { + if o == nil || IsNil(o.ErrorDebug) { var ret string return ret } @@ -90,7 +93,7 @@ func (o *RejectOAuth2Request) GetErrorDebug() string { // GetErrorDebugOk returns a tuple with the ErrorDebug field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *RejectOAuth2Request) GetErrorDebugOk() (*string, bool) { - if o == nil || o.ErrorDebug == nil { + if o == nil || IsNil(o.ErrorDebug) { return nil, false } return o.ErrorDebug, true @@ -98,7 +101,7 @@ func (o *RejectOAuth2Request) GetErrorDebugOk() (*string, bool) { // HasErrorDebug returns a boolean if a field has been set. func (o *RejectOAuth2Request) HasErrorDebug() bool { - if o != nil && o.ErrorDebug != nil { + if o != nil && !IsNil(o.ErrorDebug) { return true } @@ -112,7 +115,7 @@ func (o *RejectOAuth2Request) SetErrorDebug(v string) { // GetErrorDescription returns the ErrorDescription field value if set, zero value otherwise. func (o *RejectOAuth2Request) GetErrorDescription() string { - if o == nil || o.ErrorDescription == nil { + if o == nil || IsNil(o.ErrorDescription) { var ret string return ret } @@ -122,7 +125,7 @@ func (o *RejectOAuth2Request) GetErrorDescription() string { // GetErrorDescriptionOk returns a tuple with the ErrorDescription field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *RejectOAuth2Request) GetErrorDescriptionOk() (*string, bool) { - if o == nil || o.ErrorDescription == nil { + if o == nil || IsNil(o.ErrorDescription) { return nil, false } return o.ErrorDescription, true @@ -130,7 +133,7 @@ func (o *RejectOAuth2Request) GetErrorDescriptionOk() (*string, bool) { // HasErrorDescription returns a boolean if a field has been set. func (o *RejectOAuth2Request) HasErrorDescription() bool { - if o != nil && o.ErrorDescription != nil { + if o != nil && !IsNil(o.ErrorDescription) { return true } @@ -144,7 +147,7 @@ func (o *RejectOAuth2Request) SetErrorDescription(v string) { // GetErrorHint returns the ErrorHint field value if set, zero value otherwise. func (o *RejectOAuth2Request) GetErrorHint() string { - if o == nil || o.ErrorHint == nil { + if o == nil || IsNil(o.ErrorHint) { var ret string return ret } @@ -154,7 +157,7 @@ func (o *RejectOAuth2Request) GetErrorHint() string { // GetErrorHintOk returns a tuple with the ErrorHint field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *RejectOAuth2Request) GetErrorHintOk() (*string, bool) { - if o == nil || o.ErrorHint == nil { + if o == nil || IsNil(o.ErrorHint) { return nil, false } return o.ErrorHint, true @@ -162,7 +165,7 @@ func (o *RejectOAuth2Request) GetErrorHintOk() (*string, bool) { // HasErrorHint returns a boolean if a field has been set. func (o *RejectOAuth2Request) HasErrorHint() bool { - if o != nil && o.ErrorHint != nil { + if o != nil && !IsNil(o.ErrorHint) { return true } @@ -176,7 +179,7 @@ func (o *RejectOAuth2Request) SetErrorHint(v string) { // GetStatusCode returns the StatusCode field value if set, zero value otherwise. func (o *RejectOAuth2Request) GetStatusCode() int64 { - if o == nil || o.StatusCode == nil { + if o == nil || IsNil(o.StatusCode) { var ret int64 return ret } @@ -186,7 +189,7 @@ func (o *RejectOAuth2Request) GetStatusCode() int64 { // GetStatusCodeOk returns a tuple with the StatusCode field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *RejectOAuth2Request) GetStatusCodeOk() (*int64, bool) { - if o == nil || o.StatusCode == nil { + if o == nil || IsNil(o.StatusCode) { return nil, false } return o.StatusCode, true @@ -194,7 +197,7 @@ func (o *RejectOAuth2Request) GetStatusCodeOk() (*int64, bool) { // HasStatusCode returns a boolean if a field has been set. func (o *RejectOAuth2Request) HasStatusCode() bool { - if o != nil && o.StatusCode != nil { + if o != nil && !IsNil(o.StatusCode) { return true } @@ -207,23 +210,31 @@ func (o *RejectOAuth2Request) SetStatusCode(v int64) { } func (o RejectOAuth2Request) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o RejectOAuth2Request) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Error != nil { + if !IsNil(o.Error) { toSerialize["error"] = o.Error } - if o.ErrorDebug != nil { + if !IsNil(o.ErrorDebug) { toSerialize["error_debug"] = o.ErrorDebug } - if o.ErrorDescription != nil { + if !IsNil(o.ErrorDescription) { toSerialize["error_description"] = o.ErrorDescription } - if o.ErrorHint != nil { + if !IsNil(o.ErrorHint) { toSerialize["error_hint"] = o.ErrorHint } - if o.StatusCode != nil { + if !IsNil(o.StatusCode) { toSerialize["status_code"] = o.StatusCode } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableRejectOAuth2Request struct { diff --git a/internal/httpclient/model_rfc6749_error_json.go b/internal/httpclient/model_rfc6749_error_json.go new file mode 100644 index 00000000000..d33a2b91e08 --- /dev/null +++ b/internal/httpclient/model_rfc6749_error_json.go @@ -0,0 +1,269 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the RFC6749ErrorJson type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &RFC6749ErrorJson{} + +// RFC6749ErrorJson struct for RFC6749ErrorJson +type RFC6749ErrorJson struct { + Error *string `json:"error,omitempty"` + ErrorDebug *string `json:"error_debug,omitempty"` + ErrorDescription *string `json:"error_description,omitempty"` + ErrorHint *string `json:"error_hint,omitempty"` + StatusCode *int64 `json:"status_code,omitempty"` +} + +// NewRFC6749ErrorJson instantiates a new RFC6749ErrorJson object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewRFC6749ErrorJson() *RFC6749ErrorJson { + this := RFC6749ErrorJson{} + return &this +} + +// NewRFC6749ErrorJsonWithDefaults instantiates a new RFC6749ErrorJson object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewRFC6749ErrorJsonWithDefaults() *RFC6749ErrorJson { + this := RFC6749ErrorJson{} + return &this +} + +// GetError returns the Error field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetError() string { + if o == nil || IsNil(o.Error) { + var ret string + return ret + } + return *o.Error +} + +// GetErrorOk returns a tuple with the Error field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetErrorOk() (*string, bool) { + if o == nil || IsNil(o.Error) { + return nil, false + } + return o.Error, true +} + +// HasError returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasError() bool { + if o != nil && !IsNil(o.Error) { + return true + } + + return false +} + +// SetError gets a reference to the given string and assigns it to the Error field. +func (o *RFC6749ErrorJson) SetError(v string) { + o.Error = &v +} + +// GetErrorDebug returns the ErrorDebug field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetErrorDebug() string { + if o == nil || IsNil(o.ErrorDebug) { + var ret string + return ret + } + return *o.ErrorDebug +} + +// GetErrorDebugOk returns a tuple with the ErrorDebug field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetErrorDebugOk() (*string, bool) { + if o == nil || IsNil(o.ErrorDebug) { + return nil, false + } + return o.ErrorDebug, true +} + +// HasErrorDebug returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasErrorDebug() bool { + if o != nil && !IsNil(o.ErrorDebug) { + return true + } + + return false +} + +// SetErrorDebug gets a reference to the given string and assigns it to the ErrorDebug field. +func (o *RFC6749ErrorJson) SetErrorDebug(v string) { + o.ErrorDebug = &v +} + +// GetErrorDescription returns the ErrorDescription field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetErrorDescription() string { + if o == nil || IsNil(o.ErrorDescription) { + var ret string + return ret + } + return *o.ErrorDescription +} + +// GetErrorDescriptionOk returns a tuple with the ErrorDescription field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetErrorDescriptionOk() (*string, bool) { + if o == nil || IsNil(o.ErrorDescription) { + return nil, false + } + return o.ErrorDescription, true +} + +// HasErrorDescription returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasErrorDescription() bool { + if o != nil && !IsNil(o.ErrorDescription) { + return true + } + + return false +} + +// SetErrorDescription gets a reference to the given string and assigns it to the ErrorDescription field. +func (o *RFC6749ErrorJson) SetErrorDescription(v string) { + o.ErrorDescription = &v +} + +// GetErrorHint returns the ErrorHint field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetErrorHint() string { + if o == nil || IsNil(o.ErrorHint) { + var ret string + return ret + } + return *o.ErrorHint +} + +// GetErrorHintOk returns a tuple with the ErrorHint field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetErrorHintOk() (*string, bool) { + if o == nil || IsNil(o.ErrorHint) { + return nil, false + } + return o.ErrorHint, true +} + +// HasErrorHint returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasErrorHint() bool { + if o != nil && !IsNil(o.ErrorHint) { + return true + } + + return false +} + +// SetErrorHint gets a reference to the given string and assigns it to the ErrorHint field. +func (o *RFC6749ErrorJson) SetErrorHint(v string) { + o.ErrorHint = &v +} + +// GetStatusCode returns the StatusCode field value if set, zero value otherwise. +func (o *RFC6749ErrorJson) GetStatusCode() int64 { + if o == nil || IsNil(o.StatusCode) { + var ret int64 + return ret + } + return *o.StatusCode +} + +// GetStatusCodeOk returns a tuple with the StatusCode field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *RFC6749ErrorJson) GetStatusCodeOk() (*int64, bool) { + if o == nil || IsNil(o.StatusCode) { + return nil, false + } + return o.StatusCode, true +} + +// HasStatusCode returns a boolean if a field has been set. +func (o *RFC6749ErrorJson) HasStatusCode() bool { + if o != nil && !IsNil(o.StatusCode) { + return true + } + + return false +} + +// SetStatusCode gets a reference to the given int64 and assigns it to the StatusCode field. +func (o *RFC6749ErrorJson) SetStatusCode(v int64) { + o.StatusCode = &v +} + +func (o RFC6749ErrorJson) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o RFC6749ErrorJson) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Error) { + toSerialize["error"] = o.Error + } + if !IsNil(o.ErrorDebug) { + toSerialize["error_debug"] = o.ErrorDebug + } + if !IsNil(o.ErrorDescription) { + toSerialize["error_description"] = o.ErrorDescription + } + if !IsNil(o.ErrorHint) { + toSerialize["error_hint"] = o.ErrorHint + } + if !IsNil(o.StatusCode) { + toSerialize["status_code"] = o.StatusCode + } + return toSerialize, nil +} + +type NullableRFC6749ErrorJson struct { + value *RFC6749ErrorJson + isSet bool +} + +func (v NullableRFC6749ErrorJson) Get() *RFC6749ErrorJson { + return v.value +} + +func (v *NullableRFC6749ErrorJson) Set(val *RFC6749ErrorJson) { + v.value = val + v.isSet = true +} + +func (v NullableRFC6749ErrorJson) IsSet() bool { + return v.isSet +} + +func (v *NullableRFC6749ErrorJson) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableRFC6749ErrorJson(val *RFC6749ErrorJson) *NullableRFC6749ErrorJson { + return &NullableRFC6749ErrorJson{value: val, isSet: true} +} + +func (v NullableRFC6749ErrorJson) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableRFC6749ErrorJson) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_token_pagination.go b/internal/httpclient/model_token_pagination.go index 7d96f47f2be..d9457ccd9e8 100644 --- a/internal/httpclient/model_token_pagination.go +++ b/internal/httpclient/model_token_pagination.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the TokenPagination type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TokenPagination{} + // TokenPagination struct for TokenPagination type TokenPagination struct { // Items per page This is the number of items per page to return. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). @@ -50,7 +53,7 @@ func NewTokenPaginationWithDefaults() *TokenPagination { // GetPageSize returns the PageSize field value if set, zero value otherwise. func (o *TokenPagination) GetPageSize() int64 { - if o == nil || o.PageSize == nil { + if o == nil || IsNil(o.PageSize) { var ret int64 return ret } @@ -60,7 +63,7 @@ func (o *TokenPagination) GetPageSize() int64 { // GetPageSizeOk returns a tuple with the PageSize field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TokenPagination) GetPageSizeOk() (*int64, bool) { - if o == nil || o.PageSize == nil { + if o == nil || IsNil(o.PageSize) { return nil, false } return o.PageSize, true @@ -68,7 +71,7 @@ func (o *TokenPagination) GetPageSizeOk() (*int64, bool) { // HasPageSize returns a boolean if a field has been set. func (o *TokenPagination) HasPageSize() bool { - if o != nil && o.PageSize != nil { + if o != nil && !IsNil(o.PageSize) { return true } @@ -82,7 +85,7 @@ func (o *TokenPagination) SetPageSize(v int64) { // GetPageToken returns the PageToken field value if set, zero value otherwise. func (o *TokenPagination) GetPageToken() string { - if o == nil || o.PageToken == nil { + if o == nil || IsNil(o.PageToken) { var ret string return ret } @@ -92,7 +95,7 @@ func (o *TokenPagination) GetPageToken() string { // GetPageTokenOk returns a tuple with the PageToken field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TokenPagination) GetPageTokenOk() (*string, bool) { - if o == nil || o.PageToken == nil { + if o == nil || IsNil(o.PageToken) { return nil, false } return o.PageToken, true @@ -100,7 +103,7 @@ func (o *TokenPagination) GetPageTokenOk() (*string, bool) { // HasPageToken returns a boolean if a field has been set. func (o *TokenPagination) HasPageToken() bool { - if o != nil && o.PageToken != nil { + if o != nil && !IsNil(o.PageToken) { return true } @@ -113,14 +116,22 @@ func (o *TokenPagination) SetPageToken(v string) { } func (o TokenPagination) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TokenPagination) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.PageSize != nil { + if !IsNil(o.PageSize) { toSerialize["page_size"] = o.PageSize } - if o.PageToken != nil { + if !IsNil(o.PageToken) { toSerialize["page_token"] = o.PageToken } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableTokenPagination struct { diff --git a/internal/httpclient/model_token_pagination_headers.go b/internal/httpclient/model_token_pagination_headers.go index 7c4c657c968..537d5e59bdd 100644 --- a/internal/httpclient/model_token_pagination_headers.go +++ b/internal/httpclient/model_token_pagination_headers.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the TokenPaginationHeaders type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TokenPaginationHeaders{} + // TokenPaginationHeaders struct for TokenPaginationHeaders type TokenPaginationHeaders struct { // The link header contains pagination links. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). in: header @@ -42,7 +45,7 @@ func NewTokenPaginationHeadersWithDefaults() *TokenPaginationHeaders { // GetLink returns the Link field value if set, zero value otherwise. func (o *TokenPaginationHeaders) GetLink() string { - if o == nil || o.Link == nil { + if o == nil || IsNil(o.Link) { var ret string return ret } @@ -52,7 +55,7 @@ func (o *TokenPaginationHeaders) GetLink() string { // GetLinkOk returns a tuple with the Link field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TokenPaginationHeaders) GetLinkOk() (*string, bool) { - if o == nil || o.Link == nil { + if o == nil || IsNil(o.Link) { return nil, false } return o.Link, true @@ -60,7 +63,7 @@ func (o *TokenPaginationHeaders) GetLinkOk() (*string, bool) { // HasLink returns a boolean if a field has been set. func (o *TokenPaginationHeaders) HasLink() bool { - if o != nil && o.Link != nil { + if o != nil && !IsNil(o.Link) { return true } @@ -74,7 +77,7 @@ func (o *TokenPaginationHeaders) SetLink(v string) { // GetXTotalCount returns the XTotalCount field value if set, zero value otherwise. func (o *TokenPaginationHeaders) GetXTotalCount() string { - if o == nil || o.XTotalCount == nil { + if o == nil || IsNil(o.XTotalCount) { var ret string return ret } @@ -84,7 +87,7 @@ func (o *TokenPaginationHeaders) GetXTotalCount() string { // GetXTotalCountOk returns a tuple with the XTotalCount field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TokenPaginationHeaders) GetXTotalCountOk() (*string, bool) { - if o == nil || o.XTotalCount == nil { + if o == nil || IsNil(o.XTotalCount) { return nil, false } return o.XTotalCount, true @@ -92,7 +95,7 @@ func (o *TokenPaginationHeaders) GetXTotalCountOk() (*string, bool) { // HasXTotalCount returns a boolean if a field has been set. func (o *TokenPaginationHeaders) HasXTotalCount() bool { - if o != nil && o.XTotalCount != nil { + if o != nil && !IsNil(o.XTotalCount) { return true } @@ -105,14 +108,22 @@ func (o *TokenPaginationHeaders) SetXTotalCount(v string) { } func (o TokenPaginationHeaders) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TokenPaginationHeaders) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Link != nil { + if !IsNil(o.Link) { toSerialize["link"] = o.Link } - if o.XTotalCount != nil { + if !IsNil(o.XTotalCount) { toSerialize["x-total-count"] = o.XTotalCount } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableTokenPaginationHeaders struct { diff --git a/internal/httpclient/model_token_pagination_request_parameters.go b/internal/httpclient/model_token_pagination_request_parameters.go index 40ef780d684..e18c491d8fe 100644 --- a/internal/httpclient/model_token_pagination_request_parameters.go +++ b/internal/httpclient/model_token_pagination_request_parameters.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the TokenPaginationRequestParameters type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TokenPaginationRequestParameters{} + // TokenPaginationRequestParameters The `Link` HTTP header contains multiple links (`first`, `next`, `last`, `previous`) formatted as: `; rel=\"{page}\"` For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). type TokenPaginationRequestParameters struct { // Items per Page This is the number of items per page to return. For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). @@ -50,7 +53,7 @@ func NewTokenPaginationRequestParametersWithDefaults() *TokenPaginationRequestPa // GetPageSize returns the PageSize field value if set, zero value otherwise. func (o *TokenPaginationRequestParameters) GetPageSize() int64 { - if o == nil || o.PageSize == nil { + if o == nil || IsNil(o.PageSize) { var ret int64 return ret } @@ -60,7 +63,7 @@ func (o *TokenPaginationRequestParameters) GetPageSize() int64 { // GetPageSizeOk returns a tuple with the PageSize field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TokenPaginationRequestParameters) GetPageSizeOk() (*int64, bool) { - if o == nil || o.PageSize == nil { + if o == nil || IsNil(o.PageSize) { return nil, false } return o.PageSize, true @@ -68,7 +71,7 @@ func (o *TokenPaginationRequestParameters) GetPageSizeOk() (*int64, bool) { // HasPageSize returns a boolean if a field has been set. func (o *TokenPaginationRequestParameters) HasPageSize() bool { - if o != nil && o.PageSize != nil { + if o != nil && !IsNil(o.PageSize) { return true } @@ -82,7 +85,7 @@ func (o *TokenPaginationRequestParameters) SetPageSize(v int64) { // GetPageToken returns the PageToken field value if set, zero value otherwise. func (o *TokenPaginationRequestParameters) GetPageToken() string { - if o == nil || o.PageToken == nil { + if o == nil || IsNil(o.PageToken) { var ret string return ret } @@ -92,7 +95,7 @@ func (o *TokenPaginationRequestParameters) GetPageToken() string { // GetPageTokenOk returns a tuple with the PageToken field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TokenPaginationRequestParameters) GetPageTokenOk() (*string, bool) { - if o == nil || o.PageToken == nil { + if o == nil || IsNil(o.PageToken) { return nil, false } return o.PageToken, true @@ -100,7 +103,7 @@ func (o *TokenPaginationRequestParameters) GetPageTokenOk() (*string, bool) { // HasPageToken returns a boolean if a field has been set. func (o *TokenPaginationRequestParameters) HasPageToken() bool { - if o != nil && o.PageToken != nil { + if o != nil && !IsNil(o.PageToken) { return true } @@ -113,14 +116,22 @@ func (o *TokenPaginationRequestParameters) SetPageToken(v string) { } func (o TokenPaginationRequestParameters) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TokenPaginationRequestParameters) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.PageSize != nil { + if !IsNil(o.PageSize) { toSerialize["page_size"] = o.PageSize } - if o.PageToken != nil { + if !IsNil(o.PageToken) { toSerialize["page_token"] = o.PageToken } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableTokenPaginationRequestParameters struct { diff --git a/internal/httpclient/model_token_pagination_response_headers.go b/internal/httpclient/model_token_pagination_response_headers.go index 26722925de6..bddbcd203ea 100644 --- a/internal/httpclient/model_token_pagination_response_headers.go +++ b/internal/httpclient/model_token_pagination_response_headers.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the TokenPaginationResponseHeaders type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TokenPaginationResponseHeaders{} + // TokenPaginationResponseHeaders The `Link` HTTP header contains multiple links (`first`, `next`, `last`, `previous`) formatted as: `; rel=\"{page}\"` For details on pagination please head over to the [pagination documentation](https://www.ory.sh/docs/ecosystem/api-design#pagination). type TokenPaginationResponseHeaders struct { // The Link HTTP Header The `Link` header contains a comma-delimited list of links to the following pages: first: The first page of results. next: The next page of results. prev: The previous page of results. last: The last page of results. Pages are omitted if they do not exist. For example, if there is no next page, the `next` link is omitted. Examples: ; rel=\"first\",; rel=\"next\",; rel=\"prev\",; rel=\"last\" @@ -42,7 +45,7 @@ func NewTokenPaginationResponseHeadersWithDefaults() *TokenPaginationResponseHea // GetLink returns the Link field value if set, zero value otherwise. func (o *TokenPaginationResponseHeaders) GetLink() string { - if o == nil || o.Link == nil { + if o == nil || IsNil(o.Link) { var ret string return ret } @@ -52,7 +55,7 @@ func (o *TokenPaginationResponseHeaders) GetLink() string { // GetLinkOk returns a tuple with the Link field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TokenPaginationResponseHeaders) GetLinkOk() (*string, bool) { - if o == nil || o.Link == nil { + if o == nil || IsNil(o.Link) { return nil, false } return o.Link, true @@ -60,7 +63,7 @@ func (o *TokenPaginationResponseHeaders) GetLinkOk() (*string, bool) { // HasLink returns a boolean if a field has been set. func (o *TokenPaginationResponseHeaders) HasLink() bool { - if o != nil && o.Link != nil { + if o != nil && !IsNil(o.Link) { return true } @@ -74,7 +77,7 @@ func (o *TokenPaginationResponseHeaders) SetLink(v string) { // GetXTotalCount returns the XTotalCount field value if set, zero value otherwise. func (o *TokenPaginationResponseHeaders) GetXTotalCount() int64 { - if o == nil || o.XTotalCount == nil { + if o == nil || IsNil(o.XTotalCount) { var ret int64 return ret } @@ -84,7 +87,7 @@ func (o *TokenPaginationResponseHeaders) GetXTotalCount() int64 { // GetXTotalCountOk returns a tuple with the XTotalCount field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TokenPaginationResponseHeaders) GetXTotalCountOk() (*int64, bool) { - if o == nil || o.XTotalCount == nil { + if o == nil || IsNil(o.XTotalCount) { return nil, false } return o.XTotalCount, true @@ -92,7 +95,7 @@ func (o *TokenPaginationResponseHeaders) GetXTotalCountOk() (*int64, bool) { // HasXTotalCount returns a boolean if a field has been set. func (o *TokenPaginationResponseHeaders) HasXTotalCount() bool { - if o != nil && o.XTotalCount != nil { + if o != nil && !IsNil(o.XTotalCount) { return true } @@ -105,14 +108,22 @@ func (o *TokenPaginationResponseHeaders) SetXTotalCount(v int64) { } func (o TokenPaginationResponseHeaders) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TokenPaginationResponseHeaders) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Link != nil { + if !IsNil(o.Link) { toSerialize["link"] = o.Link } - if o.XTotalCount != nil { + if !IsNil(o.XTotalCount) { toSerialize["x-total-count"] = o.XTotalCount } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableTokenPaginationResponseHeaders struct { diff --git a/internal/httpclient/model_trust_o_auth2_jwt_grant_issuer.go b/internal/httpclient/model_trust_o_auth2_jwt_grant_issuer.go index 15f8d9575f4..5803dcffbfb 100644 --- a/internal/httpclient/model_trust_o_auth2_jwt_grant_issuer.go +++ b/internal/httpclient/model_trust_o_auth2_jwt_grant_issuer.go @@ -12,10 +12,15 @@ Contact: hi@ory.sh package openapi import ( + "bytes" "encoding/json" + "fmt" "time" ) +// checks if the TrustOAuth2JwtGrantIssuer type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TrustOAuth2JwtGrantIssuer{} + // TrustOAuth2JwtGrantIssuer Trust OAuth2 JWT Bearer Grant Type Issuer Request Body type TrustOAuth2JwtGrantIssuer struct { // The \"allow_any_subject\" indicates that the issuer is allowed to have any principal as the subject of the JWT. @@ -31,6 +36,8 @@ type TrustOAuth2JwtGrantIssuer struct { Subject *string `json:"subject,omitempty"` } +type _TrustOAuth2JwtGrantIssuer TrustOAuth2JwtGrantIssuer + // NewTrustOAuth2JwtGrantIssuer instantiates a new TrustOAuth2JwtGrantIssuer object // This constructor will assign default values to properties that have it defined, // and makes sure properties required by API are set, but the set of arguments @@ -54,7 +61,7 @@ func NewTrustOAuth2JwtGrantIssuerWithDefaults() *TrustOAuth2JwtGrantIssuer { // GetAllowAnySubject returns the AllowAnySubject field value if set, zero value otherwise. func (o *TrustOAuth2JwtGrantIssuer) GetAllowAnySubject() bool { - if o == nil || o.AllowAnySubject == nil { + if o == nil || IsNil(o.AllowAnySubject) { var ret bool return ret } @@ -64,7 +71,7 @@ func (o *TrustOAuth2JwtGrantIssuer) GetAllowAnySubject() bool { // GetAllowAnySubjectOk returns a tuple with the AllowAnySubject field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustOAuth2JwtGrantIssuer) GetAllowAnySubjectOk() (*bool, bool) { - if o == nil || o.AllowAnySubject == nil { + if o == nil || IsNil(o.AllowAnySubject) { return nil, false } return o.AllowAnySubject, true @@ -72,7 +79,7 @@ func (o *TrustOAuth2JwtGrantIssuer) GetAllowAnySubjectOk() (*bool, bool) { // HasAllowAnySubject returns a boolean if a field has been set. func (o *TrustOAuth2JwtGrantIssuer) HasAllowAnySubject() bool { - if o != nil && o.AllowAnySubject != nil { + if o != nil && !IsNil(o.AllowAnySubject) { return true } @@ -182,7 +189,7 @@ func (o *TrustOAuth2JwtGrantIssuer) SetScope(v []string) { // GetSubject returns the Subject field value if set, zero value otherwise. func (o *TrustOAuth2JwtGrantIssuer) GetSubject() string { - if o == nil || o.Subject == nil { + if o == nil || IsNil(o.Subject) { var ret string return ret } @@ -192,7 +199,7 @@ func (o *TrustOAuth2JwtGrantIssuer) GetSubject() string { // GetSubjectOk returns a tuple with the Subject field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustOAuth2JwtGrantIssuer) GetSubjectOk() (*string, bool) { - if o == nil || o.Subject == nil { + if o == nil || IsNil(o.Subject) { return nil, false } return o.Subject, true @@ -200,7 +207,7 @@ func (o *TrustOAuth2JwtGrantIssuer) GetSubjectOk() (*string, bool) { // HasSubject returns a boolean if a field has been set. func (o *TrustOAuth2JwtGrantIssuer) HasSubject() bool { - if o != nil && o.Subject != nil { + if o != nil && !IsNil(o.Subject) { return true } @@ -213,26 +220,66 @@ func (o *TrustOAuth2JwtGrantIssuer) SetSubject(v string) { } func (o TrustOAuth2JwtGrantIssuer) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TrustOAuth2JwtGrantIssuer) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.AllowAnySubject != nil { + if !IsNil(o.AllowAnySubject) { toSerialize["allow_any_subject"] = o.AllowAnySubject } - if true { - toSerialize["expires_at"] = o.ExpiresAt + toSerialize["expires_at"] = o.ExpiresAt + toSerialize["issuer"] = o.Issuer + toSerialize["jwk"] = o.Jwk + toSerialize["scope"] = o.Scope + if !IsNil(o.Subject) { + toSerialize["subject"] = o.Subject } - if true { - toSerialize["issuer"] = o.Issuer + return toSerialize, nil +} + +func (o *TrustOAuth2JwtGrantIssuer) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "expires_at", + "issuer", + "jwk", + "scope", } - if true { - toSerialize["jwk"] = o.Jwk + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err } - if true { - toSerialize["scope"] = o.Scope + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } } - if o.Subject != nil { - toSerialize["subject"] = o.Subject + + varTrustOAuth2JwtGrantIssuer := _TrustOAuth2JwtGrantIssuer{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varTrustOAuth2JwtGrantIssuer) + + if err != nil { + return err } - return json.Marshal(toSerialize) + + *o = TrustOAuth2JwtGrantIssuer(varTrustOAuth2JwtGrantIssuer) + + return err } type NullableTrustOAuth2JwtGrantIssuer struct { diff --git a/internal/httpclient/model_trusted_o_auth2_jwt_grant_issuer.go b/internal/httpclient/model_trusted_o_auth2_jwt_grant_issuer.go index 80fba647b44..7b0c1fcbca9 100644 --- a/internal/httpclient/model_trusted_o_auth2_jwt_grant_issuer.go +++ b/internal/httpclient/model_trusted_o_auth2_jwt_grant_issuer.go @@ -16,6 +16,9 @@ import ( "time" ) +// checks if the TrustedOAuth2JwtGrantIssuer type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TrustedOAuth2JwtGrantIssuer{} + // TrustedOAuth2JwtGrantIssuer OAuth2 JWT Bearer Grant Type Issuer Trust Relationship type TrustedOAuth2JwtGrantIssuer struct { // The \"allow_any_subject\" indicates that the issuer is allowed to have any principal as the subject of the JWT. @@ -53,7 +56,7 @@ func NewTrustedOAuth2JwtGrantIssuerWithDefaults() *TrustedOAuth2JwtGrantIssuer { // GetAllowAnySubject returns the AllowAnySubject field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantIssuer) GetAllowAnySubject() bool { - if o == nil || o.AllowAnySubject == nil { + if o == nil || IsNil(o.AllowAnySubject) { var ret bool return ret } @@ -63,7 +66,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetAllowAnySubject() bool { // GetAllowAnySubjectOk returns a tuple with the AllowAnySubject field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantIssuer) GetAllowAnySubjectOk() (*bool, bool) { - if o == nil || o.AllowAnySubject == nil { + if o == nil || IsNil(o.AllowAnySubject) { return nil, false } return o.AllowAnySubject, true @@ -71,7 +74,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetAllowAnySubjectOk() (*bool, bool) { // HasAllowAnySubject returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantIssuer) HasAllowAnySubject() bool { - if o != nil && o.AllowAnySubject != nil { + if o != nil && !IsNil(o.AllowAnySubject) { return true } @@ -85,7 +88,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) SetAllowAnySubject(v bool) { // GetCreatedAt returns the CreatedAt field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantIssuer) GetCreatedAt() time.Time { - if o == nil || o.CreatedAt == nil { + if o == nil || IsNil(o.CreatedAt) { var ret time.Time return ret } @@ -95,7 +98,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetCreatedAt() time.Time { // GetCreatedAtOk returns a tuple with the CreatedAt field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantIssuer) GetCreatedAtOk() (*time.Time, bool) { - if o == nil || o.CreatedAt == nil { + if o == nil || IsNil(o.CreatedAt) { return nil, false } return o.CreatedAt, true @@ -103,7 +106,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetCreatedAtOk() (*time.Time, bool) { // HasCreatedAt returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantIssuer) HasCreatedAt() bool { - if o != nil && o.CreatedAt != nil { + if o != nil && !IsNil(o.CreatedAt) { return true } @@ -117,7 +120,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) SetCreatedAt(v time.Time) { // GetExpiresAt returns the ExpiresAt field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantIssuer) GetExpiresAt() time.Time { - if o == nil || o.ExpiresAt == nil { + if o == nil || IsNil(o.ExpiresAt) { var ret time.Time return ret } @@ -127,7 +130,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetExpiresAt() time.Time { // GetExpiresAtOk returns a tuple with the ExpiresAt field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantIssuer) GetExpiresAtOk() (*time.Time, bool) { - if o == nil || o.ExpiresAt == nil { + if o == nil || IsNil(o.ExpiresAt) { return nil, false } return o.ExpiresAt, true @@ -135,7 +138,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetExpiresAtOk() (*time.Time, bool) { // HasExpiresAt returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantIssuer) HasExpiresAt() bool { - if o != nil && o.ExpiresAt != nil { + if o != nil && !IsNil(o.ExpiresAt) { return true } @@ -149,7 +152,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) SetExpiresAt(v time.Time) { // GetId returns the Id field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantIssuer) GetId() string { - if o == nil || o.Id == nil { + if o == nil || IsNil(o.Id) { var ret string return ret } @@ -159,7 +162,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetId() string { // GetIdOk returns a tuple with the Id field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantIssuer) GetIdOk() (*string, bool) { - if o == nil || o.Id == nil { + if o == nil || IsNil(o.Id) { return nil, false } return o.Id, true @@ -167,7 +170,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetIdOk() (*string, bool) { // HasId returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantIssuer) HasId() bool { - if o != nil && o.Id != nil { + if o != nil && !IsNil(o.Id) { return true } @@ -181,7 +184,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) SetId(v string) { // GetIssuer returns the Issuer field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantIssuer) GetIssuer() string { - if o == nil || o.Issuer == nil { + if o == nil || IsNil(o.Issuer) { var ret string return ret } @@ -191,7 +194,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetIssuer() string { // GetIssuerOk returns a tuple with the Issuer field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantIssuer) GetIssuerOk() (*string, bool) { - if o == nil || o.Issuer == nil { + if o == nil || IsNil(o.Issuer) { return nil, false } return o.Issuer, true @@ -199,7 +202,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetIssuerOk() (*string, bool) { // HasIssuer returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantIssuer) HasIssuer() bool { - if o != nil && o.Issuer != nil { + if o != nil && !IsNil(o.Issuer) { return true } @@ -213,7 +216,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) SetIssuer(v string) { // GetPublicKey returns the PublicKey field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantIssuer) GetPublicKey() TrustedOAuth2JwtGrantJsonWebKey { - if o == nil || o.PublicKey == nil { + if o == nil || IsNil(o.PublicKey) { var ret TrustedOAuth2JwtGrantJsonWebKey return ret } @@ -223,7 +226,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetPublicKey() TrustedOAuth2JwtGrantJsonWe // GetPublicKeyOk returns a tuple with the PublicKey field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantIssuer) GetPublicKeyOk() (*TrustedOAuth2JwtGrantJsonWebKey, bool) { - if o == nil || o.PublicKey == nil { + if o == nil || IsNil(o.PublicKey) { return nil, false } return o.PublicKey, true @@ -231,7 +234,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetPublicKeyOk() (*TrustedOAuth2JwtGrantJs // HasPublicKey returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantIssuer) HasPublicKey() bool { - if o != nil && o.PublicKey != nil { + if o != nil && !IsNil(o.PublicKey) { return true } @@ -245,7 +248,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) SetPublicKey(v TrustedOAuth2JwtGrantJsonWe // GetScope returns the Scope field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantIssuer) GetScope() []string { - if o == nil || o.Scope == nil { + if o == nil || IsNil(o.Scope) { var ret []string return ret } @@ -255,7 +258,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetScope() []string { // GetScopeOk returns a tuple with the Scope field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantIssuer) GetScopeOk() ([]string, bool) { - if o == nil || o.Scope == nil { + if o == nil || IsNil(o.Scope) { return nil, false } return o.Scope, true @@ -263,7 +266,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetScopeOk() ([]string, bool) { // HasScope returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantIssuer) HasScope() bool { - if o != nil && o.Scope != nil { + if o != nil && !IsNil(o.Scope) { return true } @@ -277,7 +280,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) SetScope(v []string) { // GetSubject returns the Subject field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantIssuer) GetSubject() string { - if o == nil || o.Subject == nil { + if o == nil || IsNil(o.Subject) { var ret string return ret } @@ -287,7 +290,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetSubject() string { // GetSubjectOk returns a tuple with the Subject field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantIssuer) GetSubjectOk() (*string, bool) { - if o == nil || o.Subject == nil { + if o == nil || IsNil(o.Subject) { return nil, false } return o.Subject, true @@ -295,7 +298,7 @@ func (o *TrustedOAuth2JwtGrantIssuer) GetSubjectOk() (*string, bool) { // HasSubject returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantIssuer) HasSubject() bool { - if o != nil && o.Subject != nil { + if o != nil && !IsNil(o.Subject) { return true } @@ -308,32 +311,40 @@ func (o *TrustedOAuth2JwtGrantIssuer) SetSubject(v string) { } func (o TrustedOAuth2JwtGrantIssuer) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TrustedOAuth2JwtGrantIssuer) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.AllowAnySubject != nil { + if !IsNil(o.AllowAnySubject) { toSerialize["allow_any_subject"] = o.AllowAnySubject } - if o.CreatedAt != nil { + if !IsNil(o.CreatedAt) { toSerialize["created_at"] = o.CreatedAt } - if o.ExpiresAt != nil { + if !IsNil(o.ExpiresAt) { toSerialize["expires_at"] = o.ExpiresAt } - if o.Id != nil { + if !IsNil(o.Id) { toSerialize["id"] = o.Id } - if o.Issuer != nil { + if !IsNil(o.Issuer) { toSerialize["issuer"] = o.Issuer } - if o.PublicKey != nil { + if !IsNil(o.PublicKey) { toSerialize["public_key"] = o.PublicKey } - if o.Scope != nil { + if !IsNil(o.Scope) { toSerialize["scope"] = o.Scope } - if o.Subject != nil { + if !IsNil(o.Subject) { toSerialize["subject"] = o.Subject } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableTrustedOAuth2JwtGrantIssuer struct { diff --git a/internal/httpclient/model_trusted_o_auth2_jwt_grant_json_web_key.go b/internal/httpclient/model_trusted_o_auth2_jwt_grant_json_web_key.go index 7b358805c77..2752cb5eeea 100644 --- a/internal/httpclient/model_trusted_o_auth2_jwt_grant_json_web_key.go +++ b/internal/httpclient/model_trusted_o_auth2_jwt_grant_json_web_key.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the TrustedOAuth2JwtGrantJsonWebKey type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &TrustedOAuth2JwtGrantJsonWebKey{} + // TrustedOAuth2JwtGrantJsonWebKey OAuth2 JWT Bearer Grant Type Issuer Trusted JSON Web Key type TrustedOAuth2JwtGrantJsonWebKey struct { // The \"key_id\" is key unique identifier (same as kid header in jws/jwt). @@ -42,7 +45,7 @@ func NewTrustedOAuth2JwtGrantJsonWebKeyWithDefaults() *TrustedOAuth2JwtGrantJson // GetKid returns the Kid field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantJsonWebKey) GetKid() string { - if o == nil || o.Kid == nil { + if o == nil || IsNil(o.Kid) { var ret string return ret } @@ -52,7 +55,7 @@ func (o *TrustedOAuth2JwtGrantJsonWebKey) GetKid() string { // GetKidOk returns a tuple with the Kid field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantJsonWebKey) GetKidOk() (*string, bool) { - if o == nil || o.Kid == nil { + if o == nil || IsNil(o.Kid) { return nil, false } return o.Kid, true @@ -60,7 +63,7 @@ func (o *TrustedOAuth2JwtGrantJsonWebKey) GetKidOk() (*string, bool) { // HasKid returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantJsonWebKey) HasKid() bool { - if o != nil && o.Kid != nil { + if o != nil && !IsNil(o.Kid) { return true } @@ -74,7 +77,7 @@ func (o *TrustedOAuth2JwtGrantJsonWebKey) SetKid(v string) { // GetSet returns the Set field value if set, zero value otherwise. func (o *TrustedOAuth2JwtGrantJsonWebKey) GetSet() string { - if o == nil || o.Set == nil { + if o == nil || IsNil(o.Set) { var ret string return ret } @@ -84,7 +87,7 @@ func (o *TrustedOAuth2JwtGrantJsonWebKey) GetSet() string { // GetSetOk returns a tuple with the Set field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *TrustedOAuth2JwtGrantJsonWebKey) GetSetOk() (*string, bool) { - if o == nil || o.Set == nil { + if o == nil || IsNil(o.Set) { return nil, false } return o.Set, true @@ -92,7 +95,7 @@ func (o *TrustedOAuth2JwtGrantJsonWebKey) GetSetOk() (*string, bool) { // HasSet returns a boolean if a field has been set. func (o *TrustedOAuth2JwtGrantJsonWebKey) HasSet() bool { - if o != nil && o.Set != nil { + if o != nil && !IsNil(o.Set) { return true } @@ -105,14 +108,22 @@ func (o *TrustedOAuth2JwtGrantJsonWebKey) SetSet(v string) { } func (o TrustedOAuth2JwtGrantJsonWebKey) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o TrustedOAuth2JwtGrantJsonWebKey) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Kid != nil { + if !IsNil(o.Kid) { toSerialize["kid"] = o.Kid } - if o.Set != nil { + if !IsNil(o.Set) { toSerialize["set"] = o.Set } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableTrustedOAuth2JwtGrantJsonWebKey struct { diff --git a/internal/httpclient/model_verifiable_credential_priming_response.go b/internal/httpclient/model_verifiable_credential_priming_response.go new file mode 100644 index 00000000000..f0bdf3309b7 --- /dev/null +++ b/internal/httpclient/model_verifiable_credential_priming_response.go @@ -0,0 +1,377 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the VerifiableCredentialPrimingResponse type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &VerifiableCredentialPrimingResponse{} + +// VerifiableCredentialPrimingResponse struct for VerifiableCredentialPrimingResponse +type VerifiableCredentialPrimingResponse struct { + CNonce *string `json:"c_nonce,omitempty"` + CNonceExpiresIn *int64 `json:"c_nonce_expires_in,omitempty"` + Error *string `json:"error,omitempty"` + ErrorDebug *string `json:"error_debug,omitempty"` + ErrorDescription *string `json:"error_description,omitempty"` + ErrorHint *string `json:"error_hint,omitempty"` + Format *string `json:"format,omitempty"` + StatusCode *int64 `json:"status_code,omitempty"` +} + +// NewVerifiableCredentialPrimingResponse instantiates a new VerifiableCredentialPrimingResponse object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewVerifiableCredentialPrimingResponse() *VerifiableCredentialPrimingResponse { + this := VerifiableCredentialPrimingResponse{} + return &this +} + +// NewVerifiableCredentialPrimingResponseWithDefaults instantiates a new VerifiableCredentialPrimingResponse object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewVerifiableCredentialPrimingResponseWithDefaults() *VerifiableCredentialPrimingResponse { + this := VerifiableCredentialPrimingResponse{} + return &this +} + +// GetCNonce returns the CNonce field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetCNonce() string { + if o == nil || IsNil(o.CNonce) { + var ret string + return ret + } + return *o.CNonce +} + +// GetCNonceOk returns a tuple with the CNonce field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetCNonceOk() (*string, bool) { + if o == nil || IsNil(o.CNonce) { + return nil, false + } + return o.CNonce, true +} + +// HasCNonce returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasCNonce() bool { + if o != nil && !IsNil(o.CNonce) { + return true + } + + return false +} + +// SetCNonce gets a reference to the given string and assigns it to the CNonce field. +func (o *VerifiableCredentialPrimingResponse) SetCNonce(v string) { + o.CNonce = &v +} + +// GetCNonceExpiresIn returns the CNonceExpiresIn field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetCNonceExpiresIn() int64 { + if o == nil || IsNil(o.CNonceExpiresIn) { + var ret int64 + return ret + } + return *o.CNonceExpiresIn +} + +// GetCNonceExpiresInOk returns a tuple with the CNonceExpiresIn field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetCNonceExpiresInOk() (*int64, bool) { + if o == nil || IsNil(o.CNonceExpiresIn) { + return nil, false + } + return o.CNonceExpiresIn, true +} + +// HasCNonceExpiresIn returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasCNonceExpiresIn() bool { + if o != nil && !IsNil(o.CNonceExpiresIn) { + return true + } + + return false +} + +// SetCNonceExpiresIn gets a reference to the given int64 and assigns it to the CNonceExpiresIn field. +func (o *VerifiableCredentialPrimingResponse) SetCNonceExpiresIn(v int64) { + o.CNonceExpiresIn = &v +} + +// GetError returns the Error field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetError() string { + if o == nil || IsNil(o.Error) { + var ret string + return ret + } + return *o.Error +} + +// GetErrorOk returns a tuple with the Error field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetErrorOk() (*string, bool) { + if o == nil || IsNil(o.Error) { + return nil, false + } + return o.Error, true +} + +// HasError returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasError() bool { + if o != nil && !IsNil(o.Error) { + return true + } + + return false +} + +// SetError gets a reference to the given string and assigns it to the Error field. +func (o *VerifiableCredentialPrimingResponse) SetError(v string) { + o.Error = &v +} + +// GetErrorDebug returns the ErrorDebug field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetErrorDebug() string { + if o == nil || IsNil(o.ErrorDebug) { + var ret string + return ret + } + return *o.ErrorDebug +} + +// GetErrorDebugOk returns a tuple with the ErrorDebug field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetErrorDebugOk() (*string, bool) { + if o == nil || IsNil(o.ErrorDebug) { + return nil, false + } + return o.ErrorDebug, true +} + +// HasErrorDebug returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasErrorDebug() bool { + if o != nil && !IsNil(o.ErrorDebug) { + return true + } + + return false +} + +// SetErrorDebug gets a reference to the given string and assigns it to the ErrorDebug field. +func (o *VerifiableCredentialPrimingResponse) SetErrorDebug(v string) { + o.ErrorDebug = &v +} + +// GetErrorDescription returns the ErrorDescription field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetErrorDescription() string { + if o == nil || IsNil(o.ErrorDescription) { + var ret string + return ret + } + return *o.ErrorDescription +} + +// GetErrorDescriptionOk returns a tuple with the ErrorDescription field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetErrorDescriptionOk() (*string, bool) { + if o == nil || IsNil(o.ErrorDescription) { + return nil, false + } + return o.ErrorDescription, true +} + +// HasErrorDescription returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasErrorDescription() bool { + if o != nil && !IsNil(o.ErrorDescription) { + return true + } + + return false +} + +// SetErrorDescription gets a reference to the given string and assigns it to the ErrorDescription field. +func (o *VerifiableCredentialPrimingResponse) SetErrorDescription(v string) { + o.ErrorDescription = &v +} + +// GetErrorHint returns the ErrorHint field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetErrorHint() string { + if o == nil || IsNil(o.ErrorHint) { + var ret string + return ret + } + return *o.ErrorHint +} + +// GetErrorHintOk returns a tuple with the ErrorHint field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetErrorHintOk() (*string, bool) { + if o == nil || IsNil(o.ErrorHint) { + return nil, false + } + return o.ErrorHint, true +} + +// HasErrorHint returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasErrorHint() bool { + if o != nil && !IsNil(o.ErrorHint) { + return true + } + + return false +} + +// SetErrorHint gets a reference to the given string and assigns it to the ErrorHint field. +func (o *VerifiableCredentialPrimingResponse) SetErrorHint(v string) { + o.ErrorHint = &v +} + +// GetFormat returns the Format field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetFormat() string { + if o == nil || IsNil(o.Format) { + var ret string + return ret + } + return *o.Format +} + +// GetFormatOk returns a tuple with the Format field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetFormatOk() (*string, bool) { + if o == nil || IsNil(o.Format) { + return nil, false + } + return o.Format, true +} + +// HasFormat returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasFormat() bool { + if o != nil && !IsNil(o.Format) { + return true + } + + return false +} + +// SetFormat gets a reference to the given string and assigns it to the Format field. +func (o *VerifiableCredentialPrimingResponse) SetFormat(v string) { + o.Format = &v +} + +// GetStatusCode returns the StatusCode field value if set, zero value otherwise. +func (o *VerifiableCredentialPrimingResponse) GetStatusCode() int64 { + if o == nil || IsNil(o.StatusCode) { + var ret int64 + return ret + } + return *o.StatusCode +} + +// GetStatusCodeOk returns a tuple with the StatusCode field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialPrimingResponse) GetStatusCodeOk() (*int64, bool) { + if o == nil || IsNil(o.StatusCode) { + return nil, false + } + return o.StatusCode, true +} + +// HasStatusCode returns a boolean if a field has been set. +func (o *VerifiableCredentialPrimingResponse) HasStatusCode() bool { + if o != nil && !IsNil(o.StatusCode) { + return true + } + + return false +} + +// SetStatusCode gets a reference to the given int64 and assigns it to the StatusCode field. +func (o *VerifiableCredentialPrimingResponse) SetStatusCode(v int64) { + o.StatusCode = &v +} + +func (o VerifiableCredentialPrimingResponse) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o VerifiableCredentialPrimingResponse) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.CNonce) { + toSerialize["c_nonce"] = o.CNonce + } + if !IsNil(o.CNonceExpiresIn) { + toSerialize["c_nonce_expires_in"] = o.CNonceExpiresIn + } + if !IsNil(o.Error) { + toSerialize["error"] = o.Error + } + if !IsNil(o.ErrorDebug) { + toSerialize["error_debug"] = o.ErrorDebug + } + if !IsNil(o.ErrorDescription) { + toSerialize["error_description"] = o.ErrorDescription + } + if !IsNil(o.ErrorHint) { + toSerialize["error_hint"] = o.ErrorHint + } + if !IsNil(o.Format) { + toSerialize["format"] = o.Format + } + if !IsNil(o.StatusCode) { + toSerialize["status_code"] = o.StatusCode + } + return toSerialize, nil +} + +type NullableVerifiableCredentialPrimingResponse struct { + value *VerifiableCredentialPrimingResponse + isSet bool +} + +func (v NullableVerifiableCredentialPrimingResponse) Get() *VerifiableCredentialPrimingResponse { + return v.value +} + +func (v *NullableVerifiableCredentialPrimingResponse) Set(val *VerifiableCredentialPrimingResponse) { + v.value = val + v.isSet = true +} + +func (v NullableVerifiableCredentialPrimingResponse) IsSet() bool { + return v.isSet +} + +func (v *NullableVerifiableCredentialPrimingResponse) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableVerifiableCredentialPrimingResponse(val *VerifiableCredentialPrimingResponse) *NullableVerifiableCredentialPrimingResponse { + return &NullableVerifiableCredentialPrimingResponse{value: val, isSet: true} +} + +func (v NullableVerifiableCredentialPrimingResponse) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableVerifiableCredentialPrimingResponse) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_verifiable_credential_proof.go b/internal/httpclient/model_verifiable_credential_proof.go new file mode 100644 index 00000000000..28eedafdb9e --- /dev/null +++ b/internal/httpclient/model_verifiable_credential_proof.go @@ -0,0 +1,161 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the VerifiableCredentialProof type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &VerifiableCredentialProof{} + +// VerifiableCredentialProof struct for VerifiableCredentialProof +type VerifiableCredentialProof struct { + Jwt *string `json:"jwt,omitempty"` + ProofType *string `json:"proof_type,omitempty"` +} + +// NewVerifiableCredentialProof instantiates a new VerifiableCredentialProof object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewVerifiableCredentialProof() *VerifiableCredentialProof { + this := VerifiableCredentialProof{} + return &this +} + +// NewVerifiableCredentialProofWithDefaults instantiates a new VerifiableCredentialProof object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewVerifiableCredentialProofWithDefaults() *VerifiableCredentialProof { + this := VerifiableCredentialProof{} + return &this +} + +// GetJwt returns the Jwt field value if set, zero value otherwise. +func (o *VerifiableCredentialProof) GetJwt() string { + if o == nil || IsNil(o.Jwt) { + var ret string + return ret + } + return *o.Jwt +} + +// GetJwtOk returns a tuple with the Jwt field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialProof) GetJwtOk() (*string, bool) { + if o == nil || IsNil(o.Jwt) { + return nil, false + } + return o.Jwt, true +} + +// HasJwt returns a boolean if a field has been set. +func (o *VerifiableCredentialProof) HasJwt() bool { + if o != nil && !IsNil(o.Jwt) { + return true + } + + return false +} + +// SetJwt gets a reference to the given string and assigns it to the Jwt field. +func (o *VerifiableCredentialProof) SetJwt(v string) { + o.Jwt = &v +} + +// GetProofType returns the ProofType field value if set, zero value otherwise. +func (o *VerifiableCredentialProof) GetProofType() string { + if o == nil || IsNil(o.ProofType) { + var ret string + return ret + } + return *o.ProofType +} + +// GetProofTypeOk returns a tuple with the ProofType field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialProof) GetProofTypeOk() (*string, bool) { + if o == nil || IsNil(o.ProofType) { + return nil, false + } + return o.ProofType, true +} + +// HasProofType returns a boolean if a field has been set. +func (o *VerifiableCredentialProof) HasProofType() bool { + if o != nil && !IsNil(o.ProofType) { + return true + } + + return false +} + +// SetProofType gets a reference to the given string and assigns it to the ProofType field. +func (o *VerifiableCredentialProof) SetProofType(v string) { + o.ProofType = &v +} + +func (o VerifiableCredentialProof) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o VerifiableCredentialProof) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.Jwt) { + toSerialize["jwt"] = o.Jwt + } + if !IsNil(o.ProofType) { + toSerialize["proof_type"] = o.ProofType + } + return toSerialize, nil +} + +type NullableVerifiableCredentialProof struct { + value *VerifiableCredentialProof + isSet bool +} + +func (v NullableVerifiableCredentialProof) Get() *VerifiableCredentialProof { + return v.value +} + +func (v *NullableVerifiableCredentialProof) Set(val *VerifiableCredentialProof) { + v.value = val + v.isSet = true +} + +func (v NullableVerifiableCredentialProof) IsSet() bool { + return v.isSet +} + +func (v *NullableVerifiableCredentialProof) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableVerifiableCredentialProof(val *VerifiableCredentialProof) *NullableVerifiableCredentialProof { + return &NullableVerifiableCredentialProof{value: val, isSet: true} +} + +func (v NullableVerifiableCredentialProof) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableVerifiableCredentialProof) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_verifiable_credential_response.go b/internal/httpclient/model_verifiable_credential_response.go new file mode 100644 index 00000000000..4c24842e668 --- /dev/null +++ b/internal/httpclient/model_verifiable_credential_response.go @@ -0,0 +1,161 @@ +/* +Ory Hydra API + +Documentation for all of Ory Hydra's APIs. + +API version: +Contact: hi@ory.sh +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package openapi + +import ( + "encoding/json" +) + +// checks if the VerifiableCredentialResponse type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &VerifiableCredentialResponse{} + +// VerifiableCredentialResponse struct for VerifiableCredentialResponse +type VerifiableCredentialResponse struct { + CredentialDraft00 *string `json:"credential_draft_00,omitempty"` + Format *string `json:"format,omitempty"` +} + +// NewVerifiableCredentialResponse instantiates a new VerifiableCredentialResponse object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewVerifiableCredentialResponse() *VerifiableCredentialResponse { + this := VerifiableCredentialResponse{} + return &this +} + +// NewVerifiableCredentialResponseWithDefaults instantiates a new VerifiableCredentialResponse object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewVerifiableCredentialResponseWithDefaults() *VerifiableCredentialResponse { + this := VerifiableCredentialResponse{} + return &this +} + +// GetCredentialDraft00 returns the CredentialDraft00 field value if set, zero value otherwise. +func (o *VerifiableCredentialResponse) GetCredentialDraft00() string { + if o == nil || IsNil(o.CredentialDraft00) { + var ret string + return ret + } + return *o.CredentialDraft00 +} + +// GetCredentialDraft00Ok returns a tuple with the CredentialDraft00 field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialResponse) GetCredentialDraft00Ok() (*string, bool) { + if o == nil || IsNil(o.CredentialDraft00) { + return nil, false + } + return o.CredentialDraft00, true +} + +// HasCredentialDraft00 returns a boolean if a field has been set. +func (o *VerifiableCredentialResponse) HasCredentialDraft00() bool { + if o != nil && !IsNil(o.CredentialDraft00) { + return true + } + + return false +} + +// SetCredentialDraft00 gets a reference to the given string and assigns it to the CredentialDraft00 field. +func (o *VerifiableCredentialResponse) SetCredentialDraft00(v string) { + o.CredentialDraft00 = &v +} + +// GetFormat returns the Format field value if set, zero value otherwise. +func (o *VerifiableCredentialResponse) GetFormat() string { + if o == nil || IsNil(o.Format) { + var ret string + return ret + } + return *o.Format +} + +// GetFormatOk returns a tuple with the Format field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *VerifiableCredentialResponse) GetFormatOk() (*string, bool) { + if o == nil || IsNil(o.Format) { + return nil, false + } + return o.Format, true +} + +// HasFormat returns a boolean if a field has been set. +func (o *VerifiableCredentialResponse) HasFormat() bool { + if o != nil && !IsNil(o.Format) { + return true + } + + return false +} + +// SetFormat gets a reference to the given string and assigns it to the Format field. +func (o *VerifiableCredentialResponse) SetFormat(v string) { + o.Format = &v +} + +func (o VerifiableCredentialResponse) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o VerifiableCredentialResponse) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + if !IsNil(o.CredentialDraft00) { + toSerialize["credential_draft_00"] = o.CredentialDraft00 + } + if !IsNil(o.Format) { + toSerialize["format"] = o.Format + } + return toSerialize, nil +} + +type NullableVerifiableCredentialResponse struct { + value *VerifiableCredentialResponse + isSet bool +} + +func (v NullableVerifiableCredentialResponse) Get() *VerifiableCredentialResponse { + return v.value +} + +func (v *NullableVerifiableCredentialResponse) Set(val *VerifiableCredentialResponse) { + v.value = val + v.isSet = true +} + +func (v NullableVerifiableCredentialResponse) IsSet() bool { + return v.isSet +} + +func (v *NullableVerifiableCredentialResponse) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableVerifiableCredentialResponse(val *VerifiableCredentialResponse) *NullableVerifiableCredentialResponse { + return &NullableVerifiableCredentialResponse{value: val, isSet: true} +} + +func (v NullableVerifiableCredentialResponse) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableVerifiableCredentialResponse) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/internal/httpclient/model_version.go b/internal/httpclient/model_version.go index 4e307b565e1..852862bcf07 100644 --- a/internal/httpclient/model_version.go +++ b/internal/httpclient/model_version.go @@ -15,6 +15,9 @@ import ( "encoding/json" ) +// checks if the Version type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &Version{} + // Version struct for Version type Version struct { // Version is the service's version. @@ -40,7 +43,7 @@ func NewVersionWithDefaults() *Version { // GetVersion returns the Version field value if set, zero value otherwise. func (o *Version) GetVersion() string { - if o == nil || o.Version == nil { + if o == nil || IsNil(o.Version) { var ret string return ret } @@ -50,7 +53,7 @@ func (o *Version) GetVersion() string { // GetVersionOk returns a tuple with the Version field value if set, nil otherwise // and a boolean to check if the value has been set. func (o *Version) GetVersionOk() (*string, bool) { - if o == nil || o.Version == nil { + if o == nil || IsNil(o.Version) { return nil, false } return o.Version, true @@ -58,7 +61,7 @@ func (o *Version) GetVersionOk() (*string, bool) { // HasVersion returns a boolean if a field has been set. func (o *Version) HasVersion() bool { - if o != nil && o.Version != nil { + if o != nil && !IsNil(o.Version) { return true } @@ -71,11 +74,19 @@ func (o *Version) SetVersion(v string) { } func (o Version) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o Version) ToMap() (map[string]interface{}, error) { toSerialize := map[string]interface{}{} - if o.Version != nil { + if !IsNil(o.Version) { toSerialize["version"] = o.Version } - return json.Marshal(toSerialize) + return toSerialize, nil } type NullableVersion struct { diff --git a/internal/httpclient/utils.go b/internal/httpclient/utils.go index 79275ec55ec..e56504bad62 100644 --- a/internal/httpclient/utils.go +++ b/internal/httpclient/utils.go @@ -13,6 +13,7 @@ package openapi import ( "encoding/json" + "reflect" "time" ) @@ -327,3 +328,21 @@ func (v *NullableTime) UnmarshalJSON(src []byte) error { v.isSet = true return json.Unmarshal(src, &v.value) } + +// IsNil checks if an input is nil +func IsNil(i interface{}) bool { + if i == nil { + return true + } + switch reflect.TypeOf(i).Kind() { + case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.UnsafePointer, reflect.Interface, reflect.Slice: + return reflect.ValueOf(i).IsNil() + case reflect.Array: + return reflect.ValueOf(i).IsZero() + } + return false +} + +type MappedNullable interface { + ToMap() (map[string]interface{}, error) +} diff --git a/internal/kratos/fake_kratos.go b/internal/kratos/fake_kratos.go new file mode 100644 index 00000000000..2303320c305 --- /dev/null +++ b/internal/kratos/fake_kratos.go @@ -0,0 +1,50 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package kratos + +import ( + "context" + + "github.com/ory/fosite" + client "github.com/ory/kratos-client-go" +) + +type ( + FakeKratos struct { + DisableSessionWasCalled bool + LastDisabledSession string + } +) + +const ( + FakeSessionID = "fake-kratos-session-id" + FakeUsername = "fake-kratos-username" + FakePassword = "fake-kratos-password" // nolint: gosec + FakeIdentityID = "fake-kratos-identity-id" +) + +var _ Client = new(FakeKratos) + +func NewFake() *FakeKratos { + return &FakeKratos{} +} + +func (f *FakeKratos) DisableSession(_ context.Context, identityProviderSessionID string) error { + f.DisableSessionWasCalled = true + f.LastDisabledSession = identityProviderSessionID + + return nil +} + +func (f *FakeKratos) Authenticate(_ context.Context, username, password string) (*client.Session, error) { + if username == FakeUsername && password == FakePassword { + return &client.Session{Identity: &client.Identity{Id: FakeIdentityID}}, nil + } + return nil, fosite.ErrNotFound +} + +func (f *FakeKratos) Reset() { + f.DisableSessionWasCalled = false + f.LastDisabledSession = "" +} diff --git a/internal/kratos/kratos.go b/internal/kratos/kratos.go new file mode 100644 index 00000000000..04e8fbfcdfb --- /dev/null +++ b/internal/kratos/kratos.go @@ -0,0 +1,124 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package kratos + +import ( + "context" + "fmt" + "net/url" + + "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" + + "github.com/ory/fosite" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/x" + client "github.com/ory/kratos-client-go" + "github.com/ory/x/httpx" + "github.com/ory/x/otelx" +) + +type ( + dependencies interface { + config.Provider + x.HTTPClientProvider + x.TracingProvider + x.RegistryLogger + } + Provider interface { + Kratos() Client + } + Client interface { + DisableSession(ctx context.Context, identityProviderSessionID string) error + Authenticate(ctx context.Context, name, secret string) (*client.Session, error) + } + Default struct { + dependencies + } +) + +func New(d dependencies) Client { + return &Default{dependencies: d} +} + +func (k *Default) Authenticate(ctx context.Context, name, secret string) (session *client.Session, err error) { + ctx, span := k.Tracer(ctx).Tracer().Start(ctx, "kratos.Authenticate") + otelx.End(span, &err) + + publicURL, ok := k.Config().KratosPublicURL(ctx) + span.SetAttributes(attribute.String("public_url", fmt.Sprintf("%+v", publicURL))) + if !ok { + span.SetAttributes(attribute.Bool("skipped", true)) + span.SetAttributes(attribute.String("reason", "kratos public url not set")) + + return nil, errors.New("kratos public url not set") + } + + kratos := k.newKratosClient(ctx, publicURL) + + flow, _, err := kratos.FrontendAPI.CreateNativeLoginFlow(ctx).Execute() + if err != nil { + return nil, err + } + + res, _, err := kratos.FrontendAPI.UpdateLoginFlow(ctx).Flow(flow.Id).UpdateLoginFlowBody(client.UpdateLoginFlowBody{ + UpdateLoginFlowWithPasswordMethod: &client.UpdateLoginFlowWithPasswordMethod{ + Method: "password", + Identifier: name, + Password: secret, + }, + }).Execute() + if err != nil { + return nil, fosite.ErrNotFound.WithWrap(err) + } + + return &res.Session, nil +} + +func (k *Default) DisableSession(ctx context.Context, identityProviderSessionID string) (err error) { + ctx, span := k.Tracer(ctx).Tracer().Start(ctx, "kratos.DisableSession") + otelx.End(span, &err) + + adminURL, ok := k.Config().KratosAdminURL(ctx) + span.SetAttributes(attribute.String("admin_url", fmt.Sprintf("%+v", adminURL))) + if !ok { + span.SetAttributes(attribute.Bool("skipped", true)) + span.SetAttributes(attribute.String("reason", "kratos admin url not set")) + + return nil + } + + if identityProviderSessionID == "" { + span.SetAttributes(attribute.Bool("skipped", true)) + span.SetAttributes(attribute.String("reason", "kratos session ID is empty")) + + return nil + } + + configuration := k.clientConfiguration(ctx, adminURL) + if header := k.Config().KratosRequestHeader(ctx); header != nil { + configuration.HTTPClient.Transport = httpx.WrapTransportWithHeader(configuration.HTTPClient.Transport, header) + } + kratos := client.NewAPIClient(configuration) + _, err = kratos.IdentityAPI.DisableSession(ctx, identityProviderSessionID).Execute() + + return err +} + +func (k *Default) clientConfiguration(ctx context.Context, adminURL *url.URL) *client.Configuration { + configuration := client.NewConfiguration() + configuration.Servers = client.ServerConfigurations{{URL: adminURL.String()}} + configuration.HTTPClient = k.HTTPClient(ctx).StandardClient() + + return configuration +} + +func (k *Default) newKratosClient(ctx context.Context, publicURL *url.URL) *client.APIClient { + configuration := k.clientConfiguration(ctx, publicURL) + if header := k.Config().KratosRequestHeader(ctx); header != nil { + configuration.HTTPClient.Transport = httpx.WrapTransportWithHeader(configuration.HTTPClient.Transport, header) + } + kratos := client.NewAPIClient(configuration) + return kratos +} diff --git a/internal/mock_generator_rs256.go b/internal/mock_generator_rs256.go deleted file mode 100644 index c9c5bd9d526..00000000000 --- a/internal/mock_generator_rs256.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package internal - -import ( - "crypto/rand" - "crypto/rsa" - "crypto/x509" - - "github.com/pborman/uuid" - "github.com/pkg/errors" - "gopkg.in/square/go-jose.v2" -) - -type veryInsecureRS256Generator struct{} - -func (g *veryInsecureRS256Generator) Generate(id, use string) (*jose.JSONWebKeySet, error) { - /* #nosec G403 - this is ok because this generator is only used in tests. */ - key, err := rsa.GenerateKey(rand.Reader, 512) - if err != nil { - return nil, errors.Errorf("Could not generate key because %s", err) - } else if err = key.Validate(); err != nil { - return nil, errors.Errorf("Validation failed because %s", err) - } - - if id == "" { - id = uuid.New() - } - - // jose does not support this... - key.Precomputed = rsa.PrecomputedValues{} - return &jose.JSONWebKeySet{ - Keys: []jose.JSONWebKey{ - { - Algorithm: "RS256", - Key: key, - Use: use, - KeyID: id, - Certificates: []*x509.Certificate{}, - }, - }, - }, nil -} diff --git a/internal/testhelpers/janitor_test_helper.go b/internal/testhelpers/janitor_test_helper.go index 5dc04e1e747..f70d7c27495 100644 --- a/internal/testhelpers/janitor_test_helper.go +++ b/internal/testhelpers/janitor_test_helper.go @@ -10,20 +10,21 @@ import ( "testing" "time" + "github.com/go-jose/go-jose/v3" "github.com/google/uuid" "github.com/stretchr/testify/require" - "gopkg.in/square/go-jose.v2" "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/oauth2/trust" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/oauth2/trust" + "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" "github.com/ory/x/logrusx" @@ -32,8 +33,8 @@ import ( type JanitorConsentTestHelper struct { uniqueName string - flushLoginRequests []*consent.LoginRequest - flushConsentRequests []*consent.OAuth2ConsentRequest + flushLoginRequests []*flow.LoginRequest + flushConsentRequests []*flow.OAuth2ConsentRequest flushAccessRequests []*fosite.Request flushRefreshRequests []*fosite.AccessRequest flushGrants []*createGrantRequest @@ -69,7 +70,7 @@ func NewConsentJanitorTestHelper(uniqueName string) *JanitorConsentTestHelper { } } -func (j *JanitorConsentTestHelper) GetDSN(ctx context.Context) string { +func (j *JanitorConsentTestHelper) GetDSN() string { return j.conf.DSN() } @@ -149,7 +150,7 @@ func (j *JanitorConsentTestHelper) RefreshTokenNotAfterValidate(ctx context.Cont } } -func (j *JanitorConsentTestHelper) GrantNotAfterSetup(ctx context.Context, cl client.Manager, gr trust.GrantManager) func(t *testing.T) { +func (j *JanitorConsentTestHelper) GrantNotAfterSetup(ctx context.Context, gr trust.GrantManager) func(t *testing.T) { return func(t *testing.T) { for _, fg := range j.flushGrants { require.NoError(t, gr.CreateGrant(ctx, fg.grant, fg.pk)) @@ -180,21 +181,29 @@ func (j *JanitorConsentTestHelper) GrantNotAfterValidate(ctx context.Context, no } } -func (j *JanitorConsentTestHelper) LoginRejectionSetup(ctx context.Context, cm consent.Manager, cl client.Manager) func(t *testing.T) { - return func(t *testing.T) { - var err error +func (j *JanitorConsentTestHelper) LoginRejectionSetup(ctx context.Context, reg interface { + consent.ManagerProvider + client.ManagerProvider + flow.CipherProvider +}) func(t *testing.T) { + cm := reg.ConsentManager() + cl := reg.ClientManager() + return func(t *testing.T) { // Create login requests for _, r := range j.flushLoginRequests { require.NoError(t, cl.CreateClient(ctx, r.Client)) - require.NoError(t, cm.CreateLoginRequest(ctx, r)) - } + f, err := cm.CreateLoginRequest(ctx, r) + require.NoError(t, err) - // Explicit rejection - for _, r := range j.flushLoginRequests { + f.RequestedAt = time.Now() // we won't handle expired flows + f.LoginAuthenticatedAt = r.AuthenticatedAt + challenge := x.Must(f.ToLoginChallenge(ctx, reg)) + + // Explicit rejection if r.ID == j.flushLoginRequests[0].ID { // accept this one - _, err = cm.HandleLoginRequest(ctx, r.ID, consent.NewHandledLoginRequest( + _, err = cm.HandleLoginRequest(ctx, f, challenge, consent.NewHandledLoginRequest( r.ID, false, r.RequestedAt, r.AuthenticatedAt)) require.NoError(t, err) @@ -202,7 +211,7 @@ func (j *JanitorConsentTestHelper) LoginRejectionSetup(ctx context.Context, cm c } // reject flush-login-2 and 3 - _, err = cm.HandleLoginRequest(ctx, r.ID, consent.NewHandledLoginRequest( + _, err = cm.HandleLoginRequest(ctx, f, challenge, consent.NewHandledLoginRequest( r.ID, true, r.RequestedAt, r.AuthenticatedAt)) require.NoError(t, err) } @@ -215,28 +224,38 @@ func (j *JanitorConsentTestHelper) LoginRejectionValidate(ctx context.Context, c for _, r := range j.flushLoginRequests { t.Logf("check login: %s", r.ID) _, err := cm.GetLoginRequest(ctx, r.ID) - if r.ID == j.flushLoginRequests[0].ID { - require.NoError(t, err) - } else { - require.Error(t, err) - } + // Login requests should never be persisted. + require.Error(t, err) } } } -func (j *JanitorConsentTestHelper) LimitSetup(ctx context.Context, cm consent.Manager, cl client.Manager) func(t *testing.T) { +func (j *JanitorConsentTestHelper) LimitSetup(ctx context.Context, reg interface { + consent.ManagerProvider + client.ManagerProvider + flow.CipherProvider +}) func(t *testing.T) { + cl := reg.ClientManager() + cm := reg.ConsentManager() + return func(t *testing.T) { - var err error + var ( + err error + f *flow.Flow + ) // Create login requests for _, r := range j.flushLoginRequests { require.NoError(t, cl.CreateClient(ctx, r.Client)) - require.NoError(t, cm.CreateLoginRequest(ctx, r)) - } + f, err = cm.CreateLoginRequest(ctx, r) + require.NoError(t, err) - // Reject each request - for _, r := range j.flushLoginRequests { - _, err = cm.HandleLoginRequest(ctx, r.ID, consent.NewHandledLoginRequest( + // Reject each request + f.RequestedAt = time.Now() // we won't handle expired flows + f.LoginAuthenticatedAt = r.AuthenticatedAt + challenge := x.Must(f.ToLoginChallenge(ctx, reg)) + + _, err = cm.HandleLoginRequest(ctx, f, challenge, consent.NewHandledLoginRequest( r.ID, true, r.RequestedAt, r.AuthenticatedAt)) require.NoError(t, err) } @@ -249,41 +268,50 @@ func (j *JanitorConsentTestHelper) LimitValidate(ctx context.Context, cm consent for _, r := range j.flushLoginRequests { t.Logf("check login: %s", r.ID) _, err := cm.GetLoginRequest(ctx, r.ID) - if r.ID == j.flushLoginRequests[0].ID { - require.NoError(t, err) - } else { - require.Error(t, err) - } + // No Requests should have been persisted. + require.Error(t, err) } } } -func (j *JanitorConsentTestHelper) ConsentRejectionSetup(ctx context.Context, cm consent.Manager, cl client.Manager) func(t *testing.T) { +func (j *JanitorConsentTestHelper) ConsentRejectionSetup(ctx context.Context, reg interface { + consent.ManagerProvider + client.ManagerProvider + flow.CipherProvider +}) func(t *testing.T) { + cl := reg.ClientManager() + cm := reg.ConsentManager() + return func(t *testing.T) { - var err error + var ( + err error + f *flow.Flow + ) // Create login requests - for _, r := range j.flushLoginRequests { - require.NoError(t, cl.CreateClient(ctx, r.Client)) - require.NoError(t, cm.CreateLoginRequest(ctx, r)) - } + for i, loginRequest := range j.flushLoginRequests { + require.NoError(t, cl.CreateClient(ctx, loginRequest.Client)) + f, err = cm.CreateLoginRequest(ctx, loginRequest) + require.NoError(t, err) - // Create consent requests - for _, r := range j.flushConsentRequests { - require.NoError(t, cm.CreateConsentRequest(ctx, r)) - } + // Create consent requests + consentRequest := j.flushConsentRequests[i] + err = cm.CreateConsentRequest(ctx, f, consentRequest) + require.NoError(t, err) - //Reject the consents - for _, r := range j.flushConsentRequests { - if r.ID == j.flushConsentRequests[0].ID { + f.RequestedAt = time.Now() // we won't handle expired flows + f.LoginAuthenticatedAt = consentRequest.AuthenticatedAt + + // Reject the consents + if consentRequest.ID == j.flushConsentRequests[0].ID { // accept this one - _, err = cm.HandleConsentRequest(ctx, consent.NewHandledConsentRequest( - r.ID, false, r.RequestedAt, r.AuthenticatedAt)) + _, err = cm.HandleConsentRequest(ctx, f, consent.NewHandledConsentRequest( + consentRequest.ID, false, consentRequest.RequestedAt, consentRequest.AuthenticatedAt)) require.NoError(t, err) continue } - _, err = cm.HandleConsentRequest(ctx, consent.NewHandledConsentRequest( - r.ID, true, r.RequestedAt, r.AuthenticatedAt)) + _, err = cm.HandleConsentRequest(ctx, f, consent.NewHandledConsentRequest( + consentRequest.ID, true, consentRequest.RequestedAt, consentRequest.AuthenticatedAt)) require.NoError(t, err) } } @@ -295,32 +323,43 @@ func (j *JanitorConsentTestHelper) ConsentRejectionValidate(ctx context.Context, for _, r := range j.flushConsentRequests { t.Logf("check consent: %s", r.ID) _, err = cm.GetConsentRequest(ctx, r.ID) - if r.ID == j.flushConsentRequests[0].ID { - require.NoError(t, err) - } else { - require.Error(t, err) - } + // Consent requests should never be persisted. + require.Error(t, err) } } } -func (j *JanitorConsentTestHelper) LoginTimeoutSetup(ctx context.Context, cm consent.Manager, cl client.Manager) func(t *testing.T) { +func (j *JanitorConsentTestHelper) LoginTimeoutSetup(ctx context.Context, reg interface { + consent.ManagerProvider + client.ManagerProvider + flow.CipherProvider +}) func(t *testing.T) { + cl := reg.ClientManager() + cm := reg.ConsentManager() + return func(t *testing.T) { - var err error + var ( + err error + f *flow.Flow + ) // Create login requests - for _, r := range j.flushLoginRequests { - require.NoError(t, cl.CreateClient(ctx, r.Client)) - require.NoError(t, cm.CreateLoginRequest(ctx, r)) - } + for i, loginRequest := range j.flushLoginRequests { + require.NoError(t, cl.CreateClient(ctx, loginRequest.Client)) + f, err = cm.CreateLoginRequest(ctx, loginRequest) + require.NoError(t, err) - // Creating at least 1 that has not timed out - _, err = cm.HandleLoginRequest(ctx, j.flushLoginRequests[0].ID, &consent.HandledLoginRequest{ - ID: j.flushLoginRequests[0].ID, - RequestedAt: j.flushLoginRequests[0].RequestedAt, - AuthenticatedAt: j.flushLoginRequests[0].AuthenticatedAt, - WasHandled: true, - }) + if i == 0 { + // Creating at least 1 that has not timed out + challenge := x.Must(f.ToLoginChallenge(ctx, reg)) + _, err = cm.HandleLoginRequest(ctx, f, challenge, &flow.HandledLoginRequest{ + ID: loginRequest.ID, + RequestedAt: loginRequest.RequestedAt, + AuthenticatedAt: loginRequest.AuthenticatedAt, + WasHandled: true, + }) + } + } require.NoError(t, err) } @@ -328,51 +367,56 @@ func (j *JanitorConsentTestHelper) LoginTimeoutSetup(ctx context.Context, cm con func (j *JanitorConsentTestHelper) LoginTimeoutValidate(ctx context.Context, cm consent.Manager) func(t *testing.T) { return func(t *testing.T) { - var err error - for _, r := range j.flushLoginRequests { - _, err = cm.GetLoginRequest(ctx, r.ID) - if r.ID == j.flushLoginRequests[0].ID { - require.NoError(t, err) - } else { - require.Error(t, err) - } + _, err := cm.GetLoginRequest(ctx, r.ID) + // Login requests should never be persisted. + require.Error(t, err) } - } } -func (j *JanitorConsentTestHelper) ConsentTimeoutSetup(ctx context.Context, cm consent.Manager, cl client.Manager) func(t *testing.T) { - return func(t *testing.T) { - var err error +func (j *JanitorConsentTestHelper) ConsentTimeoutSetup(ctx context.Context, reg interface { + consent.ManagerProvider + client.ManagerProvider + flow.CipherProvider +}) func(t *testing.T) { + cl := reg.ClientManager() + cm := reg.ConsentManager() + return func(t *testing.T) { // Let's reset and accept all login requests to test the consent requests - for _, r := range j.flushLoginRequests { - require.NoError(t, cl.CreateClient(ctx, r.Client)) - require.NoError(t, cm.CreateLoginRequest(ctx, r)) - _, err = cm.HandleLoginRequest(ctx, r.ID, &consent.HandledLoginRequest{ - ID: r.ID, - AuthenticatedAt: r.AuthenticatedAt, - RequestedAt: r.RequestedAt, + for i, loginRequest := range j.flushLoginRequests { + require.NoError(t, cl.CreateClient(ctx, loginRequest.Client)) + f, err := cm.CreateLoginRequest(ctx, loginRequest) + require.NoError(t, err) + f.RequestedAt = time.Now() // we won't handle expired flows + challenge := x.Must(f.ToLoginChallenge(ctx, reg)) + _, err = cm.HandleLoginRequest(ctx, f, challenge, &flow.HandledLoginRequest{ + ID: loginRequest.ID, + AuthenticatedAt: loginRequest.AuthenticatedAt, + RequestedAt: loginRequest.RequestedAt, WasHandled: true, }) require.NoError(t, err) - } - // Create consent requests - for _, r := range j.flushConsentRequests { - require.NoError(t, cm.CreateConsentRequest(ctx, r)) + // Create consent requests + consentRequest := j.flushConsentRequests[i] + err = cm.CreateConsentRequest(ctx, f, consentRequest) + require.NoError(t, err) + + if i == 0 { + // Create at least 1 consent request that has been accepted + _, err = cm.HandleConsentRequest(ctx, f, &flow.AcceptOAuth2ConsentRequest{ + ID: consentRequest.ID, + WasHandled: true, + HandledAt: sqlxx.NullTime(time.Now()), + RequestedAt: consentRequest.RequestedAt, + AuthenticatedAt: consentRequest.AuthenticatedAt, + }) + require.NoError(t, err) + } } - // Create at least 1 consent request that has been accepted - _, err = cm.HandleConsentRequest(ctx, &consent.AcceptOAuth2ConsentRequest{ - ID: j.flushConsentRequests[0].ID, - WasHandled: true, - HandledAt: sqlxx.NullTime(time.Now()), - RequestedAt: j.flushConsentRequests[0].RequestedAt, - AuthenticatedAt: j.flushConsentRequests[0].AuthenticatedAt, - }) - require.NoError(t, err) } } @@ -382,40 +426,58 @@ func (j *JanitorConsentTestHelper) ConsentTimeoutValidate(ctx context.Context, c for _, r := range j.flushConsentRequests { _, err = cm.GetConsentRequest(ctx, r.ID) - if r.ID == j.flushConsentRequests[0].ID { - require.NoError(t, err) - } else { - require.Error(t, err) - } + require.Error(t, err, "Unverified consent requests are never pesisted") } - } } func (j *JanitorConsentTestHelper) LoginConsentNotAfterSetup(ctx context.Context, cm consent.Manager, cl client.Manager) func(t *testing.T) { return func(t *testing.T) { + var ( + f *flow.Flow + err error + ) for _, r := range j.flushLoginRequests { require.NoError(t, cl.CreateClient(ctx, r.Client)) - require.NoError(t, cm.CreateLoginRequest(ctx, r)) + f, err = cm.CreateLoginRequest(ctx, r) + require.NoError(t, err) } for _, r := range j.flushConsentRequests { - require.NoError(t, cm.CreateConsentRequest(ctx, r)) + f.ID = r.LoginChallenge.String() + err = cm.CreateConsentRequest(ctx, f, r) + require.NoError(t, err) } } } -func (j *JanitorConsentTestHelper) LoginConsentNotAfterValidate(ctx context.Context, notAfter time.Time, consentRequestLifespan time.Time, cm consent.Manager) func(t *testing.T) { +func (j *JanitorConsentTestHelper) LoginConsentNotAfterValidate( + ctx context.Context, + notAfter time.Time, + consentRequestLifespan time.Time, + reg interface { + consent.ManagerProvider + flow.CipherProvider + }, +) func(t *testing.T) { return func(t *testing.T) { - var err error + var ( + err error + f *flow.Flow + ) for _, r := range j.flushLoginRequests { - t.Logf("login flush check:\nNotAfter: %s\nConsentRequest: %s\n%+v\n", - notAfter.String(), consentRequestLifespan.String(), r) - _, err = cm.GetLoginRequest(ctx, r.ID) + isExpired := r.RequestedAt.Before(consentRequestLifespan) + t.Logf("login flush check:\nNotAfter: %s\nLoginRequest: %s\nis expired: %v\n%+v\n", + notAfter.String(), consentRequestLifespan.String(), isExpired, r) + + f = x.Must(reg.ConsentManager().CreateLoginRequest(ctx, r)) + loginChallenge := x.Must(f.ToLoginChallenge(ctx, reg)) + + _, err = reg.ConsentManager().GetLoginRequest(ctx, loginChallenge) // if the lowest between notAfter and consent-request-lifespan is greater than requested_at // then the it should expect the value to be deleted. - if j.notAfterCheck(notAfter, consentRequestLifespan, r.RequestedAt) { + if isExpired { // value has been deleted here require.Error(t, err) } else { @@ -425,12 +487,19 @@ func (j *JanitorConsentTestHelper) LoginConsentNotAfterValidate(ctx context.Cont } for _, r := range j.flushConsentRequests { - t.Logf("consent flush check:\nNotAfter: %s\nConsentRequest: %s\n%+v\n", - notAfter.String(), consentRequestLifespan.String(), r) - _, err = cm.GetConsentRequest(ctx, r.ID) + isExpired := r.RequestedAt.Before(consentRequestLifespan) + t.Logf("consent flush check:\nNotAfter: %s\nConsentRequest: %s\nis expired: %v\n%+v\n", + notAfter.String(), consentRequestLifespan.String(), isExpired, r) + + f.ID = r.LoginChallenge.String() + require.NoError(t, reg.ConsentManager().CreateConsentRequest(ctx, f, r)) + f.RequestedAt = r.RequestedAt + consentChallenge := x.Must(f.ToConsentChallenge(ctx, reg)) + + _, err = reg.ConsentManager().GetConsentRequest(ctx, consentChallenge) // if the lowest between notAfter and consent-request-lifespan is greater than requested_at // then the it should expect the value to be deleted. - if j.notAfterCheck(notAfter, consentRequestLifespan, r.RequestedAt) { + if isExpired { // value has been deleted here require.Error(t, err) } else { @@ -470,8 +539,22 @@ func (j *JanitorConsentTestHelper) notAfterCheck(notAfter time.Time, lifespan ti return lesser.Unix() > requestedAt.Unix() } -func JanitorTests(conf *config.DefaultProvider, consentManager consent.Manager, clientManager client.Manager, fositeManager x.FositeStorer, network string, parallel bool) func(t *testing.T) { +func JanitorTests( + reg interface { + ConsentManager() consent.Manager + OAuth2Storage() x.FositeStorer + config.Provider + client.ManagerProvider + flow.CipherProvider + }, + network string, + parallel bool, +) func(t *testing.T) { return func(t *testing.T) { + consentManager := reg.ConsentManager() + clientManager := reg.ClientManager() + fositeManager := reg.OAuth2Storage() + if parallel { t.Parallel() } @@ -479,7 +562,7 @@ func JanitorTests(conf *config.DefaultProvider, consentManager consent.Manager, jt := NewConsentJanitorTestHelper(network + t.Name()) - conf.MustSet(context.Background(), config.KeyConsentRequestMaxAge, jt.GetConsentRequestLifespan(ctx)) + reg.Config().MustSet(context.Background(), config.KeyConsentRequestMaxAge, jt.GetConsentRequestLifespan(ctx)) t.Run("case=flush-consent-request-not-after", func(t *testing.T) { @@ -500,7 +583,7 @@ func JanitorTests(conf *config.DefaultProvider, consentManager consent.Manager, }) // validate test - t.Run("step=validate", jt.LoginConsentNotAfterValidate(ctx, notAfter, consentRequestLifespan, consentManager)) + t.Run("step=validate", jt.LoginConsentNotAfterValidate(ctx, notAfter, consentRequestLifespan, reg)) }) } @@ -511,7 +594,7 @@ func JanitorTests(conf *config.DefaultProvider, consentManager consent.Manager, t.Run("case=limit", func(t *testing.T) { // setup - t.Run("step=setup", jt.LimitSetup(ctx, consentManager, clientManager)) + t.Run("step=setup", jt.LimitSetup(ctx, reg)) // cleanup t.Run("step=cleanup", func(t *testing.T) { @@ -528,7 +611,7 @@ func JanitorTests(conf *config.DefaultProvider, consentManager consent.Manager, t.Run(fmt.Sprintf("case=%s", "loginRejection"), func(t *testing.T) { // setup - t.Run("step=setup", jt.LoginRejectionSetup(ctx, consentManager, clientManager)) + t.Run("step=setup", jt.LoginRejectionSetup(ctx, reg)) // cleanup t.Run("step=cleanup", func(t *testing.T) { @@ -543,7 +626,7 @@ func JanitorTests(conf *config.DefaultProvider, consentManager consent.Manager, t.Run(fmt.Sprintf("case=%s", "consentRejection"), func(t *testing.T) { // setup - t.Run("step=setup", jt.ConsentRejectionSetup(ctx, consentManager, clientManager)) + t.Run("step=setup", jt.ConsentRejectionSetup(ctx, reg)) // cleanup t.Run("step=cleanup", func(t *testing.T) { @@ -562,7 +645,7 @@ func JanitorTests(conf *config.DefaultProvider, consentManager consent.Manager, t.Run(fmt.Sprintf("case=%s", "login-timeout"), func(t *testing.T) { // setup - t.Run("step=setup", jt.LoginTimeoutSetup(ctx, consentManager, clientManager)) + t.Run("step=setup", jt.LoginTimeoutSetup(ctx, reg)) // cleanup t.Run("step=cleanup", func(t *testing.T) { @@ -579,7 +662,7 @@ func JanitorTests(conf *config.DefaultProvider, consentManager consent.Manager, t.Run(fmt.Sprintf("case=%s", "consent-timeout"), func(t *testing.T) { // setup - t.Run("step=setup", jt.ConsentTimeoutSetup(ctx, consentManager, clientManager)) + t.Run("step=setup", jt.ConsentTimeoutSetup(ctx, reg)) // cleanup t.Run("step=cleanup", func(t *testing.T) { @@ -599,7 +682,7 @@ func getAccessRequests(uniqueName string, lifespan time.Duration) []*fosite.Requ { ID: fmt.Sprintf("%s_flush-access-1", uniqueName), RequestedAt: time.Now().Round(time.Second), - Client: &client.Client{LegacyClientID: fmt.Sprintf("%s_flush-access-1", uniqueName)}, + Client: &client.Client{ID: fmt.Sprintf("%s_flush-access-1", uniqueName)}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -608,7 +691,7 @@ func getAccessRequests(uniqueName string, lifespan time.Duration) []*fosite.Requ { ID: fmt.Sprintf("%s_flush-access-2", uniqueName), RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Minute)), - Client: &client.Client{LegacyClientID: fmt.Sprintf("%s_flush-access-2", uniqueName)}, + Client: &client.Client{ID: fmt.Sprintf("%s_flush-access-2", uniqueName)}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -617,7 +700,7 @@ func getAccessRequests(uniqueName string, lifespan time.Duration) []*fosite.Requ { ID: fmt.Sprintf("%s_flush-access-3", uniqueName), RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Hour)), - Client: &client.Client{LegacyClientID: fmt.Sprintf("%s_flush-access-3", uniqueName)}, + Client: &client.Client{ID: fmt.Sprintf("%s_flush-access-3", uniqueName)}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -627,7 +710,7 @@ func getAccessRequests(uniqueName string, lifespan time.Duration) []*fosite.Requ } func getRefreshRequests(uniqueName string, lifespan time.Duration) []*fosite.AccessRequest { - var tokenSignature = "4c7c7e8b3a77ad0c3ec846a21653c48b45dbfa31" + var tokenSignature = "4c7c7e8b3a77ad0c3ec846a21653c48b45dbfa31" //nolint:gosec return []*fosite.AccessRequest{ { GrantTypes: []string{ @@ -636,7 +719,7 @@ func getRefreshRequests(uniqueName string, lifespan time.Duration) []*fosite.Acc Request: fosite.Request{ RequestedAt: time.Now().Round(time.Second), ID: fmt.Sprintf("%s_flush-refresh-1", uniqueName), - Client: &client.Client{LegacyClientID: fmt.Sprintf("%s_flush-refresh-1", uniqueName)}, + Client: &client.Client{ID: fmt.Sprintf("%s_flush-refresh-1", uniqueName)}, RequestedScope: []string{"offline"}, GrantedScope: []string{"offline"}, Session: &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "bar"}}, @@ -652,7 +735,7 @@ func getRefreshRequests(uniqueName string, lifespan time.Duration) []*fosite.Acc Request: fosite.Request{ RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Minute)), ID: fmt.Sprintf("%s_flush-refresh-2", uniqueName), - Client: &client.Client{LegacyClientID: fmt.Sprintf("%s_flush-refresh-2", uniqueName)}, + Client: &client.Client{ID: fmt.Sprintf("%s_flush-refresh-2", uniqueName)}, RequestedScope: []string{"offline"}, GrantedScope: []string{"offline"}, Session: &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "bar"}}, @@ -668,7 +751,7 @@ func getRefreshRequests(uniqueName string, lifespan time.Duration) []*fosite.Acc Request: fosite.Request{ RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Hour)), ID: fmt.Sprintf("%s_flush-refresh-3", uniqueName), - Client: &client.Client{LegacyClientID: fmt.Sprintf("%s_flush-refresh-3", uniqueName)}, + Client: &client.Client{ID: fmt.Sprintf("%s_flush-refresh-3", uniqueName)}, RequestedScope: []string{"offline"}, GrantedScope: []string{"offline"}, Session: &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "bar"}}, @@ -680,15 +763,15 @@ func getRefreshRequests(uniqueName string, lifespan time.Duration) []*fosite.Acc } } -func genLoginRequests(uniqueName string, lifespan time.Duration) []*consent.LoginRequest { - return []*consent.LoginRequest{ +func genLoginRequests(uniqueName string, lifespan time.Duration) []*flow.LoginRequest { + return []*flow.LoginRequest{ { ID: fmt.Sprintf("%s_flush-login-1", uniqueName), RequestedScope: []string{"foo", "bar"}, Subject: fmt.Sprintf("%s_flush-login-1", uniqueName), Client: &client.Client{ - LegacyClientID: fmt.Sprintf("%s_flush-login-consent-1", uniqueName), - RedirectURIs: []string{"http://redirect"}, + ID: fmt.Sprintf("%s_flush-login-consent-1", uniqueName), + RedirectURIs: []string{"http://redirect"}, }, RequestURL: "http://redirect", RequestedAt: time.Now().Round(time.Second), @@ -700,12 +783,12 @@ func genLoginRequests(uniqueName string, lifespan time.Duration) []*consent.Logi RequestedScope: []string{"foo", "bar"}, Subject: fmt.Sprintf("%s_flush-login-2", uniqueName), Client: &client.Client{ - LegacyClientID: fmt.Sprintf("%s_flush-login-consent-2", uniqueName), - RedirectURIs: []string{"http://redirect"}, + ID: fmt.Sprintf("%s_flush-login-consent-2", uniqueName), + RedirectURIs: []string{"http://redirect"}, }, RequestURL: "http://redirect", - RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Minute)), - AuthenticatedAt: sqlxx.NullTime(time.Now().Round(time.Second).Add(-(lifespan + time.Minute))), + RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + 10*time.Minute)), + AuthenticatedAt: sqlxx.NullTime(time.Now().Round(time.Second).Add(-(lifespan + 10*time.Minute))), Verifier: fmt.Sprintf("%s_flush-login-2", uniqueName), }, { @@ -713,8 +796,8 @@ func genLoginRequests(uniqueName string, lifespan time.Duration) []*consent.Logi RequestedScope: []string{"foo", "bar"}, Subject: fmt.Sprintf("%s_flush-login-3", uniqueName), Client: &client.Client{ - LegacyClientID: fmt.Sprintf("%s_flush-login-consent-3", uniqueName), - RedirectURIs: []string{"http://redirect"}, + ID: fmt.Sprintf("%s_flush-login-consent-3", uniqueName), + RedirectURIs: []string{"http://redirect"}, }, RequestURL: "http://redirect", RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Hour)), @@ -724,8 +807,8 @@ func genLoginRequests(uniqueName string, lifespan time.Duration) []*consent.Logi } } -func genConsentRequests(uniqueName string, lifespan time.Duration) []*consent.OAuth2ConsentRequest { - return []*consent.OAuth2ConsentRequest{ +func genConsentRequests(uniqueName string, lifespan time.Duration) []*flow.OAuth2ConsentRequest { + return []*flow.OAuth2ConsentRequest{ { ID: fmt.Sprintf("%s_flush-consent-1", uniqueName), RequestedScope: []string{"foo", "bar"}, diff --git a/internal/testhelpers/lifespans.go b/internal/testhelpers/lifespans.go index a3d24e42806..86477c90b09 100644 --- a/internal/testhelpers/lifespans.go +++ b/internal/testhelpers/lifespans.go @@ -6,8 +6,8 @@ package testhelpers import ( "time" - "github.com/ory/hydra/client" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/x" ) var TestLifespans = client.Lifespans{ diff --git a/internal/testhelpers/oauth2.go b/internal/testhelpers/oauth2.go index 96a8d87761a..41f0ddaec8e 100644 --- a/internal/testhelpers/oauth2.go +++ b/internal/testhelpers/oauth2.go @@ -7,16 +7,17 @@ import ( "bytes" "context" "encoding/json" + "errors" "net/http" "net/http/cookiejar" + "net/http/httptest" "net/url" "strings" "testing" "time" "github.com/stretchr/testify/assert" - - djwt "github.com/ory/fosite/token/jwt" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "github.com/ory/fosite/token/jwt" @@ -28,13 +29,11 @@ import ( "github.com/ory/x/httpx" "github.com/ory/x/ioutilx" - "net/http/httptest" - - "github.com/ory/hydra/client" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/x" ) func NewIDToken(t *testing.T, reg driver.Registry, subject string) string { @@ -51,13 +50,13 @@ func NewIDTokenWithExpiry(t *testing.T, reg driver.Registry, subject string, exp return token } -func NewIDTokenWithClaims(t *testing.T, reg driver.Registry, claims djwt.MapClaims) string { +func NewIDTokenWithClaims(t *testing.T, reg driver.Registry, claims jwt.MapClaims) string { token, _, err := reg.OpenIDJWTStrategy().Generate(context.Background(), claims, jwt.NewHeaders()) require.NoError(t, err) return token } -func NewOAuth2Server(ctx context.Context, t *testing.T, reg driver.Registry) (publicTS, adminTS *httptest.Server) { +func NewOAuth2Server(ctx context.Context, t testing.TB, reg driver.Registry) (publicTS, adminTS *httptest.Server) { // Lifespan is two seconds to avoid time synchronization issues with SQL. reg.Config().MustSet(ctx, config.KeySubjectIdentifierAlgorithmSalt, "76d5d2bf-747f-4592-9fbd-d2b895a54b3a") reg.Config().MustSet(ctx, config.KeyAccessTokenLifespan, time.Second*2) @@ -68,19 +67,22 @@ func NewOAuth2Server(ctx context.Context, t *testing.T, reg driver.Registry) (pu public, admin := x.NewRouterPublic(), x.NewRouterAdmin(reg.Config().AdminURL) - publicTS = httptest.NewServer(public) + internal.MustEnsureRegistryKeys(ctx, reg, x.OpenIDConnectKeyName) + internal.MustEnsureRegistryKeys(ctx, reg, x.OAuth2JWTKeyName) + + reg.RegisterRoutes(ctx, admin, public) + + publicTS = httptest.NewServer(otelhttp.NewHandler(public, "public", otelhttp.WithSpanNameFormatter(func(_ string, r *http.Request) string { + return r.URL.Path + }))) t.Cleanup(publicTS.Close) - adminTS = httptest.NewServer(admin) + adminTS = httptest.NewServer(otelhttp.NewHandler(admin, "admin", otelhttp.WithSpanNameFormatter(func(_ string, r *http.Request) string { + return r.URL.Path + }))) t.Cleanup(adminTS.Close) reg.Config().MustSet(ctx, config.KeyIssuerURL, publicTS.URL) - // SendDebugMessagesToClients: true, - - internal.MustEnsureRegistryKeys(reg, x.OpenIDConnectKeyName) - internal.MustEnsureRegistryKeys(reg, x.OAuth2JWTKeyName) - - reg.RegisterRoutes(ctx, admin, public) return publicTS, adminTS } @@ -95,7 +97,7 @@ func DecodeIDToken(t *testing.T, token *oauth2.Token) gjson.Result { return gjson.ParseBytes(body) } -func IntrospectToken(t *testing.T, conf *oauth2.Config, token string, adminTS *httptest.Server) gjson.Result { +func IntrospectToken(t testing.TB, conf *oauth2.Config, token string, adminTS *httptest.Server) gjson.Result { require.NotEmpty(t, token) req := httpx.MustNewRequest("POST", adminTS.URL+"/admin/oauth2/introspect", @@ -142,13 +144,13 @@ func HTTPServerNotImplementedHandler(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNotImplemented) } -func HTTPServerNoExpectedCallHandler(t *testing.T) http.HandlerFunc { +func HTTPServerNoExpectedCallHandler(t testing.TB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { t.Fatal("This should not have been called") } } -func NewLoginConsentUI(t *testing.T, c *config.DefaultProvider, login, consent http.HandlerFunc) { +func NewLoginConsentUI(t testing.TB, c *config.DefaultProvider, login, consent http.HandlerFunc) { if login == nil { login = HTTPServerNotImplementedHandler } @@ -167,7 +169,7 @@ func NewLoginConsentUI(t *testing.T, c *config.DefaultProvider, login, consent h c.MustSet(context.Background(), config.KeyConsentURL, ct.URL) } -func NewCallbackURL(t *testing.T, prefix string, h http.HandlerFunc) string { +func NewCallbackURL(t testing.TB, prefix string, h http.HandlerFunc) string { if h == nil { h = HTTPServerNotImplementedHandler } @@ -182,14 +184,35 @@ func NewCallbackURL(t *testing.T, prefix string, h http.HandlerFunc) string { return ts.URL + "/" + prefix } -func NewEmptyCookieJar(t *testing.T) *cookiejar.Jar { +func NewEmptyCookieJar(t testing.TB) *cookiejar.Jar { c, err := cookiejar.New(&cookiejar.Options{}) require.NoError(t, err) return c } -func NewEmptyJarClient(t *testing.T) *http.Client { +func NewEmptyJarClient(t testing.TB) *http.Client { return &http.Client{ - Jar: NewEmptyCookieJar(t), + Jar: NewEmptyCookieJar(t), + Transport: &loggingTransport{t}, + CheckRedirect: func(req *http.Request, via []*http.Request) error { + //t.Logf("Redirect to %s", req.URL.String()) + + if len(via) >= 20 { + for k, v := range via { + t.Logf("Failed with redirect (%d): %s", k, v.URL.String()) + } + return errors.New("stopped after 20 redirects") + } + return nil + }, } } + +type loggingTransport struct{ t testing.TB } + +func (s *loggingTransport) RoundTrip(r *http.Request) (*http.Response, error) { + //s.t.Logf("%s %s", r.Method, r.URL.String()) + //s.t.Logf("%s %s\nWith Cookies: %v", r.Method, r.URL.String(), r.Cookies()) + + return otelhttp.DefaultClient.Transport.RoundTrip(r) +} diff --git a/internal/testhelpers/uuid/uuid.go b/internal/testhelpers/uuid/uuid.go index 8fae25139ab..b8800b384e5 100644 --- a/internal/testhelpers/uuid/uuid.go +++ b/internal/testhelpers/uuid/uuid.go @@ -11,7 +11,16 @@ import ( ) // AssertUUID helper requires that a UUID is non-zero, common version/variant used in Hydra. -func AssertUUID(t *testing.T, id *uuid.UUID) { - require.Equal(t, id.Version(), uuid.V4) - require.Equal(t, id.Variant(), uuid.VariantRFC4122) +func AssertUUID[T string | uuid.UUID](t *testing.T, id T) { + var uid uuid.UUID + switch idt := any(id).(type) { + case uuid.UUID: + uid = idt + case string: + var err error + uid, err = uuid.FromString(idt) + require.NoError(t, err) + } + require.Equal(t, uid.Version(), uuid.V4) + require.Equal(t, uid.Variant(), uuid.VariantRFC4122) } diff --git a/jwk/aead.go b/jwk/aead.go deleted file mode 100644 index a3f34728ea6..00000000000 --- a/jwk/aead.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package jwk - -import ( - "context" - "encoding/base64" - - "github.com/ory/x/errorsx" - - "github.com/ory/hydra/driver/config" - - "github.com/gtank/cryptopasta" - "github.com/pkg/errors" -) - -type AEAD struct { - c *config.DefaultProvider -} - -func NewAEAD(c *config.DefaultProvider) *AEAD { - return &AEAD{c: c} -} - -func aeadKey(key []byte) *[32]byte { - var result [32]byte - copy(result[:], key[:32]) - return &result -} - -func (c *AEAD) Encrypt(ctx context.Context, plaintext []byte) (string, error) { - global, err := c.c.GetGlobalSecret(ctx) - if err != nil { - return "", err - } - - rotated, err := c.c.GetRotatedGlobalSecrets(ctx) - if err != nil { - return "", err - } - - keys := append([][]byte{global}, rotated...) - if len(keys) == 0 { - return "", errors.Errorf("at least one encryption key must be defined but none were") - } - - if len(keys[0]) < 32 { - return "", errors.Errorf("key must be exactly 32 long bytes, got %d bytes", len(keys[0])) - } - - ciphertext, err := cryptopasta.Encrypt(plaintext, aeadKey(keys[0])) - if err != nil { - return "", errorsx.WithStack(err) - } - - return base64.URLEncoding.EncodeToString(ciphertext), nil -} - -func (c *AEAD) Decrypt(ctx context.Context, ciphertext string) (p []byte, err error) { - global, err := c.c.GetGlobalSecret(ctx) - if err != nil { - return nil, err - } - - rotated, err := c.c.GetRotatedGlobalSecrets(ctx) - if err != nil { - return nil, err - } - - keys := append([][]byte{global}, rotated...) - if len(keys) == 0 { - return nil, errors.Errorf("at least one decryption key must be defined but none were") - } - - for _, key := range keys { - if p, err = c.decrypt(ciphertext, key); err == nil { - return p, nil - } - } - - return nil, err -} - -func (c *AEAD) decrypt(ciphertext string, key []byte) ([]byte, error) { - if len(key) != 32 { - return nil, errors.Errorf("key must be exactly 32 long bytes, got %d bytes", len(key)) - } - - raw, err := base64.URLEncoding.DecodeString(ciphertext) - if err != nil { - return nil, errorsx.WithStack(err) - } - - plaintext, err := cryptopasta.Decrypt(raw, aeadKey(key)) - if err != nil { - return nil, errorsx.WithStack(err) - } - - return plaintext, nil -} diff --git a/jwk/aead_test.go b/jwk/aead_test.go deleted file mode 100644 index 7b69a644f77..00000000000 --- a/jwk/aead_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package jwk_test - -import ( - "context" - "crypto/rand" - "fmt" - "io" - "testing" - - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - . "github.com/ory/hydra/jwk" - - "github.com/pborman/uuid" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func secret(t *testing.T) string { - bytes := make([]byte, 32) - _, err := io.ReadFull(rand.Reader, bytes) - require.NoError(t, err) - return fmt.Sprintf("%X", bytes) -} - -func TestAEAD(t *testing.T) { - ctx := context.Background() - c := internal.NewConfigurationWithDefaults() - t.Run("case=without-rotation", func(t *testing.T) { - c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t)}) - a := NewAEAD(c) - - plain := []byte(uuid.New()) - ct, err := a.Encrypt(ctx, plain) - assert.NoError(t, err) - - res, err := a.Decrypt(ctx, ct) - assert.NoError(t, err) - assert.Equal(t, plain, res) - }) - - t.Run("case=wrong-secret", func(t *testing.T) { - c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t)}) - a := NewAEAD(c) - - ct, err := a.Encrypt(ctx, []byte(uuid.New())) - require.NoError(t, err) - - c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t)}) - _, err = a.Decrypt(ctx, ct) - require.Error(t, err) - }) - - t.Run("case=with-rotation", func(t *testing.T) { - old := secret(t) - c.MustSet(ctx, config.KeyGetSystemSecret, []string{old}) - a := NewAEAD(c) - - plain := []byte(uuid.New()) - ct, err := a.Encrypt(ctx, plain) - require.NoError(t, err) - - // Sets the old secret as a rotated secret and creates a new one. - c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t), old}) - res, err := a.Decrypt(ctx, ct) - require.NoError(t, err) - assert.Equal(t, plain, res) - - // THis should also work when we re-encrypt the same plain text. - ct2, err := a.Encrypt(ctx, plain) - require.NoError(t, err) - assert.NotEqual(t, ct2, ct) - - res, err = a.Decrypt(ctx, ct) - require.NoError(t, err) - assert.Equal(t, plain, res) - }) - - t.Run("case=with-rotation-wrong-secret", func(t *testing.T) { - c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t)}) - a := NewAEAD(c) - - plain := []byte(uuid.New()) - ct, err := a.Encrypt(ctx, plain) - require.NoError(t, err) - - // When the secrets do not match, an error should be thrown during decryption. - c.MustSet(ctx, config.KeyGetSystemSecret, []string{secret(t), secret(t)}) - _, err = a.Decrypt(ctx, ct) - require.Error(t, err) - }) -} diff --git a/jwk/cast.go b/jwk/cast.go index 7fc2b2c8906..1b41b407852 100644 --- a/jwk/cast.go +++ b/jwk/cast.go @@ -8,8 +8,8 @@ import ( "github.com/ory/x/josex" + jose "github.com/go-jose/go-jose/v3" "github.com/pkg/errors" - jose "gopkg.in/square/go-jose.v2" ) func MustRSAPublic(key *jose.JSONWebKey) *rsa.PublicKey { diff --git a/jwk/cast_test.go b/jwk/cast_test.go index d55b81ba518..79bcfd12606 100644 --- a/jwk/cast_test.go +++ b/jwk/cast_test.go @@ -7,13 +7,14 @@ import ( "context" "testing" + "github.com/go-jose/go-jose/v3" "github.com/stretchr/testify/require" - "gopkg.in/square/go-jose.v2" "github.com/stretchr/testify/assert" ) func TestMustRSAPrivate(t *testing.T) { + t.Parallel() keys, err := GenerateJWK(context.Background(), jose.RS256, "foo", "sig") require.NoError(t, err) diff --git a/jwk/generate.go b/jwk/generate.go index e5a30592cc7..dadc9531327 100644 --- a/jwk/generate.go +++ b/jwk/generate.go @@ -9,8 +9,8 @@ import ( "github.com/gofrs/uuid" + "github.com/go-jose/go-jose/v3" "github.com/pkg/errors" - "gopkg.in/square/go-jose.v2" "github.com/ory/x/josex" ) diff --git a/jwk/generate_test.go b/jwk/generate_test.go index 01a47d4ec67..29bb6323c57 100644 --- a/jwk/generate_test.go +++ b/jwk/generate_test.go @@ -7,12 +7,13 @@ import ( "context" "testing" + "github.com/go-jose/go-jose/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/square/go-jose.v2" ) func TestGenerateJWK(t *testing.T) { + t.Parallel() jwks, err := GenerateJWK(context.Background(), jose.RS256, "", "") require.NoError(t, err) assert.NotEmpty(t, jwks.Keys[0].KeyID) diff --git a/jwk/generator.go b/jwk/generator.go index 03bdbd6a82d..99522fc4349 100644 --- a/jwk/generator.go +++ b/jwk/generator.go @@ -3,7 +3,7 @@ package jwk -import jose "gopkg.in/square/go-jose.v2" +import jose "github.com/go-jose/go-jose/v3" type KeyGenerator interface { Generate(id, use string) (*jose.JSONWebKeySet, error) diff --git a/jwk/handler.go b/jwk/handler.go index 07a7667db11..7d48445321e 100644 --- a/jwk/handler.go +++ b/jwk/handler.go @@ -7,6 +7,9 @@ import ( "encoding/json" "net/http" + "golang.org/x/sync/errgroup" + + "github.com/ory/herodot" "github.com/ory/x/httprouterx" "github.com/gofrs/uuid" @@ -18,10 +21,10 @@ import ( "github.com/ory/x/stringslice" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" + jose "github.com/go-jose/go-jose/v3" "github.com/julienschmidt/httprouter" - jose "gopkg.in/square/go-jose.v2" ) const ( @@ -36,6 +39,8 @@ type Handler struct { // JSON Web Key Set // // swagger:model jsonWebKeySet +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type jsonWebKeySet struct { // List of JSON Web Keys // @@ -75,6 +80,9 @@ func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin, public *httprouterx. // if enabled, OAuth 2.0 JWT Access Tokens. This endpoint can be used with client libraries like // [node-jwks-rsa](https://github.com/auth0/node-jwks-rsa) among others. // +// Adding custom keys requires first creating a keyset via the createJsonWebKeySet operation, +// and then configuring the webfinger.jwks.broadcast_keys configuration value to include the keyset name. +// // Consumes: // - application/json // @@ -87,25 +95,34 @@ func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin, public *httprouterx. // 200: jsonWebKeySet // default: errorOAuth2 func (h *Handler) discoverJsonWebKeys(w http.ResponseWriter, r *http.Request) { - var jwks jose.JSONWebKeySet - - ctx := r.Context() - for _, set := range stringslice.Unique(h.r.Config().WellKnownKeys(ctx)) { - keys, err := h.r.KeyManager().GetKeySet(ctx, set) - if errors.Is(err, x.ErrNotFound) { - h.r.Logger().Warnf("JSON Web Key Set \"%s\" does not exist yet, generating new key pair...", set) - keys, err = h.r.KeyManager().GenerateAndPersistKeySet(ctx, set, uuid.Must(uuid.NewV4()).String(), string(jose.RS256), "sig") - if err != nil { - h.r.Writer().WriteError(w, r, err) - return + eg, ctx := errgroup.WithContext(r.Context()) + wellKnownKeys := stringslice.Unique(h.r.Config().WellKnownKeys(ctx)) + keys := make(chan *jose.JSONWebKeySet, len(wellKnownKeys)) + for _, set := range wellKnownKeys { + set := set + eg.Go(func() error { + k, err := h.r.KeyManager().GetKeySet(ctx, set) + if errors.Is(err, x.ErrNotFound) { + h.r.Logger().Warnf("JSON Web Key Set %q does not exist yet, generating new key pair...", set) + k, err = h.r.KeyManager().GenerateAndPersistKeySet(ctx, set, uuid.Must(uuid.NewV4()).String(), string(jose.RS256), "sig") + if err != nil { + return err + } + } else if err != nil { + return err } - } else if err != nil { - h.r.Writer().WriteError(w, r, err) - return - } - - keys = ExcludePrivateKeys(keys) - jwks.Keys = append(jwks.Keys, keys.Keys...) + keys <- ExcludePrivateKeys(k) + return nil + }) + } + if err := eg.Wait(); err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + close(keys) + var jwks jose.JSONWebKeySet + for k := range keys { + jwks.Keys = append(jwks.Keys, k.Keys...) } h.r.Writer().Write(w, r, &jwks) @@ -114,6 +131,8 @@ func (h *Handler) discoverJsonWebKeys(w http.ResponseWriter, r *http.Request) { // Get JSON Web Key Request // // swagger:parameters getJsonWebKey +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type getJsonWebKey struct { // JSON Web Key Set ID // @@ -162,6 +181,8 @@ func (h *Handler) getJsonWebKey(w http.ResponseWriter, r *http.Request, ps httpr // Get JSON Web Key Set Parameters // // swagger:parameters getJsonWebKeySet +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type getJsonWebKeySet struct { // JSON Web Key Set ID // @@ -205,6 +226,8 @@ func (h *Handler) getJsonWebKeySet(w http.ResponseWriter, r *http.Request, ps ht // Create JSON Web Key Set Request // // swagger:parameters createJsonWebKeySet +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type adminCreateJsonWebKeySet struct { // The JSON Web Key Set ID // @@ -269,7 +292,8 @@ func (h *Handler) createJsonWebKeySet(w http.ResponseWriter, r *http.Request, ps var set = ps.ByName("set") if err := json.NewDecoder(r.Body).Decode(&keyRequest); err != nil { - h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + h.r.Writer().WriteError(w, r, errorsx.WithStack(herodot.ErrBadRequest.WithReasonf("Unable to decode the request body: %s", err))) + return } if keys, err := h.r.KeyManager().GenerateAndPersistKeySet(r.Context(), set, keyRequest.KeyID, keyRequest.Algorithm, keyRequest.Use); err == nil { @@ -283,6 +307,8 @@ func (h *Handler) createJsonWebKeySet(w http.ResponseWriter, r *http.Request, ps // Set JSON Web Key Set Request // // swagger:parameters setJsonWebKeySet +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type setJsonWebKeySet struct { // The JSON Web Key Set ID // @@ -318,7 +344,7 @@ func (h *Handler) setJsonWebKeySet(w http.ResponseWriter, r *http.Request, ps ht var set = ps.ByName("set") if err := json.NewDecoder(r.Body).Decode(&keySet); err != nil { - h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + h.r.Writer().WriteError(w, r, errorsx.WithStack(herodot.ErrBadRequest.WithReasonf("Unable to decode the request body: %s", err))) return } @@ -333,6 +359,8 @@ func (h *Handler) setJsonWebKeySet(w http.ResponseWriter, r *http.Request, ps ht // Set JSON Web Key Request // // swagger:parameters setJsonWebKey +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type setJsonWebKey struct { // The JSON Web Key Set ID // @@ -374,7 +402,7 @@ func (h *Handler) adminUpdateJsonWebKey(w http.ResponseWriter, r *http.Request, var set = ps.ByName("set") if err := json.NewDecoder(r.Body).Decode(&key); err != nil { - h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + h.r.Writer().WriteError(w, r, errorsx.WithStack(herodot.ErrBadRequest.WithReasonf("Unable to decode the request body: %s", err))) return } @@ -389,6 +417,8 @@ func (h *Handler) adminUpdateJsonWebKey(w http.ResponseWriter, r *http.Request, // Delete JSON Web Key Set Parameters // // swagger:parameters deleteJsonWebKeySet +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type deleteJsonWebKeySet struct { // The JSON Web Key Set // in: path @@ -429,6 +459,8 @@ func (h *Handler) adminDeleteJsonWebKeySet(w http.ResponseWriter, r *http.Reques // Delete JSON Web Key Parameters // // swagger:parameters deleteJsonWebKey +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type deleteJsonWebKey struct { // The JSON Web Key Set // in: path diff --git a/jwk/handler_test.go b/jwk/handler_test.go index 67140e7dc25..5df8182de60 100644 --- a/jwk/handler_test.go +++ b/jwk/handler_test.go @@ -12,19 +12,21 @@ import ( "github.com/ory/x/httprouterx" - "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/jwk" "github.com/ory/x/contextx" + "github.com/go-jose/go-jose/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - jose "gopkg.in/square/go-jose.v2" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/x" ) func TestHandlerWellKnown(t *testing.T) { + t.Parallel() + conf := internal.NewConfigurationWithDefaults() reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) conf.MustSet(context.Background(), config.KeyWellKnownKeys, []string{x.OpenIDConnectKeyName, x.OpenIDConnectKeyName}) @@ -37,6 +39,7 @@ func TestHandlerWellKnown(t *testing.T) { JWKPath := "/.well-known/jwks.json" t.Run("Test_Handler_WellKnown/Run_public_key_With_public_prefix", func(t *testing.T) { + t.Parallel() if conf.HSMEnabled() { t.Skip("Skipping test. Not applicable when Hardware Security Module is enabled. Public/private keys on HSM are generated with equal key id's and are not using prefixes") } @@ -50,7 +53,7 @@ func TestHandlerWellKnown(t *testing.T) { err = json.NewDecoder(res.Body).Decode(&known) require.NoError(t, err, "problem in decoding response") - require.Len(t, known.Keys, 1) + require.GreaterOrEqual(t, len(known.Keys), 1) knownKey := known.Key("test-id-1")[0].Public() require.NotNil(t, knownKey, "Could not find key public") @@ -62,6 +65,7 @@ func TestHandlerWellKnown(t *testing.T) { }) t.Run("Test_Handler_WellKnown/Run_public_key_Without_public_prefix", func(t *testing.T) { + t.Parallel() var IDKS *jose.JSONWebKeySet if conf.HSMEnabled() { @@ -84,9 +88,9 @@ func TestHandlerWellKnown(t *testing.T) { err = json.NewDecoder(res.Body).Decode(&known) require.NoError(t, err, "problem in decoding response") if conf.HSMEnabled() { - require.Len(t, known.Keys, 2) + require.GreaterOrEqual(t, len(known.Keys), 2) } else { - require.Len(t, known.Keys, 1) + require.GreaterOrEqual(t, len(known.Keys), 1) } knownKey := known.Key("test-id-2")[0] diff --git a/jwk/helper.go b/jwk/helper.go index 2506074764b..50f3a28b2d2 100644 --- a/jwk/helper.go +++ b/jwk/helper.go @@ -4,22 +4,26 @@ package jwk import ( + "bytes" "context" "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "crypto/x509" + "encoding/json" "encoding/pem" "sync" + hydra "github.com/ory/hydra-client-go/v2" + "github.com/ory/x/josex" "github.com/ory/x/errorsx" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" + jose "github.com/go-jose/go-jose/v3" "github.com/pkg/errors" - jose "gopkg.in/square/go-jose.v2" ) var mapLock sync.RWMutex @@ -119,9 +123,11 @@ func ExcludePrivateKeys(set *jose.JSONWebKeySet) *jose.JSONWebKeySet { func ExcludeOpaquePrivateKeys(set *jose.JSONWebKeySet) *jose.JSONWebKeySet { keys := new(jose.JSONWebKeySet) - for _, k := range set.Keys { - if _, opaque := k.Key.(jose.OpaqueSigner); !opaque { - keys.Keys = append(keys.Keys, k) + for i := range set.Keys { + if _, opaque := set.Keys[i].Key.(jose.OpaqueSigner); opaque { + keys.Keys = append(keys.Keys, josex.ToPublicKey(&set.Keys[i])) + } else { + keys.Keys = append(keys.Keys, set.Keys[i]) } } return keys @@ -147,3 +153,32 @@ func PEMBlockForKey(key interface{}) (*pem.Block, error) { return nil, errors.New("Invalid key type") } } + +func OnlyPublicSDKKeys(in []hydra.JsonWebKey) (out []hydra.JsonWebKey, _ error) { + var interim []jose.JSONWebKey + var b bytes.Buffer + + if err := json.NewEncoder(&b).Encode(&in); err != nil { + return nil, errors.Wrap(err, "failed to encode JSON Web Key Set") + } + + if err := json.NewDecoder(&b).Decode(&interim); err != nil { + return nil, errors.Wrap(err, "failed to encode JSON Web Key Set") + } + + for i, key := range interim { + interim[i] = key.Public() + } + + b.Reset() + if err := json.NewEncoder(&b).Encode(&interim); err != nil { + return nil, errors.Wrap(err, "failed to encode JSON Web Key Set") + } + + var keys []hydra.JsonWebKey + if err := json.NewDecoder(&b).Decode(&keys); err != nil { + return nil, errors.Wrap(err, "failed to encode JSON Web Key Set") + } + + return keys, nil +} diff --git a/jwk/helper_test.go b/jwk/helper_test.go index fa77b917cbd..c1a5ee46387 100644 --- a/jwk/helper_test.go +++ b/jwk/helper_test.go @@ -6,31 +6,31 @@ package jwk_test import ( "context" "crypto" - "crypto/dsa" + "crypto/dsa" //lint:ignore SA1019 used for testing invalid key types "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "crypto/x509" + "encoding/json" "encoding/pem" "io" "strings" "testing" + hydra "github.com/ory/hydra-client-go/v2" + + "github.com/go-jose/go-jose/v3" + "github.com/go-jose/go-jose/v3/cryptosigner" "github.com/golang/mock/gomock" "github.com/pborman/uuid" "github.com/pkg/errors" - - "github.com/ory/hydra/internal" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/x" - "github.com/ory/x/contextx" - - "gopkg.in/square/go-jose.v2/cryptosigner" - - "gopkg.in/square/go-jose.v2" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/contextx" ) type fakeSigner struct { @@ -46,7 +46,10 @@ func (f *fakeSigner) Public() crypto.PublicKey { } func TestHandlerFindPublicKey(t *testing.T) { + t.Parallel() + t.Run("Test_Helper/Run_FindPublicKey_With_RSA", func(t *testing.T) { + t.Parallel() RSIDKS, err := jwk.GenerateJWK(context.Background(), jose.RS256, "test-id-1", "sig") require.NoError(t, err) keys, err := jwk.FindPublicKey(RSIDKS) @@ -56,6 +59,7 @@ func TestHandlerFindPublicKey(t *testing.T) { }) t.Run("Test_Helper/Run_FindPublicKey_With_Opaque", func(t *testing.T) { + t.Parallel() key, err := jwk.GenerateJWK(context.Background(), jose.RS256, "test-id-1", "sig") RSIDKS := &jose.JSONWebKeySet{Keys: []jose.JSONWebKey{{ Algorithm: "RS256", @@ -82,6 +86,7 @@ func TestHandlerFindPublicKey(t *testing.T) { }) t.Run("Test_Helper/Run_FindPublicKey_With_ECDSA", func(t *testing.T) { + t.Parallel() ECDSAIDKS, err := jwk.GenerateJWK(context.Background(), jose.ES256, "test-id-2", "sig") require.NoError(t, err) keys, err := jwk.FindPublicKey(ECDSAIDKS) @@ -91,6 +96,7 @@ func TestHandlerFindPublicKey(t *testing.T) { }) t.Run("Test_Helper/Run_FindPublicKey_With_EdDSA", func(t *testing.T) { + t.Parallel() EdDSAIDKS, err := jwk.GenerateJWK(context.Background(), jose.EdDSA, "test-id-3", "sig") require.NoError(t, err) keys, err := jwk.FindPublicKey(EdDSAIDKS) @@ -100,6 +106,7 @@ func TestHandlerFindPublicKey(t *testing.T) { }) t.Run("Test_Helper/Run_FindPublicKey_With_KeyNotFound", func(t *testing.T) { + t.Parallel() keySet := &jose.JSONWebKeySet{Keys: []jose.JSONWebKey{}} _, err := jwk.FindPublicKey(keySet) require.Error(t, err) @@ -108,6 +115,7 @@ func TestHandlerFindPublicKey(t *testing.T) { } func TestHandlerFindPrivateKey(t *testing.T) { + t.Parallel() t.Run("Test_Helper/Run_FindPrivateKey_With_RSA", func(t *testing.T) { RSIDKS, _ := jwk.GenerateJWK(context.Background(), jose.RS256, "test-id-1", "sig") keys, err := jwk.FindPrivateKey(RSIDKS) @@ -143,6 +151,7 @@ func TestHandlerFindPrivateKey(t *testing.T) { } func TestPEMBlockForKey(t *testing.T) { + t.Parallel() t.Run("Test_Helper/Run_PEMBlockForKey_With_RSA", func(t *testing.T) { RSIDKS, err := jwk.GenerateJWK(context.Background(), jose.RS256, "test-id-1", "sig") require.NoError(t, err) @@ -185,15 +194,22 @@ func TestPEMBlockForKey(t *testing.T) { } func TestExcludeOpaquePrivateKeys(t *testing.T) { + t.Parallel() opaqueKeys, err := jwk.GenerateJWK(context.Background(), jose.RS256, "test-id-1", "sig") assert.NoError(t, err) require.Len(t, opaqueKeys.Keys, 1) opaqueKeys.Keys[0].Key = cryptosigner.Opaque(opaqueKeys.Keys[0].Key.(*rsa.PrivateKey)) + keys := jwk.ExcludeOpaquePrivateKeys(opaqueKeys) - require.Len(t, keys.Keys, 0) + + require.Len(t, keys.Keys, 1) + k := keys.Keys[0] + _, isPublic := k.Key.(*rsa.PublicKey) + assert.True(t, isPublic) } func TestGetOrGenerateKeys(t *testing.T) { + t.Parallel() reg := internal.NewMockedRegistry(t, &contextx.Default{}) setId := uuid.NewUUID().String() @@ -254,3 +270,20 @@ func TestGetOrGenerateKeys(t *testing.T) { assert.EqualError(t, err, "key not found") }) } + +func TestOnlyPublicSDKKeys(t *testing.T) { + set, err := jwk.GenerateJWK(context.Background(), jose.RS256, "test-id-1", "sig") + require.NoError(t, err) + + out, err := json.Marshal(set.Keys) + require.NoError(t, err) + + var sdkSet []hydra.JsonWebKey + require.NoError(t, json.Unmarshal(out, &sdkSet)) + + assert.NotEmpty(t, sdkSet[0].P) + result, err := jwk.OnlyPublicSDKKeys(sdkSet) + require.NoError(t, err) + + assert.Empty(t, result[0].P) +} diff --git a/jwk/jwt_strategy.go b/jwk/jwt_strategy.go index 76792578e24..f8ca396a1df 100644 --- a/jwk/jwt_strategy.go +++ b/jwk/jwt_strategy.go @@ -9,11 +9,11 @@ import ( "github.com/ory/x/josex" + "github.com/go-jose/go-jose/v3" "github.com/gofrs/uuid" - "gopkg.in/square/go-jose.v2" "github.com/ory/fosite" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver/config" "github.com/pkg/errors" @@ -53,7 +53,7 @@ func (j *DefaultJWTSigner) getKeys(ctx context.Context) (private *jose.JSONWebKe return nil, errors.WithStack(fosite.ErrServerError. WithWrap(err). - WithHintf(`Could not ensure that signing keys for "%s" exists. If you are running against a persistent SQL database this is most likely because your "secrets.system" ("SECRETS_SYSTEM" environment variable) is not set or changed. When running with an SQL database backend you need to make sure that the secret is set and stays the same, unless when doing key rotation. This may also happen when you forget to run "hydra migrate sql..`, j.setID)) + WithHintf(`Could not ensure that signing keys for "%s" exists. If you are running against a persistent SQL database this is most likely because your "secrets.system" ("SECRETS_SYSTEM" environment variable) is not set or changed. When running with an SQL database backend you need to make sure that the secret is set and stays the same, unless when doing key rotation. This may also happen when you forget to run "hydra migrate sql up -e".`, j.setID)) } func (j *DefaultJWTSigner) GetPublicKeyID(ctx context.Context) (string, error) { diff --git a/jwk/jwt_strategy_test.go b/jwk/jwt_strategy_test.go index 5a71febb89c..8389d20a610 100644 --- a/jwk/jwt_strategy_test.go +++ b/jwk/jwt_strategy_test.go @@ -9,18 +9,14 @@ import ( "strings" "testing" - "github.com/tidwall/gjson" - - "github.com/ory/hydra/internal" - "github.com/ory/x/contextx" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - - jwt2 "github.com/ory/fosite/token/jwt" + "github.com/tidwall/gjson" "github.com/ory/fosite/token/jwt" - . "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/internal" + . "github.com/ory/hydra/v2/jwk" + "github.com/ory/x/contextx" ) func TestJWTStrategy(t *testing.T) { @@ -34,7 +30,7 @@ func TestJWTStrategy(t *testing.T) { require.NoError(t, err) s := NewDefaultJWTSigner(conf, reg, "foo-set") - a, b, err := s.Generate(context.Background(), jwt2.MapClaims{"foo": "bar"}, &jwt.Headers{}) + a, b, err := s.Generate(context.Background(), jwt.MapClaims{"foo": "bar"}, &jwt.Headers{}) require.NoError(t, err) assert.NotEmpty(t, a) assert.NotEmpty(t, b) @@ -52,7 +48,7 @@ func TestJWTStrategy(t *testing.T) { _, err = m.GenerateAndPersistKeySet(context.Background(), "foo-set", "bar", alg, "sig") require.NoError(t, err) - a, b, err = s.Generate(context.Background(), jwt2.MapClaims{"foo": "bar"}, &jwt.Headers{}) + a, b, err = s.Generate(context.Background(), jwt.MapClaims{"foo": "bar"}, &jwt.Headers{}) require.NoError(t, err) assert.NotEmpty(t, a) assert.NotEmpty(t, b) diff --git a/jwk/manager.go b/jwk/manager.go index 3ab298b43e5..a8f3c6aacb1 100644 --- a/jwk/manager.go +++ b/jwk/manager.go @@ -5,11 +5,18 @@ package jwk import ( "context" + "encoding/json" "net/http" "time" + "github.com/pkg/errors" + + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/errorsx" + + jose "github.com/go-jose/go-jose/v3" "github.com/gofrs/uuid" - jose "gopkg.in/square/go-jose.v2" "github.com/ory/fosite" ) @@ -26,6 +33,12 @@ var ErrUnsupportedEllipticCurve = &fosite.RFC6749Error{ DescriptionField: "Unsupported elliptic curve", } +var ErrMinimalRsaKeyLength = &fosite.RFC6749Error{ + CodeField: http.StatusBadRequest, + ErrorField: http.StatusText(http.StatusBadRequest), + DescriptionField: "Unsupported RSA key length", +} + type ( Manager interface { GenerateAndPersistKeySet(ctx context.Context, set, kid, alg, use string) (*jose.JSONWebKeySet, error) @@ -58,8 +71,38 @@ type ( CreatedAt time.Time `db:"created_at"` Key string `db:"keydata"` } + + SQLDataRows []SQLData ) func (d SQLData) TableName() string { return "hydra_jwk" } + +func (d SQLDataRows) ToJWK(ctx context.Context, r interface { + KeyCipher() *aead.AESGCM +}) (keys *jose.JSONWebKeySet, err error) { + if len(d) == 0 { + return nil, errors.Wrap(x.ErrNotFound, "") + } + + keys = &jose.JSONWebKeySet{Keys: []jose.JSONWebKey{}} + for _, d := range d { + key, err := r.KeyCipher().Decrypt(ctx, d.Key, nil) + if err != nil { + return nil, errorsx.WithStack(err) + } + + var c jose.JSONWebKey + if err := json.Unmarshal(key, &c); err != nil { + return nil, errorsx.WithStack(err) + } + keys.Keys = append(keys.Keys, c) + } + + if len(keys.Keys) == 0 { + return nil, errorsx.WithStack(x.ErrNotFound) + } + + return keys, nil +} diff --git a/jwk/manager_mock_test.go b/jwk/manager_mock_test.go index 4e3dc82f03f..65627a0e595 100644 --- a/jwk/manager_mock_test.go +++ b/jwk/manager_mock_test.go @@ -11,8 +11,8 @@ import ( context "context" reflect "reflect" + jose "github.com/go-jose/go-jose/v3" gomock "github.com/golang/mock/gomock" - jose "gopkg.in/square/go-jose.v2" ) // MockManager is a mock of Manager interface. diff --git a/jwk/manager_strategy.go b/jwk/manager_strategy.go index 0119d9eeecf..2519ba3d151 100644 --- a/jwk/manager_strategy.go +++ b/jwk/manager_strategy.go @@ -6,15 +6,17 @@ package jwk import ( "context" + "github.com/go-jose/go-jose/v3" "github.com/pkg/errors" "go.opentelemetry.io/otel" - "gopkg.in/square/go-jose.v2" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/ory/x/otelx" ) -const tracingComponent = "github.com/ory/hydra/jwk" +const tracingComponent = "github.com/ory/hydra/v2/jwk" type ManagerStrategy struct { hardwareKeyManager Manager @@ -28,72 +30,52 @@ func NewManagerStrategy(hardwareKeyManager Manager, softwareKeyManager Manager) } } -func (m ManagerStrategy) GenerateAndPersistKeySet(ctx context.Context, set, kid, alg, use string) (*jose.JSONWebKeySet, error) { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - "kid": kid, - "alg": alg, - "use": use, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m ManagerStrategy) GenerateAndPersistKeySet(ctx context.Context, set, kid, alg, use string) (_ *jose.JSONWebKeySet, err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", kid), + attribute.String("alg", alg), + attribute.String("use", use))) + defer otelx.End(span, &err) return m.hardwareKeyManager.GenerateAndPersistKeySet(ctx, set, kid, alg, use) } -func (m ManagerStrategy) AddKey(ctx context.Context, set string, key *jose.JSONWebKey) error { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m ManagerStrategy) AddKey(ctx context.Context, set string, key *jose.JSONWebKey) (err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.AddKey", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) return m.softwareKeyManager.AddKey(ctx, set, key) } -func (m ManagerStrategy) AddKeySet(ctx context.Context, set string, keys *jose.JSONWebKeySet) error { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m ManagerStrategy) AddKeySet(ctx context.Context, set string, keys *jose.JSONWebKeySet) (err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.AddKeySet", trace.WithAttributes(attribute.String("set", set))) + otelx.End(span, &err) return m.softwareKeyManager.AddKeySet(ctx, set, keys) } -func (m ManagerStrategy) UpdateKey(ctx context.Context, set string, key *jose.JSONWebKey) error { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m ManagerStrategy) UpdateKey(ctx context.Context, set string, key *jose.JSONWebKey) (err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.UpdateKey", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) return m.softwareKeyManager.UpdateKey(ctx, set, key) } -func (m ManagerStrategy) UpdateKeySet(ctx context.Context, set string, keys *jose.JSONWebKeySet) error { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m ManagerStrategy) UpdateKeySet(ctx context.Context, set string, keys *jose.JSONWebKeySet) (err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.UpdateKeySet", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) return m.softwareKeyManager.UpdateKeySet(ctx, set, keys) } -func (m ManagerStrategy) GetKey(ctx context.Context, set, kid string) (*jose.JSONWebKeySet, error) { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - "kid": kid, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m ManagerStrategy) GetKey(ctx context.Context, set, kid string) (_ *jose.JSONWebKeySet, err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GetKey", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", kid))) + defer otelx.End(span, &err) keySet, err := m.hardwareKeyManager.GetKey(ctx, set, kid) if err != nil && !errors.Is(err, x.ErrNotFound) { @@ -105,13 +87,9 @@ func (m ManagerStrategy) GetKey(ctx context.Context, set, kid string) (*jose.JSO } } -func (m ManagerStrategy) GetKeySet(ctx context.Context, set string) (*jose.JSONWebKeySet, error) { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m ManagerStrategy) GetKeySet(ctx context.Context, set string) (_ *jose.JSONWebKeySet, err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GetKeySet", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) keySet, err := m.hardwareKeyManager.GetKeySet(ctx, set) if err != nil && !errors.Is(err, x.ErrNotFound) { @@ -123,16 +101,14 @@ func (m ManagerStrategy) GetKeySet(ctx context.Context, set string) (*jose.JSONW } } -func (m ManagerStrategy) DeleteKey(ctx context.Context, set, kid string) error { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - "kid": kid, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m ManagerStrategy) DeleteKey(ctx context.Context, set, kid string) (err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.DeleteKey", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", kid))) + defer otelx.End(span, &err) - err := m.hardwareKeyManager.DeleteKey(ctx, set, kid) + err = m.hardwareKeyManager.DeleteKey(ctx, set, kid) if err != nil && !errors.Is(err, x.ErrNotFound) { return err } else if errors.Is(err, x.ErrNotFound) { @@ -142,15 +118,11 @@ func (m ManagerStrategy) DeleteKey(ctx context.Context, set, kid string) error { } } -func (m ManagerStrategy) DeleteKeySet(ctx context.Context, set string) error { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.GenerateAndPersistKeySet") - defer span.End() - attrs := map[string]string{ - "set": set, - } - span.SetAttributes(otelx.StringAttrs(attrs)...) +func (m ManagerStrategy) DeleteKeySet(ctx context.Context, set string) (err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "jwk.DeleteKeySet", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) - err := m.hardwareKeyManager.DeleteKeySet(ctx, set) + err = m.hardwareKeyManager.DeleteKeySet(ctx, set) if err != nil && !errors.Is(err, x.ErrNotFound) { return err } else if errors.Is(err, x.ErrNotFound) { diff --git a/jwk/manager_strategy_test.go b/jwk/manager_strategy_test.go index 452273a123b..23d587988aa 100644 --- a/jwk/manager_strategy_test.go +++ b/jwk/manager_strategy_test.go @@ -7,16 +7,17 @@ import ( "context" "testing" + "github.com/go-jose/go-jose/v3" "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" - "gopkg.in/square/go-jose.v2" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/x" ) func TestKeyManagerStrategy(t *testing.T) { + t.Parallel() ctrl := gomock.NewController(t) softwareKeyManager := NewMockManager(ctrl) hardwareKeyManager := NewMockManager(ctrl) diff --git a/jwk/manager_test_helpers.go b/jwk/manager_test_helpers.go index 26f94cd5539..959f1827525 100644 --- a/jwk/manager_test_helpers.go +++ b/jwk/manager_test_helpers.go @@ -16,9 +16,9 @@ import ( "github.com/ory/x/errorsx" + jose "github.com/go-jose/go-jose/v3" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - jose "gopkg.in/square/go-jose.v2" ) func RandomBytes(n int) ([]byte, error) { @@ -223,6 +223,7 @@ func TestHelperManagerNIDIsolationKeySet(t1 Manager, t2 Manager, alg string) fun keys.Keys[i].Use = "enc" } err = t1.UpdateKeySet(context.TODO(), "foo", keys) + require.Error(t, err) for i := range keys.Keys { keys.Keys[i].Use = "err" } diff --git a/jwk/registry.go b/jwk/registry.go index 1fa8ae42d51..b5c3ea8d811 100644 --- a/jwk/registry.go +++ b/jwk/registry.go @@ -4,8 +4,9 @@ package jwk import ( - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/x" ) type InternalRegistry interface { @@ -18,5 +19,5 @@ type Registry interface { config.Provider KeyManager() Manager SoftwareKeyManager() Manager - KeyCipher() *AEAD + KeyCipher() *aead.AESGCM } diff --git a/jwk/registry_mock_test.go b/jwk/registry_mock_test.go index 7188054e5c7..c305fd18167 100644 --- a/jwk/registry_mock_test.go +++ b/jwk/registry_mock_test.go @@ -13,8 +13,9 @@ import ( gomock "github.com/golang/mock/gomock" herodot "github.com/ory/herodot" - config "github.com/ory/hydra/driver/config" - jwk "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/aead" + config "github.com/ory/hydra/v2/driver/config" + jwk "github.com/ory/hydra/v2/jwk" logrusx "github.com/ory/x/logrusx" ) @@ -70,10 +71,10 @@ func (mr *MockInternalRegistryMockRecorder) Config() *gomock.Call { } // KeyCipher mocks base method. -func (m *MockInternalRegistry) KeyCipher() *jwk.AEAD { +func (m *MockInternalRegistry) KeyCipher() *aead.AESGCM { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "KeyCipher") - ret0, _ := ret[0].(*jwk.AEAD) + ret0, _ := ret[0].(*aead.AESGCM) return ret0 } @@ -177,10 +178,10 @@ func (mr *MockRegistryMockRecorder) Config() *gomock.Call { } // KeyCipher mocks base method. -func (m *MockRegistry) KeyCipher() *jwk.AEAD { +func (m *MockRegistry) KeyCipher() *aead.AESGCM { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "KeyCipher") - ret0, _ := ret[0].(*jwk.AEAD) + ret0, _ := ret[0].(*aead.AESGCM) return ret0 } diff --git a/jwk/sdk_test.go b/jwk/sdk_test.go index b1c87c8e934..f7f7d6a21e8 100644 --- a/jwk/sdk_test.go +++ b/jwk/sdk_test.go @@ -9,21 +9,19 @@ import ( "net/http/httptest" "testing" - "github.com/ory/hydra/driver/config" - - hydra "github.com/ory/hydra-client-go/v2" - - "github.com/ory/hydra/internal" - "github.com/ory/hydra/x" - "github.com/ory/x/contextx" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - . "github.com/ory/hydra/jwk" + hydra "github.com/ory/hydra-client-go/v2" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + . "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/contextx" ) func TestJWKSDK(t *testing.T) { + t.Parallel() ctx := context.Background() conf := internal.NewConfigurationWithDefaults() reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) @@ -41,9 +39,10 @@ func TestJWKSDK(t *testing.T) { expectedKid := "key-bar" t.Run("JSON Web Key", func(t *testing.T) { + t.Parallel() t.Run("CreateJwkSetKey", func(t *testing.T) { // Create a key called set-foo - resultKeys, _, err := sdk.JwkApi.CreateJsonWebKeySet(context.Background(), "set-foo").CreateJsonWebKeySet(hydra.CreateJsonWebKeySet{ + resultKeys, _, err := sdk.JwkAPI.CreateJsonWebKeySet(context.Background(), "set-foo").CreateJsonWebKeySet(hydra.CreateJsonWebKeySet{ Alg: "RS256", Kid: "key-bar", Use: "sig", @@ -57,7 +56,7 @@ func TestJWKSDK(t *testing.T) { var resultKeys *hydra.JsonWebKeySet t.Run("GetJwkSetKey after create", func(t *testing.T) { - result, _, err := sdk.JwkApi.GetJsonWebKey(ctx, "set-foo", expectedKid).Execute() + result, _, err := sdk.JwkAPI.GetJsonWebKey(ctx, "set-foo", expectedKid).Execute() require.NoError(t, err) require.Len(t, result.Keys, 1) require.Equal(t, expectedKid, result.Keys[0].Kid) @@ -73,19 +72,19 @@ func TestJWKSDK(t *testing.T) { require.Len(t, resultKeys.Keys, 1) resultKeys.Keys[0].Alg = "ES256" - resultKey, _, err := sdk.JwkApi.SetJsonWebKey(ctx, "set-foo", expectedKid).JsonWebKey(resultKeys.Keys[0]).Execute() + resultKey, _, err := sdk.JwkAPI.SetJsonWebKey(ctx, "set-foo", expectedKid).JsonWebKey(resultKeys.Keys[0]).Execute() require.NoError(t, err) assert.Equal(t, expectedKid, resultKey.Kid) assert.Equal(t, "ES256", resultKey.Alg) }) t.Run("DeleteJwkSetKey after delete", func(t *testing.T) { - _, err := sdk.JwkApi.DeleteJsonWebKey(ctx, "set-foo", expectedKid).Execute() + _, err := sdk.JwkAPI.DeleteJsonWebKey(ctx, "set-foo", expectedKid).Execute() require.NoError(t, err) }) t.Run("GetJwkSetKey after delete", func(t *testing.T) { - _, res, err := sdk.JwkApi.GetJsonWebKey(ctx, "set-foo", expectedKid).Execute() + _, res, err := sdk.JwkAPI.GetJsonWebKey(ctx, "set-foo", expectedKid).Execute() require.Error(t, err) assert.Equal(t, http.StatusNotFound, res.StatusCode) }) @@ -93,10 +92,12 @@ func TestJWKSDK(t *testing.T) { }) t.Run("JWK Set", func(t *testing.T) { + t.Parallel() t.Run("CreateJwkSetKey", func(t *testing.T) { - resultKeys, _, err := sdk.JwkApi.CreateJsonWebKeySet(ctx, "set-foo2").CreateJsonWebKeySet(hydra.CreateJsonWebKeySet{ + resultKeys, _, err := sdk.JwkAPI.CreateJsonWebKeySet(ctx, "set-foo2").CreateJsonWebKeySet(hydra.CreateJsonWebKeySet{ Alg: "RS256", Kid: "key-bar", + Use: "sig", }).Execute() require.NoError(t, err) require.Len(t, resultKeys.Keys, 1) @@ -104,7 +105,7 @@ func TestJWKSDK(t *testing.T) { assert.Equal(t, "RS256", resultKeys.Keys[0].Alg) }) - resultKeys, _, err := sdk.JwkApi.GetJsonWebKeySet(ctx, "set-foo2").Execute() + resultKeys, _, err := sdk.JwkAPI.GetJsonWebKeySet(ctx, "set-foo2").Execute() t.Run("GetJwkSet after create", func(t *testing.T) { require.NoError(t, err) if conf.HSMEnabled() { @@ -125,7 +126,7 @@ func TestJWKSDK(t *testing.T) { require.Len(t, resultKeys.Keys, 1) resultKeys.Keys[0].Alg = "ES256" - result, _, err := sdk.JwkApi.SetJsonWebKeySet(ctx, "set-foo2").JsonWebKeySet(*resultKeys).Execute() + result, _, err := sdk.JwkAPI.SetJsonWebKeySet(ctx, "set-foo2").JsonWebKeySet(*resultKeys).Execute() require.NoError(t, err) require.Len(t, result.Keys, 1) assert.Equal(t, expectedKid, result.Keys[0].Kid) @@ -133,18 +134,18 @@ func TestJWKSDK(t *testing.T) { }) t.Run("DeleteJwkSet", func(t *testing.T) { - _, err := sdk.JwkApi.DeleteJsonWebKeySet(ctx, "set-foo2").Execute() + _, err := sdk.JwkAPI.DeleteJsonWebKeySet(ctx, "set-foo2").Execute() require.NoError(t, err) }) t.Run("GetJwkSet after delete", func(t *testing.T) { - _, res, err := sdk.JwkApi.GetJsonWebKeySet(ctx, "set-foo2").Execute() + _, res, err := sdk.JwkAPI.GetJsonWebKeySet(ctx, "set-foo2").Execute() require.Error(t, err) assert.Equal(t, http.StatusNotFound, res.StatusCode) }) t.Run("GetJwkSetKey after delete", func(t *testing.T) { - _, res, err := sdk.JwkApi.GetJsonWebKey(ctx, "set-foo2", expectedKid).Execute() + _, res, err := sdk.JwkAPI.GetJsonWebKey(ctx, "set-foo2", expectedKid).Execute() require.Error(t, err) assert.Equal(t, http.StatusNotFound, res.StatusCode) }) diff --git a/main.go b/main.go index 9697e46b2ad..f897ce57eb1 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,7 @@ package main import ( - "github.com/ory/hydra/cmd" + "github.com/ory/hydra/v2/cmd" "github.com/ory/x/profilex" ) diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=legacy.json similarity index 92% rename from oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured.json rename to oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=legacy.json index 66fbfb5af98..61dfba78726 100644 --- a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured.json +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=legacy.json @@ -29,7 +29,8 @@ "client_id": "app-client", "consent_challenge": "", "exclude_not_before_claim": false, - "allowed_top_level_claims": [] + "allowed_top_level_claims": [], + "mirror_top_level_claims": true }, "requester": { "client_id": "app-client", diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=new.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=new.json new file mode 100644 index 00000000000..3748c3744f1 --- /dev/null +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=new.json @@ -0,0 +1,53 @@ +{ + "session": { + "id_token": { + "id_token_claims": { + "jti": "", + "iss": "http://localhost:4444/", + "sub": "foo", + "aud": [ + "app-client" + ], + "nonce": "", + "at_hash": "", + "acr": "1", + "amr": null, + "c_hash": "", + "ext": { + "hooked": "legacy" + } + }, + "headers": { + "extra": { + } + }, + "username": "", + "subject": "foo" + }, + "extra": { + "hooked": "legacy" + }, + "client_id": "app-client", + "consent_challenge": "", + "exclude_not_before_claim": false, + "allowed_top_level_claims": [], + "mirror_top_level_claims": true + }, + "request": { + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [], + "grant_types": [ + "refresh_token" + ], + "payload": { + "grant_type": [ + "refresh_token" + ] + } + } +} diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=legacy.json similarity index 92% rename from oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured.json rename to oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=legacy.json index 66fbfb5af98..61dfba78726 100644 --- a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured.json +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=legacy.json @@ -29,7 +29,8 @@ "client_id": "app-client", "consent_challenge": "", "exclude_not_before_claim": false, - "allowed_top_level_claims": [] + "allowed_top_level_claims": [], + "mirror_top_level_claims": true }, "requester": { "client_id": "app-client", diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=new.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=new.json new file mode 100644 index 00000000000..3748c3744f1 --- /dev/null +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=new.json @@ -0,0 +1,53 @@ +{ + "session": { + "id_token": { + "id_token_claims": { + "jti": "", + "iss": "http://localhost:4444/", + "sub": "foo", + "aud": [ + "app-client" + ], + "nonce": "", + "at_hash": "", + "acr": "1", + "amr": null, + "c_hash": "", + "ext": { + "hooked": "legacy" + } + }, + "headers": { + "extra": { + } + }, + "username": "", + "subject": "foo" + }, + "extra": { + "hooked": "legacy" + }, + "client_id": "app-client", + "consent_challenge": "", + "exclude_not_before_claim": false, + "allowed_top_level_claims": [], + "mirror_top_level_claims": true + }, + "request": { + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [], + "grant_types": [ + "refresh_token" + ], + "payload": { + "grant_type": [ + "refresh_token" + ] + } + } +} diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=legacy.json similarity index 92% rename from oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured.json rename to oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=legacy.json index 66fbfb5af98..61dfba78726 100644 --- a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured.json +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=legacy.json @@ -29,7 +29,8 @@ "client_id": "app-client", "consent_challenge": "", "exclude_not_before_claim": false, - "allowed_top_level_claims": [] + "allowed_top_level_claims": [], + "mirror_top_level_claims": true }, "requester": { "client_id": "app-client", diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=new.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=new.json new file mode 100644 index 00000000000..3748c3744f1 --- /dev/null +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=new.json @@ -0,0 +1,53 @@ +{ + "session": { + "id_token": { + "id_token_claims": { + "jti": "", + "iss": "http://localhost:4444/", + "sub": "foo", + "aud": [ + "app-client" + ], + "nonce": "", + "at_hash": "", + "acr": "1", + "amr": null, + "c_hash": "", + "ext": { + "hooked": "legacy" + } + }, + "headers": { + "extra": { + } + }, + "username": "", + "subject": "foo" + }, + "extra": { + "hooked": "legacy" + }, + "client_id": "app-client", + "consent_challenge": "", + "exclude_not_before_claim": false, + "allowed_top_level_claims": [], + "mirror_top_level_claims": true + }, + "request": { + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [], + "grant_types": [ + "refresh_token" + ], + "payload": { + "grant_type": [ + "refresh_token" + ] + } + } +} diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=legacy.json similarity index 92% rename from oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured.json rename to oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=legacy.json index 66fbfb5af98..61dfba78726 100644 --- a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=jwt-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured.json +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=legacy.json @@ -29,7 +29,8 @@ "client_id": "app-client", "consent_challenge": "", "exclude_not_before_claim": false, - "allowed_top_level_claims": [] + "allowed_top_level_claims": [], + "mirror_top_level_claims": true }, "requester": { "client_id": "app-client", diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=new.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=new.json new file mode 100644 index 00000000000..3748c3744f1 --- /dev/null +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=0-description=should_pass_request_if_strategy_passes-should_call_refresh_token_hook_if_configured-hook=new.json @@ -0,0 +1,53 @@ +{ + "session": { + "id_token": { + "id_token_claims": { + "jti": "", + "iss": "http://localhost:4444/", + "sub": "foo", + "aud": [ + "app-client" + ], + "nonce": "", + "at_hash": "", + "acr": "1", + "amr": null, + "c_hash": "", + "ext": { + "hooked": "legacy" + } + }, + "headers": { + "extra": { + } + }, + "username": "", + "subject": "foo" + }, + "extra": { + "hooked": "legacy" + }, + "client_id": "app-client", + "consent_challenge": "", + "exclude_not_before_claim": false, + "allowed_top_level_claims": [], + "mirror_top_level_claims": true + }, + "request": { + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [], + "grant_types": [ + "refresh_token" + ], + "payload": { + "grant_type": [ + "refresh_token" + ] + } + } +} diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=legacy.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=legacy.json new file mode 100644 index 00000000000..61dfba78726 --- /dev/null +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=legacy.json @@ -0,0 +1,54 @@ +{ + "subject": "foo", + "session": { + "id_token": { + "id_token_claims": { + "jti": "", + "iss": "http://localhost:4444/", + "sub": "foo", + "aud": [ + "app-client" + ], + "nonce": "", + "at_hash": "", + "acr": "1", + "amr": null, + "c_hash": "", + "ext": { + "sid": "" + } + }, + "headers": { + "extra": { + } + }, + "username": "", + "subject": "foo" + }, + "extra": {}, + "client_id": "app-client", + "consent_challenge": "", + "exclude_not_before_claim": false, + "allowed_top_level_claims": [], + "mirror_top_level_claims": true + }, + "requester": { + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [], + "grant_types": [ + "refresh_token" + ] + }, + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [] +} diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=new.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=new.json new file mode 100644 index 00000000000..3748c3744f1 --- /dev/null +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured-hook=new.json @@ -0,0 +1,53 @@ +{ + "session": { + "id_token": { + "id_token_claims": { + "jti": "", + "iss": "http://localhost:4444/", + "sub": "foo", + "aud": [ + "app-client" + ], + "nonce": "", + "at_hash": "", + "acr": "1", + "amr": null, + "c_hash": "", + "ext": { + "hooked": "legacy" + } + }, + "headers": { + "extra": { + } + }, + "username": "", + "subject": "foo" + }, + "extra": { + "hooked": "legacy" + }, + "client_id": "app-client", + "consent_challenge": "", + "exclude_not_before_claim": false, + "allowed_top_level_claims": [], + "mirror_top_level_claims": true + }, + "request": { + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [], + "grant_types": [ + "refresh_token" + ], + "payload": { + "grant_type": [ + "refresh_token" + ] + } + } +} diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured.json deleted file mode 100644 index 66fbfb5af98..00000000000 --- a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=2-description=should_pass_because_prompt=none_and_max_age_is_less_than_auth_time-should_call_refresh_token_hook_if_configured.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "subject": "foo", - "session": { - "id_token": { - "id_token_claims": { - "jti": "", - "iss": "http://localhost:4444/", - "sub": "foo", - "aud": [ - "app-client" - ], - "nonce": "", - "at_hash": "", - "acr": "1", - "amr": null, - "c_hash": "", - "ext": { - "sid": "" - } - }, - "headers": { - "extra": { - } - }, - "username": "", - "subject": "foo" - }, - "extra": {}, - "client_id": "app-client", - "consent_challenge": "", - "exclude_not_before_claim": false, - "allowed_top_level_claims": [] - }, - "requester": { - "client_id": "app-client", - "granted_scopes": [ - "offline", - "openid", - "hydra.*" - ], - "granted_audience": [], - "grant_types": [ - "refresh_token" - ] - }, - "client_id": "app-client", - "granted_scopes": [ - "offline", - "openid", - "hydra.*" - ], - "granted_audience": [] -} diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=legacy.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=legacy.json new file mode 100644 index 00000000000..61dfba78726 --- /dev/null +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=legacy.json @@ -0,0 +1,54 @@ +{ + "subject": "foo", + "session": { + "id_token": { + "id_token_claims": { + "jti": "", + "iss": "http://localhost:4444/", + "sub": "foo", + "aud": [ + "app-client" + ], + "nonce": "", + "at_hash": "", + "acr": "1", + "amr": null, + "c_hash": "", + "ext": { + "sid": "" + } + }, + "headers": { + "extra": { + } + }, + "username": "", + "subject": "foo" + }, + "extra": {}, + "client_id": "app-client", + "consent_challenge": "", + "exclude_not_before_claim": false, + "allowed_top_level_claims": [], + "mirror_top_level_claims": true + }, + "requester": { + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [], + "grant_types": [ + "refresh_token" + ] + }, + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [] +} diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=new.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=new.json new file mode 100644 index 00000000000..3748c3744f1 --- /dev/null +++ b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured-hook=new.json @@ -0,0 +1,53 @@ +{ + "session": { + "id_token": { + "id_token_claims": { + "jti": "", + "iss": "http://localhost:4444/", + "sub": "foo", + "aud": [ + "app-client" + ], + "nonce": "", + "at_hash": "", + "acr": "1", + "amr": null, + "c_hash": "", + "ext": { + "hooked": "legacy" + } + }, + "headers": { + "extra": { + } + }, + "username": "", + "subject": "foo" + }, + "extra": { + "hooked": "legacy" + }, + "client_id": "app-client", + "consent_challenge": "", + "exclude_not_before_claim": false, + "allowed_top_level_claims": [], + "mirror_top_level_claims": true + }, + "request": { + "client_id": "app-client", + "granted_scopes": [ + "offline", + "openid", + "hydra.*" + ], + "granted_audience": [], + "grant_types": [ + "refresh_token" + ], + "payload": { + "grant_type": [ + "refresh_token" + ] + } + } +} diff --git a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured.json b/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured.json deleted file mode 100644 index 66fbfb5af98..00000000000 --- a/oauth2/.snapshots/TestAuthCodeWithMockStrategy-strategy=opaque-case=5-description=should_pass_with_prompt=login_when_authentication_time_is_recent-should_call_refresh_token_hook_if_configured.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "subject": "foo", - "session": { - "id_token": { - "id_token_claims": { - "jti": "", - "iss": "http://localhost:4444/", - "sub": "foo", - "aud": [ - "app-client" - ], - "nonce": "", - "at_hash": "", - "acr": "1", - "amr": null, - "c_hash": "", - "ext": { - "sid": "" - } - }, - "headers": { - "extra": { - } - }, - "username": "", - "subject": "foo" - }, - "extra": {}, - "client_id": "app-client", - "consent_challenge": "", - "exclude_not_before_claim": false, - "allowed_top_level_claims": [] - }, - "requester": { - "client_id": "app-client", - "granted_scopes": [ - "offline", - "openid", - "hydra.*" - ], - "granted_audience": [], - "grant_types": [ - "refresh_token" - ] - }, - "client_id": "app-client", - "granted_scopes": [ - "offline", - "openid", - "hydra.*" - ], - "granted_audience": [] -} diff --git a/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=false.json b/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=false.json index 330e25c43a4..5bc92ec79a5 100644 --- a/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=false.json +++ b/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=false.json @@ -10,6 +10,31 @@ "plain", "S256" ], + "credentials_endpoint_draft_00": "http://hydra.localhost/credentials", + "credentials_supported_draft_00": [ + { + "cryptographic_binding_methods_supported": [ + "jwk" + ], + "cryptographic_suites_supported": [ + "PS256", + "RS256", + "ES256", + "PS384", + "RS384", + "ES384", + "PS512", + "RS512", + "ES512", + "EdDSA" + ], + "format": "jwt_vc_json", + "types": [ + "VerifiableCredential", + "UserInfoCredential" + ] + } + ], "end_session_endpoint": "http://hydra.localhost/oauth2/sessions/logout", "frontchannel_logout_session_supported": true, "frontchannel_logout_supported": true, @@ -38,7 +63,8 @@ "require_request_uri_registration": true, "response_modes_supported": [ "query", - "fragment" + "fragment", + "form_post" ], "response_types_supported": [ "code", diff --git a/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=true.json b/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=true.json index 330e25c43a4..5bc92ec79a5 100644 --- a/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=true.json +++ b/oauth2/.snapshots/TestHandlerWellKnown-hsm_enabled=true.json @@ -10,6 +10,31 @@ "plain", "S256" ], + "credentials_endpoint_draft_00": "http://hydra.localhost/credentials", + "credentials_supported_draft_00": [ + { + "cryptographic_binding_methods_supported": [ + "jwk" + ], + "cryptographic_suites_supported": [ + "PS256", + "RS256", + "ES256", + "PS384", + "RS384", + "ES384", + "PS512", + "RS512", + "ES512", + "EdDSA" + ], + "format": "jwt_vc_json", + "types": [ + "VerifiableCredential", + "UserInfoCredential" + ] + } + ], "end_session_endpoint": "http://hydra.localhost/oauth2/sessions/logout", "frontchannel_logout_session_supported": true, "frontchannel_logout_supported": true, @@ -38,7 +63,8 @@ "require_request_uri_registration": true, "response_modes_supported": [ "query", - "fragment" + "fragment", + "form_post" ], "response_types_supported": [ "code", diff --git a/oauth2/.snapshots/TestUnmarshalSession-v1.11.8.json b/oauth2/.snapshots/TestUnmarshalSession-v1.11.8.json index 723df624f4a..03e8881ee72 100644 --- a/oauth2/.snapshots/TestUnmarshalSession-v1.11.8.json +++ b/oauth2/.snapshots/TestUnmarshalSession-v1.11.8.json @@ -17,7 +17,8 @@ "amr": [], "c_hash": "", "ext": { - "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d" + "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d", + "timestamp": 1723546027 } }, "headers": { @@ -45,5 +46,6 @@ "market", "zone", "login_session_id" - ] + ], + "mirror_top_level_claims": false } diff --git a/oauth2/.snapshots/TestUnmarshalSession-v1.11.9.json b/oauth2/.snapshots/TestUnmarshalSession-v1.11.9.json index 723df624f4a..03e8881ee72 100644 --- a/oauth2/.snapshots/TestUnmarshalSession-v1.11.9.json +++ b/oauth2/.snapshots/TestUnmarshalSession-v1.11.9.json @@ -17,7 +17,8 @@ "amr": [], "c_hash": "", "ext": { - "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d" + "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d", + "timestamp": 1723546027 } }, "headers": { @@ -45,5 +46,6 @@ "market", "zone", "login_session_id" - ] + ], + "mirror_top_level_claims": false } diff --git a/oauth2/fixtures/v1.11.8-session.json b/oauth2/fixtures/v1.11.8-session.json index a7070d03c32..4608026d74e 100644 --- a/oauth2/fixtures/v1.11.8-session.json +++ b/oauth2/fixtures/v1.11.8-session.json @@ -15,7 +15,8 @@ "AuthenticationMethodsReferences": [], "CodeHash": "", "Extra": { - "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d" + "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d", + "timestamp": 1723546027 } }, "Headers": { diff --git a/oauth2/fixtures/v1.11.9-session.json b/oauth2/fixtures/v1.11.9-session.json index 2ded034a556..9636d07b8d6 100644 --- a/oauth2/fixtures/v1.11.9-session.json +++ b/oauth2/fixtures/v1.11.9-session.json @@ -15,7 +15,8 @@ "amr": [], "c_hash": "", "ext": { - "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d" + "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d", + "timestamp": 1723546027 } }, "headers": { diff --git a/oauth2/flowctx/encoding.go b/oauth2/flowctx/encoding.go new file mode 100644 index 00000000000..8a1f8cbf270 --- /dev/null +++ b/oauth2/flowctx/encoding.go @@ -0,0 +1,101 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package flowctx + +import ( + "bytes" + "compress/gzip" + "context" + "encoding/json" + + "github.com/pkg/errors" + + "github.com/ory/hydra/v2/aead" +) + +type ( + data struct { + Purpose purpose `json:"p,omitempty"` + } + purpose int + CodecOption func(ad *data) +) + +const ( + loginChallenge purpose = iota + loginVerifier + consentChallenge + consentVerifier +) + +func withPurpose(purpose purpose) CodecOption { return func(ad *data) { ad.Purpose = purpose } } + +var ( + AsLoginChallenge = withPurpose(loginChallenge) + AsLoginVerifier = withPurpose(loginVerifier) + AsConsentChallenge = withPurpose(consentChallenge) + AsConsentVerifier = withPurpose(consentVerifier) +) + +func additionalDataFromOpts(opts ...CodecOption) []byte { + if len(opts) == 0 { + return nil + } + ad := &data{} + for _, o := range opts { + o(ad) + } + b, err := json.Marshal(ad) + if err != nil { + // Panic is OK here because the struct and the parameters are all known. + panic("failed to marshal additional data: " + errors.WithStack(err).Error()) + } + + return b +} + +// Decode decodes the given string to a value. +func Decode[T any](ctx context.Context, cipher aead.Cipher, encoded string, opts ...CodecOption) (*T, error) { + plaintext, err := cipher.Decrypt(ctx, encoded, additionalDataFromOpts(opts...)) + if err != nil { + return nil, err + } + + rawBytes, err := gzip.NewReader(bytes.NewReader(plaintext)) + if err != nil { + return nil, err + } + defer func() { _ = rawBytes.Close() }() + + var val T + if err = json.NewDecoder(rawBytes).Decode(&val); err != nil { + return nil, err + } + + return &val, nil +} + +// Encode encodes the given value to a string. +func Encode(ctx context.Context, cipher aead.Cipher, val any, opts ...CodecOption) (s string, err error) { + // Steps: + // 1. Encode to JSON + // 2. GZIP + // 3. Encrypt with AEAD (XChaCha20-Poly1305) + Base64 URL-encode + var b bytes.Buffer + + gz, err := gzip.NewWriterLevel(&b, gzip.BestCompression) + if err != nil { + return "", err + } + + if err = json.NewEncoder(gz).Encode(val); err != nil { + return "", err + } + + if err = gz.Close(); err != nil { + return "", err + } + + return cipher.Encrypt(ctx, b.Bytes(), additionalDataFromOpts(opts...)) +} diff --git a/oauth2/flowctx/encoding_test.go b/oauth2/flowctx/encoding_test.go new file mode 100644 index 00000000000..4d2ee89e62a --- /dev/null +++ b/oauth2/flowctx/encoding_test.go @@ -0,0 +1,134 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package flowctx_test + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/gofrs/uuid" + "github.com/stretchr/testify/require" + + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/oauth2/flowctx" + "github.com/ory/x/pointerx" + "github.com/ory/x/sqlxx" +) + +func TestEncoding(t *testing.T) { + f := flow.Flow{ + ID: uuid.Must(uuid.NewV4()).String(), + NID: uuid.Must(uuid.NewV4()), + RequestedScope: []string{"scope1", "scope2"}, + RequestedAudience: []string{"https://api.example.org/v1", "https://api.example.org/v2"}, + LoginSkip: false, + Subject: "some-subject@some-idp-somewhere.com", + OpenIDConnectContext: &flow.OAuth2ConsentRequestOpenIDConnectContext{ + ACRValues: []string{"acr1", "acr2"}, + UILocales: []string{"en-US", "en-GB"}, + Display: "page", + IDTokenHintClaims: map[string]interface{}{"claim1": "value1", "claim2": "value2"}, + LoginHint: "some-login-hint", + }, + Client: &client.Client{ + ID: uuid.Must(uuid.NewV4()).String(), + NID: uuid.Must(uuid.NewV4()), + Name: "some-client-name", + Secret: "some-supersafe-secret", + RedirectURIs: []string{ + "https://redirect1.example.org/callback", + "https://redirect2.example.org/callback", + }, + GrantTypes: []string{"authorization_code", "refresh_token"}, + ResponseTypes: []string{"code"}, + Scope: "scope1 scope2", + Audience: sqlxx.StringSliceJSONFormat{"https://api.example.org/v1 https://api.example.org/v2"}, + Owner: "some-owner", + TermsOfServiceURI: "https://tos.example.org", + PolicyURI: "https://policy.example.org", + ClientURI: "https://client.example.org", + LogoURI: "https://logo.example.org", + Contacts: []string{"contact1", "contact2"}, + SubjectType: "public", + JSONWebKeysURI: "https://jwks.example.org", + JSONWebKeys: nil, // TODO? + TokenEndpointAuthMethod: "client_secret_basic", + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + AllowedCORSOrigins: []string{"https://cors1.example.org", "https://cors2.example.org"}, + Metadata: sqlxx.JSONRawMessage(`{"client-metadata-key1": "val1"}`), + AccessTokenStrategy: "jwt", + SkipConsent: true, + }, + RequestURL: "https://auth.hydra.local/oauth2/auth?client_id=some-client-id&response_type=code&scope=scope1+scope2&redirect_uri=https%3A%2F%2Fredirect1.example.org%2Fcallback&state=some-state&nonce=some-nonce", + SessionID: sqlxx.NullString("some-session-id"), + LoginCSRF: uuid.Must(uuid.NewV4()).String(), + LoginInitializedAt: sqlxx.NullTime(time.Now()), + RequestedAt: time.Now(), + State: 1, + LoginRemember: true, + LoginRememberFor: 3600, + Context: sqlxx.JSONRawMessage(`{"context-key1": "val1"}`), + GrantedScope: []string{"scope1", "scope2"}, + GrantedAudience: []string{"https://api.example.org/v1", "https://api.example.org/v2"}, + ConsentRemember: true, + ConsentRememberFor: pointerx.Int(3600), + ConsentHandledAt: sqlxx.NullTime(time.Now()), + SessionIDToken: sqlxx.MapStringInterface{ + "session-id-token-key1": "val1", + "session-id-token-key2": "val2", + uuid.Must(uuid.NewV4()).String(): "val3", + uuid.Must(uuid.NewV4()).String(): "val4", + uuid.Must(uuid.NewV4()).String(): "val5", + }, + SessionAccessToken: sqlxx.MapStringInterface{ + "session-access-token-key1": "val1", + "session-access-token-key2": "val2", + uuid.Must(uuid.NewV4()).String(): "val3", + uuid.Must(uuid.NewV4()).String(): "val4", + uuid.Must(uuid.NewV4()).String(): "val5", + }, + } + + ctx := context.Background() + + t.Run("with client", func(t *testing.T) { + j, err := json.Marshal(f) + require.NoError(t, err) + t.Logf("Length (JSON): %d", len(j)) + cp := new(cipherProvider) + consentVerifier, err := flowctx.Encode(ctx, cp.FlowCipher(), f, flowctx.AsConsentVerifier) + require.NoError(t, err) + t.Logf("Length (JSON+GZIP+AEAD): %d", len(consentVerifier)) + }) + t.Run("without client", func(t *testing.T) { + f := f + f.Client = nil + j, err := json.Marshal(f) + require.NoError(t, err) + t.Logf("Length (JSON): %d", len(j)) + cp := new(cipherProvider) + consentVerifier, err := f.ToConsentVerifier(ctx, cp) + require.NoError(t, err) + t.Logf("Length (JSON+GZIP+AEAD): %d", len(consentVerifier)) + }) +} + +type cipherProvider struct{} + +func (c *cipherProvider) FlowCipher() *aead.XChaCha20Poly1305 { + return aead.NewXChaCha20Poly1305(c) +} + +func (c *cipherProvider) GetGlobalSecret(context.Context) ([]byte, error) { + return []byte("supersecret123456789123456789012"), nil +} + +func (c *cipherProvider) GetRotatedGlobalSecrets(ctx context.Context) ([][]byte, error) { + return nil, nil +} diff --git a/oauth2/fosite_store_helpers.go b/oauth2/fosite_store_helpers.go index d17f5fa25ea..553a6bae62b 100644 --- a/oauth2/fosite_store_helpers.go +++ b/oauth2/fosite_store_helpers.go @@ -8,20 +8,25 @@ import ( "crypto/sha256" "fmt" "net/url" + "slices" "testing" "time" - "github.com/ory/hydra/jwk" + "github.com/ory/x/assertx" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/jwk" + + "github.com/go-jose/go-jose/v3" "github.com/gobuffalo/pop/v6" "github.com/pborman/uuid" - "gopkg.in/square/go-jose.v2" "github.com/ory/fosite/handler/rfc7523" - "github.com/ory/hydra/oauth2/trust" + "github.com/ory/hydra/v2/oauth2/trust" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/x" "github.com/ory/fosite/storage" "github.com/ory/x/sqlxx" @@ -35,8 +40,7 @@ import ( "github.com/ory/fosite/handler/openid" "github.com/ory/x/sqlcon" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" + "github.com/ory/hydra/v2/client" ) func signatureFromJTI(jti string) string { @@ -76,16 +80,40 @@ type AssertionJWTReader interface { SetClientAssertionJWTRaw(context.Context, *BlacklistedJTI) error } +var defaultIgnoreKeys = []string{ + "id", + "session", + "requested_scope", + "granted_scope", + "form", + "created_at", + "updated_at", + "client.created_at", + "client.updated_at", + "requestedAt", + "client.client_secret", +} + var defaultRequest = fosite.Request{ - ID: "blank", - RequestedAt: time.Now().UTC().Round(time.Second), - Client: &client.Client{LegacyClientID: "foobar"}, + ID: "blank", + RequestedAt: time.Now().UTC().Round(time.Second), + Client: &client.Client{ + ID: "foobar", + Contacts: []string{}, + RedirectURIs: []string{}, + Audience: []string{}, + AllowedCORSOrigins: []string{}, + ResponseTypes: []string{}, + GrantTypes: []string{}, + JSONWebKeys: &x.JoseJSONWebKeySet{}, + Metadata: sqlxx.JSONRawMessage("{}"), + }, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, RequestedAudience: fosite.Arguments{"ad1", "ad2"}, GrantedAudience: fosite.Arguments{"ad1", "ad2"}, Form: url.Values{"foo": []string{"bar", "baz"}}, - Session: &Session{DefaultSession: &openid.DefaultSession{Subject: "bar"}}, + Session: NewSession("bar"), } var lifespan = time.Hour @@ -93,7 +121,7 @@ var flushRequests = []*fosite.Request{ { ID: "flush-1", RequestedAt: time.Now().Round(time.Second), - Client: &client.Client{LegacyClientID: "foobar"}, + Client: &client.Client{ID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -102,7 +130,7 @@ var flushRequests = []*fosite.Request{ { ID: "flush-2", RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Minute)), - Client: &client.Client{LegacyClientID: "foobar"}, + Client: &client.Client{ID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -111,7 +139,7 @@ var flushRequests = []*fosite.Request{ { ID: "flush-3", RequestedAt: time.Now().Round(time.Second).Add(-(lifespan + time.Hour)), - Client: &client.Client{LegacyClientID: "foobar"}, + Client: &client.Client{ID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -119,11 +147,11 @@ var flushRequests = []*fosite.Request{ }, } -func mockRequestForeignKey(t *testing.T, id string, x InternalRegistry, createClient bool) { - cl := &client.Client{LegacyClientID: "foobar"} - cr := &consent.OAuth2ConsentRequest{ +func mockRequestForeignKey(t *testing.T, id string, x InternalRegistry) { + cl := &client.Client{ID: "foobar"} + cr := &flow.OAuth2ConsentRequest{ Client: cl, - OpenIDConnectContext: new(consent.OAuth2ConsentRequestOpenIDConnectContext), + OpenIDConnectContext: new(flow.OAuth2ConsentRequestOpenIDConnectContext), LoginChallenge: sqlxx.NullString(id), ID: id, Verifier: id, @@ -132,18 +160,36 @@ func mockRequestForeignKey(t *testing.T, id string, x InternalRegistry, createCl RequestedAt: time.Now(), } - if createClient { - require.NoError(t, x.ClientManager().CreateClient(context.Background(), cl)) + ctx := context.Background() + if _, err := x.ClientManager().GetClient(ctx, cl.ID); errors.Is(err, sqlcon.ErrNoRows) { + require.NoError(t, x.ClientManager().CreateClient(ctx, cl)) } - require.NoError(t, x.ConsentManager().CreateLoginRequest(context.Background(), &consent.LoginRequest{Client: cl, OpenIDConnectContext: new(consent.OAuth2ConsentRequestOpenIDConnectContext), ID: id, Verifier: id, AuthenticatedAt: sqlxx.NullTime(time.Now()), RequestedAt: time.Now()})) - require.NoError(t, x.ConsentManager().CreateConsentRequest(context.Background(), cr)) - _, err := x.ConsentManager().HandleConsentRequest(context.Background(), &consent.AcceptOAuth2ConsentRequest{ - ConsentRequest: cr, Session: new(consent.AcceptOAuth2ConsentRequestSession), AuthenticatedAt: sqlxx.NullTime(time.Now()), - ID: id, - RequestedAt: time.Now(), - HandledAt: sqlxx.NullTime(time.Now()), + f, err := x.ConsentManager().CreateLoginRequest( + ctx, &flow.LoginRequest{ + Client: cl, + OpenIDConnectContext: new(flow.OAuth2ConsentRequestOpenIDConnectContext), + ID: id, + Verifier: id, + AuthenticatedAt: sqlxx.NullTime(time.Now()), + RequestedAt: time.Now(), + }) + require.NoError(t, err) + err = x.ConsentManager().CreateConsentRequest(ctx, f, cr) + require.NoError(t, err) + + encodedFlow, err := f.ToConsentVerifier(ctx, x) + require.NoError(t, err) + + _, err = x.ConsentManager().HandleConsentRequest(ctx, f, &flow.AcceptOAuth2ConsentRequest{ + ConsentRequest: cr, + Session: new(flow.AcceptOAuth2ConsentRequestSession), + AuthenticatedAt: sqlxx.NullTime(time.Now()), + ID: encodedFlow, + RequestedAt: time.Now(), + HandledAt: sqlxx.NullTime(time.Now()), }) + require.NoError(t, err) } @@ -166,6 +212,7 @@ func TestHelperRunner(t *testing.T, store InternalRegistry, k string) { } t.Run(fmt.Sprintf("case=testHelperCreateGetDeleteAuthorizeCodes/db=%s", k), testHelperCreateGetDeleteAuthorizeCodes(store)) + t.Run(fmt.Sprintf("case=testHelperExpiryFields/db=%s", k), testHelperExpiryFields(store)) t.Run(fmt.Sprintf("case=testHelperCreateGetDeleteAccessTokenSession/db=%s", k), testHelperCreateGetDeleteAccessTokenSession(store)) t.Run(fmt.Sprintf("case=testHelperNilAccessToken/db=%s", k), testHelperNilAccessToken(store)) t.Run(fmt.Sprintf("case=testHelperCreateGetDeleteOpenIDConnectSession/db=%s", k), testHelperCreateGetDeleteOpenIDConnectSession(store)) @@ -179,32 +226,34 @@ func TestHelperRunner(t *testing.T, store InternalRegistry, k string) { t.Run(fmt.Sprintf("case=testHelperDeleteAccessTokens/db=%s", k), testHelperDeleteAccessTokens(store)) t.Run(fmt.Sprintf("case=testHelperRevokeAccessToken/db=%s", k), testHelperRevokeAccessToken(store)) t.Run(fmt.Sprintf("case=testFositeJWTBearerGrantStorage/db=%s", k), testFositeJWTBearerGrantStorage(store)) + t.Run(fmt.Sprintf("case=testHelperRevokeRefreshTokenMaybeGracePeriod/db=%s", k), testHelperRevokeRefreshTokenMaybeGracePeriod(store)) } func testHelperRequestIDMultiples(m InternalRegistry, _ string) func(t *testing.T) { return func(t *testing.T) { - requestId := uuid.New() - mockRequestForeignKey(t, requestId, m, true) - cl := &client.Client{LegacyClientID: "foobar"} + ctx := context.Background() + requestID := uuid.New() + mockRequestForeignKey(t, requestID, m) + cl := &client.Client{ID: "foobar"} fositeRequest := &fosite.Request{ - ID: requestId, + ID: requestID, Client: cl, RequestedAt: time.Now().UTC().Round(time.Second), - Session: &Session{}, + Session: NewSession("bar"), } for i := 0; i < 4; i++ { signature := uuid.New() - err := m.OAuth2Storage().CreateRefreshTokenSession(context.TODO(), signature, fositeRequest) + err := m.OAuth2Storage().CreateRefreshTokenSession(ctx, signature, fositeRequest) assert.NoError(t, err) - err = m.OAuth2Storage().CreateAccessTokenSession(context.TODO(), signature, fositeRequest) + err = m.OAuth2Storage().CreateAccessTokenSession(ctx, signature, fositeRequest) assert.NoError(t, err) - err = m.OAuth2Storage().CreateOpenIDConnectSession(context.TODO(), signature, fositeRequest) + err = m.OAuth2Storage().CreateOpenIDConnectSession(ctx, signature, fositeRequest) assert.NoError(t, err) - err = m.OAuth2Storage().CreatePKCERequestSession(context.TODO(), signature, fositeRequest) + err = m.OAuth2Storage().CreatePKCERequestSession(ctx, signature, fositeRequest) assert.NoError(t, err) - err = m.OAuth2Storage().CreateAuthorizeCodeSession(context.TODO(), signature, fositeRequest) + err = m.OAuth2Storage().CreateAuthorizeCodeSession(ctx, signature, fositeRequest) assert.NoError(t, err) } } @@ -215,20 +264,20 @@ func testHelperCreateGetDeleteOpenIDConnectSession(x InternalRegistry) func(t *t m := x.OAuth2Storage() ctx := context.Background() - _, err := m.GetOpenIDConnectSession(ctx, "4321", &fosite.Request{}) + _, err := m.GetOpenIDConnectSession(ctx, "4321", &fosite.Request{Session: NewSession("bar")}) assert.NotNil(t, err) err = m.CreateOpenIDConnectSession(ctx, "4321", &defaultRequest) require.NoError(t, err) - res, err := m.GetOpenIDConnectSession(ctx, "4321", &fosite.Request{Session: &Session{}}) + res, err := m.GetOpenIDConnectSession(ctx, "4321", &fosite.Request{Session: NewSession("bar")}) require.NoError(t, err) AssertObjectKeysEqual(t, &defaultRequest, res, "RequestedScope", "GrantedScope", "Form", "Session") err = m.DeleteOpenIDConnectSession(ctx, "4321") require.NoError(t, err) - _, err = m.GetOpenIDConnectSession(ctx, "4321", &fosite.Request{}) + _, err = m.GetOpenIDConnectSession(ctx, "4321", &fosite.Request{Session: NewSession("bar")}) assert.NotNil(t, err) } } @@ -238,20 +287,20 @@ func testHelperCreateGetDeleteRefreshTokenSession(x InternalRegistry) func(t *te m := x.OAuth2Storage() ctx := context.Background() - _, err := m.GetRefreshTokenSession(ctx, "4321", &Session{}) + _, err := m.GetRefreshTokenSession(ctx, "4321", NewSession("bar")) assert.NotNil(t, err) err = m.CreateRefreshTokenSession(ctx, "4321", &defaultRequest) require.NoError(t, err) - res, err := m.GetRefreshTokenSession(ctx, "4321", &Session{}) + res, err := m.GetRefreshTokenSession(ctx, "4321", NewSession("bar")) require.NoError(t, err) AssertObjectKeysEqual(t, &defaultRequest, res, "RequestedScope", "GrantedScope", "Form", "Session") err = m.DeleteRefreshTokenSession(ctx, "4321") require.NoError(t, err) - _, err = m.GetRefreshTokenSession(ctx, "4321", &Session{}) + _, err = m.GetRefreshTokenSession(ctx, "4321", NewSession("bar")) assert.NotNil(t, err) } } @@ -261,22 +310,32 @@ func testHelperRevokeRefreshToken(x InternalRegistry) func(t *testing.T) { m := x.OAuth2Storage() ctx := context.Background() - _, err := m.GetRefreshTokenSession(ctx, "1111", &Session{}) + _, err := m.GetRefreshTokenSession(ctx, "1111", NewSession("bar")) assert.Error(t, err) reqIdOne := uuid.New() reqIdTwo := uuid.New() - mockRequestForeignKey(t, reqIdOne, x, false) - mockRequestForeignKey(t, reqIdTwo, x, false) + mockRequestForeignKey(t, reqIdOne, x) + mockRequestForeignKey(t, reqIdTwo, x) - err = m.CreateRefreshTokenSession(ctx, "1111", &fosite.Request{ID: reqIdOne, Client: &client.Client{LegacyClientID: "foobar"}, RequestedAt: time.Now().UTC().Round(time.Second), Session: &Session{}}) + err = m.CreateRefreshTokenSession(ctx, "1111", &fosite.Request{ + ID: reqIdOne, + Client: &client.Client{ID: "foobar"}, + RequestedAt: time.Now().UTC().Round(time.Second), + Session: NewSession("user"), + }) require.NoError(t, err) - err = m.CreateRefreshTokenSession(ctx, "1122", &fosite.Request{ID: reqIdTwo, Client: &client.Client{LegacyClientID: "foobar"}, RequestedAt: time.Now().UTC().Round(time.Second), Session: &Session{}}) + err = m.CreateRefreshTokenSession(ctx, "1122", &fosite.Request{ + ID: reqIdTwo, + Client: &client.Client{ID: "foobar"}, + RequestedAt: time.Now().UTC().Round(time.Second), + Session: NewSession("user"), + }) require.NoError(t, err) - _, err = m.GetRefreshTokenSession(ctx, "1111", &Session{}) + _, err = m.GetRefreshTokenSession(ctx, "1111", NewSession("bar")) require.NoError(t, err) err = m.RevokeRefreshToken(ctx, reqIdOne) @@ -285,11 +344,11 @@ func testHelperRevokeRefreshToken(x InternalRegistry) func(t *testing.T) { err = m.RevokeRefreshToken(ctx, reqIdTwo) require.NoError(t, err) - req, err := m.GetRefreshTokenSession(ctx, "1111", &Session{}) + req, err := m.GetRefreshTokenSession(ctx, "1111", NewSession("bar")) assert.NotNil(t, req) assert.EqualError(t, err, fosite.ErrInactiveToken.Error()) - req, err = m.GetRefreshTokenSession(ctx, "1122", &Session{}) + req, err = m.GetRefreshTokenSession(ctx, "1122", NewSession("bar")) assert.NotNil(t, req) assert.EqualError(t, err, fosite.ErrInactiveToken.Error()) @@ -300,36 +359,126 @@ func testHelperCreateGetDeleteAuthorizeCodes(x InternalRegistry) func(t *testing return func(t *testing.T) { m := x.OAuth2Storage() - mockRequestForeignKey(t, "blank", x, false) + mockRequestForeignKey(t, "blank", x) ctx := context.Background() - res, err := m.GetAuthorizeCodeSession(ctx, "4321", &Session{}) + res, err := m.GetAuthorizeCodeSession(ctx, "4321", NewSession("bar")) assert.Error(t, err) assert.Nil(t, res) err = m.CreateAuthorizeCodeSession(ctx, "4321", &defaultRequest) require.NoError(t, err) - res, err = m.GetAuthorizeCodeSession(ctx, "4321", &Session{}) + res, err = m.GetAuthorizeCodeSession(ctx, "4321", NewSession("bar")) require.NoError(t, err) AssertObjectKeysEqual(t, &defaultRequest, res, "RequestedScope", "GrantedScope", "Form", "Session") err = m.InvalidateAuthorizeCodeSession(ctx, "4321") require.NoError(t, err) - res, err = m.GetAuthorizeCodeSession(ctx, "4321", &Session{}) + res, err = m.GetAuthorizeCodeSession(ctx, "4321", NewSession("bar")) require.Error(t, err) assert.EqualError(t, err, fosite.ErrInvalidatedAuthorizeCode.Error()) assert.NotNil(t, res) } } +type testHelperExpiryFieldsResult struct { + ExpiresAt time.Time `db:"expires_at"` + name string +} + +func (r testHelperExpiryFieldsResult) TableName() string { + return "hydra_oauth2_" + r.name +} + +func testHelperExpiryFields(reg InternalRegistry) func(t *testing.T) { + return func(t *testing.T) { + m := reg.OAuth2Storage() + t.Parallel() + + mockRequestForeignKey(t, "blank", reg) + + ctx := context.Background() + + s := NewSession("bar") + s.SetExpiresAt(fosite.AccessToken, time.Now().Add(time.Hour).Round(time.Minute)) + s.SetExpiresAt(fosite.RefreshToken, time.Now().Add(time.Hour*2).Round(time.Minute)) + s.SetExpiresAt(fosite.AuthorizeCode, time.Now().Add(time.Hour*3).Round(time.Minute)) + request := fosite.Request{ + ID: uuid.New(), + RequestedAt: time.Now().UTC().Round(time.Second), + Client: &client.Client{ + ID: "foobar", + Metadata: sqlxx.JSONRawMessage("{}"), + }, + RequestedScope: fosite.Arguments{"fa", "ba"}, + GrantedScope: fosite.Arguments{"fa", "ba"}, + RequestedAudience: fosite.Arguments{"ad1", "ad2"}, + GrantedAudience: fosite.Arguments{"ad1", "ad2"}, + Form: url.Values{"foo": []string{"bar", "baz"}}, + Session: s, + } + + t.Run("case=CreateAccessTokenSession", func(t *testing.T) { + id := uuid.New() + err := m.CreateAccessTokenSession(ctx, id, &request) + require.NoError(t, err) + + r := testHelperExpiryFieldsResult{name: "access"} + require.NoError(t, reg.Persister().Connection(ctx).Select("expires_at").Where("signature = ?", x.SignatureHash(id)).First(&r)) + + assert.EqualValues(t, s.GetExpiresAt(fosite.AccessToken).UTC(), r.ExpiresAt.UTC()) + }) + + t.Run("case=CreateRefreshTokenSession", func(t *testing.T) { + id := uuid.New() + err := m.CreateRefreshTokenSession(ctx, id, &request) + require.NoError(t, err) + + r := testHelperExpiryFieldsResult{name: "refresh"} + require.NoError(t, reg.Persister().Connection(ctx).Select("expires_at").Where("signature = ?", id).First(&r)) + assert.EqualValues(t, s.GetExpiresAt(fosite.RefreshToken).UTC(), r.ExpiresAt.UTC()) + }) + + t.Run("case=CreateAuthorizeCodeSession", func(t *testing.T) { + id := uuid.New() + err := m.CreateAuthorizeCodeSession(ctx, id, &request) + require.NoError(t, err) + + r := testHelperExpiryFieldsResult{name: "code"} + require.NoError(t, reg.Persister().Connection(ctx).Select("expires_at").Where("signature = ?", id).First(&r)) + assert.EqualValues(t, s.GetExpiresAt(fosite.AuthorizeCode).UTC(), r.ExpiresAt.UTC()) + }) + + t.Run("case=CreatePKCERequestSession", func(t *testing.T) { + id := uuid.New() + err := m.CreatePKCERequestSession(ctx, id, &request) + require.NoError(t, err) + + r := testHelperExpiryFieldsResult{name: "pkce"} + require.NoError(t, reg.Persister().Connection(ctx).Select("expires_at").Where("signature = ?", id).First(&r)) + assert.EqualValues(t, s.GetExpiresAt(fosite.AuthorizeCode).UTC(), r.ExpiresAt.UTC()) + }) + + t.Run("case=CreateOpenIDConnectSession", func(t *testing.T) { + id := uuid.New() + err := m.CreateOpenIDConnectSession(ctx, id, &request) + require.NoError(t, err) + + r := testHelperExpiryFieldsResult{name: "oidc"} + require.NoError(t, reg.Persister().Connection(ctx).Select("expires_at").Where("signature = ?", id).First(&r)) + assert.EqualValues(t, s.GetExpiresAt(fosite.AuthorizeCode).UTC(), r.ExpiresAt.UTC()) + }) + } +} + func testHelperNilAccessToken(x InternalRegistry) func(t *testing.T) { return func(t *testing.T) { m := x.OAuth2Storage() - c := &client.Client{LegacyClientID: "nil-request-client-id-123"} + c := &client.Client{ID: "nil-request-client-id-123"} require.NoError(t, x.ClientManager().CreateClient(context.Background(), c)) - err := m.CreateAccessTokenSession(context.TODO(), "nil-request-id", &fosite.Request{ + err := m.CreateAccessTokenSession(context.Background(), "nil-request-id", &fosite.Request{ ID: "", RequestedAt: time.Now().UTC().Round(time.Second), Client: c, @@ -338,7 +487,7 @@ func testHelperNilAccessToken(x InternalRegistry) func(t *testing.T) { RequestedAudience: fosite.Arguments{"ad1", "ad2"}, GrantedAudience: fosite.Arguments{"ad1", "ad2"}, Form: url.Values{"foo": []string{"bar", "baz"}}, - Session: &Session{DefaultSession: &openid.DefaultSession{Subject: "bar"}}, + Session: NewSession("bar"), }) require.NoError(t, err) } @@ -349,20 +498,20 @@ func testHelperCreateGetDeleteAccessTokenSession(x InternalRegistry) func(t *tes m := x.OAuth2Storage() ctx := context.Background() - _, err := m.GetAccessTokenSession(ctx, "4321", &Session{}) + _, err := m.GetAccessTokenSession(ctx, "4321", NewSession("bar")) assert.Error(t, err) err = m.CreateAccessTokenSession(ctx, "4321", &defaultRequest) require.NoError(t, err) - res, err := m.GetAccessTokenSession(ctx, "4321", &Session{}) + res, err := m.GetAccessTokenSession(ctx, "4321", NewSession("bar")) require.NoError(t, err) AssertObjectKeysEqual(t, &defaultRequest, res, "RequestedScope", "GrantedScope", "Form", "Session") err = m.DeleteAccessTokenSession(ctx, "4321") require.NoError(t, err) - _, err = m.GetAccessTokenSession(ctx, "4321", &Session{}) + _, err = m.GetAccessTokenSession(ctx, "4321", NewSession("bar")) assert.Error(t, err) } } @@ -375,13 +524,13 @@ func testHelperDeleteAccessTokens(x InternalRegistry) func(t *testing.T) { err := m.CreateAccessTokenSession(ctx, "4321", &defaultRequest) require.NoError(t, err) - _, err = m.GetAccessTokenSession(ctx, "4321", &Session{}) + _, err = m.GetAccessTokenSession(ctx, "4321", NewSession("bar")) require.NoError(t, err) err = m.DeleteAccessTokens(ctx, defaultRequest.Client.GetID()) require.NoError(t, err) - req, err := m.GetAccessTokenSession(ctx, "4321", &Session{}) + req, err := m.GetAccessTokenSession(ctx, "4321", NewSession("bar")) assert.Nil(t, req) assert.EqualError(t, err, fosite.ErrNotFound.Error()) } @@ -395,37 +544,94 @@ func testHelperRevokeAccessToken(x InternalRegistry) func(t *testing.T) { err := m.CreateAccessTokenSession(ctx, "4321", &defaultRequest) require.NoError(t, err) - _, err = m.GetAccessTokenSession(ctx, "4321", &Session{}) + _, err = m.GetAccessTokenSession(ctx, "4321", NewSession("bar")) require.NoError(t, err) err = m.RevokeAccessToken(ctx, defaultRequest.GetID()) require.NoError(t, err) - req, err := m.GetAccessTokenSession(ctx, "4321", &Session{}) + req, err := m.GetAccessTokenSession(ctx, "4321", NewSession("bar")) assert.Nil(t, req) assert.EqualError(t, err, fosite.ErrNotFound.Error()) } } +func testHelperRevokeRefreshTokenMaybeGracePeriod(x InternalRegistry) func(t *testing.T) { + return func(t *testing.T) { + ctx := context.Background() + + t.Run("Revokes refresh token when grace period not configured", func(t *testing.T) { + // SETUP + m := x.OAuth2Storage() + + refreshTokenSession := fmt.Sprintf("refresh_token_%d", time.Now().Unix()) + err := m.CreateRefreshTokenSession(ctx, refreshTokenSession, &defaultRequest) + require.NoError(t, err, "precondition failed: could not create refresh token session") + + // ACT + err = m.RevokeRefreshTokenMaybeGracePeriod(ctx, defaultRequest.GetID(), refreshTokenSession) + require.NoError(t, err) + + tmpSession := new(fosite.Session) + _, err = m.GetRefreshTokenSession(ctx, refreshTokenSession, *tmpSession) + + // ASSERT + // a revoked refresh token returns an error when getting the token again + assert.ErrorIs(t, err, fosite.ErrInactiveToken) + }) + + t.Run("refresh token enters grace period when configured,", func(t *testing.T) { + // SETUP + x.Config().MustSet(ctx, config.KeyRefreshTokenRotationGracePeriod, "1m") + + // always reset back to the default + t.Cleanup(func() { + x.Config().MustSet(ctx, config.KeyRefreshTokenRotationGracePeriod, "0m") + }) + + m := x.OAuth2Storage() + + refreshTokenSession := fmt.Sprintf("refresh_token_%d_with_grace_period", time.Now().Unix()) + err := m.CreateRefreshTokenSession(ctx, refreshTokenSession, &defaultRequest) + require.NoError(t, err, "precondition failed: could not create refresh token session") + + // ACT + require.NoError(t, m.RevokeRefreshTokenMaybeGracePeriod(ctx, defaultRequest.GetID(), refreshTokenSession)) + require.NoError(t, m.RevokeRefreshTokenMaybeGracePeriod(ctx, defaultRequest.GetID(), refreshTokenSession)) + require.NoError(t, m.RevokeRefreshTokenMaybeGracePeriod(ctx, defaultRequest.GetID(), refreshTokenSession)) + + req, err := m.GetRefreshTokenSession(ctx, refreshTokenSession, nil) + + // ASSERT + // when grace period is configured the refresh token can be obtained within + // the grace period without error + assert.NoError(t, err) + + assert.Equal(t, defaultRequest.GetID(), req.GetID()) + }) + } + +} + func testHelperCreateGetDeletePKCERequestSession(x InternalRegistry) func(t *testing.T) { return func(t *testing.T) { m := x.OAuth2Storage() ctx := context.Background() - _, err := m.GetPKCERequestSession(ctx, "4321", &Session{}) + _, err := m.GetPKCERequestSession(ctx, "4321", NewSession("bar")) assert.NotNil(t, err) err = m.CreatePKCERequestSession(ctx, "4321", &defaultRequest) require.NoError(t, err) - res, err := m.GetPKCERequestSession(ctx, "4321", &Session{}) + res, err := m.GetPKCERequestSession(ctx, "4321", NewSession("bar")) require.NoError(t, err) AssertObjectKeysEqual(t, &defaultRequest, res, "RequestedScope", "GrantedScope", "Form", "Session") err = m.DeletePKCERequestSession(ctx, "4321") require.NoError(t, err) - _, err = m.GetPKCERequestSession(ctx, "4321", &Session{}) + _, err = m.GetPKCERequestSession(ctx, "4321", NewSession("bar")) assert.NotNil(t, err) } } @@ -437,7 +643,7 @@ func testHelperFlushTokens(x InternalRegistry, lifespan time.Duration) func(t *t return func(t *testing.T) { ctx := context.Background() for _, r := range flushRequests { - mockRequestForeignKey(t, r.ID, x, false) + mockRequestForeignKey(t, r.ID, x) require.NoError(t, m.CreateAccessTokenSession(ctx, r.ID, r)) _, err := m.GetAccessTokenSession(ctx, r.ID, ds) require.NoError(t, err) @@ -480,10 +686,11 @@ func testHelperFlushTokensWithLimitAndBatchSize(x InternalRegistry, limit int, b // create five expired requests id := uuid.New() - for i := 0; i < 5; i++ { + totalCount := 5 + for i := 0; i < totalCount; i++ { r := createTestRequest(fmt.Sprintf("%s-%d", id, i+1)) r.RequestedAt = time.Now().Add(-2 * time.Hour) - mockRequestForeignKey(t, r.ID, x, false) + mockRequestForeignKey(t, r.ID, x) require.NoError(t, m.CreateAccessTokenSession(ctx, r.ID, r)) _, err := m.GetAccessTokenSession(ctx, r.ID, ds) require.NoError(t, err) @@ -491,14 +698,17 @@ func testHelperFlushTokensWithLimitAndBatchSize(x InternalRegistry, limit int, b } require.NoError(t, m.FlushInactiveAccessTokens(ctx, time.Now(), limit, batchSize)) + var notFoundCount, foundCount int for i := range requests { - _, err := m.GetAccessTokenSession(ctx, requests[i].ID, ds) - if i >= limit { - require.NoError(t, err) + if _, err := m.GetAccessTokenSession(ctx, requests[i].ID, ds); err == nil { + foundCount++ } else { - require.Error(t, err) + require.ErrorIs(t, err, fosite.ErrNotFound) + notFoundCount++ } } + assert.Equal(t, limit, notFoundCount, "should have deleted %d tokens", limit) + assert.Equal(t, totalCount-limit, foundCount, "should have found %d tokens", totalCount-limit) } } @@ -581,7 +791,7 @@ func testFositeSqlStoreTransactionCommitOpenIdConnectSession(m InternalRegistry) res, err := m.OAuth2Storage().GetOpenIDConnectSession(context.Background(), signature, testRequest) // session should have been created successfully because Commit did not return an error require.NoError(t, err) - AssertObjectKeysEqual(t, &defaultRequest, res, "RequestedScope", "GrantedScope", "Form", "Session") + assertx.EqualAsJSONExcept(t, &defaultRequest, res, defaultIgnoreKeys) // test delete within a transaction ctx, err = txnStore.BeginTX(context.Background()) @@ -730,6 +940,7 @@ func testFositeStoreClientAssertionJWTValid(m InternalRegistry) func(*testing.T) func testFositeJWTBearerGrantStorage(x InternalRegistry) func(t *testing.T) { return func(t *testing.T) { + ctx := context.Background() grantManager := x.GrantManager() keyManager := x.KeyManager() grantStorage := x.OAuth2Storage().(rfc7523.RFC7523KeyStorage) @@ -752,28 +963,28 @@ func testFositeJWTBearerGrantStorage(x InternalRegistry) func(t *testing.T) { ExpiresAt: time.Now().UTC().Round(time.Second).AddDate(1, 0, 0), } - storedKeySet, err := grantStorage.GetPublicKeys(context.TODO(), issuer, subject) + storedKeySet, err := grantStorage.GetPublicKeys(ctx, issuer, subject) require.NoError(t, err) require.Len(t, storedKeySet.Keys, 0) - err = grantManager.CreateGrant(context.TODO(), grant, publicKey) + err = grantManager.CreateGrant(ctx, grant, publicKey) require.NoError(t, err) - storedKeySet, err = grantStorage.GetPublicKeys(context.TODO(), issuer, subject) + storedKeySet, err = grantStorage.GetPublicKeys(ctx, issuer, subject) require.NoError(t, err) assert.Len(t, storedKeySet.Keys, 1) - storedKey, err := grantStorage.GetPublicKey(context.TODO(), issuer, subject, publicKey.KeyID) + storedKey, err := grantStorage.GetPublicKey(ctx, issuer, subject, publicKey.KeyID) require.NoError(t, err) assert.Equal(t, publicKey.KeyID, storedKey.KeyID) assert.Equal(t, publicKey.Use, storedKey.Use) assert.Equal(t, publicKey.Key, storedKey.Key) - storedScopes, err := grantStorage.GetPublicKeyScopes(context.TODO(), issuer, subject, publicKey.KeyID) + storedScopes, err := grantStorage.GetPublicKeyScopes(ctx, issuer, subject, publicKey.KeyID) require.NoError(t, err) assert.Equal(t, grant.Scope, storedScopes) - storedKeySet, err = keyManager.GetKey(context.TODO(), issuer, publicKey.KeyID) + storedKeySet, err = keyManager.GetKey(ctx, issuer, publicKey.KeyID) require.NoError(t, err) assert.Equal(t, publicKey.KeyID, storedKeySet.Keys[0].KeyID) assert.Equal(t, publicKey.Use, storedKeySet.Keys[0].Use) @@ -781,44 +992,65 @@ func testFositeJWTBearerGrantStorage(x InternalRegistry) func(t *testing.T) { }) t.Run("case=only associated key returns", func(t *testing.T) { - keySet, err := jwk.GenerateJWK(context.Background(), jose.RS256, "some-key", "sig") - require.NoError(t, err) - - err = keyManager.AddKeySet(context.TODO(), "some-set", keySet) + keySetToNotReturn, err := jwk.GenerateJWK(context.Background(), jose.ES256, "some-key", "sig") require.NoError(t, err) + require.NoError(t, keyManager.AddKeySet(context.Background(), "some-set", keySetToNotReturn), "adding a random key should not fail") - keySet, err = jwk.GenerateJWK(context.Background(), jose.RS256, "maria-key", "sig") - require.NoError(t, err) - - publicKey := keySet.Keys[0].Public() issuer := "maria" subject := "maria@example.com" - grant := trust.Grant{ + + keySet1ToReturn, err := jwk.GenerateJWK(context.Background(), jose.ES256, "maria-key-1", "sig") + require.NoError(t, err) + require.NoError(t, grantManager.CreateGrant(context.Background(), trust.Grant{ ID: uuid.New(), Issuer: issuer, Subject: subject, AllowAnySubject: false, Scope: []string{"openid"}, - PublicKey: trust.PublicKey{Set: issuer, KeyID: publicKey.KeyID}, + PublicKey: trust.PublicKey{Set: issuer, KeyID: keySet1ToReturn.Keys[0].Public().KeyID}, CreatedAt: time.Now().UTC().Round(time.Second), ExpiresAt: time.Now().UTC().Round(time.Second).AddDate(1, 0, 0), - } + }, keySet1ToReturn.Keys[0].Public())) - err = grantManager.CreateGrant(context.TODO(), grant, publicKey) + keySet2ToReturn, err := jwk.GenerateJWK(context.Background(), jose.ES256, "maria-key-2", "sig") require.NoError(t, err) + require.NoError(t, grantManager.CreateGrant(ctx, trust.Grant{ + ID: uuid.New(), + Issuer: issuer, + Subject: subject, + AllowAnySubject: false, + Scope: []string{"openid"}, + PublicKey: trust.PublicKey{Set: issuer, KeyID: keySet2ToReturn.Keys[0].Public().KeyID}, + CreatedAt: time.Now().UTC().Round(time.Second), + ExpiresAt: time.Now().UTC().Round(time.Second).AddDate(1, 0, 0), + }, keySet2ToReturn.Keys[0].Public())) - storedKeySet, err := grantStorage.GetPublicKeys(context.TODO(), issuer, subject) + storedKeySet, err := grantStorage.GetPublicKeys(context.Background(), issuer, subject) require.NoError(t, err) - assert.Len(t, storedKeySet.Keys, 1) - assert.Equal(t, publicKey.KeyID, storedKeySet.Keys[0].KeyID) - assert.Equal(t, publicKey.Use, storedKeySet.Keys[0].Use) - assert.Equal(t, publicKey.Key, storedKeySet.Keys[0].Key) - - storedKeySet, err = grantStorage.GetPublicKeys(context.TODO(), issuer, "non-existing-subject") + require.Len(t, storedKeySet.Keys, 2) + + // Cannot rely on sort order because the created_at timestamps may alias. + idx1 := slices.IndexFunc(storedKeySet.Keys, func(k jose.JSONWebKey) bool { + return k.KeyID == keySet1ToReturn.Keys[0].Public().KeyID + }) + require.GreaterOrEqual(t, idx1, 0) + idx2 := slices.IndexFunc(storedKeySet.Keys, func(k jose.JSONWebKey) bool { + return k.KeyID == keySet2ToReturn.Keys[0].Public().KeyID + }) + require.GreaterOrEqual(t, idx2, 0) + + assert.Equal(t, keySet1ToReturn.Keys[0].Public().KeyID, storedKeySet.Keys[idx1].KeyID) + assert.Equal(t, keySet1ToReturn.Keys[0].Public().Use, storedKeySet.Keys[idx1].Use) + assert.Equal(t, keySet1ToReturn.Keys[0].Public().Key, storedKeySet.Keys[idx1].Key) + assert.Equal(t, keySet2ToReturn.Keys[0].Public().KeyID, storedKeySet.Keys[idx2].KeyID) + assert.Equal(t, keySet2ToReturn.Keys[0].Public().Use, storedKeySet.Keys[idx2].Use) + assert.Equal(t, keySet2ToReturn.Keys[0].Public().Key, storedKeySet.Keys[idx2].Key) + + storedKeySet, err = grantStorage.GetPublicKeys(context.Background(), issuer, "non-existing-subject") require.NoError(t, err) assert.Len(t, storedKeySet.Keys, 0) - _, err = grantStorage.GetPublicKeyScopes(context.TODO(), issuer, "non-existing-subject", publicKey.KeyID) + _, err = grantStorage.GetPublicKeyScopes(context.Background(), issuer, "non-existing-subject", keySet2ToReturn.Keys[0].Public().KeyID) require.Error(t, err) }) @@ -840,22 +1072,22 @@ func testFositeJWTBearerGrantStorage(x InternalRegistry) func(t *testing.T) { ExpiresAt: time.Now().UTC().Round(time.Second).AddDate(1, 0, 0), } - err = grantManager.CreateGrant(context.TODO(), grant, publicKey) + err = grantManager.CreateGrant(ctx, grant, publicKey) require.NoError(t, err) - _, err = grantStorage.GetPublicKey(context.TODO(), issuer, subject, grant.PublicKey.KeyID) + _, err = grantStorage.GetPublicKey(ctx, issuer, subject, grant.PublicKey.KeyID) require.NoError(t, err) - _, err = keyManager.GetKey(context.TODO(), issuer, publicKey.KeyID) + _, err = keyManager.GetKey(ctx, issuer, publicKey.KeyID) require.NoError(t, err) - err = grantManager.DeleteGrant(context.TODO(), grant.ID) + err = grantManager.DeleteGrant(ctx, grant.ID) require.NoError(t, err) - _, err = grantStorage.GetPublicKey(context.TODO(), issuer, subject, publicKey.KeyID) + _, err = grantStorage.GetPublicKey(ctx, issuer, subject, publicKey.KeyID) assert.Error(t, err) - _, err = keyManager.GetKey(context.TODO(), issuer, publicKey.KeyID) + _, err = keyManager.GetKey(ctx, issuer, publicKey.KeyID) assert.Error(t, err) }) @@ -877,22 +1109,22 @@ func testFositeJWTBearerGrantStorage(x InternalRegistry) func(t *testing.T) { ExpiresAt: time.Now().UTC().Round(time.Second).AddDate(1, 0, 0), } - err = grantManager.CreateGrant(context.TODO(), grant, publicKey) + err = grantManager.CreateGrant(ctx, grant, publicKey) require.NoError(t, err) - _, err = grantStorage.GetPublicKey(context.TODO(), issuer, subject, publicKey.KeyID) + _, err = grantStorage.GetPublicKey(ctx, issuer, subject, publicKey.KeyID) require.NoError(t, err) - _, err = keyManager.GetKey(context.TODO(), issuer, publicKey.KeyID) + _, err = keyManager.GetKey(ctx, issuer, publicKey.KeyID) require.NoError(t, err) - err = keyManager.DeleteKey(context.TODO(), issuer, publicKey.KeyID) + err = keyManager.DeleteKey(ctx, issuer, publicKey.KeyID) require.NoError(t, err) - _, err = keyManager.GetKey(context.TODO(), issuer, publicKey.KeyID) + _, err = keyManager.GetKey(ctx, issuer, publicKey.KeyID) assert.Error(t, err) - _, err = grantManager.GetConcreteGrant(context.TODO(), grant.ID) + _, err = grantManager.GetConcreteGrant(ctx, grant.ID) assert.Error(t, err) }) @@ -914,25 +1146,25 @@ func testFositeJWTBearerGrantStorage(x InternalRegistry) func(t *testing.T) { ExpiresAt: time.Now().UTC().Round(time.Second).AddDate(1, 0, 0), } - err = grantManager.CreateGrant(context.TODO(), grant, publicKey) + err = grantManager.CreateGrant(ctx, grant, publicKey) require.NoError(t, err) // All three get methods should only return the public key when using the valid subject - _, err = grantStorage.GetPublicKey(context.TODO(), issuer, "any-subject-1", publicKey.KeyID) + _, err = grantStorage.GetPublicKey(ctx, issuer, "any-subject-1", publicKey.KeyID) require.Error(t, err) - _, err = grantStorage.GetPublicKey(context.TODO(), issuer, subject, publicKey.KeyID) + _, err = grantStorage.GetPublicKey(ctx, issuer, subject, publicKey.KeyID) require.NoError(t, err) - _, err = grantStorage.GetPublicKeyScopes(context.TODO(), issuer, "any-subject-2", publicKey.KeyID) + _, err = grantStorage.GetPublicKeyScopes(ctx, issuer, "any-subject-2", publicKey.KeyID) require.Error(t, err) - _, err = grantStorage.GetPublicKeyScopes(context.TODO(), issuer, subject, publicKey.KeyID) + _, err = grantStorage.GetPublicKeyScopes(ctx, issuer, subject, publicKey.KeyID) require.NoError(t, err) - jwks, err := grantStorage.GetPublicKeys(context.TODO(), issuer, "any-subject-3") + jwks, err := grantStorage.GetPublicKeys(ctx, issuer, "any-subject-3") require.NoError(t, err) require.NotNil(t, jwks) require.Empty(t, jwks.Keys) - jwks, err = grantStorage.GetPublicKeys(context.TODO(), issuer, subject) + jwks, err = grantStorage.GetPublicKeys(ctx, issuer, subject) require.NoError(t, err) require.NotNil(t, jwks) require.NotEmpty(t, jwks.Keys) @@ -955,21 +1187,46 @@ func testFositeJWTBearerGrantStorage(x InternalRegistry) func(t *testing.T) { ExpiresAt: time.Now().UTC().Round(time.Second).AddDate(1, 0, 0), } - err = grantManager.CreateGrant(context.TODO(), grant, publicKey) + err = grantManager.CreateGrant(ctx, grant, publicKey) require.NoError(t, err) // All three get methods should always return the public key - _, err = grantStorage.GetPublicKey(context.TODO(), issuer, "any-subject-1", publicKey.KeyID) + _, err = grantStorage.GetPublicKey(ctx, issuer, "any-subject-1", publicKey.KeyID) require.NoError(t, err) - _, err = grantStorage.GetPublicKeyScopes(context.TODO(), issuer, "any-subject-2", publicKey.KeyID) + _, err = grantStorage.GetPublicKeyScopes(ctx, issuer, "any-subject-2", publicKey.KeyID) require.NoError(t, err) - jwks, err := grantStorage.GetPublicKeys(context.TODO(), issuer, "any-subject-3") + jwks, err := grantStorage.GetPublicKeys(ctx, issuer, "any-subject-3") require.NoError(t, err) require.NotNil(t, jwks) require.NotEmpty(t, jwks.Keys) }) + + t.Run("case=does not return expired values", func(t *testing.T) { + keySet, err := jwk.GenerateJWK(context.Background(), jose.RS256, "issuer-expired-key", "sig") + require.NoError(t, err) + + publicKey := keySet.Keys[0].Public() + issuer := "expired-issuer" + grant := trust.Grant{ + ID: uuid.New(), + Issuer: issuer, + Subject: "", + AllowAnySubject: true, + Scope: []string{"openid", "offline"}, + PublicKey: trust.PublicKey{Set: issuer, KeyID: publicKey.KeyID}, + CreatedAt: time.Now().UTC().Round(time.Second), + ExpiresAt: time.Now().UTC().Round(time.Second).AddDate(-1, 0, 0), + } + + err = grantManager.CreateGrant(ctx, grant, publicKey) + require.NoError(t, err) + + keys, err := grantStorage.GetPublicKeys(ctx, issuer, "any-subject-3") + require.NoError(t, err) + assert.Len(t, keys.Keys, 0) + }) } } @@ -991,10 +1248,11 @@ func doTestCommit(m InternalRegistry, t *testing.T, require.NoError(t, err) // Require a new context, since the old one contains the transaction. - res, err := getFn(context.Background(), signature, &Session{}) + res, err := getFn(context.Background(), signature, NewSession("bar")) // token should have been created successfully because Commit did not return an error require.NoError(t, err) - AssertObjectKeysEqual(t, &defaultRequest, res, "RequestedScope", "GrantedScope", "Form", "Session") + assertx.EqualAsJSONExcept(t, &defaultRequest, res, defaultIgnoreKeys) + // AssertObjectKeysEqual(t, &defaultRequest, res, "RequestedScope", "GrantedScope", "Form", "Session") // testrevoke within a transaction ctx, err = txnStore.BeginTX(context.Background()) @@ -1005,7 +1263,7 @@ func doTestCommit(m InternalRegistry, t *testing.T, require.NoError(t, err) // Require a new context, since the old one contains the transaction. - _, err = getFn(context.Background(), signature, &Session{}) + _, err = getFn(context.Background(), signature, NewSession("bar")) // Since commit worked for revoke, we should get an error here. require.Error(t, err) } @@ -1029,7 +1287,7 @@ func doTestRollback(m InternalRegistry, t *testing.T, // Require a new context, since the old one contains the transaction. ctx = context.Background() - _, err = getFn(ctx, signature, &Session{}) + _, err = getFn(ctx, signature, NewSession("bar")) // Since we rolled back above, the token should not exist and getting it should result in an error require.Error(t, err) @@ -1037,7 +1295,7 @@ func doTestRollback(m InternalRegistry, t *testing.T, signature2 := uuid.New() err = createFn(ctx, signature2, createTestRequest(signature2)) require.NoError(t, err) - _, err = getFn(ctx, signature2, &Session{}) + _, err = getFn(ctx, signature2, NewSession("bar")) require.NoError(t, err) ctx, err = txnStore.BeginTX(context.Background()) @@ -1047,7 +1305,7 @@ func doTestRollback(m InternalRegistry, t *testing.T, err = txnStore.Rollback(ctx) require.NoError(t, err) - _, err = getFn(context.Background(), signature2, &Session{}) + _, err = getFn(context.Background(), signature2, NewSession("bar")) require.NoError(t, err) } @@ -1055,7 +1313,7 @@ func createTestRequest(id string) *fosite.Request { return &fosite.Request{ ID: id, RequestedAt: time.Now().UTC().Round(time.Second), - Client: &client.Client{LegacyClientID: "foobar"}, + Client: &client.Client{ID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, RequestedAudience: fosite.Arguments{"ad1", "ad2"}, diff --git a/oauth2/fosite_store_test.go b/oauth2/fosite_store_test.go index c8fb8d52618..2a48a52f8e7 100644 --- a/oauth2/fosite_store_test.go +++ b/oauth2/fosite_store_test.go @@ -10,11 +10,11 @@ import ( "github.com/stretchr/testify/require" - "github.com/ory/hydra/client" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - . "github.com/ory/hydra/oauth2" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + . "github.com/ory/hydra/v2/oauth2" "github.com/ory/x/contextx" "github.com/ory/x/networkx" "github.com/ory/x/sqlcon/dockertest" @@ -23,8 +23,8 @@ import ( func TestMain(m *testing.M) { flag.Parse() - runner := dockertest.Register() - runner.Exit(m.Run()) + defer dockertest.KillAllTestDatabases() + m.Run() } var registries = make(map[string]driver.Registry) @@ -52,7 +52,7 @@ func setupRegistries(t *testing.T) { } func TestManagers(t *testing.T) { - ctx := context.TODO() + ctx := context.Background() tests := []struct { name string enableSessionEncrypted bool @@ -67,10 +67,10 @@ func TestManagers(t *testing.T) { }, } for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { + t.Run("suite="+tc.name, func(t *testing.T) { setupRegistries(t) - require.NoError(t, registries["memory"].ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foobar"})) // this is a workaround because the client is not being created for memory store by test helpers. + require.NoError(t, registries["memory"].ClientManager().CreateClient(context.Background(), &client.Client{ID: "foobar"})) // this is a workaround because the client is not being created for memory store by test helpers. for k, store := range registries { net := &networkx.Network{} diff --git a/oauth2/handler.go b/oauth2/handler.go index 009ec2d7073..288ed1f16f0 100644 --- a/oauth2/handler.go +++ b/oauth2/handler.go @@ -4,6 +4,8 @@ package oauth2 import ( + "context" + "encoding/base64" "encoding/json" "fmt" "html/template" @@ -12,28 +14,32 @@ import ( "strings" "time" - "go.step.sm/crypto/jose" + "github.com/gobuffalo/pop/v6" + "github.com/tidwall/gjson" + "github.com/pborman/uuid" + + "github.com/ory/hydra/v2/x/events" "github.com/ory/x/httprouterx" + "github.com/ory/x/josex" + "github.com/ory/x/stringsx" - "github.com/pborman/uuid" + jwtV5 "github.com/golang-jwt/jwt/v5" "github.com/ory/x/errorsx" "github.com/julienschmidt/httprouter" "github.com/pkg/errors" - jwt2 "github.com/ory/fosite/token/jwt" - "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/token/jwt" "github.com/ory/x/urlx" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/x" ) const ( @@ -46,9 +52,10 @@ const ( AuthPath = "/oauth2/auth" LogoutPath = "/oauth2/sessions/logout" - UserinfoPath = "/userinfo" - WellKnownPath = "/.well-known/openid-configuration" - JWKPath = "/.well-known/jwks.json" + VerifiableCredentialsPath = "/credentials" + UserinfoPath = "/userinfo" + WellKnownPath = "/.well-known/openid-configuration" + JWKPath = "/.well-known/jwks.json" // IntrospectPath points to the OAuth2 introspection endpoint. IntrospectPath = "/oauth2/introspect" @@ -62,7 +69,10 @@ type Handler struct { } func NewHandler(r InternalRegistry, c *config.DefaultProvider) *Handler { - return &Handler{r: r, c: c} + return &Handler{ + r: r, + c: c, + } } func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin, public *httprouterx.RouterPublic, corsMiddleware func(http.Handler) http.Handler) { @@ -93,6 +103,9 @@ func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin, public *httprouterx. public.Handler("GET", UserinfoPath, corsMiddleware(http.HandlerFunc(h.getOidcUserInfo))) public.Handler("POST", UserinfoPath, corsMiddleware(http.HandlerFunc(h.getOidcUserInfo))) + public.Handler("OPTIONS", VerifiableCredentialsPath, corsMiddleware(http.HandlerFunc(h.handleOptions))) + public.Handler("POST", VerifiableCredentialsPath, corsMiddleware(http.HandlerFunc(h.createVerifiableCredential))) + admin.POST(IntrospectPath, h.introspectOAuth2Token) admin.DELETE(DeleteTokensPath, h.deleteOAuth2Token) } @@ -112,10 +125,10 @@ func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin, public *httprouterx. // // Responses: // 302: emptyResponse -func (h *Handler) performOidcFrontOrBackChannelLogout(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +func (h *Handler) performOidcFrontOrBackChannelLogout(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { ctx := r.Context() - handled, err := h.r.ConsentStrategy().HandleOpenIDConnectLogout(ctx, w, r) + handled, err := h.r.ConsentStrategy().HandleOpenIDConnectLogout(ctx, w, r) if errors.Is(err, consent.ErrAbortOAuth2Request) { return } else if err != nil { @@ -404,6 +417,43 @@ type oidcConfiguration struct { // JSON array containing a list of Proof Key for Code Exchange (PKCE) [RFC7636] code challenge methods supported // by this authorization server. CodeChallengeMethodsSupported []string `json:"code_challenge_methods_supported"` + + // OpenID Connect Verifiable Credentials Endpoint + // + // Contains the URL of the Verifiable Credentials Endpoint. + CredentialsEndpointDraft00 string `json:"credentials_endpoint_draft_00"` + + // OpenID Connect Verifiable Credentials Supported + // + // JSON array containing a list of the Verifiable Credentials supported by this authorization server. + CredentialsSupportedDraft00 []CredentialSupportedDraft00 `json:"credentials_supported_draft_00"` +} + +// Verifiable Credentials Metadata (Draft 00) +// +// Includes information about the supported verifiable credentials. +// +// swagger:model credentialSupportedDraft00 +type CredentialSupportedDraft00 struct { + // OpenID Connect Verifiable Credentials Format + // + // Contains the format that is supported by this authorization server. + Format string `json:"format"` + + // OpenID Connect Verifiable Credentials Types + // + // Contains the types of verifiable credentials supported. + Types []string `json:"types"` + + // OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported + // + // Contains a list of cryptographic binding methods supported for signing the proof. + CryptographicBindingMethodsSupported []string `json:"cryptographic_binding_methods_supported"` + + // OpenID Connect Verifiable Credentials Cryptographic Suites Supported + // + // Contains a list of cryptographic suites methods supported for signing the proof. + CryptographicSuitesSupported []string `json:"cryptographic_suites_supported"` } // swagger:route GET /.well-known/openid-configuration oidc discoverOidcConfiguration @@ -424,29 +474,30 @@ type oidcConfiguration struct { // 200: oidcConfiguration // default: errorOAuth2 func (h *Handler) discoverOidcConfiguration(w http.ResponseWriter, r *http.Request) { - key, err := h.r.OpenIDJWTStrategy().GetPublicKey(r.Context()) + ctx := r.Context() + key, err := h.r.OpenIDJWTStrategy().GetPublicKey(ctx) if err != nil { h.r.Writer().WriteError(w, r, err) return } h.r.Writer().Write(w, r, &oidcConfiguration{ - Issuer: h.c.IssuerURL(r.Context()).String(), - AuthURL: h.c.OAuth2AuthURL(r.Context()).String(), - TokenURL: h.c.OAuth2TokenURL(r.Context()).String(), - JWKsURI: h.c.JWKSURL(r.Context()).String(), - RevocationEndpoint: urlx.AppendPaths(h.c.IssuerURL(r.Context()), RevocationPath).String(), - RegistrationEndpoint: h.c.OAuth2ClientRegistrationURL(r.Context()).String(), - SubjectTypes: h.c.SubjectTypesSupported(r.Context()), + Issuer: h.c.IssuerURL(ctx).String(), + AuthURL: h.c.OAuth2AuthURL(ctx).String(), + TokenURL: h.c.OAuth2TokenURL(ctx).String(), + JWKsURI: h.c.JWKSURL(ctx).String(), + RevocationEndpoint: urlx.AppendPaths(h.c.IssuerURL(ctx), RevocationPath).String(), + RegistrationEndpoint: h.c.OAuth2ClientRegistrationURL(ctx).String(), + SubjectTypes: h.c.SubjectTypesSupported(ctx), ResponseTypes: []string{"code", "code id_token", "id_token", "token id_token", "token", "token id_token code"}, - ClaimsSupported: h.c.OIDCDiscoverySupportedClaims(r.Context()), - ScopesSupported: h.c.OIDCDiscoverySupportedScope(r.Context()), - UserinfoEndpoint: h.c.OIDCDiscoveryUserinfoEndpoint(r.Context()).String(), + ClaimsSupported: h.c.OIDCDiscoverySupportedClaims(ctx), + ScopesSupported: h.c.OIDCDiscoverySupportedScope(ctx), + UserinfoEndpoint: h.c.OIDCDiscoveryUserinfoEndpoint(ctx).String(), TokenEndpointAuthMethodsSupported: []string{"client_secret_post", "client_secret_basic", "private_key_jwt", "none"}, IDTokenSigningAlgValuesSupported: []string{key.Algorithm}, IDTokenSignedResponseAlg: []string{key.Algorithm}, UserinfoSignedResponseAlg: []string{key.Algorithm}, GrantTypesSupported: []string{"authorization_code", "implicit", "client_credentials", "refresh_token"}, - ResponseModesSupported: []string{"query", "fragment"}, + ResponseModesSupported: []string{"query", "fragment", "form_post"}, UserinfoSigningAlgValuesSupported: []string{"none", key.Algorithm}, RequestParameterSupported: true, RequestURIParameterSupported: true, @@ -455,15 +506,29 @@ func (h *Handler) discoverOidcConfiguration(w http.ResponseWriter, r *http.Reque BackChannelLogoutSessionSupported: true, FrontChannelLogoutSupported: true, FrontChannelLogoutSessionSupported: true, - EndSessionEndpoint: urlx.AppendPaths(h.c.IssuerURL(r.Context()), LogoutPath).String(), - RequestObjectSigningAlgValuesSupported: []string{"none", string(jose.RS256), string(jose.ES256)}, + EndSessionEndpoint: urlx.AppendPaths(h.c.IssuerURL(ctx), LogoutPath).String(), + RequestObjectSigningAlgValuesSupported: []string{"none", "RS256", "ES256"}, CodeChallengeMethodsSupported: []string{"plain", "S256"}, + CredentialsEndpointDraft00: h.c.CredentialsEndpointURL(ctx).String(), + CredentialsSupportedDraft00: []CredentialSupportedDraft00{{ + Format: "jwt_vc_json", + Types: []string{"VerifiableCredential", "UserInfoCredential"}, + CryptographicBindingMethodsSupported: []string{"jwk"}, + CryptographicSuitesSupported: []string{ + "PS256", "RS256", "ES256", + "PS384", "RS384", "ES384", + "PS512", "RS512", "ES512", + "EdDSA", + }, + }}, }) } // OpenID Connect Userinfo // // swagger:model oidcUserInfo +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type oidcUserInfo struct { // Subject - Identifier for the End-User at the IssuerURL. Subject string `json:"sub"` @@ -547,7 +612,7 @@ type oidcUserInfo struct { // default: errorOAuth2 func (h *Handler) getOidcUserInfo(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - session := NewSessionWithCustomClaims("", h.c.AllowedTopLevelClaims(ctx)) + session := NewSessionWithCustomClaims(ctx, h.c, "") tokenType, ar, err := h.r.OAuth2Provider().IntrospectToken(ctx, fosite.AccessTokenFromRequest(r), fosite.AccessToken, session) if err != nil { rfcerr := fosite.ErrorToRFC6749Error(err) @@ -600,13 +665,13 @@ func (h *Handler) getOidcUserInfo(w http.ResponseWriter, r *http.Request) { interim["jti"] = uuid.New() interim["iat"] = time.Now().Unix() - keyID, err := h.r.OpenIDJWTStrategy().GetPublicKeyID(r.Context()) + keyID, err := h.r.OpenIDJWTStrategy().GetPublicKeyID(ctx) if err != nil { h.r.Writer().WriteError(w, r, err) return } - token, _, err := h.r.OpenIDJWTStrategy().Generate(ctx, jwt2.MapClaims(interim), &jwt.Headers{ + token, _, err := h.r.OpenIDJWTStrategy().Generate(ctx, interim, &jwt.Headers{ Extra: map[string]interface{}{"kid": keyID}, }) if err != nil { @@ -627,6 +692,8 @@ func (h *Handler) getOidcUserInfo(w http.ResponseWriter, r *http.Request) { // Revoke OAuth 2.0 Access or Refresh Token Request // // swagger:parameters revokeOAuth2Token +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type revokeOAuth2Token struct { // in: formData // required: true @@ -659,7 +726,8 @@ type revokeOAuth2Token struct { // 200: emptyResponse // default: errorOAuth2 func (h *Handler) revokeOAuth2Token(w http.ResponseWriter, r *http.Request) { - var ctx = r.Context() + ctx := r.Context() + events.Trace(ctx, events.AccessTokenRevoked) err := h.r.OAuth2Provider().NewRevocationRequest(ctx, r) if err != nil { @@ -672,6 +740,8 @@ func (h *Handler) revokeOAuth2Token(w http.ResponseWriter, r *http.Request) { // Introspect OAuth 2.0 Access or Refresh Token Request // // swagger:parameters introspectOAuth2Token +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type introspectOAuth2Token struct { // The string value of the token. For access tokens, this // is the "access_token" value returned from the token endpoint @@ -709,8 +779,8 @@ type introspectOAuth2Token struct { // 200: introspectedOAuth2Token // default: errorOAuth2 func (h *Handler) introspectOAuth2Token(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - var session = NewSessionWithCustomClaims("", h.c.AllowedTopLevelClaims(r.Context())) - var ctx = r.Context() + ctx := r.Context() + session := NewSessionWithCustomClaims(ctx, h.c, "") if r.Method != "POST" { err := errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("HTTP method is \"%s\", expected \"POST\".", r.Method)) @@ -795,11 +865,19 @@ func (h *Handler) introspectOAuth2Token(w http.ResponseWriter, r *http.Request, }); err != nil { x.LogError(r, errorsx.WithStack(err), h.r.Logger()) } + + events.Trace(ctx, + events.AccessTokenInspected, + events.WithSubject(session.GetSubject()), + events.WithClientID(resp.GetAccessRequester().GetClient().GetID()), + ) } // OAuth 2.0 Token Exchange Parameters // // swagger:parameters oauth2TokenExchange +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type performOAuth2TokenFlow struct { // in: formData // required: true @@ -821,6 +899,8 @@ type performOAuth2TokenFlow struct { // OAuth2 Token Exchange Result // // swagger:model oAuth2TokenExchange +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type oAuth2TokenExchange struct { // The lifetime in seconds of the access token. For // example, the value "3600" denotes that the access token will @@ -831,7 +911,7 @@ type oAuth2TokenExchange struct { Scope string `json:"scope"` // To retrieve a refresh token request the id_token scope. - IDToken int `json:"id_token"` + IDToken string `json:"id_token"` // The access token issued by the authorization server. AccessToken string `json:"access_token"` @@ -851,7 +931,8 @@ type oAuth2TokenExchange struct { // Use open source libraries to perform OAuth 2.0 and OpenID Connect // available for any programming language. You can find a list of libraries here https://oauth.net/code/ // -// The Ory SDK is not yet able to this endpoint properly. +// This endpoint should not be used via the Ory SDK and is only included for technical reasons. +// Instead, use one of the libraries linked above. // // Consumes: // - application/x-www-form-urlencoded @@ -869,40 +950,56 @@ type oAuth2TokenExchange struct { // 200: oAuth2TokenExchange // default: errorOAuth2 func (h *Handler) oauth2TokenExchange(w http.ResponseWriter, r *http.Request) { - var session = NewSessionWithCustomClaims("", h.c.AllowedTopLevelClaims(r.Context())) - var ctx = r.Context() + ctx := r.Context() + session := NewSessionWithCustomClaims(ctx, h.c, "") accessRequest, err := h.r.OAuth2Provider().NewAccessRequest(ctx, r, session) if err != nil { h.logOrAudit(err, r) h.r.OAuth2Provider().WriteAccessError(ctx, w, accessRequest, err) + events.Trace(ctx, events.TokenExchangeError) return } - if accessRequest.GetGrantTypes().ExactOne("client_credentials") || accessRequest.GetGrantTypes().ExactOne("urn:ietf:params:oauth:grant-type:jwt-bearer") { + if accessRequest.GetGrantTypes().ExactOne(string(fosite.GrantTypeClientCredentials)) || + accessRequest.GetGrantTypes().ExactOne(string(fosite.GrantTypeJWTBearer)) || + accessRequest.GetGrantTypes().ExactOne(string(fosite.GrantTypePassword)) { var accessTokenKeyID string - if h.c.AccessTokenStrategy(ctx) == "jwt" { + if h.c.AccessTokenStrategy(ctx, client.AccessTokenStrategySource(accessRequest.GetClient())) == "jwt" { accessTokenKeyID, err = h.r.AccessTokenJWTStrategy().GetPublicKeyID(ctx) if err != nil { - x.LogError(r, err, h.r.Logger()) + h.logOrAudit(err, r) h.r.OAuth2Provider().WriteAccessError(ctx, w, accessRequest, err) + events.Trace(ctx, events.TokenExchangeError, events.WithRequest(accessRequest)) return } } // only for client_credentials, otherwise Authentication is included in session - if accessRequest.GetGrantTypes().ExactOne("client_credentials") { + if accessRequest.GetGrantTypes().ExactOne(string(fosite.GrantTypeClientCredentials)) { session.Subject = accessRequest.GetClient().GetID() } + // only for password grant, otherwise Authentication is included in session + if accessRequest.GetGrantTypes().ExactOne(string(fosite.GrantTypePassword)) { + if sess, ok := accessRequest.GetSession().(fosite.ExtraClaimsSession); ok { + sess.GetExtraClaims()["username"] = accessRequest.GetRequestForm().Get("username") + session.DefaultSession.Username = accessRequest.GetRequestForm().Get("username") + } + + // Also add audience claims + for _, aud := range accessRequest.GetClient().GetAudience() { + accessRequest.GrantAudience(aud) + } + } session.ClientID = accessRequest.GetClient().GetID() session.KID = accessTokenKeyID - session.DefaultSession.Claims.Issuer = h.c.IssuerURL(r.Context()).String() + session.DefaultSession.Claims.Issuer = h.c.IssuerURL(ctx).String() session.DefaultSession.Claims.IssuedAt = time.Now().UTC() - var scopes = accessRequest.GetRequestedScopes() + scopes := accessRequest.GetRequestedScopes() // Added for compatibility with MITREid - if h.c.GrantAllClientCredentialsScopesPerDefault(r.Context()) && len(scopes) == 0 { + if h.c.GrantAllClientCredentialsScopesPerDefault(ctx) && len(scopes) == 0 { for _, scope := range accessRequest.GetClient().GetScopes() { accessRequest.GrantScope(scope) } @@ -922,17 +1019,23 @@ func (h *Handler) oauth2TokenExchange(w http.ResponseWriter, r *http.Request) { } for _, hook := range h.r.AccessRequestHooks() { - if err := hook(ctx, accessRequest); err != nil { + if err = hook(ctx, accessRequest); err != nil { h.logOrAudit(err, r) h.r.OAuth2Provider().WriteAccessError(ctx, w, accessRequest, err) + events.Trace(ctx, events.TokenExchangeError, events.WithRequest(accessRequest)) return } } - accessResponse, err := h.r.OAuth2Provider().NewAccessResponse(ctx, accessRequest) - if err != nil { + var accessResponse fosite.AccessResponder + if err := h.r.Persister().Transaction(ctx, func(ctx context.Context, _ *pop.Connection) error { + var err error + accessResponse, err = h.r.OAuth2Provider().NewAccessResponse(ctx, accessRequest) + return err + }); err != nil { h.logOrAudit(err, r) h.r.OAuth2Provider().WriteAccessError(ctx, w, accessRequest, err) + events.Trace(ctx, events.TokenExchangeError, events.WithRequest(accessRequest)) return } @@ -946,18 +1049,20 @@ func (h *Handler) oauth2TokenExchange(w http.ResponseWriter, r *http.Request) { // Use open source libraries to perform OAuth 2.0 and OpenID Connect // available for any programming language. You can find a list of libraries at https://oauth.net/code/ // -// The Ory SDK is not yet able to this endpoint properly. +// This endpoint should not be used via the Ory SDK and is only included for technical reasons. +// Instead, use one of the libraries linked above. // -// Consumes: -// - application/x-www-form-urlencoded +// Consumes: +// - application/x-www-form-urlencoded // -// Schemes: http, https +// Schemes: http, https // -// Responses: -// 302: emptyResponse -// default: errorOAuth2 +// Responses: +// +// 302: emptyResponse +// default: errorOAuth2 func (h *Handler) oAuth2Authorize(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { - var ctx = r.Context() + ctx := r.Context() authorizeRequest, err := h.r.OAuth2Provider().NewAuthorizeRequest(ctx, r) if err != nil { @@ -966,7 +1071,7 @@ func (h *Handler) oAuth2Authorize(w http.ResponseWriter, r *http.Request, _ http return } - session, err := h.r.ConsentStrategy().HandleOAuth2AuthorizationRequest(ctx, w, r, authorizeRequest) + session, flow, err := h.r.ConsentStrategy().HandleOAuth2AuthorizationRequest(ctx, w, r, authorizeRequest) if errors.Is(err, consent.ErrAbortOAuth2Request) { x.LogAudit(r, nil, h.r.AuditLogger()) // do nothing @@ -997,7 +1102,7 @@ func (h *Handler) oAuth2Authorize(w http.ResponseWriter, r *http.Request, _ http } var accessTokenKeyID string - if h.c.AccessTokenStrategy(r.Context()) == "jwt" { + if h.c.AccessTokenStrategy(ctx, client.AccessTokenStrategySource(authorizeRequest.GetClient())) == "jwt" { accessTokenKeyID, err = h.r.AccessTokenJWTStrategy().GetPublicKeyID(ctx) if err != nil { x.LogError(r, err, h.r.Logger()) @@ -1038,23 +1143,28 @@ func (h *Handler) oAuth2Authorize(w http.ResponseWriter, r *http.Request, _ http claims.Add("sid", session.ConsentRequest.LoginSessionID) // done - response, err := h.r.OAuth2Provider().NewAuthorizeResponse(ctx, authorizeRequest, &Session{ - DefaultSession: &openid.DefaultSession{ - Claims: claims, - Headers: &jwt.Headers{Extra: map[string]interface{}{ - // required for lookup on jwk endpoint - "kid": openIDKeyID, - }}, - Subject: session.ConsentRequest.Subject, - }, - Extra: session.Session.AccessToken, - KID: accessTokenKeyID, - ClientID: authorizeRequest.GetClient().GetID(), - ConsentChallenge: session.ID, - ExcludeNotBeforeClaim: h.c.ExcludeNotBeforeClaim(ctx), - AllowedTopLevelClaims: h.c.AllowedTopLevelClaims(ctx), - }) - if err != nil { + var response fosite.AuthorizeResponder + if err := h.r.Persister().Transaction(ctx, func(ctx context.Context, _ *pop.Connection) (err error) { + response, err = h.r.OAuth2Provider().NewAuthorizeResponse(ctx, authorizeRequest, &Session{ + DefaultSession: &openid.DefaultSession{ + Claims: claims, + Headers: &jwt.Headers{Extra: map[string]interface{}{ + // required for lookup on jwk endpoint + "kid": openIDKeyID, + }}, + Subject: session.ConsentRequest.Subject, + }, + Extra: session.Session.AccessToken, + KID: accessTokenKeyID, + ClientID: authorizeRequest.GetClient().GetID(), + ConsentChallenge: session.ID, + ExcludeNotBeforeClaim: h.c.ExcludeNotBeforeClaim(ctx), + AllowedTopLevelClaims: h.c.AllowedTopLevelClaims(ctx), + MirrorTopLevelClaims: h.c.MirrorTopLevelClaims(ctx), + Flow: flow, + }) + return err + }); err != nil { x.LogError(r, err, h.r.Logger()) h.writeAuthorizeError(w, r, authorizeRequest, err) return @@ -1066,6 +1176,8 @@ func (h *Handler) oAuth2Authorize(w http.ResponseWriter, r *http.Request, _ http // Delete OAuth 2.0 Access Token Parameters // // swagger:parameters deleteOAuth2Token +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type deleteOAuth2Token struct { // OAuth 2.0 Client ID // @@ -1105,7 +1217,7 @@ func (h *Handler) deleteOAuth2Token(w http.ResponseWriter, r *http.Request, _ ht // This function will not be called, OPTIONS request will be handled by cors // this is just a placeholder. -func (h *Handler) handleOptions(w http.ResponseWriter, r *http.Request) {} +func (h *Handler) handleOptions(http.ResponseWriter, *http.Request) {} func (h *Handler) forwardError(w http.ResponseWriter, r *http.Request, err error) { rfcErr := fosite.ErrorToRFC6749Error(err).WithExposeDebug(h.c.GetSendDebugMessagesToClients(r.Context())) @@ -1129,3 +1241,167 @@ func (h *Handler) logOrAudit(err error, r *http.Request) { x.LogAudit(r, err, h.r.Logger()) } } + +// swagger:route POST /credentials oidc createVerifiableCredential +// +// # Issues a Verifiable Credential +// +// This endpoint creates a verifiable credential that attests that the user +// authenticated with the provided access token owns a certain public/private key +// pair. +// +// More information can be found at +// https://openid.net/specs/openid-connect-userinfo-vc-1_0.html. +// +// Consumes: +// - application/json +// +// Schemes: http, https +// +// Responses: +// 200: verifiableCredentialResponse +// 400: verifiableCredentialPrimingResponse +// default: errorOAuth2 +func (h *Handler) createVerifiableCredential(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + session := NewSessionWithCustomClaims(ctx, h.c, "") + accessToken := fosite.AccessTokenFromRequest(r) + tokenType, _, err := h.r.OAuth2Provider().IntrospectToken(ctx, accessToken, fosite.AccessToken, session) + + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + if tokenType != fosite.AccessToken { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The provided token is not an access token."))) + return + } + + var request CreateVerifiableCredentialRequestBody + if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithWrap(err).WithHint("Unable to decode request body."))) + return + } + + if request.Format != "jwt_vc_json" { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The format %q is not supported.", request.Format))) + return + } + if request.Proof == nil { + // Handle priming request + nonceLifespan := h.r.Config().GetVerifiableCredentialsNonceLifespan(ctx) + nonceExpiresIn := time.Now().Add(nonceLifespan).UTC() + nonce, err := h.r.OAuth2Storage().NewNonce(ctx, accessToken, nonceExpiresIn) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + h.r.Writer().WriteCode(w, r, http.StatusBadRequest, &VerifiableCredentialPrimingResponse{ + RFC6749ErrorJson: fosite.RFC6749ErrorJson{ + Name: "missing_proof", + Description: "Could not issue a verifiable credential because the proof is missing in the request.", + }, + Format: "jwt_vc", + Nonce: nonce, + NonceExpiresIn: int64(nonceLifespan.Seconds()), + }) + return + } + if request.Proof.ProofType != "jwt" { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The proof type %q is not supported.", request.Proof.ProofType))) + return + } + + header, _, ok := strings.Cut(request.Proof.JWT, ".") + if !ok { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The JWT in the proof is malformed."))) + return + } + + rawHeader, err := jwtV5.NewParser().DecodeSegment(header) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The JWT header in the proof is malformed."))) + return + } + jwk := gjson.GetBytes(rawHeader, "jwk").String() + proofJWK, err := josex.LoadJSONWebKey([]byte(jwk), true) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The JWK in the JWT header is malformed."))) + return + } + + token, err := jwt.Parse(request.Proof.JWT, func(token *jwt.Token) (any, error) { + return proofJWK, nil + }) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The JWT was not signed with the correct key supplied in the JWK header."))) + return + } + + nonce, ok := token.Claims["nonce"].(string) + if !ok { + h.r.Writer().WriteError(w, r, errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf(`The JWT did not contain the "nonce" claim.`))) + return + } + + if err = h.r.OAuth2Storage().IsNonceValid(ctx, accessToken, nonce); err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + + var response VerifiableCredentialResponse + response.Format = "jwt_vc_json" + + proofJWKJSON, err := json.Marshal(proofJWK) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + return + } + + // Encode ID according to https://github.com/quartzjer/did-jwk/blob/main/spec.md + vcID := fmt.Sprintf("did:jwk:%s", base64.RawURLEncoding.EncodeToString(proofJWKJSON)) + vcClaims := &VerifableCredentialClaims{ + RegisteredClaims: jwtV5.RegisteredClaims{ + Issuer: session.Claims.Issuer, + ID: stringsx.Coalesce(session.Claims.JTI, uuid.New()), + IssuedAt: jwtV5.NewNumericDate(session.Claims.IssuedAt), + NotBefore: jwtV5.NewNumericDate(session.Claims.IssuedAt), + ExpiresAt: jwtV5.NewNumericDate(session.Claims.IssuedAt.Add(1 * time.Hour)), + Subject: vcID, + }, + VerifiableCredential: VerifiableCredentialClaim{ + Context: []string{"https://www.w3.org/2018/credentials/v1"}, + Type: []string{"VerifiableCredential", "UserInfoCredential"}, + Subject: map[string]any{ + "id": vcID, + "sub": session.Claims.Subject, + }, + }, + } + if session.Claims.Extra != nil { + for claim, val := range session.Claims.Extra { + vcClaims.VerifiableCredential.Subject[claim] = val + } + } + + signingKeyID, err := h.r.OpenIDJWTStrategy().GetPublicKeyID(ctx) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + return + } + headers := jwt.NewHeaders() + headers.Add("kid", signingKeyID) + mapClaims, err := vcClaims.ToMapClaims() + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + return + } + rawToken, _, err := h.r.OpenIDJWTStrategy().Generate(ctx, mapClaims, headers) + if err != nil { + h.r.Writer().WriteError(w, r, errorsx.WithStack(err)) + return + } + + response.Credential = rawToken + h.r.Writer().Write(w, r, &response) +} diff --git a/oauth2/handler_fallback_endpoints.go b/oauth2/handler_fallback_endpoints.go index 5f2830b1790..1ae49efbbda 100644 --- a/oauth2/handler_fallback_endpoints.go +++ b/oauth2/handler_fallback_endpoints.go @@ -7,7 +7,7 @@ import ( "html/template" "net/http" - "github.com/ory/hydra/driver/config" + "github.com/ory/hydra/v2/driver/config" "github.com/julienschmidt/httprouter" ) diff --git a/oauth2/handler_fallback_endpoints_test.go b/oauth2/handler_fallback_endpoints_test.go index b72f1452ab6..191cd15a03a 100644 --- a/oauth2/handler_fallback_endpoints_test.go +++ b/oauth2/handler_fallback_endpoints_test.go @@ -12,12 +12,12 @@ import ( "github.com/ory/x/httprouterx" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/oauth2" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/oauth2" "github.com/stretchr/testify/assert" ) diff --git a/oauth2/handler_test.go b/oauth2/handler_test.go index bcf52de4a25..f2d159af614 100644 --- a/oauth2/handler_test.go +++ b/oauth2/handler_test.go @@ -23,24 +23,22 @@ import ( "github.com/ory/x/contextx" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/x" "github.com/golang/mock/gomock" "github.com/pkg/errors" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - - jwt2 "github.com/ory/fosite/token/jwt" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/token/jwt" - "github.com/ory/hydra/client" - "github.com/ory/hydra/oauth2" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/oauth2" ) var lifespan = time.Hour @@ -59,7 +57,7 @@ func TestHandlerDeleteHandler(t *testing.T) { deleteRequest := &fosite.Request{ ID: "del-1", RequestedAt: time.Now().Round(time.Second), - Client: &client.Client{LegacyClientID: "foobar"}, + Client: &client.Client{ID: "foobar"}, RequestedScope: fosite.Arguments{"fa", "ba"}, GrantedScope: fosite.Arguments{"fa", "ba"}, Form: url.Values{"foo": []string{"bar", "baz"}}, @@ -79,7 +77,7 @@ func TestHandlerDeleteHandler(t *testing.T) { c.GetConfig().Servers = hydra.ServerConfigurations{{URL: ts.URL}} _, err := c. - OAuth2Api.DeleteOAuth2Token(context.Background()). + OAuth2API.DeleteOAuth2Token(context.Background()). ClientId("foobar").Execute() require.NoError(t, err) @@ -95,7 +93,7 @@ func TestUserinfo(t *testing.T) { conf.MustSet(ctx, config.KeyAuthCodeLifespan, lifespan) conf.MustSet(ctx, config.KeyIssuerURL, "http://hydra.localhost") reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) - internal.MustEnsureRegistryKeys(reg, x.OpenIDConnectKeyName) + internal.MustEnsureRegistryKeys(ctx, reg, x.OpenIDConnectKeyName) ctrl := gomock.NewController(t) op := NewMockOAuth2Provider(ctrl) @@ -149,8 +147,8 @@ func TestUserinfo(t *testing.T) { setup: func(t *testing.T) { op.EXPECT(). IntrospectToken(gomock.Any(), gomock.Eq("access-token"), gomock.Eq(fosite.AccessToken), gomock.Any()). - DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, session fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { - session = &oauth2.Session{ + DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, _ fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { + session := &oauth2.Session{ DefaultSession: &openid.DefaultSession{ Claims: &jwt.IDTokenClaims{ Subject: "alice", @@ -164,7 +162,7 @@ func TestUserinfo(t *testing.T) { return fosite.AccessToken, &fosite.AccessRequest{ Request: fosite.Request{ Client: &client.Client{ - LegacyClientID: "foobar", + ID: "foobar", }, Session: session, }, @@ -182,8 +180,8 @@ func TestUserinfo(t *testing.T) { setup: func(t *testing.T) { op.EXPECT(). IntrospectToken(gomock.Any(), gomock.Eq("access-token"), gomock.Eq(fosite.AccessToken), gomock.Any()). - DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, session fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { - session = &oauth2.Session{ + DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, _ fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { + session := &oauth2.Session{ DefaultSession: &openid.DefaultSession{ Claims: &jwt.IDTokenClaims{ Subject: "another-alice", @@ -198,7 +196,7 @@ func TestUserinfo(t *testing.T) { return fosite.AccessToken, &fosite.AccessRequest{ Request: fosite.Request{ Client: &client.Client{ - LegacyClientID: "foobar", + ID: "foobar", }, Session: session, }, @@ -217,8 +215,8 @@ func TestUserinfo(t *testing.T) { setup: func(t *testing.T) { op.EXPECT(). IntrospectToken(gomock.Any(), gomock.Eq("access-token"), gomock.Eq(fosite.AccessToken), gomock.Any()). - DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, session fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { - session = &oauth2.Session{ + DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, _ fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { + session := &oauth2.Session{ DefaultSession: &openid.DefaultSession{ Claims: &jwt.IDTokenClaims{ Subject: "alice", @@ -233,7 +231,7 @@ func TestUserinfo(t *testing.T) { return fosite.AccessToken, &fosite.AccessRequest{ Request: fosite.Request{ Client: &client.Client{ - LegacyClientID: "foobar", + ID: "foobar", UserinfoSignedResponseAlg: "none", }, Session: session, @@ -252,8 +250,8 @@ func TestUserinfo(t *testing.T) { setup: func(t *testing.T) { op.EXPECT(). IntrospectToken(gomock.Any(), gomock.Eq("access-token"), gomock.Eq(fosite.AccessToken), gomock.Any()). - DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, session fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { - session = &oauth2.Session{ + DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, _ fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { + session := &oauth2.Session{ DefaultSession: &openid.DefaultSession{ Claims: &jwt.IDTokenClaims{ Subject: "alice", @@ -280,8 +278,8 @@ func TestUserinfo(t *testing.T) { setup: func(t *testing.T) { op.EXPECT(). IntrospectToken(gomock.Any(), gomock.Eq("access-token"), gomock.Eq(fosite.AccessToken), gomock.Any()). - DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, session fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { - session = &oauth2.Session{ + DoAndReturn(func(_ context.Context, _ string, _ fosite.TokenType, _ fosite.Session, _ ...string) (fosite.TokenType, fosite.AccessRequester, error) { + session := &oauth2.Session{ DefaultSession: &openid.DefaultSession{ Claims: &jwt.IDTokenClaims{ Subject: "alice", @@ -295,7 +293,7 @@ func TestUserinfo(t *testing.T) { return fosite.AccessToken, &fosite.AccessRequest{ Request: fosite.Request{ Client: &client.Client{ - LegacyClientID: "foobar-client", + ID: "foobar-client", UserinfoSignedResponseAlg: "RS256", }, Session: session, @@ -305,11 +303,11 @@ func TestUserinfo(t *testing.T) { }, expectStatusCode: http.StatusOK, checkForSuccess: func(t *testing.T, body []byte) { - claims, err := jwt2.Parse(string(body), func(token *jwt2.Token) (interface{}, error) { + claims, err := jwt.Parse(string(body), func(token *jwt.Token) (interface{}, error) { keys, err := reg.KeyManager().GetKeySet(context.Background(), x.OpenIDConnectKeyName) require.NoError(t, err) t.Logf("%+v", keys) - key, err := jwk.FindPublicKey(keys) + key, _ := jwk.FindPublicKey(keys) return key.Key, nil }) require.NoError(t, err) diff --git a/oauth2/helper_test.go b/oauth2/helper_test.go index 74c25bdcfb0..3a40592bfdd 100644 --- a/oauth2/helper_test.go +++ b/oauth2/helper_test.go @@ -12,7 +12,7 @@ import ( ) func Tokens(c fosite.Configurator, length int) (res [][]string) { - s := &oauth2.HMACSHAStrategy{Enigma: &hmac.HMACStrategy{Config: c}, Config: c} + s := oauth2.NewHMACSHAStrategy(&hmac.HMACStrategy{Config: c}, c) for i := 0; i < length; i++ { tok, sig, _ := s.Enigma.Generate(context.Background()) diff --git a/oauth2/hook.go b/oauth2/hook.go deleted file mode 100644 index 10985466d98..00000000000 --- a/oauth2/hook.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package oauth2 - -import ( - "bytes" - "context" - "encoding/json" - "net/http" - - "github.com/hashicorp/go-retryablehttp" - - "github.com/ory/hydra/x" - - "github.com/ory/fosite" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/driver/config" - "github.com/ory/x/errorsx" -) - -// AccessRequestHook is called when an access token is being refreshed. -type AccessRequestHook func(ctx context.Context, requester fosite.AccessRequester) error - -// Requester is a token endpoint's request context. -// -// swagger:ignore -type Requester struct { - // ClientID is the identifier of the OAuth 2.0 client. - ClientID string `json:"client_id"` - // GrantedScopes is the list of scopes granted to the OAuth 2.0 client. - GrantedScopes []string `json:"granted_scopes"` - // GrantedAudience is the list of audiences granted to the OAuth 2.0 client. - GrantedAudience []string `json:"granted_audience"` - // GrantTypes is the requests grant types. - GrantTypes []string `json:"grant_types"` -} - -// RefreshTokenHookRequest is the request body sent to the refresh token hook. -// -// swagger:ignore -type RefreshTokenHookRequest struct { - // Subject is the identifier of the authenticated end-user. - Subject string `json:"subject"` - // Session is the request's session.. - Session *Session `json:"session"` - // Requester is a token endpoint's request context. - Requester Requester `json:"requester"` - // ClientID is the identifier of the OAuth 2.0 client. - ClientID string `json:"client_id"` - // GrantedScopes is the list of scopes granted to the OAuth 2.0 client. - GrantedScopes []string `json:"granted_scopes"` - // GrantedAudience is the list of audiences granted to the OAuth 2.0 client. - GrantedAudience []string `json:"granted_audience"` -} - -// RefreshTokenHookResponse is the response body received from the refresh token hook. -// -// swagger:ignore -type RefreshTokenHookResponse struct { - // Session is the session data returned by the hook. - Session consent.AcceptOAuth2ConsentRequestSession `json:"session"` -} - -// RefreshTokenHook is an AccessRequestHook called for `refresh_token` grant type. -func RefreshTokenHook(reg interface { - config.Provider - x.HTTPClientProvider -}) AccessRequestHook { - return func(ctx context.Context, requester fosite.AccessRequester) error { - hookURL := reg.Config().TokenRefreshHookURL(ctx) - if hookURL == nil { - return nil - } - - if !requester.GetGrantTypes().ExactOne("refresh_token") { - return nil - } - - session, ok := requester.GetSession().(*Session) - if !ok { - return nil - } - - requesterInfo := Requester{ - ClientID: requester.GetClient().GetID(), - GrantedScopes: requester.GetGrantedScopes(), - GrantedAudience: requester.GetGrantedAudience(), - GrantTypes: requester.GetGrantTypes(), - } - - reqBody := RefreshTokenHookRequest{ - Session: session, - Requester: requesterInfo, - Subject: session.GetSubject(), - ClientID: requester.GetClient().GetID(), - GrantedScopes: requester.GetGrantedScopes(), - GrantedAudience: requester.GetGrantedAudience(), - } - reqBodyBytes, err := json.Marshal(&reqBody) - if err != nil { - return errorsx.WithStack( - fosite.ErrServerError. - WithWrap(err). - WithDescription("An error occurred while encoding the refresh token hook."). - WithDebugf("Unable to encode the refresh token hook body: %s", err), - ) - } - - req, err := retryablehttp.NewRequestWithContext(ctx, http.MethodPost, hookURL.String(), bytes.NewReader(reqBodyBytes)) - if err != nil { - return errorsx.WithStack( - fosite.ErrServerError. - WithWrap(err). - WithDescription("An error occurred while preparing the refresh token hook."). - WithDebugf("Unable to prepare the HTTP Request: %s", err), - ) - } - req.Header.Set("Content-Type", "application/json; charset=UTF-8") - - resp, err := reg.HTTPClient(ctx).Do(req) - if err != nil { - return errorsx.WithStack( - fosite.ErrServerError. - WithWrap(err). - WithDescription("An error occurred while executing the refresh token hook."). - WithDebugf("Unable to execute HTTP Request: %s", err), - ) - } - defer resp.Body.Close() - - switch resp.StatusCode { - case http.StatusOK: - // Token refresh permitted with new session data - case http.StatusNoContent: - // Token refresh is permitted without overriding session data - return nil - case http.StatusForbidden: - return errorsx.WithStack( - fosite.ErrAccessDenied. - WithDescription("The refresh token hook target responded with an error."). - WithDebugf("Refresh token hook responded with HTTP status code: %s", resp.Status), - ) - default: - return errorsx.WithStack( - fosite.ErrServerError. - WithDescription("The refresh token hook target responded with an error."). - WithDebugf("Refresh token hook responded with HTTP status code: %s", resp.Status), - ) - } - - var respBody RefreshTokenHookResponse - if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil { - return errorsx.WithStack( - fosite.ErrServerError. - WithWrap(err). - WithDescription("The refresh token hook target responded with an error."). - WithDebugf("Response from refresh token hook could not be decoded: %s", err), - ) - } - - // Overwrite existing session data (extra claims). - session.Extra = respBody.Session.AccessToken - idTokenClaims := session.IDTokenClaims() - idTokenClaims.Extra = respBody.Session.IDToken - return nil - } -} diff --git a/oauth2/introspector_test.go b/oauth2/introspector_test.go index 72fb08387d9..16b279f036f 100644 --- a/oauth2/introspector_test.go +++ b/oauth2/introspector_test.go @@ -16,11 +16,11 @@ import ( "github.com/ory/x/httprouterx" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -35,7 +35,7 @@ func TestIntrospectorSDK(t *testing.T) { conf.MustSet(ctx, config.KeyIssuerURL, "https://foobariss") reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) - internal.MustEnsureRegistryKeys(reg, x.OpenIDConnectKeyName) + internal.MustEnsureRegistryKeys(ctx, reg, x.OpenIDConnectKeyName) internal.AddFositeExamples(reg) tokens := Tokens(reg.OAuth2ProviderConfig(), 4) @@ -83,8 +83,8 @@ func TestIntrospectorSDK(t *testing.T) { // token: tokens[0][1], // expectInactive: true, // expectCode: http.StatusUnauthorized, - // prepare: func(*testing.T) *hydra.OAuth2Api.{ - // client := hydra.Ne.OAuth2Api.ithBasePath(server.URL) + // prepare: func(*testing.T) *hydra.OAuth2API.{ + // client := hydra.Ne.OAuth2API.ithBasePath(server.URL) // client.config.Username = "foo" // client.config.Password = "foo" // return client @@ -148,7 +148,7 @@ func TestIntrospectorSDK(t *testing.T) { client.GetConfig().Servers = hydra.ServerConfigurations{{URL: server.URL}} } - ctx, _, err := client.OAuth2Api.IntrospectOAuth2Token(context.Background()). + ctx, _, err := client.OAuth2API.IntrospectOAuth2Token(context.Background()). Token(c.token).Scope(strings.Join(c.scopes, " ")).Execute() require.NoError(t, err) diff --git a/oauth2/oauth2_auth_code_bench_test.go b/oauth2/oauth2_auth_code_bench_test.go new file mode 100644 index 00000000000..568ff00287c --- /dev/null +++ b/oauth2/oauth2_auth_code_bench_test.go @@ -0,0 +1,305 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oauth2_test + +import ( + "context" + "flag" + "net/http" + "os" + "runtime" + "runtime/pprof" + "strings" + "sync/atomic" + "testing" + "time" + + "github.com/go-jose/go-jose/v3" + "github.com/pborman/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" + "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp" + "go.opentelemetry.io/otel/propagation" + "go.opentelemetry.io/otel/sdk/resource" + "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/sdk/trace/tracetest" + semconv "go.opentelemetry.io/otel/semconv/v1.12.0" + "golang.org/x/oauth2" + + hydra "github.com/ory/hydra-client-go/v2" + hc "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/internal/testhelpers" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/contextx" + "github.com/ory/x/pointerx" + "github.com/ory/x/stringsx" +) + +var ( + prof = flag.String("profile", "", "write a CPU profile to this filename") + conc = flag.Int("conc", 100, "dispatch this many requests concurrently") + tracing = flag.Bool("tracing", false, "send OpenTelemetry traces to localhost:4318") +) + +func BenchmarkAuthCode(b *testing.B) { + flag.Parse() + + ctx := context.Background() + + spans := tracetest.NewSpanRecorder() + opts := []trace.TracerProviderOption{ + trace.WithSpanProcessor(spans), + trace.WithResource(resource.NewWithAttributes( + semconv.SchemaURL, attribute.String(string(semconv.ServiceNameKey), "BenchmarkAuthCode"), + )), + } + if *tracing { + exporter, err := otlptracehttp.New(ctx, otlptracehttp.WithInsecure(), otlptracehttp.WithEndpoint("localhost:4318")) + require.NoError(b, err) + opts = append(opts, trace.WithSpanProcessor(trace.NewSimpleSpanProcessor(exporter))) + } + provider := trace.NewTracerProvider(opts...) + + tracer := provider.Tracer("BenchmarkAuthCode") + otel.SetTextMapPropagator(propagation.TraceContext{}) + otel.SetTracerProvider(provider) + + ctx, span := tracer.Start(ctx, "BenchmarkAuthCode") + defer span.End() + + ctx = context.WithValue(ctx, oauth2.HTTPClient, otelhttp.DefaultClient) + + dsn := stringsx.Coalesce(os.Getenv("DSN"), "postgres://postgres:secret@127.0.0.1:3445/postgres?sslmode=disable&max_conns=20&max_idle_conns=20") + // dsn := "mysql://root:secret@tcp(localhost:3444)/mysql?max_conns=16&max_idle_conns=16" + // dsn := "cockroach://root@localhost:3446/defaultdb?sslmode=disable&max_conns=16&max_idle_conns=16" + reg := internal.NewRegistrySQLFromURL(b, dsn, true, new(contextx.Default)).WithTracer(tracer) + reg.Config().MustSet(ctx, config.KeyLogLevel, "error") + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") + reg.Config().MustSet(ctx, config.KeyRefreshTokenHook, "") + oauth2Keys, err := jwk.GenerateJWK(ctx, jose.ES256, x.OAuth2JWTKeyName, "sig") + require.NoError(b, err) + oidcKeys, err := jwk.GenerateJWK(ctx, jose.ES256, x.OpenIDConnectKeyName, "sig") + require.NoError(b, err) + _, _ = oauth2Keys, oidcKeys + require.NoError(b, reg.KeyManager().UpdateKeySet(ctx, x.OAuth2JWTKeyName, oauth2Keys)) + require.NoError(b, reg.KeyManager().UpdateKeySet(ctx, x.OpenIDConnectKeyName, oidcKeys)) + _, adminTS := testhelpers.NewOAuth2Server(ctx, b, reg) + var ( + authURL = reg.Config().OAuth2AuthURL(ctx).String() + tokenURL = reg.Config().OAuth2TokenURL(ctx).String() + nonce = uuid.New() + ) + + newOAuth2Client := func(b *testing.B, cb string) (*hc.Client, *oauth2.Config) { + secret := uuid.New() + c := &hc.Client{ + Secret: secret, + RedirectURIs: []string{cb}, + ResponseTypes: []string{"id_token", "code", "token"}, + GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, + Scope: "hydra offline openid", + Audience: []string{"https://api.ory.sh/"}, + } + require.NoError(b, reg.ClientManager().CreateClient(ctx, c)) + return c, &oauth2.Config{ + ClientID: c.GetID(), + ClientSecret: secret, + Endpoint: oauth2.Endpoint{ + AuthURL: authURL, + TokenURL: tokenURL, + AuthStyle: oauth2.AuthStyleInHeader, + }, + Scopes: strings.Split(c.Scope, " "), + } + } + + cfg := hydra.NewConfiguration() + cfg.HTTPClient = otelhttp.DefaultClient + adminClient := hydra.NewAPIClient(cfg) + adminClient.GetConfig().Servers = hydra.ServerConfigurations{{URL: adminTS.URL}} + + getAuthorizeCode := func(ctx context.Context, b *testing.B, conf *oauth2.Config, c *http.Client, params ...oauth2.AuthCodeOption) (string, *http.Response) { + if c == nil { + c = testhelpers.NewEmptyJarClient(b) + } + + state := uuid.New() + + req, err := http.NewRequestWithContext(ctx, "GET", conf.AuthCodeURL(state, params...), nil) + require.NoError(b, err) + resp, err := c.Do(req) + require.NoError(b, err) + defer resp.Body.Close() + + q := resp.Request.URL.Query() + require.EqualValues(b, state, q.Get("state")) + return q.Get("code"), resp + } + + acceptLoginHandler := func(b *testing.B, c *hc.Client, checkRequestPayload func(request *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest) http.HandlerFunc { + return otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + rr, _, err := adminClient.OAuth2API.GetOAuth2LoginRequest(ctx).LoginChallenge(r.URL.Query().Get("login_challenge")).Execute() + require.NoError(b, err) + + assert.EqualValues(b, c.GetID(), pointerx.Deref(rr.Client.ClientId)) + assert.Empty(b, pointerx.Deref(rr.Client.ClientSecret)) + assert.EqualValues(b, c.GrantTypes, rr.Client.GrantTypes) + assert.EqualValues(b, c.LogoURI, pointerx.Deref(rr.Client.LogoUri)) + assert.EqualValues(b, c.RedirectURIs, rr.Client.RedirectUris) + assert.EqualValues(b, r.URL.Query().Get("login_challenge"), rr.Challenge) + assert.EqualValues(b, []string{"hydra", "offline", "openid"}, rr.RequestedScope) + assert.Contains(b, rr.RequestUrl, authURL) + + acceptBody := hydra.AcceptOAuth2LoginRequest{ + Subject: uuid.New(), + Remember: pointerx.Ptr(!rr.Skip), + Acr: pointerx.Ptr("1"), + Amr: []string{"pwd"}, + Context: map[string]interface{}{"context": "bar"}, + } + if checkRequestPayload != nil { + if b := checkRequestPayload(rr); b != nil { + acceptBody = *b + } + } + + v, _, err := adminClient.OAuth2API.AcceptOAuth2LoginRequest(ctx). + LoginChallenge(r.URL.Query().Get("login_challenge")). + AcceptOAuth2LoginRequest(acceptBody). + Execute() + require.NoError(b, err) + require.NotEmpty(b, v.RedirectTo) + http.Redirect(w, r, v.RedirectTo, http.StatusFound) + }), "acceptLoginHandler").ServeHTTP + } + + acceptConsentHandler := func(b *testing.B, c *hc.Client, checkRequestPayload func(*hydra.OAuth2ConsentRequest)) http.HandlerFunc { + return otelhttp.NewHandler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + rr, _, err := adminClient.OAuth2API.GetOAuth2ConsentRequest(ctx).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() + require.NoError(b, err) + + assert.EqualValues(b, c.GetID(), pointerx.Deref(rr.Client.ClientId)) + assert.Empty(b, pointerx.Deref(rr.Client.ClientSecret)) + assert.EqualValues(b, c.GrantTypes, rr.Client.GrantTypes) + assert.EqualValues(b, c.LogoURI, pointerx.Deref(rr.Client.LogoUri)) + assert.EqualValues(b, c.RedirectURIs, rr.Client.RedirectUris) + // assert.EqualValues(b, subject, pointerx.Deref(rr.Subject)) + assert.EqualValues(b, []string{"hydra", "offline", "openid"}, rr.RequestedScope) + assert.EqualValues(b, r.URL.Query().Get("consent_challenge"), rr.Challenge) + assert.Contains(b, *rr.RequestUrl, authURL) + if checkRequestPayload != nil { + checkRequestPayload(rr) + } + + assert.Equal(b, map[string]interface{}{"context": "bar"}, rr.Context) + v, _, err := adminClient.OAuth2API.AcceptOAuth2ConsentRequest(ctx). + ConsentChallenge(r.URL.Query().Get("consent_challenge")). + AcceptOAuth2ConsentRequest(hydra.AcceptOAuth2ConsentRequest{ + GrantScope: []string{"hydra", "offline", "openid"}, Remember: pointerx.Ptr(true), RememberFor: pointerx.Ptr[int64](0), + GrantAccessTokenAudience: rr.RequestedAccessTokenAudience, + Session: &hydra.AcceptOAuth2ConsentRequestSession{ + AccessToken: map[string]interface{}{"foo": "bar"}, + IdToken: map[string]interface{}{"bar": "baz"}, + }, + }). + Execute() + require.NoError(b, err) + require.NotEmpty(b, v.RedirectTo) + http.Redirect(w, r, v.RedirectTo, http.StatusFound) + }), "acceptConsentHandler").ServeHTTP + } + + run := func(b *testing.B, strategy string) func(*testing.B) { + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + c, conf := newOAuth2Client(b, testhelpers.NewCallbackURL(b, "callback", testhelpers.HTTPServerNotImplementedHandler)) + testhelpers.NewLoginConsentUI(b, reg.Config(), + acceptLoginHandler(b, c, nil), + acceptConsentHandler(b, c, nil), + ) + + return func(b *testing.B) { + //pop.Debug = true + code, _ := getAuthorizeCode(ctx, b, conf, nil, oauth2.SetAuthURLParam("nonce", nonce)) + require.NotEmpty(b, code) + + _, err := conf.Exchange(ctx, code) + //pop.Debug = false + require.NoError(b, err) + } + } + + b.ResetTimer() + + b.SetParallelism(*conc / runtime.GOMAXPROCS(0)) + + b.Run("strategy=jwt", func(b *testing.B) { + initialDBSpans := dbSpans(spans) + B := run(b, "jwt") + + stop := profile(b) + defer stop() + + var totalMS int64 = 0 + b.RunParallel(func(p *testing.PB) { + defer func(t0 time.Time) { + atomic.AddInt64(&totalMS, int64(time.Since(t0).Milliseconds())) + }(time.Now()) + for p.Next() { + B(b) + } + }) + + b.ReportMetric(0, "ns/op") + b.ReportMetric(float64(atomic.LoadInt64(&totalMS))/float64(b.N), "ms/op") + b.ReportMetric((float64(dbSpans(spans)-initialDBSpans))/float64(b.N), "queries/op") + b.ReportMetric(float64(b.N)/b.Elapsed().Seconds(), "ops/s") + }) + + b.Run("strategy=opaque", func(b *testing.B) { + initialDBSpans := dbSpans(spans) + B := run(b, "opaque") + + stop := profile(b) + defer stop() + + var totalMS int64 = 0 + b.RunParallel(func(p *testing.PB) { + defer func(t0 time.Time) { + atomic.AddInt64(&totalMS, int64(time.Since(t0).Milliseconds())) + }(time.Now()) + for p.Next() { + B(b) + } + }) + + b.ReportMetric(0, "ns/op") + b.ReportMetric(float64(atomic.LoadInt64(&totalMS))/float64(b.N), "ms/op") + b.ReportMetric((float64(dbSpans(spans)-initialDBSpans))/float64(b.N), "queries/op") + b.ReportMetric(float64(b.N)/b.Elapsed().Seconds(), "ops/s") + }) + +} + +func profile(t testing.TB) (stop func()) { + t.Helper() + if *prof == "" { + return func() {} // noop + } + f, err := os.Create(*prof) + require.NoError(t, err) + require.NoError(t, pprof.StartCPUProfile(f)) + return func() { + pprof.StopCPUProfile() + require.NoError(t, f.Close()) + t.Log("Wrote profile to", f.Name()) + } +} diff --git a/oauth2/oauth2_auth_code_test.go b/oauth2/oauth2_auth_code_test.go index 1a1ef0120e5..feea2451e27 100644 --- a/oauth2/oauth2_auth_code_test.go +++ b/oauth2/oauth2_auth_code_test.go @@ -6,7 +6,9 @@ package oauth2_test import ( "bytes" "context" + "encoding/base64" "encoding/json" + "errors" "fmt" "io" "net/http" @@ -18,48 +20,46 @@ import ( "testing" "time" - "github.com/ory/x/ioutilx" - "github.com/ory/x/requirex" - - hydra "github.com/ory/hydra-client-go/v2" - - "github.com/ory/x/httprouterx" - - "github.com/ory/x/assertx" - - "github.com/pborman/uuid" - "github.com/tidwall/gjson" - - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/internal/testhelpers" - "github.com/ory/x/contextx" - + "github.com/go-jose/go-jose/v3" + "github.com/golang-jwt/jwt/v5" "github.com/julienschmidt/httprouter" + "github.com/pborman/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" "golang.org/x/oauth2" - goauth2 "golang.org/x/oauth2" "golang.org/x/oauth2/clientcredentials" "github.com/ory/fosite" - hc "github.com/ory/hydra/client" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - hydraoauth2 "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/x" + hydra "github.com/ory/hydra-client-go/v2" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/internal/testhelpers" + hydraoauth2 "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/assertx" + "github.com/ory/x/contextx" + "github.com/ory/x/httprouterx" + "github.com/ory/x/httpx" + "github.com/ory/x/ioutilx" + "github.com/ory/x/josex" "github.com/ory/x/pointerx" + "github.com/ory/x/requirex" "github.com/ory/x/snapshotx" + "github.com/ory/x/stringsx" ) -func noopHandler(t *testing.T) httprouter.Handle { +func noopHandler(*testing.T) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { w.WriteHeader(http.StatusNotImplemented) } } type clientCreator interface { - CreateClient(cxt context.Context, client *hc.Client) error + CreateClient(context.Context, *client.Client) error } // TestAuthCodeWithDefaultStrategy runs proper integration tests against in-memory and database connectors, specifically @@ -76,35 +76,14 @@ type clientCreator interface { // - [x] If `id_token_hint` is handled properly // - [x] What happens if `id_token_hint` does not match the value from the handled authentication request ("accept login") func TestAuthCodeWithDefaultStrategy(t *testing.T) { - ctx := context.TODO() + ctx := context.Background() reg := internal.NewMockedRegistry(t, &contextx.Default{}) reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") - reg.Config().MustSet(ctx, config.KeyRefreshTokenHookURL, "") + reg.Config().MustSet(ctx, config.KeyRefreshTokenHook, "") publicTS, adminTS := testhelpers.NewOAuth2Server(ctx, t, reg) - newOAuth2Client := func(t *testing.T, cb string) (*hc.Client, *oauth2.Config) { - secret := uuid.New() - c := &hc.Client{ - Secret: secret, - RedirectURIs: []string{cb}, - ResponseTypes: []string{"id_token", "code", "token"}, - GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, - Scope: "hydra offline openid", - Audience: []string{"https://api.ory.sh/"}, - } - require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), c)) - return c, &oauth2.Config{ - ClientID: c.GetID(), - ClientSecret: secret, - Endpoint: oauth2.Endpoint{ - AuthURL: reg.Config().OAuth2AuthURL(ctx).String(), - TokenURL: reg.Config().OAuth2TokenURL(ctx).String(), - AuthStyle: oauth2.AuthStyleInHeader, - }, - Scopes: strings.Split(c.Scope, " "), - } - } - + publicClient := hydra.NewAPIClient(hydra.NewConfiguration()) + publicClient.GetConfig().Servers = hydra.ServerConfigurations{{URL: publicTS.URL}} adminClient := hydra.NewAPIClient(hydra.NewConfiguration()) adminClient.GetConfig().Servers = hydra.ServerConfigurations{{URL: adminTS.URL}} @@ -125,13 +104,13 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { acceptLoginHandler := func(t *testing.T, c *client.Client, subject string, checkRequestPayload func(request *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - rr, _, err := adminClient.OAuth2Api.GetOAuth2LoginRequest(context.Background()).LoginChallenge(r.URL.Query().Get("login_challenge")).Execute() + rr, _, err := adminClient.OAuth2API.GetOAuth2LoginRequest(context.Background()).LoginChallenge(r.URL.Query().Get("login_challenge")).Execute() require.NoError(t, err) - assert.EqualValues(t, c.GetID(), pointerx.StringR(rr.Client.ClientId)) - assert.Empty(t, pointerx.StringR(rr.Client.ClientSecret)) + assert.EqualValues(t, c.GetID(), pointerx.Deref(rr.Client.ClientId)) + assert.Empty(t, pointerx.Deref(rr.Client.ClientSecret)) assert.EqualValues(t, c.GrantTypes, rr.Client.GrantTypes) - assert.EqualValues(t, c.LogoURI, pointerx.StringR(rr.Client.LogoUri)) + assert.EqualValues(t, c.LogoURI, pointerx.Deref(rr.Client.LogoUri)) assert.EqualValues(t, c.RedirectURIs, rr.Client.RedirectUris) assert.EqualValues(t, r.URL.Query().Get("login_challenge"), rr.Challenge) assert.EqualValues(t, []string{"hydra", "offline", "openid"}, rr.RequestedScope) @@ -139,8 +118,8 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { acceptBody := hydra.AcceptOAuth2LoginRequest{ Subject: subject, - Remember: pointerx.Bool(!rr.Skip), - Acr: pointerx.String("1"), + Remember: pointerx.Ptr(!rr.Skip), + Acr: pointerx.Ptr("1"), Amr: []string{"pwd"}, Context: map[string]interface{}{"context": "bar"}, } @@ -150,7 +129,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { } } - v, _, err := adminClient.OAuth2Api.AcceptOAuth2LoginRequest(context.Background()). + v, _, err := adminClient.OAuth2API.AcceptOAuth2LoginRequest(context.Background()). LoginChallenge(r.URL.Query().Get("login_challenge")). AcceptOAuth2LoginRequest(acceptBody). Execute() @@ -162,15 +141,15 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { acceptConsentHandler := func(t *testing.T, c *client.Client, subject string, checkRequestPayload func(*hydra.OAuth2ConsentRequest)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { - rr, _, err := adminClient.OAuth2Api.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() + rr, _, err := adminClient.OAuth2API.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() require.NoError(t, err) - assert.EqualValues(t, c.GetID(), pointerx.StringR(rr.Client.ClientId)) - assert.Empty(t, pointerx.StringR(rr.Client.ClientSecret)) + assert.EqualValues(t, c.GetID(), pointerx.Deref(rr.Client.ClientId)) + assert.Empty(t, pointerx.Deref(rr.Client.ClientSecret)) assert.EqualValues(t, c.GrantTypes, rr.Client.GrantTypes) - assert.EqualValues(t, c.LogoURI, pointerx.StringR(rr.Client.LogoUri)) + assert.EqualValues(t, c.LogoURI, pointerx.Deref(rr.Client.LogoUri)) assert.EqualValues(t, c.RedirectURIs, rr.Client.RedirectUris) - assert.EqualValues(t, subject, pointerx.StringR(rr.Subject)) + assert.EqualValues(t, subject, pointerx.Deref(rr.Subject)) assert.EqualValues(t, []string{"hydra", "offline", "openid"}, rr.RequestedScope) assert.EqualValues(t, r.URL.Query().Get("consent_challenge"), rr.Challenge) assert.Contains(t, *rr.RequestUrl, reg.Config().OAuth2AuthURL(ctx).String()) @@ -179,14 +158,14 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { } assert.Equal(t, map[string]interface{}{"context": "bar"}, rr.Context) - v, _, err := adminClient.OAuth2Api.AcceptOAuth2ConsentRequest(context.Background()). + v, _, err := adminClient.OAuth2API.AcceptOAuth2ConsentRequest(context.Background()). ConsentChallenge(r.URL.Query().Get("consent_challenge")). AcceptOAuth2ConsentRequest(hydra.AcceptOAuth2ConsentRequest{ - GrantScope: []string{"hydra", "offline", "openid"}, Remember: pointerx.Bool(true), RememberFor: pointerx.Int64(0), + GrantScope: []string{"hydra", "offline", "openid"}, Remember: pointerx.Ptr(true), RememberFor: pointerx.Ptr[int64](0), GrantAccessTokenAudience: rr.RequestedAccessTokenAudience, Session: &hydra.AcceptOAuth2ConsentRequestSession{ AccessToken: map[string]interface{}{"foo": "bar"}, - IdToken: map[string]interface{}{"bar": "baz"}, + IdToken: map[string]interface{}{"bar": "baz", "email": "foo@bar.com"}, }, }). Execute() @@ -197,8 +176,9 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { } assertRefreshToken := func(t *testing.T, token *oauth2.Token, c *oauth2.Config, expectedExp time.Time) { - actualExp, err := strconv.ParseInt(testhelpers.IntrospectToken(t, c, token.RefreshToken, adminTS).Get("exp").String(), 10, 64) - require.NoError(t, err) + introspect := testhelpers.IntrospectToken(t, c, token.RefreshToken, adminTS) + actualExp, err := strconv.ParseInt(introspect.Get("exp").String(), 10, 64) + require.NoError(t, err, "%s", introspect) requirex.EqualTime(t, expectedExp, time.Unix(actualExp, 0), time.Second) } @@ -227,6 +207,8 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { assert.EqualValues(t, expectedSubject, claims.Get("sub").String(), "%s", claims) assert.EqualValues(t, expectedNonce, claims.Get("nonce").String(), "%s", claims) assert.EqualValues(t, `baz`, claims.Get("bar").String(), "%s", claims) + assert.EqualValues(t, `foo@bar.com`, claims.Get("email").String(), "%s", claims) + assert.NotEmpty(t, claims.Get("sid").String(), "%s", claims) return claims } @@ -237,11 +219,11 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { assert.True(t, i.Get("active").Bool(), "%s", i) assert.EqualValues(t, conf.ClientID, i.Get("client_id").String(), "%s", i) assert.EqualValues(t, expectedSubject, i.Get("sub").String(), "%s", i) - assert.EqualValues(t, `{"foo":"bar"}`, i.Get("ext").Raw, "%s", i) + assert.EqualValues(t, `bar`, i.Get("ext.foo").String(), "%s", i) return i } - assertJWTAccessToken := func(t *testing.T, strat string, conf *oauth2.Config, token *oauth2.Token, expectedSubject string, expectedExp time.Time) gjson.Result { + assertJWTAccessToken := func(t *testing.T, strat string, conf *oauth2.Config, token *oauth2.Token, expectedSubject string, expectedExp time.Time, scopes string) gjson.Result { require.NotEmpty(t, token.AccessToken) parts := strings.Split(token.AccessToken, ".") if strat != "jwt" { @@ -262,8 +244,8 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { assert.True(t, time.Now().After(time.Unix(i.Get("nbf").Int(), 0)), "%s", i) assert.True(t, time.Now().Before(time.Unix(i.Get("exp").Int(), 0)), "%s", i) requirex.EqualTime(t, expectedExp, time.Unix(i.Get("exp").Int(), 0), time.Second) - assert.EqualValues(t, `{"foo":"bar"}`, i.Get("ext").Raw, "%s", i) - assert.EqualValues(t, `["hydra","offline","openid"]`, i.Get("scp").Raw, "%s", i) + assert.EqualValues(t, `bar`, i.Get("ext.foo").String(), "%s", i) + assert.EqualValues(t, scopes, i.Get("scp").Raw, "%s", i) return i } @@ -273,7 +255,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { t.Run("case=checks if request fails when audience does not match", func(t *testing.T) { testhelpers.NewLoginConsentUI(t, reg.Config(), testhelpers.HTTPServerNoExpectedCallHandler(t), testhelpers.HTTPServerNoExpectedCallHandler(t)) - _, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + _, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) code, _ := getAuthorizeCode(t, conf, nil, oauth2.SetAuthURLParam("audience", "https://not-ory-api/")) require.Empty(t, code) }) @@ -282,7 +264,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { nonce := uuid.New() t.Run("case=perform authorize code flow with ID token and refresh tokens", func(t *testing.T) { run := func(t *testing.T, strategy string) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -294,8 +276,10 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { iat := time.Now() require.NoError(t, err) + assert.Empty(t, token.Extra("c_nonce_draft_00"), "should not be set if not requested") + assert.Empty(t, token.Extra("c_nonce_expires_in_draft_00"), "should not be set if not requested") introspectAccessToken(t, conf, token, subject) - assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx))) + assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx)), `["hydra","offline","openid"]`) assertIDToken(t, token, conf, subject, nonce, iat.Add(reg.Config().GetIDTokenLifespan(ctx))) assertRefreshToken(t, token, conf, iat.Add(reg.Config().GetRefreshTokenLifespan(ctx))) @@ -312,7 +296,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { introspectAccessToken(t, conf, refreshedToken, subject) t.Run("followup=refreshed tokens contain valid tokens", func(t *testing.T) { - assertJWTAccessToken(t, strategy, conf, refreshedToken, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx))) + assertJWTAccessToken(t, strategy, conf, refreshedToken, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx)), `["hydra","offline","openid"]`) assertIDToken(t, refreshedToken, conf, subject, nonce, iat.Add(reg.Config().GetIDTokenLifespan(ctx))) assertRefreshToken(t, refreshedToken, conf, iat.Add(reg.Config().GetRefreshTokenLifespan(ctx))) }) @@ -349,24 +333,508 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) }) + t.Run("case=graceful token rotation", func(t *testing.T) { + run := func(t *testing.T, strategy string) { + reg.Config().MustSet(ctx, config.KeyRefreshTokenRotationGracePeriod, "5s") + t.Cleanup(func() { + reg.Config().MustSet(ctx, config.KeyRefreshTokenRotationGracePeriod, nil) + }) + + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + testhelpers.NewLoginConsentUI(t, reg.Config(), + acceptLoginHandler(t, c, subject, nil), + acceptConsentHandler(t, c, subject, nil), + ) + + issueTokens := func(t *testing.T) *oauth2.Token { + code, _ := getAuthorizeCode(t, conf, nil, oauth2.SetAuthURLParam("nonce", nonce)) + require.NotEmpty(t, code) + token, err := conf.Exchange(context.Background(), code) + iat := time.Now() + require.NoError(t, err) + + introspectAccessToken(t, conf, token, subject) + assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx)), `["hydra","offline","openid"]`) + assertIDToken(t, token, conf, subject, nonce, iat.Add(reg.Config().GetIDTokenLifespan(ctx))) + assertRefreshToken(t, token, conf, iat.Add(reg.Config().GetRefreshTokenLifespan(ctx))) + return token + } + + refreshTokens := func(t *testing.T, token *oauth2.Token) *oauth2.Token { + require.NotEmpty(t, token.RefreshToken) + token.Expiry = token.Expiry.Add(-time.Hour * 24) + iat := time.Now() + refreshedToken, err := conf.TokenSource(context.Background(), token).Token() + require.NoError(t, err) + + require.NotEqual(t, token.AccessToken, refreshedToken.AccessToken) + require.NotEqual(t, token.RefreshToken, refreshedToken.RefreshToken) + require.NotEqual(t, token.Extra("id_token"), refreshedToken.Extra("id_token")) + + introspectAccessToken(t, conf, refreshedToken, subject) + assertJWTAccessToken(t, strategy, conf, refreshedToken, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx)), `["hydra","offline","openid"]`) + assertIDToken(t, refreshedToken, conf, subject, nonce, iat.Add(reg.Config().GetIDTokenLifespan(ctx))) + assertRefreshToken(t, refreshedToken, conf, iat.Add(reg.Config().GetRefreshTokenLifespan(ctx))) + return refreshedToken + } + + t.Run("followup=successfully perform refresh token flow", func(t *testing.T) { + start := time.Now() + + token := issueTokens(t) + var first, second *oauth2.Token + t.Run("followup=first refresh", func(t *testing.T) { + first = refreshTokens(t, token) + }) + + t.Run("followup=second refresh", func(t *testing.T) { + second = refreshTokens(t, token) + }) + + // Sleep until the grace period is over + time.Sleep(time.Until(start.Add(5*time.Second + time.Millisecond*10))) + t.Run("followup=refresh failure invalidates all tokens", func(t *testing.T) { + _, err := conf.TokenSource(context.Background(), token).Token() + assert.Error(t, err) + + i := testhelpers.IntrospectToken(t, conf, first.AccessToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + + i = testhelpers.IntrospectToken(t, conf, second.AccessToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + + i = testhelpers.IntrospectToken(t, conf, first.RefreshToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + + i = testhelpers.IntrospectToken(t, conf, second.RefreshToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + }) + }) + + t.Run("followup=successfully perform refresh token flow", func(t *testing.T) { + start := time.Now() + + token := issueTokens(t) + var first, second *oauth2.Token + t.Run("followup=first refresh", func(t *testing.T) { + first = refreshTokens(t, token) + }) + + t.Run("followup=second refresh", func(t *testing.T) { + second = refreshTokens(t, token) + }) + + // Sleep until the grace period is over + time.Sleep(time.Until(start.Add(5*time.Second + time.Millisecond*10))) + t.Run("followup=revoking consent revokes all tokens", func(t *testing.T) { + err := reg.ConsentManager().RevokeSubjectConsentSession(context.Background(), subject) + require.NoError(t, err) + + _, err = conf.TokenSource(context.Background(), token).Token() + assert.Error(t, err) + + i := testhelpers.IntrospectToken(t, conf, first.AccessToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + + i = testhelpers.IntrospectToken(t, conf, second.AccessToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + + i = testhelpers.IntrospectToken(t, conf, first.RefreshToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + + i = testhelpers.IntrospectToken(t, conf, second.RefreshToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + }) + }) + + t.Run("followup=graceful refresh tokens are all refreshed", func(t *testing.T) { + start := time.Now() + token := issueTokens(t) + var a1Refresh, b1Refresh, a2RefreshA, a2RefreshB, b2RefreshA, b2RefreshB *oauth2.Token + t.Run("followup=first refresh", func(t *testing.T) { + a1Refresh = refreshTokens(t, token) + }) + + t.Run("followup=second refresh", func(t *testing.T) { + b1Refresh = refreshTokens(t, token) + }) + + t.Run("followup=first refresh from first refresh", func(t *testing.T) { + a2RefreshA = refreshTokens(t, a1Refresh) + }) + + t.Run("followup=second refresh from first refresh", func(t *testing.T) { + a2RefreshB = refreshTokens(t, a1Refresh) + }) + + t.Run("followup=first refresh from second refresh", func(t *testing.T) { + b2RefreshA = refreshTokens(t, b1Refresh) + }) + + t.Run("followup=second refresh from second refresh", func(t *testing.T) { + b2RefreshB = refreshTokens(t, b1Refresh) + }) + + // Sleep until the grace period is over + time.Sleep(time.Until(start.Add(5*time.Second + time.Millisecond*10))) + t.Run("followup=refresh failure invalidates all tokens", func(t *testing.T) { + _, err := conf.TokenSource(context.Background(), token).Token() + assert.Error(t, err) + + for k, token := range []*oauth2.Token{ + a1Refresh, b1Refresh, a2RefreshA, a2RefreshB, b2RefreshA, b2RefreshB, + } { + t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { + i := testhelpers.IntrospectToken(t, conf, token.AccessToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + + i = testhelpers.IntrospectToken(t, conf, token.AccessToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + + i = testhelpers.IntrospectToken(t, conf, token.RefreshToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + + i = testhelpers.IntrospectToken(t, conf, token.RefreshToken, adminTS) + assert.False(t, i.Get("active").Bool(), "%s", i) + }) + } + }) + }) + } + + t.Run("strategy=jwt", func(t *testing.T) { + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "jwt") + run(t, "jwt") + }) + + t.Run("strategy=opaque", func(t *testing.T) { + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") + run(t, "opaque") + }) + }) + + t.Run("case=perform authorize code flow with verifable credentials", func(t *testing.T) { + // Make sure we test against all crypto suites that we advertise. + cfg, _, err := publicClient.OidcAPI.DiscoverOidcConfiguration(ctx).Execute() + require.NoError(t, err) + supportedCryptoSuites := cfg.CredentialsSupportedDraft00[0].CryptographicSuitesSupported + + run := func(t *testing.T, strategy string) { + _, conf := newOAuth2Client( + t, + reg, + testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler), + withScope("openid userinfo_credential_draft_00"), + ) + testhelpers.NewLoginConsentUI(t, reg.Config(), + func(w http.ResponseWriter, r *http.Request) { + acceptBody := hydra.AcceptOAuth2LoginRequest{ + Subject: subject, + Acr: pointerx.Ptr("1"), + Amr: []string{"pwd"}, + Context: map[string]interface{}{"context": "bar"}, + } + v, _, err := adminClient.OAuth2API.AcceptOAuth2LoginRequest(context.Background()). + LoginChallenge(r.URL.Query().Get("login_challenge")). + AcceptOAuth2LoginRequest(acceptBody). + Execute() + require.NoError(t, err) + require.NotEmpty(t, v.RedirectTo) + http.Redirect(w, r, v.RedirectTo, http.StatusFound) + }, + func(w http.ResponseWriter, r *http.Request) { + rr, _, err := adminClient.OAuth2API.GetOAuth2ConsentRequest(context.Background()).ConsentChallenge(r.URL.Query().Get("consent_challenge")).Execute() + require.NoError(t, err) + + assert.Equal(t, map[string]interface{}{"context": "bar"}, rr.Context) + v, _, err := adminClient.OAuth2API.AcceptOAuth2ConsentRequest(context.Background()). + ConsentChallenge(r.URL.Query().Get("consent_challenge")). + AcceptOAuth2ConsentRequest(hydra.AcceptOAuth2ConsentRequest{ + GrantScope: []string{"openid", "userinfo_credential_draft_00"}, + GrantAccessTokenAudience: rr.RequestedAccessTokenAudience, + Session: &hydra.AcceptOAuth2ConsentRequestSession{ + AccessToken: map[string]interface{}{"foo": "bar"}, + IdToken: map[string]interface{}{"email": "foo@bar.com", "bar": "baz"}, + }, + }). + Execute() + require.NoError(t, err) + require.NotEmpty(t, v.RedirectTo) + http.Redirect(w, r, v.RedirectTo, http.StatusFound) + }, + ) + + code, _ := getAuthorizeCode(t, conf, nil, + oauth2.SetAuthURLParam("nonce", nonce), + oauth2.SetAuthURLParam("scope", "openid userinfo_credential_draft_00"), + ) + require.NotEmpty(t, code) + token, err := conf.Exchange(context.Background(), code) + require.NoError(t, err) + iat := time.Now() + + vcNonce := token.Extra("c_nonce_draft_00").(string) + assert.NotEmpty(t, vcNonce) + expiry := token.Extra("c_nonce_expires_in_draft_00") + assert.NotEmpty(t, expiry) + assert.NoError(t, reg.Persister().IsNonceValid(ctx, token.AccessToken, vcNonce)) + + t.Run("followup=successfully create a verifiable credential", func(t *testing.T) { + t.Parallel() + + for _, alg := range supportedCryptoSuites { + alg := alg + t.Run(fmt.Sprintf("alg=%s", alg), func(t *testing.T) { + t.Parallel() + assertCreateVerifiableCredential(t, reg, vcNonce, token, jose.SignatureAlgorithm(alg)) + }) + } + }) + + t.Run("followup=get new nonce from priming request", func(t *testing.T) { + t.Parallel() + // Assert that we can fetch a verifiable credential with the nonce. + res, err := doPrimingRequest(t, reg, token, &hydraoauth2.CreateVerifiableCredentialRequestBody{ + Format: "jwt_vc_json", + Types: []string{"VerifiableCredential", "UserInfoCredential"}, + }) + assert.NoError(t, err) + + t.Run("followup=successfully create a verifiable credential from fresh nonce", func(t *testing.T) { + assertCreateVerifiableCredential(t, reg, res.Nonce, token, jose.ES256) + }) + }) + + t.Run("followup=rejects proof signed by another key", func(t *testing.T) { + t.Parallel() + for _, tc := range []struct { + name string + format string + proofType string + proof func() string + }{ + { + name: "proof=mismatching keys", + proof: func() string { + // Create mismatching public and private keys. + pubKey, _, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + _, privKey, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(jose.ES256)} + return createVCProofJWT(t, pubKeyJWK, privKey, vcNonce) + }, + }, + { + name: "proof=invalid format", + format: "invalid_format", + proof: func() string { + // Create mismatching public and private keys. + pubKey, privKey, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(jose.ES256)} + return createVCProofJWT(t, pubKeyJWK, privKey, vcNonce) + }, + }, + { + name: "proof=invalid type", + proofType: "invalid", + proof: func() string { + // Create mismatching public and private keys. + pubKey, privKey, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(jose.ES256)} + return createVCProofJWT(t, pubKeyJWK, privKey, vcNonce) + }, + }, + { + name: "proof=invalid nonce", + proof: func() string { + // Create mismatching public and private keys. + pubKey, privKey, err := josex.NewSigningKey(jose.ES256, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(jose.ES256)} + return createVCProofJWT(t, pubKeyJWK, privKey, "invalid nonce") + }, + }, + } { + tc := tc + t.Run(tc.name, func(t *testing.T) { + t.Parallel() + _, res := createVerifiableCredential(t, reg, token, &hydraoauth2.CreateVerifiableCredentialRequestBody{ + Format: stringsx.Coalesce(tc.format, "jwt_vc_json"), + Types: []string{"VerifiableCredential", "UserInfoCredential"}, + Proof: &hydraoauth2.VerifiableCredentialProof{ + ProofType: stringsx.Coalesce(tc.proofType, "jwt"), + JWT: tc.proof(), + }, + }) + require.NoError(t, err) + require.NotNil(t, res) + assert.Equal(t, "invalid_request", res.Error()) + }) + } + + }) + + t.Run("followup=access token and id token are valid", func(t *testing.T) { + assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(reg.Config().GetAccessTokenLifespan(ctx)), `["openid","userinfo_credential_draft_00"]`) + assertIDToken(t, token, conf, subject, nonce, iat.Add(reg.Config().GetIDTokenLifespan(ctx))) + }) + } + + t.Run("strategy=jwt", func(t *testing.T) { + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "jwt") + run(t, "jwt") + }) + + t.Run("strategy=opaque", func(t *testing.T) { + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") + run(t, "opaque") + }) + }) + + t.Run("suite=invalid query params", func(t *testing.T) { + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + otherClient, _ := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + testhelpers.NewLoginConsentUI(t, reg.Config(), + acceptLoginHandler(t, c, subject, nil), + acceptConsentHandler(t, c, subject, nil), + ) + + withWrongClientAfterLogin := &http.Client{ + Jar: testhelpers.NewEmptyCookieJar(t), + CheckRedirect: func(req *http.Request, _ []*http.Request) error { + if req.URL.Path != "/oauth2/auth" { + return nil + } + q := req.URL.Query() + if !q.Has("login_verifier") { + return nil + } + q.Set("client_id", otherClient.GetID()) + req.URL.RawQuery = q.Encode() + return nil + }, + } + withWrongClientAfterConsent := &http.Client{ + Jar: testhelpers.NewEmptyCookieJar(t), + CheckRedirect: func(req *http.Request, _ []*http.Request) error { + if req.URL.Path != "/oauth2/auth" { + return nil + } + q := req.URL.Query() + if !q.Has("consent_verifier") { + return nil + } + q.Set("client_id", otherClient.GetID()) + req.URL.RawQuery = q.Encode() + return nil + }, + } + + withWrongScopeAfterLogin := &http.Client{ + Jar: testhelpers.NewEmptyCookieJar(t), + CheckRedirect: func(req *http.Request, _ []*http.Request) error { + if req.URL.Path != "/oauth2/auth" { + return nil + } + q := req.URL.Query() + if !q.Has("login_verifier") { + return nil + } + q.Set("scope", "invalid scope") + req.URL.RawQuery = q.Encode() + return nil + }, + } + + withWrongScopeAfterConsent := &http.Client{ + Jar: testhelpers.NewEmptyCookieJar(t), + CheckRedirect: func(req *http.Request, _ []*http.Request) error { + if req.URL.Path != "/oauth2/auth" { + return nil + } + q := req.URL.Query() + if !q.Has("consent_verifier") { + return nil + } + q.Set("scope", "invalid scope") + req.URL.RawQuery = q.Encode() + return nil + }, + } + for _, tc := range []struct { + name string + client *http.Client + expectedResponse string + }{{ + name: "fails with wrong client ID after login", + client: withWrongClientAfterLogin, + expectedResponse: "invalid_client", + }, { + name: "fails with wrong client ID after consent", + client: withWrongClientAfterConsent, + expectedResponse: "invalid_client", + }, { + name: "fails with wrong scopes after login", + client: withWrongScopeAfterLogin, + expectedResponse: "invalid_scope", + }, { + name: "fails with wrong scopes after consent", + client: withWrongScopeAfterConsent, + expectedResponse: "invalid_scope", + }} { + t.Run("case="+tc.name, func(t *testing.T) { + state := uuid.New() + resp, err := tc.client.Get(conf.AuthCodeURL(state)) + require.NoError(t, err) + assert.Equal(t, tc.expectedResponse, resp.Request.URL.Query().Get("error"), "%s", resp.Request.URL.RawQuery) + resp.Body.Close() + }) + } + }) + t.Run("case=checks if request fails when subject is empty", func(t *testing.T) { testhelpers.NewLoginConsentUI(t, reg.Config(), func(w http.ResponseWriter, r *http.Request) { - _, res, err := adminClient.OAuth2Api.AcceptOAuth2LoginRequest(ctx). + _, res, err := adminClient.OAuth2API.AcceptOAuth2LoginRequest(ctx). LoginChallenge(r.URL.Query().Get("login_challenge")). - AcceptOAuth2LoginRequest(hydra.AcceptOAuth2LoginRequest{Subject: "", Remember: pointerx.Bool(true)}).Execute() + AcceptOAuth2LoginRequest(hydra.AcceptOAuth2LoginRequest{Subject: "", Remember: pointerx.Ptr(true)}).Execute() require.Error(t, err) // expects 400 body := string(ioutilx.MustReadAll(res.Body)) assert.Contains(t, body, "Field 'subject' must not be empty", "%s", body) }, testhelpers.HTTPServerNoExpectedCallHandler(t)) - _, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + _, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) _, err := testhelpers.NewEmptyJarClient(t).Get(conf.AuthCodeURL(uuid.New())) require.NoError(t, err) }) + t.Run("case=perform flow with prompt=registration", func(t *testing.T) { + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + + regUI := httptest.NewServer(acceptLoginHandler(t, c, subject, nil)) + t.Cleanup(regUI.Close) + reg.Config().MustSet(ctx, config.KeyRegistrationURL, regUI.URL) + + testhelpers.NewLoginConsentUI(t, reg.Config(), + nil, + acceptConsentHandler(t, c, subject, nil)) + + code, _ := getAuthorizeCode(t, conf, nil, + oauth2.SetAuthURLParam("prompt", "registration"), + oauth2.SetAuthURLParam("nonce", nonce)) + require.NotEmpty(t, code) + + token, err := conf.Exchange(context.Background(), code) + require.NoError(t, err) + + assertIDToken(t, token, conf, subject, nonce, time.Now().Add(reg.Config().GetIDTokenLifespan(ctx))) + }) + t.Run("case=perform flow with audience", func(t *testing.T) { expectAud := "https://api.ory.sh/" - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { assert.False(t, r.Skip) @@ -395,7 +863,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=respects client token lifespan configuration", func(t *testing.T) { - run := func(t *testing.T, strategy string, c *hc.Client, conf *oauth2.Config, expectedLifespans client.Lifespans) { + run := func(t *testing.T, strategy string, c *client.Client, conf *oauth2.Config, expectedLifespans client.Lifespans) { testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -410,7 +878,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { body := introspectAccessToken(t, conf, token, subject) requirex.EqualTime(t, iat.Add(expectedLifespans.AuthorizationCodeGrantAccessTokenLifespan.Duration), time.Unix(body.Get("exp").Int(), 0), time.Second) - assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(expectedLifespans.AuthorizationCodeGrantAccessTokenLifespan.Duration)) + assertJWTAccessToken(t, strategy, conf, token, subject, iat.Add(expectedLifespans.AuthorizationCodeGrantAccessTokenLifespan.Duration), `["hydra","offline","openid"]`) assertIDToken(t, token, conf, subject, nonce, iat.Add(expectedLifespans.AuthorizationCodeGrantIDTokenLifespan.Duration)) assertRefreshToken(t, token, conf, iat.Add(expectedLifespans.AuthorizationCodeGrantRefreshTokenLifespan.Duration)) @@ -421,7 +889,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { iat = time.Now() require.NoError(t, err) assertRefreshToken(t, refreshedToken, conf, iat.Add(expectedLifespans.RefreshTokenGrantRefreshTokenLifespan.Duration)) - assertJWTAccessToken(t, strategy, conf, refreshedToken, subject, iat.Add(expectedLifespans.RefreshTokenGrantAccessTokenLifespan.Duration)) + assertJWTAccessToken(t, strategy, conf, refreshedToken, subject, iat.Add(expectedLifespans.RefreshTokenGrantAccessTokenLifespan.Duration), `["hydra","offline","openid"]`) assertIDToken(t, refreshedToken, conf, subject, nonce, iat.Add(expectedLifespans.RefreshTokenGrantIDTokenLifespan.Duration)) require.NotEqual(t, token.AccessToken, refreshedToken.AccessToken) @@ -444,12 +912,12 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { } t.Run("case=custom-lifespans-active-jwt", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) ls := testhelpers.TestLifespans ls.AuthorizationCodeGrantAccessTokenLifespan = x.NullDuration{Valid: true, Duration: 6 * time.Second} testhelpers.UpdateClientTokenLifespans( t, - &goauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, + &oauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, c.GetID(), ls, adminTS, ) @@ -458,12 +926,12 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=custom-lifespans-active-opaque", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) ls := testhelpers.TestLifespans ls.AuthorizationCodeGrantAccessTokenLifespan = x.NullDuration{Valid: true, Duration: 6 * time.Second} testhelpers.UpdateClientTokenLifespans( t, - &goauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, + &oauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, c.GetID(), ls, adminTS, ) @@ -472,11 +940,12 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=custom-lifespans-unset", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) - testhelpers.UpdateClientTokenLifespans(t, &goauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, c.GetID(), testhelpers.TestLifespans, adminTS) - testhelpers.UpdateClientTokenLifespans(t, &goauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, c.GetID(), client.Lifespans{}, adminTS) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + testhelpers.UpdateClientTokenLifespans(t, &oauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, c.GetID(), testhelpers.TestLifespans, adminTS) + testhelpers.UpdateClientTokenLifespans(t, &oauth2.Config{ClientID: c.GetID(), ClientSecret: conf.ClientSecret}, c.GetID(), client.Lifespans{}, adminTS) reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") + //goland:noinspection GoDeprecation expectedLifespans := client.Lifespans{ AuthorizationCodeGrantAccessTokenLifespan: x.NullDuration{Valid: true, Duration: reg.Config().GetAccessTokenLifespan(ctx)}, AuthorizationCodeGrantIDTokenLifespan: x.NullDuration{Valid: true, Duration: reg.Config().GetIDTokenLifespan(ctx)}, @@ -496,7 +965,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=use remember feature and prompt=none", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -594,7 +1063,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=should fail if prompt=none but no auth session given", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -608,7 +1077,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=requires re-authentication when id_token_hint is set to a user 'patrik-neu' but the session is 'aeneas-rekkas' and then fails because the user id from the log in endpoint is 'aeneas-rekkas'", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { require.False(t, r.Skip) @@ -632,7 +1101,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=should not cause issues if max_age is very low and consent takes a long time", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { time.Sleep(time.Second * 2) @@ -646,7 +1115,7 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { }) t.Run("case=ensure consistent claims returned for userinfo", func(t *testing.T) { - c, conf := newOAuth2Client(t, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) testhelpers.NewLoginConsentUI(t, reg.Config(), acceptLoginHandler(t, c, subject, nil), acceptConsentHandler(t, c, subject, nil), @@ -684,6 +1153,323 @@ func TestAuthCodeWithDefaultStrategy(t *testing.T) { assert.Empty(t, uiClaims.Get(f).Raw, "%s: %s", f, uiClaims) } }) + + t.Run("case=add ext claims from hook if configured", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.Header.Get("Content-Type"), "application/json; charset=UTF-8") + assert.Equal(t, r.Header.Get("Authorization"), "Bearer secret value") + + var hookReq hydraoauth2.TokenHookRequest + require.NoError(t, json.NewDecoder(r.Body).Decode(&hookReq)) + require.NotEmpty(t, hookReq.Session) + require.Equal(t, map[string]interface{}{"foo": "bar"}, hookReq.Session.Extra) + require.NotEmpty(t, hookReq.Request) + require.ElementsMatch(t, []string{}, hookReq.Request.GrantedAudience) + require.Equal(t, map[string][]string{"grant_type": {"authorization_code"}}, hookReq.Request.Payload) + + claims := map[string]interface{}{ + "hooked": true, + } + + hookResp := hydraoauth2.TokenHookResponse{ + Session: flow.AcceptOAuth2ConsentRequestSession{ + AccessToken: claims, + IDToken: claims, + }, + } + + w.WriteHeader(http.StatusOK) + require.NoError(t, json.NewEncoder(w).Encode(&hookResp)) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, &config.HookConfig{ + URL: hs.URL, + Auth: &config.Auth{ + Type: "api_key", + Config: config.AuthConfig{ + In: "header", + Name: "Authorization", + Value: "Bearer secret value", + }, + }, + }) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + expectAud := "https://api.ory.sh/" + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + testhelpers.NewLoginConsentUI(t, reg.Config(), + acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { + assert.False(t, r.Skip) + assert.EqualValues(t, []string{expectAud}, r.RequestedAccessTokenAudience) + return nil + }), + acceptConsentHandler(t, c, subject, func(r *hydra.OAuth2ConsentRequest) { + assert.False(t, *r.Skip) + assert.EqualValues(t, []string{expectAud}, r.RequestedAccessTokenAudience) + })) + + code, _ := getAuthorizeCode(t, conf, nil, + oauth2.SetAuthURLParam("audience", "https://api.ory.sh/"), + oauth2.SetAuthURLParam("nonce", nonce)) + require.NotEmpty(t, code) + + token, err := conf.Exchange(context.Background(), code) + require.NoError(t, err) + + assertJWTAccessToken(t, strategy, conf, token, subject, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx)), `["hydra","offline","openid"]`) + + // NOTE: using introspect to cover both jwt and opaque strategies + accessTokenClaims := introspectAccessToken(t, conf, token, subject) + require.True(t, accessTokenClaims.Get("ext.hooked").Bool()) + + idTokenClaims := assertIDToken(t, token, conf, subject, nonce, time.Now().Add(reg.Config().GetIDTokenLifespan(ctx))) + require.True(t, idTokenClaims.Get("hooked").Bool()) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("case=fail token exchange if hook fails", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + expectAud := "https://api.ory.sh/" + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + testhelpers.NewLoginConsentUI(t, reg.Config(), + acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { + assert.False(t, r.Skip) + assert.EqualValues(t, []string{expectAud}, r.RequestedAccessTokenAudience) + return nil + }), + acceptConsentHandler(t, c, subject, func(r *hydra.OAuth2ConsentRequest) { + assert.False(t, *r.Skip) + assert.EqualValues(t, []string{expectAud}, r.RequestedAccessTokenAudience) + })) + + code, _ := getAuthorizeCode(t, conf, nil, + oauth2.SetAuthURLParam("audience", "https://api.ory.sh/"), + oauth2.SetAuthURLParam("nonce", nonce)) + require.NotEmpty(t, code) + + _, err := conf.Exchange(context.Background(), code) + require.Error(t, err) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("case=fail token exchange if hook denies the request", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusForbidden) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + expectAud := "https://api.ory.sh/" + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + testhelpers.NewLoginConsentUI(t, reg.Config(), + acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { + assert.False(t, r.Skip) + assert.EqualValues(t, []string{expectAud}, r.RequestedAccessTokenAudience) + return nil + }), + acceptConsentHandler(t, c, subject, func(r *hydra.OAuth2ConsentRequest) { + assert.False(t, *r.Skip) + assert.EqualValues(t, []string{expectAud}, r.RequestedAccessTokenAudience) + })) + + code, _ := getAuthorizeCode(t, conf, nil, + oauth2.SetAuthURLParam("audience", "https://api.ory.sh/"), + oauth2.SetAuthURLParam("nonce", nonce)) + require.NotEmpty(t, code) + + _, err := conf.Exchange(context.Background(), code) + require.Error(t, err) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("case=fail token exchange if hook response is malformed", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + expectAud := "https://api.ory.sh/" + c, conf := newOAuth2Client(t, reg, testhelpers.NewCallbackURL(t, "callback", testhelpers.HTTPServerNotImplementedHandler)) + testhelpers.NewLoginConsentUI(t, reg.Config(), + acceptLoginHandler(t, c, subject, func(r *hydra.OAuth2LoginRequest) *hydra.AcceptOAuth2LoginRequest { + assert.False(t, r.Skip) + assert.EqualValues(t, []string{expectAud}, r.RequestedAccessTokenAudience) + return nil + }), + acceptConsentHandler(t, c, subject, func(r *hydra.OAuth2ConsentRequest) { + assert.False(t, *r.Skip) + assert.EqualValues(t, []string{expectAud}, r.RequestedAccessTokenAudience) + })) + + code, _ := getAuthorizeCode(t, conf, nil, + oauth2.SetAuthURLParam("audience", "https://api.ory.sh/"), + oauth2.SetAuthURLParam("nonce", nonce)) + require.NotEmpty(t, code) + + _, err := conf.Exchange(context.Background(), code) + require.Error(t, err) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) +} + +func assertCreateVerifiableCredential(t *testing.T, reg driver.Registry, nonce string, accessToken *oauth2.Token, alg jose.SignatureAlgorithm) { + // Build a proof from the nonce. + pubKey, privKey, err := josex.NewSigningKey(alg, 0) + require.NoError(t, err) + pubKeyJWK := &jose.JSONWebKey{Key: pubKey, Algorithm: string(alg)} + proofJWT := createVCProofJWT(t, pubKeyJWK, privKey, nonce) + + // Assert that we can fetch a verifiable credential with the nonce. + verifiableCredential, _ := createVerifiableCredential(t, reg, accessToken, &hydraoauth2.CreateVerifiableCredentialRequestBody{ + Format: "jwt_vc_json", + Types: []string{"VerifiableCredential", "UserInfoCredential"}, + Proof: &hydraoauth2.VerifiableCredentialProof{ + ProofType: "jwt", + JWT: proofJWT, + }, + }) + require.NoError(t, err) + require.NotNil(t, verifiableCredential) + + _, claims := claimsFromVCResponse(t, reg, verifiableCredential) + assertClaimsContainPublicKey(t, claims, pubKeyJWK) +} + +func claimsFromVCResponse(t *testing.T, reg driver.Registry, vc *hydraoauth2.VerifiableCredentialResponse) (*jwt.Token, *hydraoauth2.VerifableCredentialClaims) { + ctx := context.Background() + token, err := jwt.ParseWithClaims(vc.Credential, new(hydraoauth2.VerifableCredentialClaims), func(token *jwt.Token) (interface{}, error) { + kid, found := token.Header["kid"] + if !found { + return nil, errors.New("missing kid header") + } + openIDKey, err := reg.OpenIDJWTStrategy().GetPublicKeyID(ctx) + if err != nil { + return nil, err + } + if kid != openIDKey { + return nil, errors.New("invalid kid header") + } + + return x.Must(reg.OpenIDJWTStrategy().GetPublicKey(ctx)).Key, nil + }) + require.NoError(t, err) + + return token, token.Claims.(*hydraoauth2.VerifableCredentialClaims) +} + +func assertClaimsContainPublicKey(t *testing.T, claims *hydraoauth2.VerifableCredentialClaims, pubKeyJWK *jose.JSONWebKey) { + pubKeyRaw, err := pubKeyJWK.MarshalJSON() + require.NoError(t, err) + expectedID := fmt.Sprintf("did:jwk:%s", base64.RawURLEncoding.EncodeToString(pubKeyRaw)) + require.Equal(t, expectedID, claims.VerifiableCredential.Subject["id"]) +} + +func createVerifiableCredential( + t *testing.T, + reg driver.Registry, + token *oauth2.Token, + createVerifiableCredentialReq *hydraoauth2.CreateVerifiableCredentialRequestBody, +) (vcRes *hydraoauth2.VerifiableCredentialResponse, vcErr *fosite.RFC6749Error) { + var ( + ctx = context.Background() + body bytes.Buffer + ) + require.NoError(t, json.NewEncoder(&body).Encode(createVerifiableCredentialReq)) + req := httpx.MustNewRequest("POST", reg.Config().CredentialsEndpointURL(ctx).String(), &body, "application/json") + req.Header.Set("Authorization", "Bearer "+token.AccessToken) + res, err := http.DefaultClient.Do(req) + require.NoError(t, err) + defer res.Body.Close() + + if res.StatusCode != http.StatusOK { + var errRes fosite.RFC6749Error + require.NoError(t, json.NewDecoder(res.Body).Decode(&errRes)) + return nil, &errRes + } + require.Equal(t, http.StatusOK, res.StatusCode) + var vc hydraoauth2.VerifiableCredentialResponse + require.NoError(t, json.NewDecoder(res.Body).Decode(&vc)) + + return &vc, vcErr +} + +func doPrimingRequest( + t *testing.T, + reg driver.Registry, + token *oauth2.Token, + createVerifiableCredentialReq *hydraoauth2.CreateVerifiableCredentialRequestBody, +) (*hydraoauth2.VerifiableCredentialPrimingResponse, error) { + var ( + ctx = context.Background() + body bytes.Buffer + ) + require.NoError(t, json.NewEncoder(&body).Encode(createVerifiableCredentialReq)) + req := httpx.MustNewRequest("POST", reg.Config().CredentialsEndpointURL(ctx).String(), &body, "application/json") + req.Header.Set("Authorization", "Bearer "+token.AccessToken) + res, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + defer res.Body.Close() + require.Equal(t, http.StatusBadRequest, res.StatusCode) + var vc hydraoauth2.VerifiableCredentialPrimingResponse + require.NoError(t, json.NewDecoder(res.Body).Decode(&vc)) + + return &vc, nil +} + +func createVCProofJWT(t *testing.T, pubKey *jose.JSONWebKey, privKey any, nonce string) string { + proofToken := jwt.NewWithClaims(jwt.GetSigningMethod(string(pubKey.Algorithm)), jwt.MapClaims{"nonce": nonce}) + proofToken.Header["jwk"] = pubKey + proofJWT, err := proofToken.SignedString(privKey) + require.NoError(t, err) + + return proofJWT } // TestAuthCodeWithMockStrategy runs the authorization_code flow against various ConsentStrategy scenarios. @@ -705,8 +1491,8 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { conf.MustSet(ctx, config.KeyScopeStrategy, "DEPRECATED_HIERARCHICAL_SCOPE_STRATEGY") conf.MustSet(ctx, config.KeyAccessTokenStrategy, strat.d) reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) - internal.MustEnsureRegistryKeys(reg, x.OpenIDConnectKeyName) - internal.MustEnsureRegistryKeys(reg, x.OAuth2JWTKeyName) + internal.MustEnsureRegistryKeys(ctx, reg, x.OpenIDConnectKeyName) + internal.MustEnsureRegistryKeys(ctx, reg, x.OAuth2JWTKeyName) consentStrategy := &consentMock{} router := x.NewRouterPublic() @@ -725,13 +1511,13 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { }) var mutex sync.Mutex - require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), &hc.Client{ - LegacyClientID: "app-client", - Secret: "secret", - RedirectURIs: []string{ts.URL + "/callback"}, - ResponseTypes: []string{"id_token", "code", "token"}, - GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, - Scope: "hydra.* offline openid", + require.NoError(t, reg.ClientManager().CreateClient(context.TODO(), &client.Client{ + ID: "app-client", + Secret: "secret", + RedirectURIs: []string{ts.URL + "/callback"}, + ResponseTypes: []string{"id_token", "code", "token"}, + GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, + Scope: "hydra.* offline openid", })) oauthConfig := &oauth2.Config{ @@ -768,7 +1554,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { code = r.URL.Query().Get("code") require.NotEmpty(t, code) - w.Write([]byte(r.URL.Query().Get("code"))) + _, _ = w.Write([]byte(r.URL.Query().Get("code"))) } }, assertAccessToken: func(t *testing.T, token string) { @@ -819,7 +1605,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { code = r.URL.Query().Get("code") require.NotEmpty(t, code) - w.Write([]byte(r.URL.Query().Get("code"))) + _, _ = w.Write([]byte(r.URL.Query().Get("code"))) } }, }, @@ -861,7 +1647,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { return func(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { code = r.URL.Query().Get("code") require.NotEmpty(t, code) - w.Write([]byte(r.URL.Query().Get("code"))) + _, _ = w.Write([]byte(r.URL.Query().Get("code"))) } }, }, @@ -913,7 +1699,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { require.NotEmpty(t, code) - token, err := oauthConfig.Exchange(oauth2.NoContext, code) + token, err := oauthConfig.Exchange(context.TODO(), code) if tc.expectOAuthTokenError { require.Error(t, err) return @@ -1021,157 +1807,227 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { }) t.Run("should call refresh token hook if configured", func(t *testing.T) { - hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - assert.Equal(t, r.Header.Get("Content-Type"), "application/json; charset=UTF-8") - - expectedGrantedScopes := []string{"openid", "offline", "hydra.*"} - expectedSubject := "foo" - - var hookReq hydraoauth2.RefreshTokenHookRequest - require.NoError(t, json.NewDecoder(r.Body).Decode(&hookReq)) - require.Equal(t, hookReq.Subject, expectedSubject) - require.ElementsMatch(t, hookReq.GrantedScopes, expectedGrantedScopes) - require.ElementsMatch(t, hookReq.GrantedAudience, []string{}) - require.Equal(t, hookReq.ClientID, oauthConfig.ClientID) - require.NotEmpty(t, hookReq.Session) - require.Equal(t, hookReq.Session.Subject, expectedSubject) - require.Equal(t, hookReq.Session.ClientID, oauthConfig.ClientID) - require.Equal(t, hookReq.Session.Extra, map[string]interface{}{}) - require.NotEmpty(t, hookReq.Requester) - require.Equal(t, hookReq.Requester.ClientID, oauthConfig.ClientID) - require.ElementsMatch(t, hookReq.Requester.GrantedScopes, expectedGrantedScopes) - - except := []string{ - "session.kid", - "session.id_token.expires_at", - "session.id_token.headers.extra.kid", - "session.id_token.id_token_claims.iat", - "session.id_token.id_token_claims.exp", - "session.id_token.id_token_claims.rat", - "session.id_token.id_token_claims.auth_time", - } - snapshotx.SnapshotTExcept(t, hookReq, except) - - claims := map[string]interface{}{ - "hooked": true, + run := func(hookType string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.Header.Get("Content-Type"), "application/json; charset=UTF-8") + + expectedGrantedScopes := []string{"openid", "offline", "hydra.*"} + expectedSubject := "foo" + + exceptKeys := []string{ + "session.kid", + "session.id_token.expires_at", + "session.id_token.headers.extra.kid", + "session.id_token.id_token_claims.iat", + "session.id_token.id_token_claims.exp", + "session.id_token.id_token_claims.rat", + "session.id_token.id_token_claims.auth_time", + } + + if hookType == "legacy" { + var hookReq hydraoauth2.RefreshTokenHookRequest + require.NoError(t, json.NewDecoder(r.Body).Decode(&hookReq)) + require.Equal(t, hookReq.Subject, expectedSubject) + require.ElementsMatch(t, hookReq.GrantedScopes, expectedGrantedScopes) + require.ElementsMatch(t, hookReq.GrantedAudience, []string{}) + require.Equal(t, hookReq.ClientID, oauthConfig.ClientID) + require.NotEmpty(t, hookReq.Session) + require.Equal(t, hookReq.Session.Subject, expectedSubject) + require.Equal(t, hookReq.Session.ClientID, oauthConfig.ClientID) + require.NotEmpty(t, hookReq.Requester) + require.Equal(t, hookReq.Requester.ClientID, oauthConfig.ClientID) + require.ElementsMatch(t, hookReq.Requester.GrantedScopes, expectedGrantedScopes) + + snapshotx.SnapshotT(t, hookReq, snapshotx.ExceptPaths(exceptKeys...)) + } else { + var hookReq hydraoauth2.TokenHookRequest + require.NoError(t, json.NewDecoder(r.Body).Decode(&hookReq)) + require.NotEmpty(t, hookReq.Session) + require.Equal(t, hookReq.Session.Subject, expectedSubject) + require.Equal(t, hookReq.Session.ClientID, oauthConfig.ClientID) + require.NotEmpty(t, hookReq.Request) + require.Equal(t, hookReq.Request.ClientID, oauthConfig.ClientID) + require.ElementsMatch(t, hookReq.Request.GrantedScopes, expectedGrantedScopes) + require.ElementsMatch(t, hookReq.Request.GrantedAudience, []string{}) + require.Equal(t, hookReq.Request.Payload, map[string][]string{"grant_type": {"refresh_token"}}) + + snapshotx.SnapshotT(t, hookReq, snapshotx.ExceptPaths(exceptKeys...)) + } + + claims := map[string]interface{}{ + "hooked": hookType, + } + + hookResp := hydraoauth2.TokenHookResponse{ + Session: flow.AcceptOAuth2ConsentRequestSession{ + AccessToken: claims, + IDToken: claims, + }, + } + + w.WriteHeader(http.StatusOK) + require.NoError(t, json.NewEncoder(w).Encode(&hookResp)) + })) + defer hs.Close() + + if hookType == "legacy" { + conf.MustSet(ctx, config.KeyRefreshTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyRefreshTokenHook, nil) + } else { + conf.MustSet(ctx, config.KeyTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyTokenHook, nil) + } + + res, err := testRefresh(t, &refreshedToken, ts.URL, false) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) + + body, err := io.ReadAll(res.Body) + require.NoError(t, err) + require.NoError(t, json.Unmarshal(body, &refreshedToken)) + + accessTokenClaims := testhelpers.IntrospectToken(t, oauthConfig, refreshedToken.AccessToken, ts) + require.Equal(t, accessTokenClaims.Get("ext.hooked").String(), hookType) + + idTokenBody, err := x.DecodeSegment( + strings.Split( + gjson.GetBytes(body, "id_token").String(), + ".", + )[1], + ) + require.NoError(t, err) + + require.Equal(t, gjson.GetBytes(idTokenBody, "hooked").String(), hookType) } - - hookResp := hydraoauth2.RefreshTokenHookResponse{ - Session: consent.AcceptOAuth2ConsentRequestSession{ - AccessToken: claims, - IDToken: claims, - }, - } - - w.WriteHeader(http.StatusOK) - require.NoError(t, json.NewEncoder(w).Encode(&hookResp)) - })) - defer hs.Close() - - conf.MustSet(ctx, config.KeyRefreshTokenHookURL, hs.URL) - defer conf.MustSet(ctx, config.KeyRefreshTokenHookURL, nil) - - res, err := testRefresh(t, &refreshedToken, ts.URL, false) - require.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) - - body, err := io.ReadAll(res.Body) - require.NoError(t, err) - require.NoError(t, json.Unmarshal(body, &refreshedToken)) - - accessTokenClaims := testhelpers.IntrospectToken(t, oauthConfig, refreshedToken.AccessToken, ts) - require.True(t, accessTokenClaims.Get("ext.hooked").Bool()) - - idTokenBody, err := x.DecodeSegment( - strings.Split( - gjson.GetBytes(body, "id_token").String(), - ".", - )[1], - ) - require.NoError(t, err) - - require.True(t, gjson.GetBytes(idTokenBody, "hooked").Bool()) + } + t.Run("hook=legacy", run("legacy")) + t.Run("hook=new", run("new")) }) t.Run("should not override session data if token refresh hook returns no content", func(t *testing.T) { - hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusNoContent) - })) - defer hs.Close() - - conf.MustSet(ctx, config.KeyRefreshTokenHookURL, hs.URL) - defer conf.MustSet(ctx, config.KeyRefreshTokenHookURL, nil) - - origAccessTokenClaims := testhelpers.IntrospectToken(t, oauthConfig, refreshedToken.AccessToken, ts) - - res, err := testRefresh(t, &refreshedToken, ts.URL, false) - require.NoError(t, err) - assert.Equal(t, http.StatusOK, res.StatusCode) - - body, err = io.ReadAll(res.Body) - require.NoError(t, err) - - require.NoError(t, json.Unmarshal(body, &refreshedToken)) - - refreshedAccessTokenClaims := testhelpers.IntrospectToken(t, oauthConfig, refreshedToken.AccessToken, ts) - assertx.EqualAsJSONExcept(t, json.RawMessage(origAccessTokenClaims.Raw), json.RawMessage(refreshedAccessTokenClaims.Raw), []string{"exp", "iat", "nbf"}) + run := func(hookType string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNoContent) + })) + defer hs.Close() + + if hookType == "legacy" { + conf.MustSet(ctx, config.KeyRefreshTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyRefreshTokenHook, nil) + } else { + conf.MustSet(ctx, config.KeyTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyTokenHook, nil) + } + + origAccessTokenClaims := testhelpers.IntrospectToken(t, oauthConfig, refreshedToken.AccessToken, ts) + + res, err := testRefresh(t, &refreshedToken, ts.URL, false) + require.NoError(t, err) + assert.Equal(t, http.StatusOK, res.StatusCode) + + body, err = io.ReadAll(res.Body) + require.NoError(t, err) + + require.NoError(t, json.Unmarshal(body, &refreshedToken)) + + refreshedAccessTokenClaims := testhelpers.IntrospectToken(t, oauthConfig, refreshedToken.AccessToken, ts) + assertx.EqualAsJSONExcept(t, json.RawMessage(origAccessTokenClaims.Raw), json.RawMessage(refreshedAccessTokenClaims.Raw), []string{"exp", "iat", "nbf"}) + } + } + t.Run("hook=legacy", run("legacy")) + t.Run("hook=new", run("new")) }) - t.Run("should fail token refresh with `server_error` if hook fails", func(t *testing.T) { - hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - })) - defer hs.Close() - - conf.MustSet(ctx, config.KeyRefreshTokenHookURL, hs.URL) - defer conf.MustSet(ctx, config.KeyRefreshTokenHookURL, nil) - - res, err := testRefresh(t, &refreshedToken, ts.URL, false) - require.NoError(t, err) - assert.Equal(t, http.StatusInternalServerError, res.StatusCode) - - var errBody fosite.RFC6749ErrorJson - require.NoError(t, json.NewDecoder(res.Body).Decode(&errBody)) - require.Equal(t, fosite.ErrServerError.Error(), errBody.Name) - require.Equal(t, "An error occurred while executing the refresh token hook.", errBody.Description) + t.Run("should fail token refresh with `server_error` if refresh hook fails", func(t *testing.T) { + run := func(hookType string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer hs.Close() + + if hookType == "legacy" { + conf.MustSet(ctx, config.KeyRefreshTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyRefreshTokenHook, nil) + } else { + conf.MustSet(ctx, config.KeyTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyTokenHook, nil) + } + + res, err := testRefresh(t, &refreshedToken, ts.URL, false) + require.NoError(t, err) + assert.Equal(t, http.StatusInternalServerError, res.StatusCode) + + var errBody fosite.RFC6749ErrorJson + require.NoError(t, json.NewDecoder(res.Body).Decode(&errBody)) + require.Equal(t, fosite.ErrServerError.Error(), errBody.Name) + require.Equal(t, "An error occurred while executing the token hook.", errBody.Description) + } + } + t.Run("hook=legacy", run("legacy")) + t.Run("hook=new", run("new")) }) - t.Run("should fail token refresh with `access_denied` if hook denied the request", func(t *testing.T) { - hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusForbidden) - })) - defer hs.Close() - - conf.MustSet(ctx, config.KeyRefreshTokenHookURL, hs.URL) - defer conf.MustSet(ctx, config.KeyRefreshTokenHookURL, nil) - - res, err := testRefresh(t, &refreshedToken, ts.URL, false) - require.NoError(t, err) - assert.Equal(t, http.StatusForbidden, res.StatusCode) - - var errBody fosite.RFC6749ErrorJson - require.NoError(t, json.NewDecoder(res.Body).Decode(&errBody)) - require.Equal(t, fosite.ErrAccessDenied.Error(), errBody.Name) - require.Equal(t, "The refresh token hook target responded with an error. Make sure that the request you are making is valid. Maybe the credential or request parameters you are using are limited in scope or otherwise restricted.", errBody.Description) + t.Run("should fail token refresh with `access_denied` if legacy refresh hook denied the request", func(t *testing.T) { + run := func(hookType string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusForbidden) + })) + defer hs.Close() + + if hookType == "legacy" { + conf.MustSet(ctx, config.KeyRefreshTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyRefreshTokenHook, nil) + } else { + conf.MustSet(ctx, config.KeyTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyTokenHook, nil) + } + + res, err := testRefresh(t, &refreshedToken, ts.URL, false) + require.NoError(t, err) + assert.Equal(t, http.StatusForbidden, res.StatusCode) + + var errBody fosite.RFC6749ErrorJson + require.NoError(t, json.NewDecoder(res.Body).Decode(&errBody)) + require.Equal(t, fosite.ErrAccessDenied.Error(), errBody.Name) + require.Equal(t, "The token hook target responded with an error. Make sure that the request you are making is valid. Maybe the credential or request parameters you are using are limited in scope or otherwise restricted.", errBody.Description) + } + } + t.Run("hook=legacy", run("legacy")) + t.Run("hook=new", run("new")) }) - t.Run("should fail token refresh with `server_error` if hook response is malformed", func(t *testing.T) { - hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - })) - defer hs.Close() - - conf.MustSet(ctx, config.KeyRefreshTokenHookURL, hs.URL) - defer conf.MustSet(ctx, config.KeyRefreshTokenHookURL, nil) - - res, err := testRefresh(t, &refreshedToken, ts.URL, false) - require.NoError(t, err) - assert.Equal(t, http.StatusInternalServerError, res.StatusCode) - - var errBody fosite.RFC6749ErrorJson - require.NoError(t, json.NewDecoder(res.Body).Decode(&errBody)) - require.Equal(t, fosite.ErrServerError.Error(), errBody.Name) - require.Equal(t, "The refresh token hook target responded with an error.", errBody.Description) + t.Run("should fail token refresh with `server_error` if refresh hook response is malformed", func(t *testing.T) { + run := func(hookType string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + defer hs.Close() + + if hookType == "legacy" { + conf.MustSet(ctx, config.KeyRefreshTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyRefreshTokenHook, nil) + } else { + conf.MustSet(ctx, config.KeyTokenHook, hs.URL) + defer conf.MustSet(ctx, config.KeyTokenHook, nil) + } + + res, err := testRefresh(t, &refreshedToken, ts.URL, false) + require.NoError(t, err) + assert.Equal(t, http.StatusInternalServerError, res.StatusCode) + + var errBody fosite.RFC6749ErrorJson + require.NoError(t, json.NewDecoder(res.Body).Decode(&errBody)) + require.Equal(t, fosite.ErrServerError.Error(), errBody.Name) + require.Equal(t, "The token hook target responded with an error.", errBody.Description) + } + } + t.Run("hook=legacy", run("legacy")) + t.Run("hook=new", run("new")) }) t.Run("refreshing old token should no longer work", func(t *testing.T) { @@ -1187,7 +2043,7 @@ func TestAuthCodeWithMockStrategy(t *testing.T) { }) t.Run("duplicate code exchange fails", func(t *testing.T) { - token, err := oauthConfig.Exchange(oauth2.NoContext, code) + token, err := oauthConfig.Exchange(context.TODO(), code) require.Error(t, err) require.Nil(t, token) }) @@ -1222,3 +2078,54 @@ func testRefresh(t *testing.T, token *oauth2.Token, u string, sleep bool) (*http return http.DefaultClient.Do(req) } + +func withScope(scope string) func(*client.Client) { + return func(c *client.Client) { + c.Scope = scope + } +} + +func newOAuth2Client( + t *testing.T, + reg interface { + config.Provider + client.Registry + }, + callbackURL string, + opts ...func(*client.Client), +) (*client.Client, *oauth2.Config) { + ctx := context.Background() + secret := uuid.New() + c := &client.Client{ + Secret: secret, + RedirectURIs: []string{callbackURL}, + ResponseTypes: []string{"id_token", "code", "token"}, + GrantTypes: []string{ + "implicit", + "refresh_token", + "authorization_code", + "password", + "client_credentials", + }, + Scope: "hydra offline openid", + Audience: []string{"https://api.ory.sh/"}, + } + + // apply options + for _, o := range opts { + o(c) + } + + require.NoError(t, reg.ClientManager().CreateClient(ctx, c)) + return c, &oauth2.Config{ + ClientID: c.GetID(), + ClientSecret: secret, + RedirectURL: callbackURL, + Endpoint: oauth2.Endpoint{ + AuthURL: reg.Config().OAuth2AuthURL(ctx).String(), + TokenURL: reg.Config().OAuth2TokenURL(ctx).String(), + AuthStyle: oauth2.AuthStyleInHeader, + }, + Scopes: strings.Split(c.Scope, " "), + } +} diff --git a/oauth2/oauth2_client_credentials_bench_test.go b/oauth2/oauth2_client_credentials_bench_test.go new file mode 100644 index 00000000000..310727f34cc --- /dev/null +++ b/oauth2/oauth2_client_credentials_bench_test.go @@ -0,0 +1,162 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oauth2_test + +import ( + "context" + "encoding/json" + "net/url" + "strings" + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/tidwall/gjson" + "go.opentelemetry.io/otel/sdk/trace" + "go.opentelemetry.io/otel/sdk/trace/tracetest" + goauth2 "golang.org/x/oauth2" + "golang.org/x/oauth2/clientcredentials" + + hc "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/internal/testhelpers" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/contextx" + "github.com/ory/x/requirex" +) + +func BenchmarkClientCredentials(b *testing.B) { + ctx := context.Background() + + spans := tracetest.NewSpanRecorder() + tracer := trace.NewTracerProvider(trace.WithSpanProcessor(spans)).Tracer("") + + dsn := "postgres://postgres:secret@127.0.0.1:3445/postgres?sslmode=disable" + reg := internal.NewRegistrySQLFromURL(b, dsn, true, new(contextx.Default)).WithTracer(tracer) + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "opaque") + public, admin := testhelpers.NewOAuth2Server(ctx, b, reg) + + var newCustomClient = func(b *testing.B, c *hc.Client) (*hc.Client, clientcredentials.Config) { + unhashedSecret := c.Secret + require.NoError(b, reg.ClientManager().CreateClient(ctx, c)) + return c, clientcredentials.Config{ + ClientID: c.GetID(), + ClientSecret: unhashedSecret, + TokenURL: reg.Config().OAuth2TokenURL(ctx).String(), + Scopes: strings.Split(c.Scope, " "), + EndpointParams: url.Values{"audience": c.Audience}, + } + } + + var newClient = func(b *testing.B) (*hc.Client, clientcredentials.Config) { + cc, config := newCustomClient(b, &hc.Client{ + Secret: uuid.New().String(), + RedirectURIs: []string{public.URL + "/callback"}, + ResponseTypes: []string{"token"}, + GrantTypes: []string{"client_credentials"}, + Scope: "foobar", + Audience: []string{"https://api.ory.sh/"}, + }) + return cc, config + } + + var getToken = func(t *testing.B, conf clientcredentials.Config) (*goauth2.Token, error) { + conf.AuthStyle = goauth2.AuthStyleInHeader + return conf.Token(context.Background()) + } + + var encodeOr = func(b *testing.B, val interface{}, or string) string { + out, err := json.Marshal(val) + require.NoError(b, err) + if string(out) == "null" { + return or + } + + return string(out) + } + + var inspectToken = func(b *testing.B, token *goauth2.Token, cl *hc.Client, conf clientcredentials.Config, strategy string, expectedExp time.Time, checkExtraClaims bool) { + introspection := testhelpers.IntrospectToken(b, &goauth2.Config{ClientID: cl.GetID(), ClientSecret: conf.ClientSecret}, token.AccessToken, admin) + + check := func(res gjson.Result) { + assert.EqualValues(b, cl.GetID(), res.Get("client_id").String(), "%s", res.Raw) + assert.EqualValues(b, cl.GetID(), res.Get("sub").String(), "%s", res.Raw) + assert.EqualValues(b, reg.Config().IssuerURL(ctx).String(), res.Get("iss").String(), "%s", res.Raw) + + assert.EqualValues(b, res.Get("nbf").Int(), res.Get("iat").Int(), "%s", res.Raw) + requirex.EqualTime(b, expectedExp, time.Unix(res.Get("exp").Int(), 0), time.Second) + + assert.EqualValues(b, encodeOr(b, conf.EndpointParams["audience"], "[]"), res.Get("aud").Raw, "%s", res.Raw) + + if checkExtraClaims { + require.True(b, res.Get("ext.hooked").Bool()) + } + } + + check(introspection) + assert.True(b, introspection.Get("active").Bool()) + assert.EqualValues(b, "access_token", introspection.Get("token_use").String()) + assert.EqualValues(b, "Bearer", introspection.Get("token_type").String()) + assert.EqualValues(b, strings.Join(conf.Scopes, " "), introspection.Get("scope").String(), "%s", introspection.Raw) + + if strategy != "jwt" { + return + } + + body, err := x.DecodeSegment(strings.Split(token.AccessToken, ".")[1]) + require.NoError(b, err) + + jwtClaims := gjson.ParseBytes(body) + assert.NotEmpty(b, jwtClaims.Get("jti").String()) + assert.EqualValues(b, encodeOr(b, conf.Scopes, "[]"), jwtClaims.Get("scp").Raw, "%s", introspection.Raw) + check(jwtClaims) + } + + var getAndInspectToken = func(b *testing.B, cl *hc.Client, conf clientcredentials.Config, strategy string, expectedExp time.Time, checkExtraClaims bool) { + token, err := getToken(b, conf) + require.NoError(b, err) + inspectToken(b, token, cl, conf, strategy, expectedExp, checkExtraClaims) + } + + run := func(strategy string) func(b *testing.B) { + return func(t *testing.B) { + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + + cl, conf := newClient(b) + getAndInspectToken(b, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx)), false) + } + } + + b.Run("strategy=jwt", func(b *testing.B) { + initialDBSpans := dbSpans(spans) + for i := 0; i < b.N; i++ { + run("jwt")(b) + } + b.ReportMetric(0, "ns/op") + b.ReportMetric(float64(b.Elapsed().Milliseconds())/float64(b.N), "ms/op") + b.ReportMetric((float64(dbSpans(spans)-initialDBSpans))/float64(b.N), "queries/op") + }) + + b.Run("strategy=opaque", func(b *testing.B) { + initialDBSpans := dbSpans(spans) + for i := 0; i < b.N; i++ { + run("opaque")(b) + } + b.ReportMetric(0, "ns/op") + b.ReportMetric(float64(b.Elapsed().Milliseconds())/float64(b.N), "ms/op") + b.ReportMetric((float64(dbSpans(spans)-initialDBSpans))/float64(b.N), "queries/op") + }) +} + +func dbSpans(spans *tracetest.SpanRecorder) (count int) { + for _, s := range spans.Started() { + if strings.HasPrefix(s.Name(), "sql-") { + count++ + } + } + return +} diff --git a/oauth2/oauth2_client_credentials_test.go b/oauth2/oauth2_client_credentials_test.go index 5f0de59aef8..9d5067dafb1 100644 --- a/oauth2/oauth2_client_credentials_test.go +++ b/oauth2/oauth2_client_credentials_test.go @@ -6,7 +6,8 @@ package oauth2_test import ( "context" "encoding/json" - "math" + "net/http" + "net/http/httptest" "net/url" "strings" "testing" @@ -20,13 +21,15 @@ import ( goauth2 "golang.org/x/oauth2" "golang.org/x/oauth2/clientcredentials" - "github.com/ory/hydra/internal/testhelpers" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/internal/testhelpers" + hydraoauth2 "github.com/ory/hydra/v2/oauth2" "github.com/ory/x/contextx" - hc "github.com/ory/hydra/client" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/x" + hc "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/x" "github.com/ory/x/requirex" ) @@ -75,7 +78,7 @@ func TestClientCredentials(t *testing.T) { return string(out) } - var inspectToken = func(t *testing.T, token *goauth2.Token, cl *hc.Client, conf clientcredentials.Config, strategy string, expectedExp time.Time) { + var inspectToken = func(t *testing.T, token *goauth2.Token, cl *hc.Client, conf clientcredentials.Config, strategy string, expectedExp time.Time, checkExtraClaims bool) { introspection := testhelpers.IntrospectToken(t, &goauth2.Config{ClientID: cl.GetID(), ClientSecret: conf.ClientSecret}, token.AccessToken, admin) check := func(res gjson.Result) { @@ -87,6 +90,10 @@ func TestClientCredentials(t *testing.T) { requirex.EqualTime(t, expectedExp, time.Unix(res.Get("exp").Int(), 0), time.Second) assert.EqualValues(t, encodeOr(t, conf.EndpointParams["audience"], "[]"), res.Get("aud").Raw, "%s", res.Raw) + + if checkExtraClaims { + require.True(t, res.Get("ext.hooked").Bool()) + } } check(introspection) @@ -108,10 +115,10 @@ func TestClientCredentials(t *testing.T) { check(jwtClaims) } - var getAndInspectToken = func(t *testing.T, cl *hc.Client, conf clientcredentials.Config, strategy string, expectedExp time.Time) { + var getAndInspectToken = func(t *testing.T, cl *hc.Client, conf clientcredentials.Config, strategy string, expectedExp time.Time, checkExtraClaims bool) { token, err := getToken(t, conf) require.NoError(t, err) - inspectToken(t, token, cl, conf, strategy, expectedExp) + inspectToken(t, token, cl, conf, strategy, expectedExp, checkExtraClaims) } t.Run("case=should fail because audience is not allowed", func(t *testing.T) { @@ -134,7 +141,7 @@ func TestClientCredentials(t *testing.T) { reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) cl, conf := newClient(t) - getAndInspectToken(t, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx))) + getAndInspectToken(t, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx)), false) } } @@ -149,7 +156,7 @@ func TestClientCredentials(t *testing.T) { cl, conf := newClient(t) conf.EndpointParams = url.Values{} - getAndInspectToken(t, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx))) + getAndInspectToken(t, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx)), false) } } @@ -164,7 +171,7 @@ func TestClientCredentials(t *testing.T) { cl, conf := newClient(t) conf.Scopes = []string{} - getAndInspectToken(t, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx))) + getAndInspectToken(t, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx)), false) } } @@ -188,7 +195,7 @@ func TestClientCredentials(t *testing.T) { // We reset this so that introspectToken is going to check for the default scope. conf.Scopes = defaultScope - inspectToken(t, token, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx))) + inspectToken(t, token, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx)), false) } } @@ -211,7 +218,7 @@ func TestClientCredentials(t *testing.T) { Audience: []string{"https://api.ory.sh/"}, }) testhelpers.UpdateClientTokenLifespans(t, &goauth2.Config{ClientID: cl.GetID(), ClientSecret: conf.ClientSecret}, cl.GetID(), testhelpers.TestLifespans, admin) - getAndInspectToken(t, cl, conf, strategy, time.Now().Add(testhelpers.TestLifespans.ClientCredentialsGrantAccessTokenLifespan.Duration)) + getAndInspectToken(t, cl, conf, strategy, time.Now().Add(testhelpers.TestLifespans.ClientCredentialsGrantAccessTokenLifespan.Duration), false) } } @@ -230,11 +237,155 @@ func TestClientCredentials(t *testing.T) { conf.Scopes = []string{} token, err := getToken(t, conf) require.NoError(t, err) + expected := time.Now().Add(duration) + assert.WithinDuration(t, expected, token.Expiry, 5*time.Second) + introspection := testhelpers.IntrospectToken(t, &goauth2.Config{ClientID: cl.GetID(), ClientSecret: conf.ClientSecret}, token.AccessToken, admin) + assert.WithinDuration(t, expected, time.Unix(introspection.Get("exp").Int(), 0), 5*time.Second) + } + } - assert.True(t, math.Abs(float64(time.Now().Add(duration).Round(time.Minute).Unix())-float64(token.Expiry.Round(time.Minute).Unix())) < 5) + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) - introspection := testhelpers.IntrospectToken(t, &goauth2.Config{ClientID: cl.GetID(), ClientSecret: conf.ClientSecret}, token.AccessToken, admin) - assert.EqualValues(t, time.Now().Add(duration).Round(time.Minute), time.Unix(introspection.Get("exp").Int(), 0).Round(time.Minute)) + t.Run("should call token hook if configured", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + scope := "foobar" + audience := []string{"https://api.ory.sh/"} + + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.Header.Get("Content-Type"), "application/json; charset=UTF-8") + assert.Equal(t, r.Header.Get("Authorization"), "Bearer secret value") + + expectedGrantedScopes := []string{"foobar"} + expectedGrantedAudience := []string{"https://api.ory.sh/"} + + var hookReq hydraoauth2.TokenHookRequest + require.NoError(t, json.NewDecoder(r.Body).Decode(&hookReq)) + require.NotEmpty(t, hookReq.Session) + require.Equal(t, hookReq.Session.Extra, map[string]interface{}{}) + require.NotEmpty(t, hookReq.Request) + require.ElementsMatch(t, hookReq.Request.GrantedScopes, expectedGrantedScopes) + require.ElementsMatch(t, hookReq.Request.GrantedAudience, expectedGrantedAudience) + require.Equal(t, hookReq.Request.Payload, map[string][]string{ + "grant_type": {"client_credentials"}, + "scope": {"foobar"}, + }) + + claims := map[string]interface{}{ + "hooked": true, + } + + hookResp := hydraoauth2.TokenHookResponse{ + Session: flow.AcceptOAuth2ConsentRequestSession{ + AccessToken: claims, + IDToken: claims, + }, + } + + w.WriteHeader(http.StatusOK) + require.NoError(t, json.NewEncoder(w).Encode(&hookResp)) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, &config.HookConfig{ + URL: hs.URL, + Auth: &config.Auth{ + Type: "api_key", + Config: config.AuthConfig{ + In: "header", + Name: "Authorization", + Value: "Bearer secret value", + }, + }, + }) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + secret := uuid.New().String() + cl, conf := newCustomClient(t, &hc.Client{ + Secret: secret, + RedirectURIs: []string{public.URL + "/callback"}, + ResponseTypes: []string{"token"}, + GrantTypes: []string{"client_credentials"}, + Scope: scope, + Audience: audience, + }) + getAndInspectToken(t, cl, conf, strategy, time.Now().Add(reg.Config().GetAccessTokenLifespan(ctx)), true) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("should fail token if hook fails", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + _, conf := newClient(t) + + _, err := getToken(t, conf) + require.Error(t, err) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("should fail token if hook denied the request", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusForbidden) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + _, conf := newClient(t) + + _, err := getToken(t, conf) + require.Error(t, err) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("should fail token if hook response is malformed", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + _, conf := newClient(t) + + _, err := getToken(t, conf) + require.Error(t, err) } } diff --git a/oauth2/oauth2_helper_test.go b/oauth2/oauth2_helper_test.go index a1d4f5ad9bb..52a30e5975e 100644 --- a/oauth2/oauth2_helper_test.go +++ b/oauth2/oauth2_helper_test.go @@ -11,10 +11,11 @@ import ( "github.com/pkg/errors" "github.com/ory/fosite" + "github.com/ory/hydra/v2/flow" "github.com/ory/x/sqlxx" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" ) var _ consent.Strategy = new(consentMock) @@ -25,27 +26,31 @@ type consentMock struct { requestTime time.Time } -func (c *consentMock) HandleOAuth2AuthorizationRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, req fosite.AuthorizeRequester) (*consent.AcceptOAuth2ConsentRequest, error) { +func (c *consentMock) HandleOAuth2AuthorizationRequest(ctx context.Context, w http.ResponseWriter, r *http.Request, req fosite.AuthorizeRequester) (*flow.AcceptOAuth2ConsentRequest, *flow.Flow, error) { if c.deny { - return nil, fosite.ErrRequestForbidden + return nil, nil, fosite.ErrRequestForbidden } - return &consent.AcceptOAuth2ConsentRequest{ - ConsentRequest: &consent.OAuth2ConsentRequest{ + return &flow.AcceptOAuth2ConsentRequest{ + ConsentRequest: &flow.OAuth2ConsentRequest{ Subject: "foo", ACR: "1", }, AuthenticatedAt: sqlxx.NullTime(c.authTime), GrantedScope: []string{"offline", "openid", "hydra.*"}, - Session: &consent.AcceptOAuth2ConsentRequestSession{ + Session: &flow.AcceptOAuth2ConsentRequestSession{ AccessToken: map[string]interface{}{}, IDToken: map[string]interface{}{}, }, RequestedAt: c.requestTime, - }, nil + }, nil, nil } -func (c *consentMock) HandleOpenIDConnectLogout(ctx context.Context, w http.ResponseWriter, r *http.Request) (*consent.LogoutResult, error) { +func (c *consentMock) HandleOpenIDConnectLogout(ctx context.Context, w http.ResponseWriter, r *http.Request) (*flow.LogoutResult, error) { + panic("not implemented") +} + +func (c *consentMock) HandleHeadlessLogout(ctx context.Context, w http.ResponseWriter, r *http.Request, sid string) error { panic("not implemented") } diff --git a/oauth2/oauth2_jwt_bearer_test.go b/oauth2/oauth2_jwt_bearer_test.go index 755dc883a36..e9e7ddf9120 100644 --- a/oauth2/oauth2_jwt_bearer_test.go +++ b/oauth2/oauth2_jwt_bearer_test.go @@ -9,31 +9,34 @@ import ( "fmt" "io" "net/http" + "net/http/httptest" "net/url" "strings" "testing" "time" + "github.com/go-jose/go-jose/v3" "github.com/google/uuid" "github.com/tidwall/gjson" - "gopkg.in/square/go-jose.v2" "github.com/ory/fosite/token/jwt" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/oauth2/trust" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/jwk" + hydraoauth2 "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/oauth2/trust" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" goauth2 "golang.org/x/oauth2" "golang.org/x/oauth2/clientcredentials" - "github.com/ory/hydra/internal/testhelpers" + "github.com/ory/hydra/v2/internal/testhelpers" "github.com/ory/x/contextx" - hc "github.com/ory/hydra/client" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/x" + hc "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/x" ) func TestJWTBearer(t *testing.T) { @@ -61,11 +64,13 @@ func TestJWTBearer(t *testing.T) { } var getToken = func(t *testing.T, conf *clientcredentials.Config) (*goauth2.Token, error) { - conf.AuthStyle = goauth2.AuthStyleInHeader + if conf.AuthStyle == goauth2.AuthStyleAutoDetect { + conf.AuthStyle = goauth2.AuthStyleInHeader + } return conf.Token(context.Background()) } - var inspectToken = func(t *testing.T, token *goauth2.Token, cl *hc.Client, strategy string, grant trust.Grant) { + var inspectToken = func(t *testing.T, token *goauth2.Token, cl *hc.Client, strategy string, grant trust.Grant, checkExtraClaims bool) { introspection := testhelpers.IntrospectToken(t, &goauth2.Config{ClientID: cl.GetID(), ClientSecret: cl.Secret}, token.AccessToken, admin) check := func(res gjson.Result) { @@ -77,6 +82,10 @@ func TestJWTBearer(t *testing.T) { assert.True(t, res.Get("exp").Int() >= res.Get("iat").Int()+int64(reg.Config().GetAccessTokenLifespan(ctx).Seconds()), "%s", res.Raw) assert.EqualValues(t, fmt.Sprintf(`["%s"]`, reg.Config().OAuth2TokenURL(ctx).String()), res.Get("aud").Raw, "%s", res.Raw) + + if checkExtraClaims { + require.True(t, res.Get("ext.hooked").Bool()) + } } check(introspection) @@ -248,7 +257,7 @@ func TestJWTBearer(t *testing.T) { result, err := getToken(t, conf) require.NoError(t, err) - inspectToken(t, result, client, strategy, trustGrant) + inspectToken(t, result, client, strategy, trustGrant, false) } } @@ -288,7 +297,264 @@ func TestJWTBearer(t *testing.T) { require.NoError(t, json.Unmarshal(body, &result)) assert.NotEmpty(t, result.AccessToken, "%s", body) - inspectToken(t, &result, client, strategy, trustGrant) + inspectToken(t, &result, client, strategy, trustGrant, false) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("should call token hook if configured", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + audience := reg.Config().OAuth2TokenURL(ctx).String() + grantType := "urn:ietf:params:oauth:grant-type:jwt-bearer" + + token, _, err := signer.Generate(ctx, jwt.MapClaims{ + "jti": uuid.NewString(), + "iss": trustGrant.Issuer, + "sub": trustGrant.Subject, + "aud": audience, + "exp": time.Now().Add(time.Hour).Unix(), + "iat": time.Now().Add(-time.Minute).Unix(), + }, &jwt.Headers{Extra: map[string]interface{}{"kid": kid}}) + require.NoError(t, err) + + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.Header.Get("Content-Type"), "application/json; charset=UTF-8") + + expectedGrantedScopes := []string{client.Scope} + expectedGrantedAudience := []string{audience} + expectedPayload := map[string][]string{ + "assertion": {token}, + "grant_type": {"urn:ietf:params:oauth:grant-type:jwt-bearer"}, + "scope": {"offline_access"}, + } + + var hookReq hydraoauth2.TokenHookRequest + require.NoError(t, json.NewDecoder(r.Body).Decode(&hookReq)) + require.NotEmpty(t, hookReq.Session) + require.Equal(t, hookReq.Session.Extra, map[string]interface{}{}) + require.NotEmpty(t, hookReq.Request) + require.ElementsMatch(t, hookReq.Request.GrantedScopes, expectedGrantedScopes) + require.ElementsMatch(t, hookReq.Request.GrantedAudience, expectedGrantedAudience) + require.Equal(t, expectedPayload, hookReq.Request.Payload) + + claims := map[string]interface{}{ + "hooked": true, + } + + hookResp := hydraoauth2.TokenHookResponse{ + Session: flow.AcceptOAuth2ConsentRequestSession{ + AccessToken: claims, + IDToken: claims, + }, + } + + w.WriteHeader(http.StatusOK) + require.NoError(t, json.NewEncoder(w).Encode(&hookResp)) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + conf := newConf(client) + conf.EndpointParams = url.Values{"grant_type": {grantType}, "assertion": {token}} + + result, err := getToken(t, conf) + require.NoError(t, err) + + inspectToken(t, result, client, strategy, trustGrant, true) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("should call token hook if configured and omit client_secret from payload", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + audience := reg.Config().OAuth2TokenURL(ctx).String() + grantType := "urn:ietf:params:oauth:grant-type:jwt-bearer" + + token, _, err := signer.Generate(ctx, jwt.MapClaims{ + "jti": uuid.NewString(), + "iss": trustGrant.Issuer, + "sub": trustGrant.Subject, + "aud": audience, + "exp": time.Now().Add(time.Hour).Unix(), + "iat": time.Now().Add(-time.Minute).Unix(), + }, &jwt.Headers{Extra: map[string]interface{}{"kid": kid}}) + require.NoError(t, err) + + client := &hc.Client{ + Secret: secret, + GrantTypes: []string{"urn:ietf:params:oauth:grant-type:jwt-bearer"}, + Scope: "offline_access", + TokenEndpointAuthMethod: "client_secret_post", + } + require.NoError(t, reg.ClientManager().CreateClient(ctx, client)) + + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.Header.Get("Content-Type"), "application/json; charset=UTF-8") + + expectedGrantedScopes := []string{client.Scope} + expectedGrantedAudience := []string{audience} + expectedPayload := map[string][]string{ + "assertion": {token}, + "client_id": {client.GetID()}, + "grant_type": {"urn:ietf:params:oauth:grant-type:jwt-bearer"}, + "scope": {"offline_access"}, + } + + var hookReq hydraoauth2.TokenHookRequest + require.NoError(t, json.NewDecoder(r.Body).Decode(&hookReq)) + require.NotEmpty(t, hookReq.Session) + require.Equal(t, hookReq.Session.Extra, map[string]interface{}{}) + require.NotEmpty(t, hookReq.Request) + require.ElementsMatch(t, hookReq.Request.GrantedScopes, expectedGrantedScopes) + require.ElementsMatch(t, hookReq.Request.GrantedAudience, expectedGrantedAudience) + require.Equal(t, hookReq.Request.Payload, expectedPayload) + + claims := map[string]interface{}{ + "hooked": true, + } + + hookResp := hydraoauth2.TokenHookResponse{ + Session: flow.AcceptOAuth2ConsentRequestSession{ + AccessToken: claims, + IDToken: claims, + }, + } + + w.WriteHeader(http.StatusOK) + require.NoError(t, json.NewEncoder(w).Encode(&hookResp)) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + conf := newConf(client) + conf.AuthStyle = goauth2.AuthStyleInParams + conf.EndpointParams = url.Values{"grant_type": {grantType}, "assertion": {token}} + + result, err := getToken(t, conf) + require.NoError(t, err) + + inspectToken(t, result, client, strategy, trustGrant, true) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("should fail token if hook fails", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + token, _, err := signer.Generate(ctx, jwt.MapClaims{ + "jti": uuid.NewString(), + "iss": trustGrant.Issuer, + "sub": trustGrant.Subject, + "aud": reg.Config().OAuth2TokenURL(ctx).String(), + "exp": time.Now().Add(time.Hour).Unix(), + "iat": time.Now().Add(-time.Minute).Unix(), + }, &jwt.Headers{Extra: map[string]interface{}{"kid": kid}}) + require.NoError(t, err) + + conf := newConf(client) + conf.EndpointParams = url.Values{"grant_type": {"urn:ietf:params:oauth:grant-type:jwt-bearer"}, "assertion": {token}} + + _, tokenError := getToken(t, conf) + require.Error(t, tokenError) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("should fail token if hook denied the request", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusForbidden) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + token, _, err := signer.Generate(ctx, jwt.MapClaims{ + "jti": uuid.NewString(), + "iss": trustGrant.Issuer, + "sub": trustGrant.Subject, + "aud": reg.Config().OAuth2TokenURL(ctx).String(), + "exp": time.Now().Add(time.Hour).Unix(), + "iat": time.Now().Add(-time.Minute).Unix(), + }, &jwt.Headers{Extra: map[string]interface{}{"kid": kid}}) + require.NoError(t, err) + + conf := newConf(client) + conf.EndpointParams = url.Values{"grant_type": {"urn:ietf:params:oauth:grant-type:jwt-bearer"}, "assertion": {token}} + + _, tokenError := getToken(t, conf) + require.Error(t, tokenError) + } + } + + t.Run("strategy=opaque", run("opaque")) + t.Run("strategy=jwt", run("jwt")) + }) + + t.Run("should fail token if hook response is malformed", func(t *testing.T) { + run := func(strategy string) func(t *testing.T) { + return func(t *testing.T) { + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, strategy) + reg.Config().MustSet(ctx, config.KeyTokenHook, hs.URL) + + defer reg.Config().MustSet(ctx, config.KeyTokenHook, nil) + + token, _, err := signer.Generate(ctx, jwt.MapClaims{ + "jti": uuid.NewString(), + "iss": trustGrant.Issuer, + "sub": trustGrant.Subject, + "aud": reg.Config().OAuth2TokenURL(ctx).String(), + "exp": time.Now().Add(time.Hour).Unix(), + "iat": time.Now().Add(-time.Minute).Unix(), + }, &jwt.Headers{Extra: map[string]interface{}{"kid": kid}}) + require.NoError(t, err) + + conf := newConf(client) + conf.EndpointParams = url.Values{"grant_type": {"urn:ietf:params:oauth:grant-type:jwt-bearer"}, "assertion": {token}} + + _, tokenError := getToken(t, conf) + require.Error(t, tokenError) } } diff --git a/oauth2/oauth2_refresh_token_test.go b/oauth2/oauth2_refresh_token_test.go index 1d40e0af4d1..849fae06460 100644 --- a/oauth2/oauth2_refresh_token_test.go +++ b/oauth2/oauth2_refresh_token_test.go @@ -20,10 +20,10 @@ import ( "github.com/stretchr/testify/require" "github.com/ory/fosite" - hc "github.com/ory/hydra/client" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/oauth2" + hc "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/oauth2" "github.com/ory/x/contextx" "github.com/ory/x/dbal" "github.com/ory/x/networkx" @@ -49,10 +49,10 @@ func TestCreateRefreshTokenSessionStress(t *testing.T) { // first read. workers := 10 - token := "234c678fed33c1d2025537ae464a1ebf7d23fc4a" - tokenSignature := "4c7c7e8b3a77ad0c3ec846a21653c48b45dbfa31" + token := "234c678fed33c1d2025537ae464a1ebf7d23fc4a" //nolint:gosec + tokenSignature := "4c7c7e8b3a77ad0c3ec846a21653c48b45dbfa31" //nolint:gosec testClient := hc.Client{ - ID: uuid.Must(uuid.NewV4()), + ID: uuid.Must(uuid.NewV4()).String(), Secret: "secret", ResponseTypes: []string{"id_token", "code", "token"}, GrantTypes: []string{"implicit", "refresh_token", "authorization_code", "password", "client_credentials"}, @@ -68,7 +68,7 @@ func TestCreateRefreshTokenSessionStress(t *testing.T) { RequestedAt: time.Now(), ID: uuid.Must(uuid.NewV4()).String(), Client: &hc.Client{ - ID: uuid.FromStringOrNil(testClient.GetID()), + ID: testClient.GetID(), }, RequestedScope: []string{"offline"}, GrantedScope: []string{"offline"}, @@ -91,7 +91,8 @@ func TestCreateRefreshTokenSessionStress(t *testing.T) { require.NoError(t, dbRegistry.Persister().Connection(context.Background()).First(net)) dbRegistry.WithContextualizer(&contextx.Static{NID: net.ID, C: internal.NewConfigurationWithDefaults().Source(context.Background())}) - ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second)) + ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(30*time.Second)) + t.Cleanup(cancel) require.NoError(t, dbRegistry.OAuth2Storage().(clientCreator).CreateClient(ctx, &testClient)) require.NoError(t, dbRegistry.OAuth2Storage().CreateRefreshTokenSession(ctx, tokenSignature, request)) _, err := dbRegistry.OAuth2Storage().GetRefreshTokenSession(ctx, tokenSignature, nil) @@ -109,8 +110,9 @@ func TestCreateRefreshTokenSessionStress(t *testing.T) { wg.Add(1) go func(run, worker int) { defer wg.Done() - ctx, _ := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second)) - time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + time.Sleep(time.Duration(rand.Intn(100)) * time.Millisecond) //nolint:gosec // all workers will block here until the for loop above has launched all the worker go-routines // this is to ensure we fire all the workers off at the same <-barrier diff --git a/oauth2/oauth2_rop_test.go b/oauth2/oauth2_rop_test.go new file mode 100644 index 00000000000..4adb4904452 --- /dev/null +++ b/oauth2/oauth2_rop_test.go @@ -0,0 +1,161 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oauth2_test + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + "time" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "golang.org/x/oauth2" + + "github.com/ory/fosite/compose" + "github.com/ory/fosite/token/jwt" + hydra "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/fositex" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/internal/kratos" + "github.com/ory/hydra/v2/internal/testhelpers" + hydraoauth2 "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/contextx" + "github.com/ory/x/sqlxx" +) + +func TestResourceOwnerPasswordGrant(t *testing.T) { + ctx := context.Background() + fakeKratos := kratos.NewFake() + reg := internal.NewMockedRegistry(t, &contextx.Default{}) + reg.WithKratos(fakeKratos) + reg.WithExtraFositeFactories([]fositex.Factory{compose.OAuth2ResourceOwnerPasswordCredentialsFactory}) + publicTS, adminTS := testhelpers.NewOAuth2Server(ctx, t, reg) + + secret := uuid.New().String() + audience := sqlxx.StringSliceJSONFormat{"https://aud.example.com"} + client := &hydra.Client{ + Secret: secret, + GrantTypes: []string{"password", "refresh_token"}, + Scope: "offline", + Audience: audience, + Lifespans: hydra.Lifespans{ + PasswordGrantAccessTokenLifespan: x.NullDuration{Duration: 1 * time.Hour, Valid: true}, + PasswordGrantRefreshTokenLifespan: x.NullDuration{Duration: 1 * time.Hour, Valid: true}, + }, + } + require.NoError(t, reg.ClientManager().CreateClient(ctx, client)) + + oauth2Config := &oauth2.Config{ + ClientID: client.GetID(), + ClientSecret: secret, + Endpoint: oauth2.Endpoint{ + AuthURL: reg.Config().OAuth2AuthURL(ctx).String(), + TokenURL: reg.Config().OAuth2TokenURL(ctx).String(), + AuthStyle: oauth2.AuthStyleInHeader, + }, + Scopes: []string{"offline"}, + } + + hs := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, r.Header.Get("Content-Type"), "application/json; charset=UTF-8") + assert.Equal(t, r.Header.Get("Authorization"), "Bearer secret value") + + var hookReq hydraoauth2.TokenHookRequest + require.NoError(t, json.NewDecoder(r.Body).Decode(&hookReq)) + assert.NotEmpty(t, hookReq.Session) + assert.NotEmpty(t, hookReq.Request) + + claims := hookReq.Session.Extra + claims["hooked"] = true + if hookReq.Request.GrantTypes[0] == "refresh_token" { + claims["refreshed"] = true + } + + hookResp := hydraoauth2.TokenHookResponse{ + Session: flow.AcceptOAuth2ConsentRequestSession{ + AccessToken: claims, + IDToken: claims, + }, + } + + w.WriteHeader(http.StatusOK) + require.NoError(t, json.NewEncoder(w).Encode(&hookResp)) + })) + defer hs.Close() + + reg.Config().MustSet(ctx, config.KeyTokenHook, &config.HookConfig{ + URL: hs.URL, + Auth: &config.Auth{ + Type: "api_key", + Config: config.AuthConfig{ + In: "header", + Name: "Authorization", + Value: "Bearer secret value", + }, + }, + }) + reg.Config().MustSet(ctx, config.KeyAccessTokenStrategy, "jwt") + + t.Run("case=get ROP grant token with valid username and password", func(t *testing.T) { + token, err := oauth2Config.PasswordCredentialsToken(ctx, kratos.FakeUsername, kratos.FakePassword) + require.NoError(t, err) + require.NotEmpty(t, token.AccessToken) + + // Access token should have hook and identity_id claims + jwtAT, err := jwt.Parse(token.AccessToken, func(token *jwt.Token) (interface{}, error) { + return reg.AccessTokenJWTStrategy().GetPublicKey(ctx) + }) + require.NoError(t, err) + assert.Equal(t, kratos.FakeUsername, jwtAT.Claims["ext"].(map[string]any)["username"]) + assert.Equal(t, kratos.FakeIdentityID, jwtAT.Claims["sub"]) + assert.Equal(t, publicTS.URL, jwtAT.Claims["iss"]) + assert.True(t, jwtAT.Claims["ext"].(map[string]any)["hooked"].(bool)) + assert.ElementsMatch(t, audience, jwtAT.Claims["aud"]) + + t.Run("case=introspect token", func(t *testing.T) { + // Introspected token should have hook and identity_id claims + i := testhelpers.IntrospectToken(t, oauth2Config, token.AccessToken, adminTS) + assert.True(t, i.Get("active").Bool(), "%s", i) + assert.Equal(t, kratos.FakeUsername, i.Get("ext.username").String(), "%s", i) + assert.Equal(t, kratos.FakeIdentityID, i.Get("sub").String(), "%s", i) + assert.True(t, i.Get("ext.hooked").Bool(), "%s", i) + assert.EqualValues(t, oauth2Config.ClientID, i.Get("client_id").String(), "%s", i) + }) + + t.Run("case=refresh token", func(t *testing.T) { + // Refreshed access token should have hook and identity_id claims + require.NotEmpty(t, token.RefreshToken) + token.Expiry = token.Expiry.Add(-time.Hour * 24) + refreshedToken, err := oauth2Config.TokenSource(context.Background(), token).Token() + require.NoError(t, err) + + require.NotEqual(t, token.AccessToken, refreshedToken.AccessToken) + require.NotEqual(t, token.RefreshToken, refreshedToken.RefreshToken) + + jwtAT, err := jwt.Parse(refreshedToken.AccessToken, func(token *jwt.Token) (interface{}, error) { + return reg.AccessTokenJWTStrategy().GetPublicKey(ctx) + }) + require.NoError(t, err) + assert.Equal(t, kratos.FakeIdentityID, jwtAT.Claims["sub"]) + assert.Equal(t, kratos.FakeUsername, jwtAT.Claims["ext"].(map[string]any)["username"]) + assert.True(t, jwtAT.Claims["ext"].(map[string]any)["hooked"].(bool)) + assert.True(t, jwtAT.Claims["ext"].(map[string]any)["refreshed"].(bool)) + }) + }) + + t.Run("case=access denied for invalid password", func(t *testing.T) { + _, err := oauth2Config.PasswordCredentialsToken(ctx, kratos.FakeUsername, "invalid") + retrieveError := new(oauth2.RetrieveError) + require.Error(t, err) + require.ErrorAs(t, err, &retrieveError) + assert.Contains(t, retrieveError.ErrorDescription, "Unable to authenticate the provided username and password credentials") + }) +} diff --git a/oauth2/refresh_hook.go b/oauth2/refresh_hook.go new file mode 100644 index 00000000000..c1087655d71 --- /dev/null +++ b/oauth2/refresh_hook.go @@ -0,0 +1,102 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oauth2 + +import ( + "context" + "encoding/json" + + "github.com/ory/hydra/v2/x" + "github.com/ory/x/errorsx" + + "github.com/ory/fosite" + "github.com/ory/hydra/v2/driver/config" +) + +// Requester is a token endpoint's request context. +// +// swagger:ignore +type Requester struct { + // ClientID is the identifier of the OAuth 2.0 client. + ClientID string `json:"client_id"` + // GrantedScopes is the list of scopes granted to the OAuth 2.0 client. + GrantedScopes []string `json:"granted_scopes"` + // GrantedAudience is the list of audiences granted to the OAuth 2.0 client. + GrantedAudience []string `json:"granted_audience"` + // GrantTypes is the requests grant types. + GrantTypes []string `json:"grant_types"` +} + +// RefreshTokenHookRequest is the request body sent to the refresh token hook. +// +// swagger:ignore +type RefreshTokenHookRequest struct { + // Subject is the identifier of the authenticated end-user. + Subject string `json:"subject"` + // Session is the request's session.. + Session *Session `json:"session"` + // Requester is a token endpoint's request context. + Requester Requester `json:"requester"` + // ClientID is the identifier of the OAuth 2.0 client. + ClientID string `json:"client_id"` + // GrantedScopes is the list of scopes granted to the OAuth 2.0 client. + GrantedScopes []string `json:"granted_scopes"` + // GrantedAudience is the list of audiences granted to the OAuth 2.0 client. + GrantedAudience []string `json:"granted_audience"` +} + +// RefreshTokenHook is an AccessRequestHook called for `refresh_token` grant type. +func RefreshTokenHook(reg interface { + config.Provider + x.HTTPClientProvider +}) AccessRequestHook { + return func(ctx context.Context, requester fosite.AccessRequester) error { + hookConfig := reg.Config().TokenRefreshHookConfig(ctx) + if hookConfig == nil { + return nil + } + + if !requester.GetGrantTypes().ExactOne("refresh_token") { + return nil + } + + session, ok := requester.GetSession().(*Session) + if !ok { + return nil + } + + requesterInfo := Requester{ + ClientID: requester.GetClient().GetID(), + GrantedScopes: requester.GetGrantedScopes(), + GrantedAudience: requester.GetGrantedAudience(), + GrantTypes: requester.GetGrantTypes(), + } + + reqBody := RefreshTokenHookRequest{ + Session: session, + Requester: requesterInfo, + Subject: session.GetSubject(), + ClientID: requester.GetClient().GetID(), + GrantedScopes: requester.GetGrantedScopes(), + GrantedAudience: requester.GetGrantedAudience(), + } + + reqBodyBytes, err := json.Marshal(&reqBody) + if err != nil { + return errorsx.WithStack( + fosite.ErrServerError. + WithWrap(err). + WithDescription("An error occurred while encoding the token hook."). + WithDebugf("Unable to encode the token hook body: %s", err), + ) + } + + err = executeHookAndUpdateSession(ctx, reg, hookConfig, reqBodyBytes, session) + if err != nil { + return err + } + + return nil + } +} diff --git a/oauth2/registry.go b/oauth2/registry.go index 53a9e84cf80..0e7cdfae81a 100644 --- a/oauth2/registry.go +++ b/oauth2/registry.go @@ -6,11 +6,13 @@ package oauth2 import ( "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/oauth2/trust" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/oauth2/trust" + "github.com/ory/hydra/v2/persistence" + "github.com/ory/hydra/v2/x" ) type InternalRegistry interface { @@ -20,7 +22,9 @@ type InternalRegistry interface { x.RegistryWriter x.RegistryLogger consent.Registry + persistence.Provider Registry + FlowCipher() *aead.XChaCha20Poly1305 } type Registry interface { diff --git a/oauth2/revocator_test.go b/oauth2/revocator_test.go index 62ca3754b06..4ad0be8cac7 100644 --- a/oauth2/revocator_test.go +++ b/oauth2/revocator_test.go @@ -15,19 +15,19 @@ import ( "github.com/ory/x/httprouterx" - "github.com/ory/hydra/persistence/sql" + "github.com/ory/hydra/v2/persistence/sql" "github.com/ory/x/contextx" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/internal" + "github.com/ory/hydra/v2/internal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ory/fosite" - "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/x" ) func createAccessTokenSession(subject, client string, token string, expiresAt time.Time, fs x.FositeStorer, scopes fosite.Arguments) { @@ -63,7 +63,7 @@ func TestRevoke(t *testing.T) { conf := internal.NewConfigurationWithDefaults() reg := internal.NewRegistryMemory(t, conf, &contextx.Default{}) - internal.MustEnsureRegistryKeys(reg, x.OpenIDConnectKeyName) + internal.MustEnsureRegistryKeys(context.Background(), reg, x.OpenIDConnectKeyName) internal.AddFositeExamples(reg) tokens := Tokens(reg.OAuth2ProviderConfig(), 4) @@ -125,7 +125,7 @@ func TestRevoke(t *testing.T) { }, } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { - _, err := client.OAuth2Api.RevokeOAuth2Token( + _, err := client.OAuth2API.RevokeOAuth2Token( context.WithValue( context.Background(), hydra.ContextBasicAuth, diff --git a/oauth2/session.go b/oauth2/session.go index e543a1e123f..0630cb09142 100644 --- a/oauth2/session.go +++ b/oauth2/session.go @@ -4,19 +4,22 @@ package oauth2 import ( - "encoding/json" + "bytes" + "context" "time" + jjson "github.com/go-jose/go-jose/v3/json" + "github.com/mohae/deepcopy" "github.com/pkg/errors" "github.com/tidwall/gjson" "github.com/tidwall/sjson" - "github.com/mohae/deepcopy" - "github.com/ory/fosite" "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/token/jwt" - + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/flow" + "github.com/ory/x/logrusx" "github.com/ory/x/stringslice" ) @@ -29,13 +32,20 @@ type Session struct { ConsentChallenge string `json:"consent_challenge"` ExcludeNotBeforeClaim bool `json:"exclude_not_before_claim"` AllowedTopLevelClaims []string `json:"allowed_top_level_claims"` + MirrorTopLevelClaims bool `json:"mirror_top_level_claims"` + + Flow *flow.Flow `json:"-"` } func NewSession(subject string) *Session { - return NewSessionWithCustomClaims(subject, nil) + ctx := context.Background() + provider := config.MustNew(ctx, logrusx.New("", "")) + return NewSessionWithCustomClaims(ctx, provider, subject) } -func NewSessionWithCustomClaims(subject string, allowedTopLevelClaims []string) *Session { +func NewSessionWithCustomClaims(ctx context.Context, p *config.DefaultProvider, subject string) *Session { + allowedTopLevelClaims := p.AllowedTopLevelClaims(ctx) + mirrorTopLevelClaims := p.MirrorTopLevelClaims(ctx) return &Session{ DefaultSession: &openid.DefaultSession{ Claims: new(jwt.IDTokenClaims), @@ -44,35 +54,38 @@ func NewSessionWithCustomClaims(subject string, allowedTopLevelClaims []string) }, Extra: map[string]interface{}{}, AllowedTopLevelClaims: allowedTopLevelClaims, + MirrorTopLevelClaims: mirrorTopLevelClaims, } } func (s *Session) GetJWTClaims() jwt.JWTClaimsContainer { - //a slice of claims that are reserved and should not be overridden - var reservedClaims = []string{"iss", "sub", "aud", "exp", "nbf", "iat", "jti", "client_id", "scp", "ext"} + // a slice of claims that are reserved and should not be overridden + reservedClaims := []string{"iss", "sub", "aud", "exp", "nbf", "iat", "jti", "client_id", "scp", "ext"} - //remove any reserved claims from the custom claims + // remove any reserved claims from the custom claims allowedClaimsFromConfigWithoutReserved := stringslice.Filter(s.AllowedTopLevelClaims, func(s string) bool { return stringslice.Has(reservedClaims, s) }) - //our new extra map which will be added to the jwt - var topLevelExtraWithMirrorExt = map[string]interface{}{} + // our new extra map which will be added to the jwt + topLevelExtraWithMirrorExt := map[string]interface{}{} - //setting every allowed claim top level in jwt with respective value + // setting every allowed claim top level in jwt with respective value for _, allowedClaim := range allowedClaimsFromConfigWithoutReserved { if cl, ok := s.Extra[allowedClaim]; ok { topLevelExtraWithMirrorExt[allowedClaim] = cl } } - //for every other claim that was already reserved and for mirroring, add original extra under "ext" - topLevelExtraWithMirrorExt["ext"] = s.Extra + // for every other claim that was already reserved and for mirroring, add original extra under "ext" + if s.MirrorTopLevelClaims { + topLevelExtraWithMirrorExt["ext"] = s.Extra + } claims := &jwt.JWTClaims{ Subject: s.Subject, Issuer: s.DefaultSession.Claims.Issuer, - //set our custom extra map as claims.Extra + // set our custom extra map as claims.Extra Extra: topLevelExtraWithMirrorExt, ExpiresAt: s.GetExpiresAt(fosite.AccessToken), IssuedAt: time.Now(), @@ -171,10 +184,27 @@ func (s *Session) UnmarshalJSON(original []byte) (err error) { } } + // https://github.com/go-jose/go-jose/issues/144 + dec := jjson.NewDecoder(bytes.NewReader(transformed)) + dec.SetNumberType(jjson.UnmarshalIntOrFloat) type t Session - if err := json.Unmarshal(transformed, (*t)(s)); err != nil { + if err := dec.Decode((*t)(s)); err != nil { return errors.WithStack(err) } return nil } + +// GetExtraClaims implements ExtraClaimsSession for Session. +// The returned value can be modified in-place. +func (s *Session) GetExtraClaims() map[string]interface{} { + if s == nil { + return nil + } + + if s.Extra == nil { + s.Extra = make(map[string]interface{}) + } + + return s.Extra +} diff --git a/oauth2/session_custom_claims_test.go b/oauth2/session_custom_claims_test.go index c9b72af534d..5fbe3c5c1a5 100644 --- a/oauth2/session_custom_claims_test.go +++ b/oauth2/session_custom_claims_test.go @@ -10,15 +10,17 @@ import ( "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/token/jwt" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/oauth2" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/oauth2" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func createSessionWithCustomClaims(extra map[string]interface{}, allowedTopLevelClaims []string) oauth2.Session { +func createSessionWithCustomClaims(ctx context.Context, p *config.DefaultProvider, extra map[string]interface{}) oauth2.Session { + allowedTopLevelClaims := p.AllowedTopLevelClaims(ctx) + mirrorTopLevelClaims := p.MirrorTopLevelClaims(ctx) session := &oauth2.Session{ DefaultSession: &openid.DefaultSession{ Claims: &jwt.IDTokenClaims{ @@ -30,6 +32,7 @@ func createSessionWithCustomClaims(extra map[string]interface{}, allowedTopLevel }, Extra: extra, AllowedTopLevelClaims: allowedTopLevelClaims, + MirrorTopLevelClaims: mirrorTopLevelClaims, } return *session } @@ -41,7 +44,7 @@ func TestCustomClaimsInSession(t *testing.T) { t.Run("no_custom_claims", func(t *testing.T) { c.MustSet(ctx, config.KeyAllowedTopLevelClaims, []string{}) - session := createSessionWithCustomClaims(nil, c.AllowedTopLevelClaims(ctx)) + session := createSessionWithCustomClaims(ctx, c, nil) claims := session.GetJWTClaims().ToMapClaims() assert.EqualValues(t, "alice", claims["sub"]) @@ -56,7 +59,7 @@ func TestCustomClaimsInSession(t *testing.T) { c.MustSet(ctx, config.KeyAllowedTopLevelClaims, []string{"foo"}) extra := map[string]interface{}{"foo": "bar"} - session := createSessionWithCustomClaims(extra, c.AllowedTopLevelClaims(ctx)) + session := createSessionWithCustomClaims(ctx, c, extra) claims := session.GetJWTClaims().ToMapClaims() @@ -80,7 +83,7 @@ func TestCustomClaimsInSession(t *testing.T) { c.MustSet(ctx, config.KeyAllowedTopLevelClaims, []string{"foo", "iss", "sub"}) extra := map[string]interface{}{"foo": "bar", "iss": "hydra.remote", "sub": "another-alice"} - session := createSessionWithCustomClaims(extra, c.AllowedTopLevelClaims(ctx)) + session := createSessionWithCustomClaims(ctx, c, extra) claims := session.GetJWTClaims().ToMapClaims() @@ -111,7 +114,7 @@ func TestCustomClaimsInSession(t *testing.T) { c.MustSet(ctx, config.KeyAllowedTopLevelClaims, []string{}) extra := map[string]interface{}{"foo": "bar", "iss": "hydra.remote", "sub": "another-alice"} - session := createSessionWithCustomClaims(extra, c.AllowedTopLevelClaims(ctx)) + session := createSessionWithCustomClaims(ctx, c, extra) claims := session.GetJWTClaims().ToMapClaims() @@ -140,7 +143,7 @@ func TestCustomClaimsInSession(t *testing.T) { c.MustSet(ctx, config.KeyAllowedTopLevelClaims, []string{"foo", "baz", "bar", "iss"}) extra := map[string]interface{}{"foo": "foo_value", "sub": "another-alice"} - session := createSessionWithCustomClaims(extra, c.AllowedTopLevelClaims(ctx)) + session := createSessionWithCustomClaims(ctx, c, extra) claims := session.GetJWTClaims().ToMapClaims() @@ -168,7 +171,7 @@ func TestCustomClaimsInSession(t *testing.T) { c.MustSet(ctx, config.KeyAllowedTopLevelClaims, []string{"foo", "sub"}) extra := map[string]interface{}{"foo": "foo_value", "bar": "bar_value", "baz": "baz_value", "sub": "another-alice"} - session := createSessionWithCustomClaims(extra, c.AllowedTopLevelClaims(ctx)) + session := createSessionWithCustomClaims(ctx, c, extra) claims := session.GetJWTClaims().ToMapClaims() @@ -198,7 +201,7 @@ func TestCustomClaimsInSession(t *testing.T) { c.MustSet(ctx, config.KeyAllowedTopLevelClaims, []string{"foo", "bar"}) extra := map[string]interface{}{"foo": "foo_value", "baz": "baz_value", "sub": "another-alice"} - session := createSessionWithCustomClaims(extra, c.AllowedTopLevelClaims(ctx)) + session := createSessionWithCustomClaims(ctx, c, extra) claims := session.GetJWTClaims().ToMapClaims() @@ -228,7 +231,7 @@ func TestCustomClaimsInSession(t *testing.T) { c.MustSet(ctx, config.KeyAllowedTopLevelClaims, []string{"iss", "sub"}) extra := map[string]interface{}{"iss": "hydra.remote", "sub": "another-alice"} - session := createSessionWithCustomClaims(extra, c.AllowedTopLevelClaims(ctx)) + session := createSessionWithCustomClaims(ctx, c, extra) claims := session.GetJWTClaims().ToMapClaims() diff --git a/oauth2/session_test.go b/oauth2/session_test.go index 146f018db7b..461d753581a 100644 --- a/oauth2/session_test.go +++ b/oauth2/session_test.go @@ -49,7 +49,8 @@ func TestUnmarshalSession(t *testing.T) { AuthenticationMethodsReferences: []string{}, CodeHash: "", Extra: map[string]interface{}{ - "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d", + "sid": "177e1f44-a1e9-415c-bfa3-8b62280b182d", + "timestamp": 1723546027, }, }, Headers: &jwt.Headers{Extra: map[string]interface{}{ @@ -85,7 +86,7 @@ func TestUnmarshalSession(t *testing.T) { snapshotx.SnapshotTExcept(t, &actual, nil) }) - t.Run("v1.11.9", func(t *testing.T) { + t.Run("v1.11.9" /* and later versions */, func(t *testing.T) { var actual Session require.NoError(t, json.Unmarshal(v1119Session, &actual)) assertx.EqualAsJSON(t, expect, &actual) diff --git a/oauth2/token_hook.go b/oauth2/token_hook.go new file mode 100644 index 00000000000..5d5d212e4b8 --- /dev/null +++ b/oauth2/token_hook.go @@ -0,0 +1,201 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oauth2 + +import ( + "bytes" + "context" + "encoding/json" + "io" + "net/http" + + "github.com/pkg/errors" + + "github.com/hashicorp/go-retryablehttp" + + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/x" + + "github.com/ory/fosite" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/x/errorsx" +) + +// AccessRequestHook is called when an access token request is performed. +type AccessRequestHook func(ctx context.Context, requester fosite.AccessRequester) error + +// Request is a token endpoint's request context. +// +// swagger:ignore +type Request struct { + // ClientID is the identifier of the OAuth 2.0 client. + ClientID string `json:"client_id"` + // GrantedScopes is the list of scopes granted to the OAuth 2.0 client. + GrantedScopes []string `json:"granted_scopes"` + // GrantedAudience is the list of audiences granted to the OAuth 2.0 client. + GrantedAudience []string `json:"granted_audience"` + // GrantTypes is the requests grant types. + GrantTypes []string `json:"grant_types"` + // Payload is the requests payload. + Payload map[string][]string `json:"payload"` +} + +// TokenHookRequest is the request body sent to the token hook. +// +// swagger:ignore +type TokenHookRequest struct { + // Session is the request's session.. + Session *Session `json:"session"` + // Requester is a token endpoint's request context. + Request Request `json:"request"` +} + +// TokenHookResponse is the response body received from the token hook. +// +// swagger:ignore +type TokenHookResponse struct { + // Session is the session data returned by the hook. + Session flow.AcceptOAuth2ConsentRequestSession `json:"session"` +} + +type APIKeyAuthConfig struct { + In string `json:"in"` + Name string `json:"name"` + Value string `json:"value"` +} + +func applyAuth(req *retryablehttp.Request, auth *config.Auth) error { + if auth == nil { + return nil + } + + switch auth.Type { + case "api_key": + switch auth.Config.In { + case "header": + req.Header.Set(auth.Config.Name, auth.Config.Value) + case "cookie": + req.AddCookie(&http.Cookie{Name: auth.Config.Name, Value: auth.Config.Value}) + } + default: + return errors.Errorf("unsupported auth type %q", auth.Type) + } + return nil +} + +func executeHookAndUpdateSession(ctx context.Context, reg x.HTTPClientProvider, hookConfig *config.HookConfig, reqBodyBytes []byte, session *Session) error { + req, err := retryablehttp.NewRequestWithContext(ctx, http.MethodPost, hookConfig.URL, bytes.NewReader(reqBodyBytes)) + if err != nil { + return errorsx.WithStack( + fosite.ErrServerError. + WithWrap(err). + WithDescription("An error occurred while preparing the token hook."). + WithDebugf("Unable to prepare the HTTP Request: %s", err), + ) + } + if err := applyAuth(req, hookConfig.Auth); err != nil { + return errorsx.WithStack( + fosite.ErrServerError. + WithWrap(err). + WithDescription("An error occurred while applying the token hook authentication."). + WithDebugf("Unable to apply the token hook authentication: %s", err)) + } + req.Header.Set("Content-Type", "application/json; charset=UTF-8") + + resp, err := reg.HTTPClient(ctx).Do(req) + if err != nil { + return errorsx.WithStack( + fosite.ErrServerError. + WithWrap(err). + WithDescription("An error occurred while executing the token hook."). + WithDebugf("Unable to execute HTTP Request: %s", err), + ) + } + defer resp.Body.Close() + resp.Body = io.NopCloser(io.LimitReader(resp.Body, 5<<20 /* 5 MiB */)) + + switch resp.StatusCode { + case http.StatusOK: + // Token permitted with new session data + case http.StatusNoContent: + // Token is permitted without overriding session data + return nil + case http.StatusForbidden: + return errorsx.WithStack( + fosite.ErrAccessDenied. + WithDescription("The token hook target responded with an error."). + WithDebugf("Token hook responded with HTTP status code: %s", resp.Status), + ) + default: + return errorsx.WithStack( + fosite.ErrServerError. + WithDescription("The token hook target responded with an error."). + WithDebugf("Token hook responded with HTTP status code: %s", resp.Status), + ) + } + + var respBody TokenHookResponse + if err := json.NewDecoder(resp.Body).Decode(&respBody); err != nil { + return errorsx.WithStack( + fosite.ErrServerError. + WithWrap(err). + WithDescription("The token hook target responded with an error."). + WithDebugf("Response from token hook could not be decoded: %s", err), + ) + } + + // Overwrite existing session data (extra claims). + session.Extra = respBody.Session.AccessToken + idTokenClaims := session.IDTokenClaims() + idTokenClaims.Extra = respBody.Session.IDToken + return nil +} + +// TokenHook is an AccessRequestHook called for all grant types. +func TokenHook(reg interface { + config.Provider + x.HTTPClientProvider +}) AccessRequestHook { + return func(ctx context.Context, requester fosite.AccessRequester) error { + hookConfig := reg.Config().TokenHookConfig(ctx) + if hookConfig == nil { + return nil + } + + session, ok := requester.GetSession().(*Session) + if !ok { + return nil + } + + request := Request{ + ClientID: requester.GetClient().GetID(), + GrantedScopes: requester.GetGrantedScopes(), + GrantedAudience: requester.GetGrantedAudience(), + GrantTypes: requester.GetGrantTypes(), + Payload: requester.Sanitize([]string{"assertion"}).GetRequestForm(), + } + + reqBody := TokenHookRequest{ + Session: session, + Request: request, + } + + reqBodyBytes, err := json.Marshal(&reqBody) + if err != nil { + return errorsx.WithStack( + fosite.ErrServerError. + WithWrap(err). + WithDescription("An error occurred while encoding the token hook."). + WithDebugf("Unable to encode the token hook body: %s", err), + ) + } + + err = executeHookAndUpdateSession(ctx, reg, hookConfig, reqBodyBytes, session) + if err != nil { + return err + } + + return nil + } +} diff --git a/oauth2/trust/doc.go b/oauth2/trust/doc.go index c30e9521ac0..16de4977dd3 100644 --- a/oauth2/trust/doc.go +++ b/oauth2/trust/doc.go @@ -14,11 +14,15 @@ import ( // OAuth2 JWT Bearer Grant Type Issuer Trust Relationships // // swagger:model trustedOAuth2JwtGrantIssuers +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type trustedOAuth2JwtGrantIssuers []trustedOAuth2JwtGrantIssuer // OAuth2 JWT Bearer Grant Type Issuer Trust Relationship // // swagger:model trustedOAuth2JwtGrantIssuer +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type trustedOAuth2JwtGrantIssuer struct { // example: 9edc811f-4e28-453c-9b46-4de65f00217f ID string `json:"id"` @@ -51,6 +55,8 @@ type trustedOAuth2JwtGrantIssuer struct { // OAuth2 JWT Bearer Grant Type Issuer Trusted JSON Web Key // // swagger:model trustedOAuth2JwtGrantJsonWebKey +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type trustedOAuth2JwtGrantJsonWebKey struct { // The "set" is basically a name for a group(set) of keys. Will be the same as "issuer" in grant. // example: https://jwt-idp.example.com diff --git a/oauth2/trust/handler.go b/oauth2/trust/handler.go index 7b236eaef13..d46e6ca371c 100644 --- a/oauth2/trust/handler.go +++ b/oauth2/trust/handler.go @@ -8,9 +8,10 @@ import ( "net/http" "time" + "github.com/ory/fosite" "github.com/ory/x/pagination/tokenpagination" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/ory/x/httprouterx" @@ -43,6 +44,8 @@ func (h *Handler) SetRoutes(admin *httprouterx.RouterAdmin) { // Trust OAuth2 JWT Bearer Grant Type Issuer Request Body // // swagger:model trustOAuth2JwtGrantIssuer +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type trustOAuth2JwtGrantIssuerBody struct { // The "issuer" identifies the principal that issued the JWT assertion (same as "iss" claim in JWT). // @@ -78,6 +81,8 @@ type trustOAuth2JwtGrantIssuerBody struct { // Trust OAuth2 JWT Bearer Grant Type Issuer Request // // swagger:parameters trustOAuth2JwtGrantIssuer +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type trustOAuth2JwtGrantIssuer struct { // in: body Body trustOAuth2JwtGrantIssuerBody @@ -106,7 +111,12 @@ func (h *Handler) trustOAuth2JwtGrantIssuer(w http.ResponseWriter, r *http.Reque var grantRequest createGrantRequest if err := json.NewDecoder(r.Body).Decode(&grantRequest); err != nil { - h.registry.Writer().WriteError(w, r, errorsx.WithStack(err)) + h.registry.Writer().WriteError(w, r, + errorsx.WithStack(&fosite.RFC6749Error{ + ErrorField: "error", + DescriptionField: err.Error(), + CodeField: http.StatusBadRequest, + })) return } @@ -140,6 +150,8 @@ func (h *Handler) trustOAuth2JwtGrantIssuer(w http.ResponseWriter, r *http.Reque // Get Trusted OAuth2 JWT Bearer Grant Type Issuer Request // // swagger:parameters getTrustedOAuth2JwtGrantIssuer +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type getTrustedOAuth2JwtGrantIssuer struct { // The id of the desired grant // @@ -181,6 +193,8 @@ func (h *Handler) getTrustedOAuth2JwtGrantIssuer(w http.ResponseWriter, r *http. // Delete Trusted OAuth2 JWT Bearer Grant Type Issuer Request // // swagger:parameters deleteTrustedOAuth2JwtGrantIssuer +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type deleteTrustedOAuth2JwtGrantIssuer struct { // The id of the desired grant // in: path @@ -223,6 +237,8 @@ func (h *Handler) deleteTrustedOAuth2JwtGrantIssuer(w http.ResponseWriter, r *ht // List Trusted OAuth2 JWT Bearer Grant Type Issuers Request // // swagger:parameters listTrustedOAuth2JwtGrantIssuers +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type listTrustedOAuth2JwtGrantIssuers struct { // If optional "issuer" is supplied, only jwt-bearer grants with this issuer will be returned. // diff --git a/oauth2/trust/handler_test.go b/oauth2/trust/handler_test.go index 929b9840b57..daacc8ed282 100644 --- a/oauth2/trust/handler_test.go +++ b/oauth2/trust/handler_test.go @@ -9,30 +9,32 @@ import ( "crypto/rand" "crypto/rsa" "encoding/json" + "io" "net/http" "net/http/httptest" "testing" "time" - "gopkg.in/square/go-jose.v2" + "github.com/go-jose/go-jose/v3" + "github.com/tidwall/gjson" "github.com/ory/x/pointerx" "github.com/stretchr/testify/assert" - "github.com/ory/hydra/oauth2/trust" + "github.com/ory/hydra/v2/oauth2/trust" "github.com/ory/x/contextx" "github.com/google/uuid" "github.com/stretchr/testify/suite" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/jwk" hydra "github.com/ory/hydra-client-go/v2" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/x" ) // Define the suite, and absorb the built-in basic suite @@ -98,7 +100,7 @@ func (s *HandlerTestSuite) TestGrantCanBeCreatedAndFetched() { model := createRequestParams ctx := context.Background() - createResult, _, err := s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(ctx).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + createResult, _, err := s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(ctx).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().NoError(err, "no errors expected on grant creation") s.NotEmpty(createResult.Id, " grant id expected to be non-empty") s.Equal(model.Issuer, *createResult.Issuer, "issuer must match") @@ -108,7 +110,7 @@ func (s *HandlerTestSuite) TestGrantCanBeCreatedAndFetched() { s.Equal(model.Jwk.Kid, *createResult.PublicKey.Kid, "public key id must match") s.Equal(model.ExpiresAt.Round(time.Second).UTC().String(), createResult.ExpiresAt.Round(time.Second).UTC().String(), "expiration date must match") - getResult, _, err := s.hydraClient.OAuth2Api.GetTrustedOAuth2JwtGrantIssuer(ctx, *createResult.Id).Execute() + getResult, _, err := s.hydraClient.OAuth2API.GetTrustedOAuth2JwtGrantIssuer(ctx, *createResult.Id).Execute() s.Require().NoError(err, "no errors expected on grant fetching") s.Equal(*createResult.Id, *getResult.Id, " grant id must match") s.Equal(model.Issuer, *getResult.Issuer, "issuer must match") @@ -129,15 +131,15 @@ func (s *HandlerTestSuite) TestGrantCanNotBeCreatedWithSameIssuerSubjectKey() { ) ctx := context.Background() - _, _, err := s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(ctx).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + _, _, err := s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(ctx).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().NoError(err, "no errors expected on grant creation") - _, _, err = s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(ctx).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + _, _, err = s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(ctx).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().Error(err, "expected error, because grant with same issuer+subject+kid exists") kid := uuid.New().String() createRequestParams.Jwk.Kid = kid - _, _, err = s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(ctx).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + _, _, err = s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(ctx).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.NoError(err, "no errors expected on grant creation, because kid is now different") } @@ -150,10 +152,28 @@ func (s *HandlerTestSuite) TestGrantCanNotBeCreatedWithSubjectAndAnySubject() { time.Now().Add(time.Hour), ) - _, _, err := s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + _, _, err := s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().Error(err, "expected error, because a grant with a subject and allow_any_subject cannot be created") } +func (s *HandlerTestSuite) TestGrantCanNotBeCreatedWithUnknownJWK() { + createRequestParams := hydra.TrustOAuth2JwtGrantIssuer{ + AllowAnySubject: pointerx.Ptr(true), + ExpiresAt: time.Now().Add(1 * time.Hour), + Issuer: "ory", + Jwk: hydra.JsonWebKey{ + Alg: "unknown", + }, + Scope: []string{"openid", "offline", "profile"}, + } + + _, res, err := s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + s.Assert().Equal(http.StatusBadRequest, res.StatusCode) + body, _ := io.ReadAll(res.Body) + s.Contains(gjson.GetBytes(body, "error_description").String(), "unknown json web key type") + s.Require().Error(err, "expected error, because the key type was unknown") +} + func (s *HandlerTestSuite) TestGrantCanNotBeCreatedWithMissingFields() { createRequestParams := s.newCreateJwtBearerGrantParams( "", @@ -163,7 +183,7 @@ func (s *HandlerTestSuite) TestGrantCanNotBeCreatedWithMissingFields() { time.Now().Add(time.Hour), ) - _, _, err := s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + _, _, err := s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().Error(err, "expected error, because grant missing issuer") createRequestParams = s.newCreateJwtBearerGrantParams( @@ -174,7 +194,7 @@ func (s *HandlerTestSuite) TestGrantCanNotBeCreatedWithMissingFields() { time.Now().Add(time.Hour), ) - _, _, err = s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + _, _, err = s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().Error(err, "expected error, because grant missing subject") createRequestParams = s.newCreateJwtBearerGrantParams( @@ -185,7 +205,7 @@ func (s *HandlerTestSuite) TestGrantCanNotBeCreatedWithMissingFields() { time.Time{}, ) - _, _, err = s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + _, _, err = s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Error(err, "expected error, because grant missing expiration date") } @@ -198,10 +218,10 @@ func (s *HandlerTestSuite) TestGrantPublicCanBeFetched() { time.Now().Add(time.Hour), ) - _, _, err := s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + _, _, err := s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().NoError(err, "no error expected on grant creation") - getResult, _, err := s.hydraClient.JwkApi.GetJsonWebKey(context.Background(), createRequestParams.Issuer, createRequestParams.Jwk.Kid).Execute() + getResult, _, err := s.hydraClient.JwkAPI.GetJsonWebKey(context.Background(), createRequestParams.Issuer, createRequestParams.Jwk.Kid).Execute() s.Require().NoError(err, "no error expected on fetching public key") s.Equal(createRequestParams.Jwk.Kid, getResult.Keys[0].Kid) @@ -216,7 +236,7 @@ func (s *HandlerTestSuite) TestGrantWithAnySubjectCanBeCreated() { time.Now().Add(time.Hour), ) - grant, _, err := s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + grant, _, err := s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().NoError(err, "no error expected on grant creation") assert.Empty(s.T(), grant.Subject) @@ -239,17 +259,17 @@ func (s *HandlerTestSuite) TestGrantListCanBeFetched() { time.Now().Add(time.Hour), ) - _, _, err := s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + _, _, err := s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().NoError(err, "no errors expected on grant creation") - _, _, err = s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams2).Execute() + _, _, err = s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams2).Execute() s.Require().NoError(err, "no errors expected on grant creation") - getResult, _, err := s.hydraClient.OAuth2Api.ListTrustedOAuth2JwtGrantIssuers(context.Background()).Execute() + getResult, _, err := s.hydraClient.OAuth2API.ListTrustedOAuth2JwtGrantIssuers(context.Background()).Execute() s.Require().NoError(err, "no errors expected on grant list fetching") s.Len(getResult, 2, "expected to get list of 2 grants") - getResult, _, err = s.hydraClient.OAuth2Api.ListTrustedOAuth2JwtGrantIssuers(context.Background()).Issuer(createRequestParams2.Issuer).Execute() + getResult, _, err = s.hydraClient.OAuth2API.ListTrustedOAuth2JwtGrantIssuers(context.Background()).Issuer(createRequestParams2.Issuer).Execute() s.Require().NoError(err, "no errors expected on grant list fetching") s.Len(getResult, 1, "expected to get list of 1 grant, when filtering by issuer") @@ -265,13 +285,13 @@ func (s *HandlerTestSuite) TestGrantCanBeDeleted() { time.Now().Add(time.Hour), ) - createResult, _, err := s.hydraClient.OAuth2Api.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() + createResult, _, err := s.hydraClient.OAuth2API.TrustOAuth2JwtGrantIssuer(context.Background()).TrustOAuth2JwtGrantIssuer(createRequestParams).Execute() s.Require().NoError(err, "no errors expected on grant creation") - _, err = s.hydraClient.OAuth2Api.DeleteTrustedOAuth2JwtGrantIssuer(context.Background(), *createResult.Id).Execute() + _, err = s.hydraClient.OAuth2API.DeleteTrustedOAuth2JwtGrantIssuer(context.Background(), *createResult.Id).Execute() s.Require().NoError(err, "no errors expected on grant deletion") - _, err = s.hydraClient.OAuth2Api.DeleteTrustedOAuth2JwtGrantIssuer(context.Background(), *createResult.Id).Execute() + _, err = s.hydraClient.OAuth2API.DeleteTrustedOAuth2JwtGrantIssuer(context.Background(), *createResult.Id).Execute() s.Error(err, "expected error, because grant has been already deleted") } diff --git a/oauth2/trust/manager.go b/oauth2/trust/manager.go index 3e822b60d3c..adf3135135d 100644 --- a/oauth2/trust/manager.go +++ b/oauth2/trust/manager.go @@ -7,8 +7,8 @@ import ( "context" "time" + "github.com/go-jose/go-jose/v3" "github.com/gofrs/uuid" - "gopkg.in/square/go-jose.v2" ) type GrantManager interface { diff --git a/oauth2/trust/manager_test_helpers.go b/oauth2/trust/manager_test_helpers.go index e51407b905b..e19c0791186 100644 --- a/oauth2/trust/manager_test_helpers.go +++ b/oauth2/trust/manager_test_helpers.go @@ -11,12 +11,12 @@ import ( "github.com/ory/x/josex" + "github.com/go-jose/go-jose/v3" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "gopkg.in/square/go-jose.v2" - "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/jwk" ) func TestHelperGrantManagerCreateGetDeleteGrant(t1 GrantManager, km jwk.Manager, parallel bool) func(t *testing.T) { diff --git a/oauth2/trust/registry.go b/oauth2/trust/registry.go index 6184f8e9072..6d857dca9d0 100644 --- a/oauth2/trust/registry.go +++ b/oauth2/trust/registry.go @@ -4,7 +4,7 @@ package trust import ( - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" ) type InternalRegistry interface { diff --git a/oauth2/trust/request.go b/oauth2/trust/request.go index 3ba7be2655b..853b7e00d53 100644 --- a/oauth2/trust/request.go +++ b/oauth2/trust/request.go @@ -6,7 +6,7 @@ package trust import ( "time" - "gopkg.in/square/go-jose.v2" + "github.com/go-jose/go-jose/v3" ) type createGrantRequest struct { diff --git a/oauth2/trust/validator_test.go b/oauth2/trust/validator_test.go index 1d07b5def05..07241cff301 100644 --- a/oauth2/trust/validator_test.go +++ b/oauth2/trust/validator_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "gopkg.in/square/go-jose.v2" + "github.com/go-jose/go-jose/v3" ) func TestEmptyIssuerIsInvalid(t *testing.T) { diff --git a/oauth2/verifiable_credentials.go b/oauth2/verifiable_credentials.go new file mode 100644 index 00000000000..3af47e09229 --- /dev/null +++ b/oauth2/verifiable_credentials.go @@ -0,0 +1,87 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package oauth2 + +import ( + "encoding/json" + + "github.com/golang-jwt/jwt/v5" + + "github.com/ory/fosite" +) + +// Request a Verifiable Credential +// +// swagger:parameters createVerifiableCredential +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions +type createVerifiableCredentialRequest struct { + // in: body + Body CreateVerifiableCredentialRequestBody +} + +// CreateVerifiableCredentialRequestBody contains the request body to request a verifiable credential. +// +// swagger:parameters createVerifiableCredentialRequestBody +type CreateVerifiableCredentialRequestBody struct { + Format string `json:"format"` + Types []string `json:"types"` + Proof *VerifiableCredentialProof `json:"proof"` +} + +// VerifiableCredentialProof contains the proof of a verifiable credential. +// +// swagger:parameters verifiableCredentialProof +type VerifiableCredentialProof struct { + ProofType string `json:"proof_type"` + JWT string `json:"jwt"` +} + +// VerifiableCredentialResponse contains the verifiable credential. +// +// swagger:model verifiableCredentialResponse +type VerifiableCredentialResponse struct { + Format string `json:"format"` + Credential string `json:"credential_draft_00"` +} + +// VerifiableCredentialPrimingResponse contains the nonce to include in the proof-of-possession JWT. +// +// swagger:model verifiableCredentialPrimingResponse +type VerifiableCredentialPrimingResponse struct { + Format string `json:"format"` + Nonce string `json:"c_nonce"` + NonceExpiresIn int64 `json:"c_nonce_expires_in"` + + fosite.RFC6749ErrorJson +} + +type VerifableCredentialClaims struct { + jwt.RegisteredClaims + VerifiableCredential VerifiableCredentialClaim `json:"vc"` +} +type VerifiableCredentialClaim struct { + Context []string `json:"@context"` + Subject map[string]any `json:"credentialSubject"` + Type []string `json:"type"` +} + +func (v *VerifableCredentialClaims) GetAudience() (jwt.ClaimStrings, error) { + return jwt.ClaimStrings{}, nil +} + +func (v *VerifableCredentialClaims) ToMapClaims() (res map[string]any, err error) { + res = map[string]any{} + + bs, err := json.Marshal(v) + if err != nil { + return nil, err + } + err = json.Unmarshal(bs, &res) + if err != nil { + return nil, err + } + + return res, nil +} diff --git a/openapitools.json b/openapitools.json index 54d00804a3d..64f2cbb5416 100644 --- a/openapitools.json +++ b/openapitools.json @@ -2,6 +2,6 @@ "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json", "spaces": 2, "generator-cli": { - "version": "6.0.1" + "version": "7.2.0" } } diff --git a/package-lock.json b/package-lock.json index bb5fafedbb9..c63a282ff4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "@oryd/hydra", "version": "0.0.0", "dependencies": { - "@openapitools/openapi-generator-cli": "^2.1.18", + "@openapitools/openapi-generator-cli": "^2.13.5", "conventional-changelog-cli": "~2.2.2", "doctoc": "^2.2.1" }, @@ -22,7 +22,7 @@ "prettier-plugin-packagejson": "^2.2.18", "standard": "^12.0.1", "uuid": "^8.3.2", - "wait-on": "^3.2.0" + "wait-on": "^7.0.1" } }, "node_modules/@babel/code-frame": { @@ -73,9 +73,9 @@ } }, "node_modules/@cypress/request": { - "version": "2.88.10", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", - "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", + "version": "2.88.12", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz", + "integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==", "dev": true, "dependencies": { "aws-sign2": "~0.7.0", @@ -91,9 +91,9 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "~6.5.2", + "qs": "~6.10.3", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", + "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" }, @@ -130,19 +130,6 @@ "verror": "1.10.0" } }, - "node_modules/@cypress/request/node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/@cypress/xvfb": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", @@ -153,6 +140,21 @@ "lodash.once": "^4.1.1" } }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, "node_modules/@hutson/parse-repository-url": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", @@ -161,6 +163,14 @@ "node": ">=6.9.0" } }, + "node_modules/@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==", + "engines": { + "node": ">=8" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -278,26 +288,29 @@ } }, "node_modules/@openapitools/openapi-generator-cli": { - "version": "2.4.26", - "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.4.26.tgz", - "integrity": "sha512-O42H9q1HWGoIpcpMaUu318b6bmOgcjP3MieHwOrFdoG3KyttceBGlbLf9Kbf7WM91WSNCDXum7cnEKASuoGjAg==", + "version": "2.13.5", + "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.13.5.tgz", + "integrity": "sha512-9VgeKOTiiatKSwZDKKB3C86cW8tN9eDcFohotD4eisdK38UQswk/4Ysoq9KChRCbymjoMp6AIDHPtK1DQ2fTgw==", "hasInstallScript": true, "dependencies": { - "@nestjs/common": "8.2.6", - "@nestjs/core": "8.2.6", + "@nestjs/axios": "3.0.2", + "@nestjs/common": "10.3.0", + "@nestjs/core": "10.3.0", "@nuxtjs/opencollective": "0.3.2", + "axios": "1.7.4", "chalk": "4.1.2", "commander": "8.3.0", - "compare-versions": "3.6.0", + "compare-versions": "4.1.4", "concurrently": "6.5.1", "console.table": "0.10.0", - "fs-extra": "10.0.0", - "glob": "7.1.6", - "inquirer": "8.2.0", + "fs-extra": "10.1.0", + "glob": "7.2.3", + "https-proxy-agent": "7.0.4", + "inquirer": "8.2.6", "lodash": "4.17.21", "reflect-metadata": "0.1.13", - "rxjs": "7.5.2", - "tslib": "2.0.3" + "rxjs": "7.8.1", + "tslib": "2.6.2" }, "bin": { "openapi-generator-cli": "main.js" @@ -310,31 +323,36 @@ "url": "https://opencollective.com/openapi_generator" } }, + "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/axios": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.2.tgz", + "integrity": "sha512-Z6GuOUdNQjP7FX+OuV2Ybyamse+/e0BFdTWBX5JxpBDKA+YkdLynDgG6HTF04zy6e9zPa19UX0WA2VDoehwhXQ==", + "peerDependencies": { + "@nestjs/common": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0", + "axios": "^1.3.1", + "rxjs": "^6.0.0 || ^7.0.0" + } + }, "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/common": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.2.6.tgz", - "integrity": "sha512-flLYSXunxcKyjbYddrhwbc49uE705MxBt85rS3mHyhDbAIPSGGeZEqME44YyAzCg1NTfJSNe7ztmOce5kNkb9A==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.3.0.tgz", + "integrity": "sha512-DGv34UHsZBxCM3H5QGE2XE/+oLJzz5+714JQjBhjD9VccFlQs3LRxo/epso4l7nJIiNlZkPyIUC8WzfU/5RTsQ==", "dependencies": { - "axios": "0.24.0", "iterare": "1.2.1", - "tslib": "2.3.1", - "uuid": "8.3.2" + "tslib": "2.6.2", + "uid": "2.0.2" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/nest" }, "peerDependencies": { - "cache-manager": "*", "class-transformer": "*", "class-validator": "*", "reflect-metadata": "^0.1.12", "rxjs": "^7.1.0" }, "peerDependenciesMeta": { - "cache-manager": { - "optional": true - }, "class-transformer": { "optional": true }, @@ -343,34 +361,28 @@ } } }, - "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/common/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/core": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.2.6.tgz", - "integrity": "sha512-NwPcEIMmCsucs3QaDlQvkoU1FlFM2wm/WjaqLQhkSoIEmAR1gNtBo88f5io5cpMwCo1k5xYhqGlaSl6TfngwWQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.3.0.tgz", + "integrity": "sha512-N06P5ncknW/Pm8bj964WvLIZn2gNhHliCBoAO1LeBvNImYkecqKcrmLbY49Fa1rmMfEM3MuBHeDys3edeuYAOA==", "hasInstallScript": true, "dependencies": { "@nuxtjs/opencollective": "0.3.2", "fast-safe-stringify": "2.1.1", "iterare": "1.2.1", - "object-hash": "2.2.0", "path-to-regexp": "3.2.0", - "tslib": "2.3.1", - "uuid": "8.3.2" + "tslib": "2.6.2", + "uid": "2.0.2" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/nest" }, "peerDependencies": { - "@nestjs/common": "^8.0.0", - "@nestjs/microservices": "^8.0.0", - "@nestjs/platform-express": "^8.0.0", - "@nestjs/websockets": "^8.0.0", + "@nestjs/common": "^10.0.0", + "@nestjs/microservices": "^10.0.0", + "@nestjs/platform-express": "^10.0.0", + "@nestjs/websockets": "^10.0.0", "reflect-metadata": "^0.1.12", "rxjs": "^7.1.0" }, @@ -386,11 +398,6 @@ } } }, - "node_modules/@openapitools/openapi-generator-cli/node_modules/@nestjs/core/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, "node_modules/@openapitools/openapi-generator-cli/node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -493,9 +500,9 @@ } }, "node_modules/@openapitools/openapi-generator-cli/node_modules/fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -514,9 +521,9 @@ } }, "node_modules/@openapitools/openapi-generator-cli/node_modules/inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -528,13 +535,14 @@ "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^7.2.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" }, "engines": { - "node": ">=8.0.0" + "node": ">=12.0.0" } }, "node_modules/@openapitools/openapi-generator-cli/node_modules/mute-stream": { @@ -543,18 +551,13 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "node_modules/@openapitools/openapi-generator-cli/node_modules/rxjs": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.2.tgz", - "integrity": "sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dependencies": { "tslib": "^2.1.0" } }, - "node_modules/@openapitools/openapi-generator-cli/node_modules/rxjs/node_modules/tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - }, "node_modules/@openapitools/openapi-generator-cli/node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -578,18 +581,44 @@ } }, "node_modules/@openapitools/openapi-generator-cli/node_modules/tslib": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", - "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "node_modules/@openapitools/openapi-generator-cli/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "bin": { - "uuid": "dist/bin/uuid" + "node_modules/@openapitools/openapi-generator-cli/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" } }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, "node_modules/@textlint/ast-node-types": { "version": "12.2.2", "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-12.2.2.tgz", @@ -723,6 +752,33 @@ "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==" }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -922,8 +978,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "node_modules/at-least-node": { "version": "1.0.0", @@ -950,13 +1005,33 @@ "dev": true }, "node_modules/axios": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", - "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dependencies": { - "follow-redirects": "^1.14.4" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, + "node_modules/axios/node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -1067,12 +1142,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1125,6 +1200,19 @@ "node": ">=6" } }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -1284,9 +1372,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "engines": { "node": ">=6" }, @@ -1388,10 +1476,9 @@ "dev": true }, "node_modules/combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", - "dev": true, + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -1427,9 +1514,9 @@ } }, "node_modules/compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz", + "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==" }, "node_modules/concat-map": { "version": "0.0.1", @@ -1719,9 +1806,9 @@ } }, "node_modules/conventional-changelog-core/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -1819,9 +1906,9 @@ } }, "node_modules/conventional-changelog-writer/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -1857,12 +1944,6 @@ "node": ">=10" } }, - "node_modules/core-js": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", - "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==", - "dev": true - }, "node_modules/core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -2003,9 +2084,9 @@ "dev": true }, "node_modules/cypress/node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -2044,9 +2125,9 @@ } }, "node_modules/cypress/node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -2132,9 +2213,9 @@ "dev": true }, "node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "dependencies": { "ms": "^2.1.1" @@ -2236,7 +2317,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -2998,9 +3078,9 @@ } }, "node_modules/extract-zip/node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -3120,9 +3200,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -3164,9 +3244,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", @@ -3252,6 +3332,21 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/get-pkg-repo": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", @@ -3413,9 +3508,9 @@ } }, "node_modules/git-semver-tags/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "bin": { "semver": "bin/semver.js" } @@ -3434,14 +3529,14 @@ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" }, "node_modules/glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, @@ -3541,28 +3636,6 @@ "uglify-js": "^3.1.4" } }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "dependencies": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -3602,22 +3675,28 @@ "node": ">=4" } }, - "node_modules/has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", "dev": true, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hoek": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", - "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==", + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true, "engines": { - "node": ">=8.9.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/hosted-git-info": { @@ -3643,19 +3722,32 @@ "entities": "^3.0.1" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, "node_modules/human-signals": { @@ -4129,18 +4221,6 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, - "node_modules/isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "dev": true, - "dependencies": { - "punycode": "2.x.x" - }, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4162,17 +4242,16 @@ } }, "node_modules/joi": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz", - "integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==", + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", "dev": true, "dependencies": { - "hoek": "5.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" - }, - "engines": { - "node": ">=8.9.0" + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" } }, "node_modules/js-tokens": { @@ -4289,21 +4368,6 @@ "npm": ">=1.4.28" } }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/jsx-ast-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz", @@ -5108,9 +5172,9 @@ } }, "node_modules/meow/node_modules/read-pkg/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -5124,9 +5188,9 @@ } }, "node_modules/meow/node_modules/semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -5313,7 +5377,6 @@ "version": "1.38.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -5322,7 +5385,6 @@ "version": "2.1.22", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", - "dev": true, "dependencies": { "mime-db": "~1.38.0" }, @@ -5359,9 +5421,12 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/minimist-options": { "version": "4.1.0", @@ -5433,9 +5498,9 @@ "dev": true }, "node_modules/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -5502,15 +5567,6 @@ "node": ">=8" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5520,12 +5576,13 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", - "engines": { - "node": ">= 6" + "node_modules/object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/object-keys": { @@ -6012,9 +6069,9 @@ "dev": true }, "node_modules/psl": { - "version": "1.1.31", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", - "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "node_modules/pump": { @@ -6046,14 +6103,26 @@ } }, "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true + }, "node_modules/quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", @@ -6305,37 +6374,6 @@ "node": ">=0.10" } }, - "node_modules/request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 4" - } - }, "node_modules/request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", @@ -6345,16 +6383,6 @@ "throttleit": "^1.0.0" } }, - "node_modules/request/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6376,8 +6404,14 @@ "node": ">=0.10.0" } }, - "node_modules/resolve": { - "version": "1.10.0", + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, + "node_modules/resolve": { + "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", "dependencies": { @@ -6441,12 +6475,6 @@ "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", "dev": true }, - "node_modules/rx": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", - "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", - "dev": true - }, "node_modules/rxjs": { "version": "5.5.12", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", @@ -6484,9 +6512,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "bin": { "semver": "bin/semver" } @@ -6512,6 +6540,20 @@ "node": ">=0.10.0" } }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -7020,44 +7062,34 @@ "node": ">=8.0" } }, - "node_modules/topo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", - "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", - "dev": true, - "dependencies": { - "hoek": "6.x.x" - } - }, - "node_modules/topo/node_modules/hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", - "dev": true - }, "node_modules/tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "dependencies": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "engines": { - "node": ">=0.8" + "node": ">=6" } }, - "node_modules/tough-cookie/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/traverse": { "version": "0.6.7", @@ -7159,6 +7191,17 @@ "node": ">=0.8.0" } }, + "node_modules/uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "dependencies": { + "@lukeed/csprng": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/underscore": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", @@ -7252,6 +7295,16 @@ "punycode": "^2.1.0" } }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -7324,24 +7377,39 @@ } }, "node_modules/wait-on": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-3.2.0.tgz", - "integrity": "sha512-QUGNKlKLDyY6W/qHdxaRlXUAgLPe+3mLL/tRByHpRNcHs/c7dZXbu+OnJWGNux6tU1WFh/Z8aEwvbuzSAu79Zg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", "dev": true, "dependencies": { - "core-js": "^2.5.7", - "joi": "^13.0.0", - "minimist": "^1.2.0", - "request": "^2.88.0", - "rx": "^4.1.0" + "axios": "^1.6.1", + "joi": "^17.11.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.1" }, "bin": { "wait-on": "bin/wait-on" }, "engines": { - "node": ">=4.0.0" + "node": ">=12.0.0" + } + }, + "node_modules/wait-on/node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" } }, + "node_modules/wait-on/node_modules/tslib": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "dev": true + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -7353,12 +7421,12 @@ "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -7568,9 +7636,9 @@ "optional": true }, "@cypress/request": { - "version": "2.88.10", - "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.10.tgz", - "integrity": "sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg==", + "version": "2.88.12", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.12.tgz", + "integrity": "sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -7586,9 +7654,9 @@ "json-stringify-safe": "~5.0.1", "mime-types": "~2.1.19", "performance-now": "^2.1.0", - "qs": "~6.5.2", + "qs": "~6.10.3", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", + "tough-cookie": "^4.1.3", "tunnel-agent": "^0.6.0", "uuid": "^8.3.2" }, @@ -7615,16 +7683,6 @@ "json-schema": "0.4.0", "verror": "1.10.0" } - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } } } }, @@ -7638,11 +7696,31 @@ "lodash.once": "^4.1.1" } }, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, "@hutson/parse-repository-url": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz", "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==" }, + "@lukeed/csprng": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@lukeed/csprng/-/csprng-1.1.0.tgz", + "integrity": "sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -7725,64 +7803,57 @@ } }, "@openapitools/openapi-generator-cli": { - "version": "2.4.26", - "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.4.26.tgz", - "integrity": "sha512-O42H9q1HWGoIpcpMaUu318b6bmOgcjP3MieHwOrFdoG3KyttceBGlbLf9Kbf7WM91WSNCDXum7cnEKASuoGjAg==", + "version": "2.13.5", + "resolved": "https://registry.npmjs.org/@openapitools/openapi-generator-cli/-/openapi-generator-cli-2.13.5.tgz", + "integrity": "sha512-9VgeKOTiiatKSwZDKKB3C86cW8tN9eDcFohotD4eisdK38UQswk/4Ysoq9KChRCbymjoMp6AIDHPtK1DQ2fTgw==", "requires": { - "@nestjs/common": "8.2.6", - "@nestjs/core": "8.2.6", + "@nestjs/axios": "3.0.2", + "@nestjs/common": "10.3.0", + "@nestjs/core": "10.3.0", "@nuxtjs/opencollective": "0.3.2", + "axios": "1.7.4", "chalk": "4.1.2", "commander": "8.3.0", - "compare-versions": "3.6.0", + "compare-versions": "4.1.4", "concurrently": "6.5.1", "console.table": "0.10.0", - "fs-extra": "10.0.0", - "glob": "7.1.6", - "inquirer": "8.2.0", + "fs-extra": "10.1.0", + "glob": "7.2.3", + "https-proxy-agent": "7.0.4", + "inquirer": "8.2.6", "lodash": "4.17.21", "reflect-metadata": "0.1.13", - "rxjs": "7.5.2", - "tslib": "2.0.3" + "rxjs": "7.8.1", + "tslib": "2.6.2" }, "dependencies": { + "@nestjs/axios": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@nestjs/axios/-/axios-3.0.2.tgz", + "integrity": "sha512-Z6GuOUdNQjP7FX+OuV2Ybyamse+/e0BFdTWBX5JxpBDKA+YkdLynDgG6HTF04zy6e9zPa19UX0WA2VDoehwhXQ==", + "requires": {} + }, "@nestjs/common": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-8.2.6.tgz", - "integrity": "sha512-flLYSXunxcKyjbYddrhwbc49uE705MxBt85rS3mHyhDbAIPSGGeZEqME44YyAzCg1NTfJSNe7ztmOce5kNkb9A==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@nestjs/common/-/common-10.3.0.tgz", + "integrity": "sha512-DGv34UHsZBxCM3H5QGE2XE/+oLJzz5+714JQjBhjD9VccFlQs3LRxo/epso4l7nJIiNlZkPyIUC8WzfU/5RTsQ==", "requires": { - "axios": "0.24.0", "iterare": "1.2.1", - "tslib": "2.3.1", - "uuid": "8.3.2" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - } + "tslib": "2.6.2", + "uid": "2.0.2" } }, "@nestjs/core": { - "version": "8.2.6", - "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-8.2.6.tgz", - "integrity": "sha512-NwPcEIMmCsucs3QaDlQvkoU1FlFM2wm/WjaqLQhkSoIEmAR1gNtBo88f5io5cpMwCo1k5xYhqGlaSl6TfngwWQ==", + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@nestjs/core/-/core-10.3.0.tgz", + "integrity": "sha512-N06P5ncknW/Pm8bj964WvLIZn2gNhHliCBoAO1LeBvNImYkecqKcrmLbY49Fa1rmMfEM3MuBHeDys3edeuYAOA==", "requires": { "@nuxtjs/opencollective": "0.3.2", "fast-safe-stringify": "2.1.1", "iterare": "1.2.1", - "object-hash": "2.2.0", "path-to-regexp": "3.2.0", - "tslib": "2.3.1", - "uuid": "8.3.2" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - } + "tslib": "2.6.2", + "uid": "2.0.2" } }, "ansi-escapes": { @@ -7854,9 +7925,9 @@ } }, "fs-extra": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", - "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "requires": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -7869,9 +7940,9 @@ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, "inquirer": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", - "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", + "version": "8.2.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", + "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", "requires": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -7883,10 +7954,11 @@ "mute-stream": "0.0.8", "ora": "^5.4.1", "run-async": "^2.4.0", - "rxjs": "^7.2.0", + "rxjs": "^7.5.5", "string-width": "^4.1.0", "strip-ansi": "^6.0.0", - "through": "^2.3.6" + "through": "^2.3.6", + "wrap-ansi": "^6.0.1" } }, "mute-stream": { @@ -7895,18 +7967,11 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, "rxjs": { - "version": "7.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.5.2.tgz", - "integrity": "sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==", + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "requires": { "tslib": "^2.1.0" - }, - "dependencies": { - "tslib": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", - "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" - } } }, "strip-ansi": { @@ -7926,17 +7991,43 @@ } }, "tslib": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", - "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==" + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } } } }, + "@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dev": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, "@textlint/ast-node-types": { "version": "12.2.2", "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-12.2.2.tgz", @@ -8058,6 +8149,24 @@ "resolved": "https://registry.npmjs.org/add-stream/-/add-stream-1.0.0.tgz", "integrity": "sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==" }, + "agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "requires": { + "debug": "^4.3.4" + }, + "dependencies": { + "debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "requires": { + "ms": "2.1.2" + } + } + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -8208,8 +8317,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "at-least-node": { "version": "1.0.0", @@ -8230,11 +8338,30 @@ "dev": true }, "axios": { - "version": "0.24.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", - "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.4.tgz", + "integrity": "sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==", "requires": { - "follow-redirects": "^1.14.4" + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + }, + "dependencies": { + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + } } }, "babel-code-frame": { @@ -8325,12 +8452,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "buffer": { @@ -8360,6 +8487,16 @@ "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", "dev": true }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, "caller-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", @@ -8475,9 +8612,9 @@ } }, "cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==" + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==" }, "cli-table3": { "version": "0.6.2", @@ -8555,10 +8692,9 @@ "dev": true }, "combined-stream": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", - "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", - "dev": true, + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "requires": { "delayed-stream": "~1.0.0" } @@ -8585,9 +8721,9 @@ } }, "compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==" + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.4.tgz", + "integrity": "sha512-FemMreK9xNyL8gQevsdRMrvO4lFCkQP7qbuktn1q8ndcNk1+0mz7lgE7b/sNvbhVgY4w6tMN1FDp6aADjqw2rw==" }, "concat-map": { "version": "0.0.1", @@ -8806,9 +8942,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -8878,9 +9014,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -8906,12 +9042,6 @@ "through2": "^4.0.0" } }, - "core-js": { - "version": "2.6.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz", - "integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==", - "dev": true - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", @@ -9026,9 +9156,9 @@ "dev": true }, "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -9050,9 +9180,9 @@ } }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -9109,9 +9239,9 @@ "dev": true }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" @@ -9198,8 +9328,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "detect-indent": { "version": "6.1.0", @@ -9807,9 +9936,9 @@ }, "dependencies": { "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { "ms": "2.1.2" @@ -9904,9 +10033,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -9939,9 +10068,9 @@ } }, "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" }, "forever-agent": { "version": "0.6.1", @@ -9998,6 +10127,18 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, + "get-intrinsic": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz", + "integrity": "sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3" + } + }, "get-pkg-repo": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz", @@ -10125,9 +10266,9 @@ }, "dependencies": { "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" } } }, @@ -10147,14 +10288,14 @@ } }, "glob": { - "version": "7.1.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", - "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.4", + "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } @@ -10224,22 +10365,6 @@ "wordwrap": "^1.0.0" } }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, "hard-rejection": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", @@ -10267,16 +10392,16 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", "dev": true }, - "hoek": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.4.tgz", - "integrity": "sha512-Alr4ZQgoMlnere5FZJsIyfIjORBqZll5POhDsF4q64dPuJR6rNxXdDxtHSQq8OXRurhmx+PWYEE8bXRROY8h0w==", + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", "dev": true }, "hosted-git-info": { @@ -10295,15 +10420,23 @@ "entities": "^3.0.1" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, + "https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "agent-base": "^7.0.2", + "debug": "4" + }, + "dependencies": { + "debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "requires": { + "ms": "2.1.2" + } + } } }, "human-signals": { @@ -10627,15 +10760,6 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, - "isemail": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/isemail/-/isemail-3.2.0.tgz", - "integrity": "sha512-zKqkK+O+dGqevc93KNsbZ/TqTUFd46MwWjYOoMrjIMZ51eU7DtQG3Wmd9SQQT7i7RVnuTPEiYEWHU3MSbxC1Tg==", - "dev": true, - "requires": { - "punycode": "2.x.x" - } - }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -10654,14 +10778,16 @@ "integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q==" }, "joi": { - "version": "13.7.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-13.7.0.tgz", - "integrity": "sha512-xuY5VkHfeOYK3Hdi91ulocfuFopwgbSORmIwzcwHKESQhC7w1kD5jaVSPnqDxS2I8t3RZ9omCKAxNwXN5zG1/Q==", + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", "dev": true, "requires": { - "hoek": "5.x.x", - "isemail": "3.x.x", - "topo": "3.x.x" + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" } }, "js-tokens": { @@ -10760,18 +10886,6 @@ "semver": "^5.6.0" } }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } - }, "jsx-ast-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz", @@ -11354,9 +11468,9 @@ } }, "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "type-fest": { "version": "0.6.0", @@ -11383,9 +11497,9 @@ } }, "semver": { - "version": "7.3.8", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", - "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "requires": { "lru-cache": "^6.0.0" } @@ -11507,14 +11621,12 @@ "mime-db": { "version": "1.38.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", - "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==", - "dev": true + "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" }, "mime-types": { "version": "2.1.22", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", - "dev": true, "requires": { "mime-db": "~1.38.0" } @@ -11539,9 +11651,9 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" }, "minimist-options": { "version": "4.1.0", @@ -11603,9 +11715,9 @@ "dev": true }, "node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "requires": { "whatwg-url": "^5.0.0" } @@ -11654,22 +11766,17 @@ } } }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "dev": true }, - "object-hash": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", - "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==" + "object-inspect": { + "version": "1.12.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz", + "integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==", + "dev": true }, "object-keys": { "version": "1.1.1", @@ -12026,9 +12133,9 @@ "dev": true }, "psl": { - "version": "1.1.31", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", - "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "pump": { @@ -12053,9 +12160,18 @@ "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==" }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", "dev": true }, "quick-lru": { @@ -12256,42 +12372,6 @@ "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==" }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - } - } - }, "request-progress": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", @@ -12316,6 +12396,12 @@ "resolve-from": "^1.0.0" } }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true + }, "resolve": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", @@ -12365,12 +12451,6 @@ "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==", "dev": true }, - "rx": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", - "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", - "dev": true - }, "rxjs": { "version": "5.5.12", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz", @@ -12391,9 +12471,9 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "shebang-command": { "version": "1.2.0", @@ -12410,6 +12490,17 @@ "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", "dev": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", @@ -12823,37 +12914,22 @@ "is-number": "^7.0.0" } }, - "topo": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/topo/-/topo-3.0.3.tgz", - "integrity": "sha512-IgpPtvD4kjrJ7CRA3ov2FhWQADwv+Tdqbsf1ZnPUSAtCJ9e1Z44MmoSGDXGk4IppoZA7jd/QRkNddlLJWlUZsQ==", - "dev": true, - "requires": { - "hoek": "6.x.x" - }, - "dependencies": { - "hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", - "dev": true - } - } - }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" }, "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true } } @@ -12861,7 +12937,7 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "traverse": { "version": "0.6.7", @@ -12929,6 +13005,14 @@ "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", "optional": true }, + "uid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz", + "integrity": "sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==", + "requires": { + "@lukeed/csprng": "^1.0.0" + } + }, "underscore": { "version": "1.13.6", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", @@ -13000,6 +13084,16 @@ "punycode": "^2.1.0" } }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -13058,16 +13152,33 @@ } }, "wait-on": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-3.2.0.tgz", - "integrity": "sha512-QUGNKlKLDyY6W/qHdxaRlXUAgLPe+3mLL/tRByHpRNcHs/c7dZXbu+OnJWGNux6tU1WFh/Z8aEwvbuzSAu79Zg==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", "dev": true, "requires": { - "core-js": "^2.5.7", - "joi": "^13.0.0", - "minimist": "^1.2.0", - "request": "^2.88.0", - "rx": "^4.1.0" + "axios": "^1.6.1", + "joi": "^17.11.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.1" + }, + "dependencies": { + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "requires": { + "tslib": "^2.1.0" + } + }, + "tslib": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz", + "integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig==", + "dev": true + } } }, "wcwidth": { @@ -13081,12 +13192,12 @@ "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" diff --git a/package.json b/package.json index 7a6a8e55250..b57785fd06b 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ }, "prettier": "ory-prettier-styles", "dependencies": { - "@openapitools/openapi-generator-cli": "^2.1.18", + "@openapitools/openapi-generator-cli": "^2.13.5", "conventional-changelog-cli": "~2.2.2", "doctoc": "^2.2.1" }, @@ -25,6 +25,6 @@ "prettier-plugin-packagejson": "^2.2.18", "standard": "^12.0.1", "uuid": "^8.3.2", - "wait-on": "^3.2.0" + "wait-on": "^7.0.1" } } diff --git a/persistence/definitions.go b/persistence/definitions.go index 88e6c444662..ac9076eb2d3 100644 --- a/persistence/definitions.go +++ b/persistence/definitions.go @@ -6,13 +6,17 @@ package persistence import ( "context" + "github.com/gofrs/uuid" + + "github.com/ory/x/networkx" + "github.com/gobuffalo/pop/v6" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/oauth2/trust" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/oauth2/trust" + "github.com/ory/hydra/v2/x" "github.com/ory/x/popx" ) @@ -29,9 +33,16 @@ type ( MigrateUp(context.Context) error PrepareMigration(context.Context) error Connection(context.Context) *pop.Connection - Ping() error + Transaction(context.Context, func(ctx context.Context, c *pop.Connection) error) error + Ping(context.Context) error + Networker } Provider interface { Persister() Persister } + + Networker interface { + NetworkID(ctx context.Context) uuid.UUID + DetermineNetwork(ctx context.Context) (*networkx.Network, error) + } ) diff --git a/persistence/sql/migratest/assertion_helpers.go b/persistence/sql/migratest/assertion_helpers.go index faa32ff9b9f..6cfa2764ec6 100644 --- a/persistence/sql/migratest/assertion_helpers.go +++ b/persistence/sql/migratest/assertion_helpers.go @@ -8,21 +8,21 @@ import ( "time" "github.com/gofrs/uuid" - "github.com/instana/testify/require" + "github.com/stretchr/testify/require" - "github.com/ory/hydra/flow" - testhelpersuuid "github.com/ory/hydra/internal/testhelpers/uuid" + "github.com/ory/hydra/v2/flow" + testhelpersuuid "github.com/ory/hydra/v2/internal/testhelpers/uuid" "github.com/ory/x/sqlxx" ) func fixturizeFlow(t *testing.T, f *flow.Flow) { - testhelpersuuid.AssertUUID(t, &f.NID) + testhelpersuuid.AssertUUID(t, f.NID) f.NID = uuid.Nil require.NotZero(t, f.ClientID) f.ClientID = "" require.NotNil(t, f.Client) f.Client = nil - recently := time.Now().Add(-time.Minute) + recently := time.Now().Add(-2 * time.Minute) require.Greater(t, time.Time(f.LoginInitializedAt).UnixNano(), recently.UnixNano()) f.LoginInitializedAt = sqlxx.NullTime{} require.True(t, f.RequestedAt.After(recently)) diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0001.json b/persistence/sql/migratest/fixtures/hydra_client/client-0001.json index 52c544377e7..eb65327c43f 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0001.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0001.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [], "Audience": [], "BackChannelLogoutSessionRequired": false, @@ -13,12 +14,11 @@ "GrantTypes": [ "grant-0001_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0001", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "", - "LegacyClientID": "client-0001", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -74,6 +74,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0001", "Owner": "owner-0001", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 1, "PolicyURI": "http://policy/0001", "PostLogoutRedirectURIs": [], @@ -92,6 +96,11 @@ "Secret": "secret-0001", "SecretExpiresAt": 0, "SectorIdentifierURI": "", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "", "TermsOfServiceURI": "http://tos/0001", "TokenEndpointAuthMethod": "none", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0002.json b/persistence/sql/migratest/fixtures/hydra_client/client-0002.json index de81d74bda6..d58301981be 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0002.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0002.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [], "Audience": [], "BackChannelLogoutSessionRequired": false, @@ -13,12 +14,11 @@ "GrantTypes": [ "grant-0002_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0002", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "", - "LegacyClientID": "client-0002", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -74,6 +74,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0002", "Owner": "owner-0002", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 2, "PolicyURI": "http://policy/0002", "PostLogoutRedirectURIs": [], @@ -92,6 +96,11 @@ "Secret": "secret-0002", "SecretExpiresAt": 0, "SectorIdentifierURI": "", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "", "TermsOfServiceURI": "http://tos/0002", "TokenEndpointAuthMethod": "none", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0003.json b/persistence/sql/migratest/fixtures/hydra_client/client-0003.json index cd9a90bdaa9..b0a9c4116b0 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0003.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0003.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [], "Audience": [], "BackChannelLogoutSessionRequired": false, @@ -13,12 +14,11 @@ "GrantTypes": [ "grant-0003_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0003", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "", - "LegacyClientID": "client-0003", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -74,6 +74,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0003", "Owner": "owner-0003", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 3, "PolicyURI": "http://policy/0003", "PostLogoutRedirectURIs": [], @@ -92,6 +96,11 @@ "Secret": "secret-0003", "SecretExpiresAt": 0, "SectorIdentifierURI": "", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "", "TermsOfServiceURI": "http://tos/0003", "TokenEndpointAuthMethod": "none", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0004.json b/persistence/sql/migratest/fixtures/hydra_client/client-0004.json index 158ad3f866c..ad8ddb8fa58 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0004.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0004.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [], "Audience": [], "BackChannelLogoutSessionRequired": false, @@ -13,12 +14,11 @@ "GrantTypes": [ "grant-0004_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0004", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0004", - "LegacyClientID": "client-0004", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -74,6 +74,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0004", "Owner": "owner-0004", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 4, "PolicyURI": "http://policy/0004", "PostLogoutRedirectURIs": [], @@ -94,6 +98,11 @@ "Secret": "secret-0004", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0004", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "", "TermsOfServiceURI": "http://tos/0004", "TokenEndpointAuthMethod": "none", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0005.json b/persistence/sql/migratest/fixtures/hydra_client/client-0005.json index 798a586bc03..295a11833a1 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0005.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0005.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [], "Audience": [], "BackChannelLogoutSessionRequired": false, @@ -13,12 +14,11 @@ "GrantTypes": [ "grant-0005_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0005", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0005", - "LegacyClientID": "client-0005", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -74,6 +74,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0005", "Owner": "owner-0005", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 5, "PolicyURI": "http://policy/0005", "PostLogoutRedirectURIs": [], @@ -94,6 +98,11 @@ "Secret": "secret-0005", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0005", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "", "TermsOfServiceURI": "http://tos/0005", "TokenEndpointAuthMethod": "token_auth-0005", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0006.json b/persistence/sql/migratest/fixtures/hydra_client/client-0006.json index 59911f9a747..9864869db0a 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0006.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0006.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [], "Audience": [], "BackChannelLogoutSessionRequired": false, @@ -13,12 +14,11 @@ "GrantTypes": [ "grant-0006_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0006", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0006", - "LegacyClientID": "client-0006", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -74,6 +74,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0006", "Owner": "owner-0006", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 6, "PolicyURI": "http://policy/0006", "PostLogoutRedirectURIs": [], @@ -94,6 +98,11 @@ "Secret": "secret-0006", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0006", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0006", "TermsOfServiceURI": "http://tos/0006", "TokenEndpointAuthMethod": "token_auth-0006", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0007.json b/persistence/sql/migratest/fixtures/hydra_client/client-0007.json index f8cccf2f5b5..8186c89de28 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0007.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0007.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [], "Audience": [], "BackChannelLogoutSessionRequired": false, @@ -13,12 +14,11 @@ "GrantTypes": [ "grant-0007_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0007", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0007", - "LegacyClientID": "client-0007", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -74,6 +74,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0007", "Owner": "owner-0007", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 7, "PolicyURI": "http://policy/0007", "PostLogoutRedirectURIs": [], @@ -94,6 +98,11 @@ "Secret": "secret-0007", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0007", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0007", "TermsOfServiceURI": "http://tos/0007", "TokenEndpointAuthMethod": "token_auth-0007", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0008.json b/persistence/sql/migratest/fixtures/hydra_client/client-0008.json index 518af6a985e..84bf09f3572 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0008.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0008.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/0008_1" ], @@ -15,12 +16,11 @@ "GrantTypes": [ "grant-0008_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0008", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0008", - "LegacyClientID": "client-0008", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -76,6 +76,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0008", "Owner": "owner-0008", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 8, "PolicyURI": "http://policy/0008", "PostLogoutRedirectURIs": [], @@ -96,6 +100,11 @@ "Secret": "secret-0008", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0008", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0008", "TermsOfServiceURI": "http://tos/0008", "TokenEndpointAuthMethod": "token_auth-0008", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0009.json b/persistence/sql/migratest/fixtures/hydra_client/client-0009.json index 9da29f7ca17..afae63b8668 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0009.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0009.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/0009_1" ], @@ -15,12 +16,11 @@ "GrantTypes": [ "grant-0009_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0009", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0009", - "LegacyClientID": "client-0009", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -76,6 +76,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0009", "Owner": "owner-0009", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 9, "PolicyURI": "http://policy/0009", "PostLogoutRedirectURIs": [], @@ -96,6 +100,11 @@ "Secret": "secret-0009", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0009", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0009", "TermsOfServiceURI": "http://tos/0009", "TokenEndpointAuthMethod": "token_auth-0009", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0010.json b/persistence/sql/migratest/fixtures/hydra_client/client-0010.json index 728a66c2bda..5385cde2a58 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0010.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0010.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/0010_1" ], @@ -15,12 +16,11 @@ "GrantTypes": [ "grant-0010_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0010", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0010", - "LegacyClientID": "client-0010", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -76,6 +76,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0010", "Owner": "owner-0010", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 10, "PolicyURI": "http://policy/0010", "PostLogoutRedirectURIs": [], @@ -96,6 +100,11 @@ "Secret": "secret-0010", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0010", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0010", "TermsOfServiceURI": "http://tos/0010", "TokenEndpointAuthMethod": "token_auth-0010", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0011.json b/persistence/sql/migratest/fixtures/hydra_client/client-0011.json index 3335f98fa13..7e3e68023fc 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0011.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0011.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/0011_1" ], @@ -17,12 +18,11 @@ "GrantTypes": [ "grant-0011_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0011", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0011", - "LegacyClientID": "client-0011", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -78,6 +78,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0011", "Owner": "owner-0011", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 11, "PolicyURI": "http://policy/0011", "PostLogoutRedirectURIs": [], @@ -98,6 +102,11 @@ "Secret": "secret-0011", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0011", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0011", "TermsOfServiceURI": "http://tos/0011", "TokenEndpointAuthMethod": "token_auth-0011", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0012.json b/persistence/sql/migratest/fixtures/hydra_client/client-0012.json index d5c7523feb5..cd61f01cbbe 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0012.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0012.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/0012_1" ], @@ -17,12 +18,11 @@ "GrantTypes": [ "grant-0012_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0012", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0012", - "LegacyClientID": "client-0012", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -78,6 +78,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0012", "Owner": "owner-0012", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 12, "PolicyURI": "http://policy/0012", "PostLogoutRedirectURIs": [], @@ -98,6 +102,11 @@ "Secret": "secret-0012", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0012", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0012", "TermsOfServiceURI": "http://tos/0012", "TokenEndpointAuthMethod": "token_auth-0012", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0013.json b/persistence/sql/migratest/fixtures/hydra_client/client-0013.json index a4a8438a9d3..7eaff4d8137 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0013.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0013.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/0013_1" ], @@ -17,12 +18,11 @@ "GrantTypes": [ "grant-0013_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0013", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0013", - "LegacyClientID": "client-0013", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -78,6 +78,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0013", "Owner": "owner-0013", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 13, "PolicyURI": "http://policy/0013", "PostLogoutRedirectURIs": [ @@ -100,6 +104,11 @@ "Secret": "secret-0013", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0013", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0013", "TermsOfServiceURI": "http://tos/0013", "TokenEndpointAuthMethod": "token_auth-0013", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0014.json b/persistence/sql/migratest/fixtures/hydra_client/client-0014.json index 28aec74413a..7571ef23533 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0014.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0014.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/0014_1" ], @@ -17,12 +18,11 @@ "GrantTypes": [ "grant-0014_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0014", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0014", - "LegacyClientID": "client-0014", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -80,6 +80,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0014", "Owner": "owner-0014", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 14, "PolicyURI": "http://policy/0014", "PostLogoutRedirectURIs": [ @@ -102,6 +106,11 @@ "Secret": "secret-0014", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0014", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0014", "TermsOfServiceURI": "http://tos/0014", "TokenEndpointAuthMethod": "token_auth-0014", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-0015.json b/persistence/sql/migratest/fixtures/hydra_client/client-0015.json index 029feb8eb30..ab4ee61170d 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-0015.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-0015.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/0015_1" ], @@ -17,12 +18,11 @@ "GrantTypes": [ "grant-0015_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-0015", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/0015", - "LegacyClientID": "client-0015", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 151000000000, @@ -80,6 +80,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 0015", "Owner": "owner-0015", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 15, "PolicyURI": "http://policy/0015", "PostLogoutRedirectURIs": [ @@ -102,6 +106,11 @@ "Secret": "secret-0015", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/0015", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-0015", "TermsOfServiceURI": "http://tos/0015", "TokenEndpointAuthMethod": "token_auth-0015", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-20.json b/persistence/sql/migratest/fixtures/hydra_client/client-20.json index ab1579564c5..63339ce7da9 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-20.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-20.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/20_1" ], @@ -17,12 +18,11 @@ "GrantTypes": [ "grant-20_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-20", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/20", - "LegacyClientID": "client-20", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -80,6 +80,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 20", "Owner": "owner-20", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 0, "PolicyURI": "http://policy/20", "PostLogoutRedirectURIs": [ @@ -102,6 +106,11 @@ "Secret": "secret-20", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/20", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-20", "TermsOfServiceURI": "http://tos/20", "TokenEndpointAuthMethod": "token_auth-20", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-2005.json b/persistence/sql/migratest/fixtures/hydra_client/client-2005.json index 475204dc723..140d8a42021 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-2005.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-2005.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/2005_1" ], @@ -17,12 +18,11 @@ "GrantTypes": [ "grant-2005_1" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-2005", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/2005", - "LegacyClientID": "client-2005", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -80,6 +80,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 2005", "Owner": "owner-2005", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 2005, "PolicyURI": "http://policy/2005", "PostLogoutRedirectURIs": [ @@ -102,6 +106,11 @@ "Secret": "secret-2005", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/2005", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-2005", "TermsOfServiceURI": "http://tos/2005", "TokenEndpointAuthMethod": "token_auth-2005", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-21.json b/persistence/sql/migratest/fixtures/hydra_client/client-21.json index 55e565b54db..6bc3911af94 100644 --- a/persistence/sql/migratest/fixtures/hydra_client/client-21.json +++ b/persistence/sql/migratest/fixtures/hydra_client/client-21.json @@ -1,4 +1,5 @@ { + "AccessTokenStrategy": "", "AllowedCORSOrigins": [ "http://cors/21_1", "http://cors/21_2" @@ -21,12 +22,11 @@ "grant-21_1", "grant-21_2" ], - "ID": "00000000-0000-0000-0000-000000000000", + "ID": "client-21", "JSONWebKeys": { "JSONWebKeySet": null }, "JSONWebKeysURI": "http://jwks/21", - "LegacyClientID": "client-21", "Lifespans": { "AuthorizationCodeGrantAccessTokenLifespan": { "Duration": 0, @@ -84,6 +84,10 @@ "NID": "00000000-0000-0000-0000-000000000000", "Name": "Client 21", "Owner": "owner-21", + "PK": { + "String": "", + "Valid": false + }, "PKDeprecated": 0, "PolicyURI": "http://policy/21", "PostLogoutRedirectURIs": [ @@ -110,6 +114,11 @@ "Secret": "secret-21", "SecretExpiresAt": 0, "SectorIdentifierURI": "http://sector_id/21", + "SkipConsent": false, + "SkipLogoutConsent": { + "Bool": false, + "Valid": false + }, "SubjectType": "subject-21", "TermsOfServiceURI": "http://tos/21", "TokenEndpointAuthMethod": "token_auth-21", diff --git a/persistence/sql/migratest/fixtures/hydra_client/client-22.json b/persistence/sql/migratest/fixtures/hydra_client/client-22.json new file mode 100644 index 00000000000..13a940c8416 --- /dev/null +++ b/persistence/sql/migratest/fixtures/hydra_client/client-22.json @@ -0,0 +1,128 @@ +{ + "AccessTokenStrategy": "", + "AllowedCORSOrigins": [ + "http://cors/22_1", + "http://cors/22_2" + ], + "Audience": [ + "autdience-22_1", + "autdience-22_2" + ], + "BackChannelLogoutSessionRequired": true, + "BackChannelLogoutURI": "http://back_logout/22", + "ClientURI": "http://client/22", + "Contacts": [ + "contact-22_1", + "contact-22_2" + ], + "CreatedAt": "0001-01-01T00:00:00Z", + "FrontChannelLogoutSessionRequired": true, + "FrontChannelLogoutURI": "http://front_logout/22", + "GrantTypes": [ + "grant-22_1", + "grant-22_2" + ], + "ID": "client-22", + "JSONWebKeys": { + "JSONWebKeySet": null + }, + "JSONWebKeysURI": "http://jwks/22", + "Lifespans": { + "AuthorizationCodeGrantAccessTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "AuthorizationCodeGrantIDTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "AuthorizationCodeGrantRefreshTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "ClientCredentialsGrantAccessTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "ImplicitGrantAccessTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "ImplicitGrantIDTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "JwtBearerGrantAccessTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "PasswordGrantAccessTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "PasswordGrantRefreshTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "RefreshTokenGrantAccessTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "RefreshTokenGrantIDTokenLifespan": { + "Duration": 0, + "Valid": false + }, + "RefreshTokenGrantRefreshTokenLifespan": { + "Duration": 0, + "Valid": false + } + }, + "LogoURI": "http://logo/22", + "Metadata": { + "migration": "22" + }, + "NID": "00000000-0000-0000-0000-000000000000", + "Name": "Client 22", + "Owner": "owner-22", + "PK": { + "String": "", + "Valid": false + }, + "PKDeprecated": 0, + "PolicyURI": "http://policy/22", + "PostLogoutRedirectURIs": [ + "http://post_redirect/22_1", + "http://post_redirect/22_2" + ], + "RedirectURIs": [ + "http://redirect/22_1", + "http://redirect/22_2" + ], + "RegistrationAccessToken": "", + "RegistrationAccessTokenSignature": "", + "RegistrationClientURI": "", + "RequestObjectSigningAlgorithm": "r_alg-22", + "RequestURIs": [ + "http://request/22_1", + "http://request/22_2" + ], + "ResponseTypes": [ + "response-22_1", + "response-22_2" + ], + "Scope": "scope-22", + "Secret": "secret-22", + "SecretExpiresAt": 0, + "SectorIdentifierURI": "http://sector_id/22", + "SkipConsent": true, + "SkipLogoutConsent": { + "Bool": true, + "Valid": true + }, + "SubjectType": "subject-22", + "TermsOfServiceURI": "http://tos/22", + "TokenEndpointAuthMethod": "token_auth-22", + "TokenEndpointAuthSigningAlgorithm": "", + "UpdatedAt": "0001-01-01T00:00:00Z", + "UserinfoSignedResponseAlg": "u_alg-22" +} diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0001.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0001.json index a642f6606bf..eb6ec18517e 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0001.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0001.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0001", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0002.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0002.json index 65d132ab888..130b019ccff 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0002.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0002.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0002", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0003.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0003.json index dfa9ae21e86..c6a2c35901f 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0003.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0003.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0003", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0004.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0004.json index 4411c2064a5..5da2bd40758 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0004.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0004.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0004", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0005.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0005.json index cba9dcf6125..0b3c6f8f4d7 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0005.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0005.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0005", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0006.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0006.json index 2081943455f..aa63cb104bb 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0006.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0006.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0006", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0007.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0007.json index c701732aac3..07b96a3d592 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0007.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0007.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0007", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0008.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0008.json index b8fc116b728..2e781eeda86 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0008.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0008.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0008", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0009.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0009.json index 57cee5ecb1e..204d0fffaf2 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0009.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0009.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0009", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0010.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0010.json index 3e6b4d5fa10..02608ae43f4 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0010.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0010.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0010", + "IdentityProviderSessionID": "", "Remember": true } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0011.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0011.json index 1344d7158fb..33d7187e6e2 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0011.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0011.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0011", + "IdentityProviderSessionID": "", "Remember": false } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0012.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0012.json index 876277e2440..5269cc061b2 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0012.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0012.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0012", + "IdentityProviderSessionID": "", "Remember": false } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0013.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0013.json index 404a1b4fe37..b4a2ee9f13d 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0013.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0013.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0013", + "IdentityProviderSessionID": "", "Remember": false } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0014.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0014.json index 472bef86c13..a9bb155e485 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0014.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0014.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0014", + "IdentityProviderSessionID": "", "Remember": false } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0015.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0015.json index 1f82a76af6b..c88a473e7cc 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0015.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0015.json @@ -3,5 +3,6 @@ "NID": "00000000-0000-0000-0000-000000000000", "AuthenticatedAt": null, "Subject": "subject-0015", + "IdentityProviderSessionID": "", "Remember": false } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0016.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0016.json new file mode 100644 index 00000000000..e2d69a9796b --- /dev/null +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0016.json @@ -0,0 +1,8 @@ +{ + "ID": "auth_session-0016", + "NID": "00000000-0000-0000-0000-000000000000", + "AuthenticatedAt": null, + "Subject": "subject-0016", + "IdentityProviderSessionID": "", + "Remember": true +} diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0017.json b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0017.json new file mode 100644 index 00000000000..aea0119e354 --- /dev/null +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_authentication_session/auth_session-0017.json @@ -0,0 +1,8 @@ +{ + "ID": "auth_session-0017", + "NID": "00000000-0000-0000-0000-000000000000", + "AuthenticatedAt": null, + "Subject": "subject-0017", + "IdentityProviderSessionID": "identity_provider_session_id-0017", + "Remember": true +} diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0001.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0001.json index e6c93405db7..fae8513d60a 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0001.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0001.json @@ -1,62 +1,57 @@ { - "ID": "challenge-0001", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0001", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0001_1" ], - "RequestedAudience": [], - "LoginSkip": true, - "Subject": "subject-0001", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0001", + "oc": { "display": "display-0001" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0001", - "SessionID": "", - "LoginVerifier": "verifier-0001", - "LoginCSRF": "csrf-0001", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 1, - "ACR": "acr-0001", - "AMR": [], - "ForceSubjectIdentifier": "", - "Context": {}, - "LoginWasUsed": true, - "LoginError": { + "r": "http://request/0001", + "lv": "verifier-0001", + "lc": "csrf-0001", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 1, + "a": "acr-0001", + "ct": {}, + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0001", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0001", - "ConsentCSRF": "csrf-0001", - "GrantedScope": [ + "la": null, + "cc": "challenge-0001", + "cs": true, + "cv": "verifier-0001", + "cr": "csrf-0001", + "gs": [ "granted_scope-0001_1" ], - "GrantedAudience": [], - "ConsentRemember": true, - "ConsentRememberFor": 1, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 1, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0001": "0001" }, - "SessionAccessToken": { + "sa": { "session_access_token-0001": "0001" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0002.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0002.json index 61c8b0e1e8f..bc73e23fc21 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0002.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0002.json @@ -1,62 +1,58 @@ { - "ID": "challenge-0002", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0002", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0002_1" ], - "RequestedAudience": [], - "LoginSkip": true, - "Subject": "subject-0002", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0002", + "oc": { "display": "display-0002" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0002", - "SessionID": "", - "LoginVerifier": "verifier-0002", - "LoginCSRF": "csrf-0002", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 2, - "ACR": "acr-0002", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0002", - "Context": {}, - "LoginWasUsed": true, - "LoginError": { + "r": "http://request/0002", + "lv": "verifier-0002", + "lc": "csrf-0002", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 2, + "a": "acr-0002", + "fs": "force_subject_id-0002", + "ct": {}, + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0002", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0002", - "ConsentCSRF": "csrf-0002", - "GrantedScope": [ + "la": null, + "cc": "challenge-0002", + "cs": true, + "cv": "verifier-0002", + "cr": "csrf-0002", + "gs": [ "granted_scope-0002_1" ], - "GrantedAudience": [], - "ConsentRemember": true, - "ConsentRememberFor": 2, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 2, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0002": "0002" }, - "SessionAccessToken": { + "sa": { "session_access_token-0002": "0002" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0003.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0003.json index 3a0023de89d..f04dee37267 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0003.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0003.json @@ -1,62 +1,59 @@ { - "ID": "challenge-0003", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0003", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0003_1" ], - "RequestedAudience": [], - "LoginSkip": true, - "Subject": "subject-0003", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0003", + "oc": { "display": "display-0003" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0003", - "SessionID": "auth_session-0003", - "LoginVerifier": "verifier-0003", - "LoginCSRF": "csrf-0003", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 3, - "ACR": "acr-0003", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0003", - "Context": {}, - "LoginWasUsed": true, - "LoginError": { + "r": "http://request/0003", + "si": "auth_session-0003", + "lv": "verifier-0003", + "lc": "csrf-0003", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 3, + "a": "acr-0003", + "fs": "force_subject_id-0003", + "ct": {}, + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0003", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0003", - "ConsentCSRF": "csrf-0003", - "GrantedScope": [ + "la": null, + "cc": "challenge-0003", + "cs": true, + "cv": "verifier-0003", + "cr": "csrf-0003", + "gs": [ "granted_scope-0003_1" ], - "GrantedAudience": [], - "ConsentRemember": true, - "ConsentRememberFor": 3, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 3, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0003": "0003" }, - "SessionAccessToken": { + "sa": { "session_access_token-0003": "0003" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0004.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0004.json index af2fa42e3af..e3b5d630dd2 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0004.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0004.json @@ -1,66 +1,65 @@ { - "ID": "challenge-0004", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0004", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0004_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0004_1" ], - "LoginSkip": true, - "Subject": "subject-0004", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0004", + "oc": { "display": "display-0004" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0004", - "SessionID": "auth_session-0004", - "LoginVerifier": "verifier-0004", - "LoginCSRF": "csrf-0004", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 4, - "ACR": "acr-0004", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0004", - "Context": {}, - "LoginWasUsed": true, - "LoginError": { + "r": "http://request/0004", + "si": "auth_session-0004", + "lv": "verifier-0004", + "lc": "csrf-0004", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 4, + "a": "acr-0004", + "fs": "force_subject_id-0004", + "ct": {}, + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0004", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0004", - "ConsentCSRF": "csrf-0004", - "GrantedScope": [ + "la": null, + "cc": "challenge-0004", + "cs": true, + "cv": "verifier-0004", + "cr": "csrf-0004", + "gs": [ "granted_scope-0004_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0004_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 4, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 4, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0004": "0004" }, - "SessionAccessToken": { + "sa": { "session_access_token-0004": "0004" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0005.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0005.json index 66e356b42c2..db4e0787291 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0005.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0005.json @@ -1,66 +1,65 @@ { - "ID": "challenge-0005", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0005", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0005_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0005_1" ], - "LoginSkip": true, - "Subject": "subject-0005", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0005", + "oc": { "display": "display-0005" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0005", - "SessionID": "auth_session-0005", - "LoginVerifier": "verifier-0005", - "LoginCSRF": "csrf-0005", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 5, - "ACR": "acr-0005", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0005", - "Context": {}, - "LoginWasUsed": true, - "LoginError": { + "r": "http://request/0005", + "si": "auth_session-0005", + "lv": "verifier-0005", + "lc": "csrf-0005", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 5, + "a": "acr-0005", + "fs": "force_subject_id-0005", + "ct": {}, + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0005", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0005", - "ConsentCSRF": "csrf-0005", - "GrantedScope": [ + "la": null, + "cc": "challenge-0005", + "cs": true, + "cv": "verifier-0005", + "cr": "csrf-0005", + "gs": [ "granted_scope-0005_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0005_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 5, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 5, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0005": "0005" }, - "SessionAccessToken": { + "sa": { "session_access_token-0005": "0005" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0006.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0006.json index c457b1caba8..7a8b9fd8890 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0006.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0006.json @@ -1,66 +1,65 @@ { - "ID": "challenge-0006", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0006", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0006_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0006_1" ], - "LoginSkip": true, - "Subject": "subject-0006", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0006", + "oc": { "display": "display-0006" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0006", - "SessionID": "auth_session-0006", - "LoginVerifier": "verifier-0006", - "LoginCSRF": "csrf-0006", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 6, - "ACR": "acr-0006", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0006", - "Context": {}, - "LoginWasUsed": true, - "LoginError": { + "r": "http://request/0006", + "si": "auth_session-0006", + "lv": "verifier-0006", + "lc": "csrf-0006", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 6, + "a": "acr-0006", + "fs": "force_subject_id-0006", + "ct": {}, + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0006", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0006", - "ConsentCSRF": "csrf-0006", - "GrantedScope": [ + "la": null, + "cc": "challenge-0006", + "cs": true, + "cv": "verifier-0006", + "cr": "csrf-0006", + "gs": [ "granted_scope-0006_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0006_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 6, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 6, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0006": "0006" }, - "SessionAccessToken": { + "sa": { "session_access_token-0006": "0006" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0007.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0007.json index 55f894ef216..b5f6814ea47 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0007.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0007.json @@ -1,66 +1,65 @@ { - "ID": "challenge-0007", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0007", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0007_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0007_1" ], - "LoginSkip": true, - "Subject": "subject-0007", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0007", + "oc": { "display": "display-0007" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0007", - "SessionID": "auth_session-0007", - "LoginVerifier": "verifier-0007", - "LoginCSRF": "csrf-0007", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 7, - "ACR": "acr-0007", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0007", - "Context": {}, - "LoginWasUsed": true, - "LoginError": { + "r": "http://request/0007", + "si": "auth_session-0007", + "lv": "verifier-0007", + "lc": "csrf-0007", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 7, + "a": "acr-0007", + "fs": "force_subject_id-0007", + "ct": {}, + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0007", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0007", - "ConsentCSRF": "csrf-0007", - "GrantedScope": [ + "la": null, + "cc": "challenge-0007", + "cs": true, + "cv": "verifier-0007", + "cr": "csrf-0007", + "gs": [ "granted_scope-0007_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0007_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 7, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 7, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0007": "0007" }, - "SessionAccessToken": { + "sa": { "session_access_token-0007": "0007" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0008.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0008.json index adef19a20fb..e821518707f 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0008.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0008.json @@ -1,68 +1,67 @@ { - "ID": "challenge-0008", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0008", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0008_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0008_1" ], - "LoginSkip": true, - "Subject": "subject-0008", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0008", + "oc": { "display": "display-0008" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0008", - "SessionID": "auth_session-0008", - "LoginVerifier": "verifier-0008", - "LoginCSRF": "csrf-0008", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 8, - "ACR": "acr-0008", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0008", - "Context": { + "r": "http://request/0008", + "si": "auth_session-0008", + "lv": "verifier-0008", + "lc": "csrf-0008", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 8, + "a": "acr-0008", + "fs": "force_subject_id-0008", + "ct": { "context": "0008" }, - "LoginWasUsed": true, - "LoginError": { + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0008", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0008", - "ConsentCSRF": "csrf-0008", - "GrantedScope": [ + "la": null, + "cc": "challenge-0008", + "cs": true, + "cv": "verifier-0008", + "cr": "csrf-0008", + "gs": [ "granted_scope-0008_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0008_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 8, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 8, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0008": "0008" }, - "SessionAccessToken": { + "sa": { "session_access_token-0008": "0008" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0009.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0009.json index 6ee8a6293cd..be51195ca6a 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0009.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0009.json @@ -1,68 +1,67 @@ { - "ID": "challenge-0009", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0009", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0009_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0009_1" ], - "LoginSkip": true, - "Subject": "subject-0009", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0009", + "oc": { "display": "display-0009" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0009", - "SessionID": "auth_session-0009", - "LoginVerifier": "verifier-0009", - "LoginCSRF": "csrf-0009", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 9, - "ACR": "acr-0009", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0009", - "Context": { + "r": "http://request/0009", + "si": "auth_session-0009", + "lv": "verifier-0009", + "lc": "csrf-0009", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 9, + "a": "acr-0009", + "fs": "force_subject_id-0009", + "ct": { "context": "0009" }, - "LoginWasUsed": true, - "LoginError": { + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0009", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0009", - "ConsentCSRF": "csrf-0009", - "GrantedScope": [ + "la": null, + "cc": "challenge-0009", + "cs": true, + "cv": "verifier-0009", + "cr": "csrf-0009", + "gs": [ "granted_scope-0009_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0009_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 9, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 9, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0009": "0009" }, - "SessionAccessToken": { + "sa": { "session_access_token-0009": "0009" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0010.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0010.json index 92acf0ecbf6..353ed37ffe5 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0010.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0010.json @@ -1,68 +1,67 @@ { - "ID": "challenge-0010", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0010", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0010_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0010_1" ], - "LoginSkip": true, - "Subject": "subject-0010", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0010", + "oc": { "display": "display-0010" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0010", - "SessionID": "auth_session-0010", - "LoginVerifier": "verifier-0010", - "LoginCSRF": "csrf-0010", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 10, - "ACR": "acr-0010", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0010", - "Context": { + "r": "http://request/0010", + "si": "auth_session-0010", + "lv": "verifier-0010", + "lc": "csrf-0010", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 10, + "a": "acr-0010", + "fs": "force_subject_id-0010", + "ct": { "context": "0010" }, - "LoginWasUsed": true, - "LoginError": { + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0010", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0010", - "ConsentCSRF": "csrf-0010", - "GrantedScope": [ + "la": null, + "cc": "challenge-0010", + "cs": true, + "cv": "verifier-0010", + "cr": "csrf-0010", + "gs": [ "granted_scope-0010_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0010_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 10, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 10, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0010": "0010" }, - "SessionAccessToken": { + "sa": { "session_access_token-0010": "0010" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0011.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0011.json index 0ed7c88f2aa..ed92bbce294 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0011.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0011.json @@ -1,68 +1,67 @@ { - "ID": "challenge-0011", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0011", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0011_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0011_1" ], - "LoginSkip": true, - "Subject": "subject-0011", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0011", + "oc": { "display": "display-0011" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0011", - "SessionID": "auth_session-0011", - "LoginVerifier": "verifier-0011", - "LoginCSRF": "csrf-0011", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 11, - "ACR": "acr-0011", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0011", - "Context": { + "r": "http://request/0011", + "si": "auth_session-0011", + "lv": "verifier-0011", + "lc": "csrf-0011", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 11, + "a": "acr-0011", + "fs": "force_subject_id-0011", + "ct": { "context": "0011" }, - "LoginWasUsed": true, - "LoginError": { + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0011", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0011", - "ConsentCSRF": "csrf-0011", - "GrantedScope": [ + "la": null, + "cc": "challenge-0011", + "cs": true, + "cv": "verifier-0011", + "cr": "csrf-0011", + "gs": [ "granted_scope-0011_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0011_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 11, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 11, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0011": "0011" }, - "SessionAccessToken": { + "sa": { "session_access_token-0011": "0011" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0012.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0012.json index f8cc3c232f4..6375e369280 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0012.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0012.json @@ -1,68 +1,67 @@ { - "ID": "challenge-0012", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0012", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0012_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0012_1" ], - "LoginSkip": true, - "Subject": "subject-0012", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0012", + "oc": { "display": "display-0012" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0012", - "SessionID": "auth_session-0012", - "LoginVerifier": "verifier-0012", - "LoginCSRF": "csrf-0012", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 12, - "ACR": "acr-0012", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0012", - "Context": { + "r": "http://request/0012", + "si": "auth_session-0012", + "lv": "verifier-0012", + "lc": "csrf-0012", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 12, + "a": "acr-0012", + "fs": "force_subject_id-0012", + "ct": { "context": "0012" }, - "LoginWasUsed": true, - "LoginError": { + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0012", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0012", - "ConsentCSRF": "csrf-0012", - "GrantedScope": [ + "la": null, + "cc": "challenge-0012", + "cs": true, + "cv": "verifier-0012", + "cr": "csrf-0012", + "gs": [ "granted_scope-0012_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0012_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 12, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 12, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0012": "0012" }, - "SessionAccessToken": { + "sa": { "session_access_token-0012": "0012" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0013.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0013.json index b480e3813db..3939f00e959 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0013.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0013.json @@ -1,68 +1,67 @@ { - "ID": "challenge-0013", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0013", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0013_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0013_1" ], - "LoginSkip": true, - "Subject": "subject-0013", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0013", + "oc": { "display": "display-0013" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0013", - "SessionID": "auth_session-0013", - "LoginVerifier": "verifier-0013", - "LoginCSRF": "csrf-0013", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 13, - "ACR": "acr-0013", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0013", - "Context": { + "r": "http://request/0013", + "si": "auth_session-0013", + "lv": "verifier-0013", + "lc": "csrf-0013", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 13, + "a": "acr-0013", + "fs": "force_subject_id-0013", + "ct": { "context": "0013" }, - "LoginWasUsed": true, - "LoginError": { + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0013", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0013", - "ConsentCSRF": "csrf-0013", - "GrantedScope": [ + "la": null, + "cc": "challenge-0013", + "cs": true, + "cv": "verifier-0013", + "cr": "csrf-0013", + "gs": [ "granted_scope-0013_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0013_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 13, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 13, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0013": "0013" }, - "SessionAccessToken": { + "sa": { "session_access_token-0013": "0013" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0014.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0014.json index 44e10ddac7d..38e0af54056 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0014.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0014.json @@ -1,68 +1,67 @@ { - "ID": "challenge-0014", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0014", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0014_1" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0014_1" ], - "LoginSkip": true, - "Subject": "subject-0014", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0014", + "oc": { "display": "display-0014" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0014", - "SessionID": "auth_session-0014", - "LoginVerifier": "verifier-0014", - "LoginCSRF": "csrf-0014", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 14, - "ACR": "acr-0014", - "AMR": [], - "ForceSubjectIdentifier": "force_subject_id-0014", - "Context": { + "r": "http://request/0014", + "si": "auth_session-0014", + "lv": "verifier-0014", + "lc": "csrf-0014", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 14, + "a": "acr-0014", + "fs": "force_subject_id-0014", + "ct": { "context": "0014" }, - "LoginWasUsed": true, - "LoginError": { + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0014", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0014", - "ConsentCSRF": "csrf-0014", - "GrantedScope": [ + "la": null, + "cc": "challenge-0014", + "cs": true, + "cv": "verifier-0014", + "cr": "csrf-0014", + "gs": [ "granted_scope-0014_1" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0014_1" ], - "ConsentRemember": true, - "ConsentRememberFor": 14, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 14, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0014": "0014" }, - "SessionAccessToken": { + "sa": { "session_access_token-0014": "0014" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0015.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0015.json index 67ab4b4ce1d..f55d9d59c0a 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0015.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0015.json @@ -1,75 +1,75 @@ { - "ID": "challenge-0015", - "NID": "00000000-0000-0000-0000-000000000000", - "RequestedScope": [ + "i": "challenge-0015", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ "requested_scope-0015_1", "requested_scope-0015_2" ], - "RequestedAudience": [ + "ra": [ "requested_audience-0015_1", "requested_audience-0015_2" ], - "LoginSkip": true, - "Subject": "subject-0015", - "OpenIDConnectContext": { + "ls": true, + "s": "subject-0015", + "oc": { "display": "display-0015" }, - "Client": null, - "ClientID": "", - "RequestURL": "http://request/0015", - "SessionID": "auth_session-0015", - "LoginVerifier": "verifier-0015", - "LoginCSRF": "csrf-0015", - "LoginInitializedAt": null, - "RequestedAt": "0001-01-01T00:00:00Z", - "State": 128, - "LoginRemember": true, - "LoginRememberFor": 15, - "ACR": "acr-0015", - "AMR": [ + "r": "http://request/0015", + "si": "auth_session-0015", + "lv": "verifier-0015", + "lc": "csrf-0015", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 15, + "a": "acr-0015", + "am": [ "amr-0015-1", "amr-0015-2" ], - "ForceSubjectIdentifier": "force_subject_id-0015", - "Context": { + "fs": "force_subject_id-0015", + "ct": { "context": "0015" }, - "LoginWasUsed": true, - "LoginError": { + "lu": true, + "le": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "LoginAuthenticatedAt": null, - "ConsentChallengeID": "challenge-0015", - "ConsentSkip": true, - "ConsentVerifier": "verifier-0015", - "ConsentCSRF": "csrf-0015", - "GrantedScope": [ + "la": null, + "cc": "challenge-0015", + "cs": true, + "cv": "verifier-0015", + "cr": "csrf-0015", + "gs": [ "granted_scope-0015_1", "granted_scope-0015_2" ], - "GrantedAudience": [ + "ga": [ "granted_audience-0015_1", "granted_audience-0015_2" ], - "ConsentRemember": true, - "ConsentRememberFor": 15, - "ConsentHandledAt": null, - "ConsentWasHandled": true, - "ConsentError": { + "ce": true, + "cf": 15, + "ch": null, + "cw": true, + "cx": { "error": "", "error_description": "", "error_hint": "", "status_code": 0, - "error_debug": "" + "error_debug": "", + "valid": false }, - "SessionIDToken": { + "st": { "session_id_token-0015": "0015" }, - "SessionAccessToken": { + "sa": { "session_access_token-0015": "0015" } } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0016.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0016.json new file mode 100644 index 00000000000..be6ca67a2d1 --- /dev/null +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0016.json @@ -0,0 +1,76 @@ +{ + "i": "challenge-0016", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ + "requested_scope-0016_1", + "requested_scope-0016_2" + ], + "ra": [ + "requested_audience-0016_1", + "requested_audience-0016_2" + ], + "ls": true, + "s": "subject-0016", + "oc": { + "display": "display-0016" + }, + "r": "http://request/0016", + "si": "auth_session-0016", + "lv": "verifier-0016", + "lc": "csrf-0016", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 15, + "ll": true, + "a": "acr-0016", + "am": [ + "amr-0016-1", + "amr-0016-2" + ], + "fs": "force_subject_id-0016", + "ct": { + "context": "0016" + }, + "lu": true, + "le": { + "error": "", + "error_description": "", + "error_hint": "", + "status_code": 0, + "error_debug": "", + "valid": false + }, + "la": null, + "cc": "challenge-0016", + "cs": true, + "cv": "verifier-0016", + "cr": "csrf-0016", + "gs": [ + "granted_scope-0016_1", + "granted_scope-0016_2" + ], + "ga": [ + "granted_audience-0016_1", + "granted_audience-0016_2" + ], + "ce": true, + "cf": 15, + "ch": null, + "cw": true, + "cx": { + "error": "", + "error_description": "", + "error_hint": "", + "status_code": 0, + "error_debug": "", + "valid": false + }, + "st": { + "session_id_token-0016": "0016" + }, + "sa": { + "session_access_token-0016": "0016" + } +} diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0017.json b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0017.json new file mode 100644 index 00000000000..e8f9235696b --- /dev/null +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_flow/challenge-0017.json @@ -0,0 +1,77 @@ +{ + "i": "challenge-0017", + "n": "00000000-0000-0000-0000-000000000000", + "rs": [ + "requested_scope-0016_1", + "requested_scope-0016_2" + ], + "ra": [ + "requested_audience-0016_1", + "requested_audience-0016_2" + ], + "ls": true, + "s": "subject-0017", + "oc": { + "display": "display-0017" + }, + "r": "http://request/0017", + "si": "auth_session-0017", + "is": "identity_provider_session_id-0017", + "lv": "verifier-0017", + "lc": "csrf-0017", + "li": null, + "ia": "0001-01-01T00:00:00Z", + "q": 128, + "lr": true, + "lf": 15, + "ll": true, + "a": "acr-0017", + "am": [ + "amr-0017-1", + "amr-0017-2" + ], + "fs": "force_subject_id-0017", + "ct": { + "context": "0017" + }, + "lu": true, + "le": { + "error": "", + "error_description": "", + "error_hint": "", + "status_code": 0, + "error_debug": "", + "valid": false + }, + "la": null, + "cc": "challenge-0017", + "cs": true, + "cv": "verifier-0017", + "cr": "csrf-0017", + "gs": [ + "granted_scope-0016_1", + "granted_scope-0016_2" + ], + "ga": [ + "granted_audience-0016_1", + "granted_audience-0016_2" + ], + "ce": true, + "cf": 15, + "ch": null, + "cw": true, + "cx": { + "error": "", + "error_description": "", + "error_hint": "", + "status_code": 0, + "error_debug": "", + "valid": false + }, + "st": { + "session_id_token-0017": "0017" + }, + "sa": { + "session_access_token-0017": "0017" + } +} diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0009.json b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0009.json index 669ab25c23d..7681dc70e21 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0009.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0009.json @@ -4,5 +4,7 @@ "sid": "session_id-0009", "request_url": "http://request/0009", "rp_initiated": true, + "expires_at": null, + "requested_at": null, "client": null } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0010.json b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0010.json index 783139fc5a7..d1cb5f6aa61 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0010.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0010.json @@ -4,5 +4,7 @@ "sid": "session_id-0010", "request_url": "http://request/0010", "rp_initiated": true, + "expires_at": null, + "requested_at": null, "client": null } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0011.json b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0011.json index 2650d028e15..3c81d38cb47 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0011.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0011.json @@ -4,5 +4,7 @@ "sid": "session_id-0011", "request_url": "http://request/0011", "rp_initiated": true, + "expires_at": null, + "requested_at": null, "client": null } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0012.json b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0012.json index 8454181a885..67c839b88a0 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0012.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0012.json @@ -4,5 +4,7 @@ "sid": "session_id-0012", "request_url": "http://request/0012", "rp_initiated": true, + "expires_at": null, + "requested_at": null, "client": null } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0013.json b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0013.json index fdb8f04be53..f8b84db4b56 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0013.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0013.json @@ -4,5 +4,7 @@ "sid": "session_id-0013", "request_url": "http://request/0013", "rp_initiated": true, + "expires_at": null, + "requested_at": null, "client": null } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0014.json b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0014.json index 1f6e5ef98e9..c5194805b6a 100644 --- a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0014.json +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-0014.json @@ -4,5 +4,7 @@ "sid": "session_id-0014", "request_url": "http://request/0014", "rp_initiated": true, + "expires_at": null, + "requested_at": null, "client": null } diff --git a/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-20240916105610000001.json b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-20240916105610000001.json new file mode 100644 index 00000000000..8b1841c9be6 --- /dev/null +++ b/persistence/sql/migratest/fixtures/hydra_oauth2_logout_request/challenge-20240916105610000001.json @@ -0,0 +1,10 @@ +{ + "challenge": "challenge-20240916105610000001", + "subject": "subject-0014", + "sid": "session_id-0014", + "request_url": "http://request/0014", + "rp_initiated": true, + "expires_at": "2022-02-15T22:20:20Z", + "requested_at": "2022-02-15T22:20:20Z", + "client": null +} diff --git a/persistence/sql/migratest/migration_test.go b/persistence/sql/migratest/migration_test.go index 6ca2cf1d543..8564cfab969 100644 --- a/persistence/sql/migratest/migration_test.go +++ b/persistence/sql/migratest/migration_test.go @@ -5,6 +5,7 @@ package migratest import ( "context" + stdsql "database/sql" "encoding/json" "fmt" "os" @@ -12,14 +13,14 @@ import ( "testing" "time" - "github.com/ory/hydra/internal" + "github.com/ory/hydra/v2/internal" "github.com/ory/x/contextx" "github.com/bradleyjkemp/cupaloy/v2" "github.com/fatih/structs" "github.com/gofrs/uuid" - "github.com/instana/testify/assert" "github.com/sirupsen/logrus" + "github.com/stretchr/testify/assert" "github.com/gobuffalo/pop/v6" @@ -27,20 +28,20 @@ import ( "github.com/ory/x/networkx" "github.com/ory/x/sqlxx" - "github.com/ory/hydra/flow" - testhelpersuuid "github.com/ory/hydra/internal/testhelpers/uuid" - "github.com/ory/hydra/persistence/sql" + "github.com/ory/hydra/v2/flow" + testhelpersuuid "github.com/ory/hydra/v2/internal/testhelpers/uuid" + "github.com/ory/hydra/v2/persistence/sql" "github.com/ory/x/popx" "github.com/ory/x/sqlcon/dockertest" "github.com/stretchr/testify/require" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/x" ) func snapshotFor(paths ...string) *cupaloy.Config { @@ -60,7 +61,6 @@ func CompareWithFixture(t *testing.T, actual interface{}, prefix string, id stri } func TestMigrations(t *testing.T) { - //pop.Debug = true connections := make(map[string]*pop.Connection, 1) if testing.Short() { @@ -88,22 +88,13 @@ func TestMigrations(t *testing.T) { return func(t *testing.T) { ctx := context.Background() x.CleanSQLPop(t, c) - url := c.URL() - - // workaround for https://github.com/gobuffalo/pop/issues/538 - if db == "mysql" { - url = "mysql://" + url - } else if db == "sqlite" { - url = "sqlite://" + url - } l := logrusx.New("", "", logrusx.ForceLevel(logrus.DebugLevel)) tm, err := popx.NewMigrationBox( - os.DirFS("../migrations"), + sql.Migrations, popx.NewMigrator(c, l, nil, 1*time.Minute), popx.WithTestdata(t, os.DirFS("./testdata"))) - //tm := popx.NewTestMigrator(t, c, os.DirFS("../migrations"), os.DirFS("./testdata"), l) require.NoError(t, err) require.NoError(t, tm.Up(ctx)) @@ -111,17 +102,17 @@ func TestMigrations(t *testing.T) { t.Run("case=hydra_client", func(t *testing.T) { cs := []client.Client{} require.NoError(t, c.All(&cs)) - require.Equal(t, 18, len(cs)) + require.Equal(t, 19, len(cs)) for _, c := range cs { require.False(t, c.CreatedAt.IsZero()) require.False(t, c.UpdatedAt.IsZero()) c.CreatedAt = time.Time{} // Some CreatedAt and UpdatedAt values are generated during migrations so we zero them in the fixtures c.UpdatedAt = time.Time{} - testhelpersuuid.AssertUUID(t, &c.ID) - testhelpersuuid.AssertUUID(t, &c.NID) - c.ID = uuid.Nil + testhelpersuuid.AssertUUID(t, c.NID) + testhelpersuuid.AssertUUID(t, c.PK.String) c.NID = uuid.Nil - CompareWithFixture(t, structs.Map(c), "hydra_client", c.LegacyClientID) + c.PK = stdsql.NullString{} + CompareWithFixture(t, structs.Map(c), "hydra_client", c.ID) } }) @@ -130,8 +121,8 @@ func TestMigrations(t *testing.T) { require.NoError(t, c.All(&js)) require.Equal(t, 7, len(js)) for _, j := range js { - testhelpersuuid.AssertUUID(t, &j.ID) - testhelpersuuid.AssertUUID(t, &j.NID) + testhelpersuuid.AssertUUID(t, j.ID) + testhelpersuuid.AssertUUID(t, j.NID) j.ID = uuid.Nil // Some IDs are generated at migration time so we zero them in the fixtures j.NID = uuid.Nil require.False(t, j.CreatedAt.IsZero()) @@ -142,7 +133,7 @@ func TestMigrations(t *testing.T) { flows := []flow.Flow{} require.NoError(t, c.All(&flows)) - require.Equal(t, 15, len(flows)) + require.Equal(t, 17, len(flows)) t.Run("case=hydra_oauth2_flow", func(t *testing.T) { for _, f := range flows { @@ -152,12 +143,12 @@ func TestMigrations(t *testing.T) { }) t.Run("case=hydra_oauth2_authentication_session", func(t *testing.T) { - ss := []consent.LoginSession{} - c.All(&ss) - require.Equal(t, 15, len(ss)) + ss := []flow.LoginSession{} + require.NoError(t, c.All(&ss)) + require.Equal(t, 17, len(ss)) for _, s := range ss { - testhelpersuuid.AssertUUID(t, &s.NID) + testhelpersuuid.AssertUUID(t, s.NID) s.NID = uuid.Nil s.AuthenticatedAt = sqlxx.NullTime(time.Time{}) CompareWithFixture(t, s, "hydra_oauth2_authentication_session", s.ID) @@ -166,23 +157,23 @@ func TestMigrations(t *testing.T) { t.Run("case=hydra_oauth2_obfuscated_authentication_session", func(t *testing.T) { ss := []consent.ForcedObfuscatedLoginSession{} - c.All(&ss) + require.NoError(t, c.All(&ss)) require.Equal(t, 13, len(ss)) for _, s := range ss { - testhelpersuuid.AssertUUID(t, &s.NID) + testhelpersuuid.AssertUUID(t, s.NID) s.NID = uuid.Nil CompareWithFixture(t, s, "hydra_oauth2_obfuscated_authentication_session", fmt.Sprintf("%s_%s", s.Subject, s.ClientID)) } }) t.Run("case=hydra_oauth2_logout_request", func(t *testing.T) { - lrs := []consent.LogoutRequest{} - c.All(&lrs) - require.Equal(t, 6, len(lrs)) + lrs := []flow.LogoutRequest{} + require.NoError(t, c.All(&lrs)) + require.Equal(t, 7, len(lrs)) for _, s := range lrs { - testhelpersuuid.AssertUUID(t, &s.NID) + testhelpersuuid.AssertUUID(t, s.NID) s.NID = uuid.Nil s.Client = nil CompareWithFixture(t, s, "hydra_oauth2_logout_request", s.ID) @@ -191,10 +182,10 @@ func TestMigrations(t *testing.T) { t.Run("case=hydra_oauth2_jti_blacklist", func(t *testing.T) { bjtis := []oauth2.BlacklistedJTI{} - c.All(&bjtis) + require.NoError(t, c.All(&bjtis)) require.Equal(t, 1, len(bjtis)) for _, bjti := range bjtis { - testhelpersuuid.AssertUUID(t, &bjti.NID) + testhelpersuuid.AssertUUID(t, bjti.NID) bjti.NID = uuid.Nil bjti.Expiry = time.Time{} CompareWithFixture(t, bjti, "hydra_oauth2_jti_blacklist", bjti.ID) @@ -203,11 +194,11 @@ func TestMigrations(t *testing.T) { t.Run("case=hydra_oauth2_access", func(t *testing.T) { as := []sql.OAuth2RequestSQL{} - c.RawQuery("SELECT * FROM hydra_oauth2_access").All(&as) + require.NoError(t, c.RawQuery("SELECT * FROM hydra_oauth2_access").All(&as)) require.Equal(t, 13, len(as)) for _, a := range as { - testhelpersuuid.AssertUUID(t, &a.NID) + testhelpersuuid.AssertUUID(t, a.NID) a.NID = uuid.Nil require.False(t, a.RequestedAt.IsZero()) a.RequestedAt = time.Time{} @@ -219,11 +210,11 @@ func TestMigrations(t *testing.T) { t.Run("case=hydra_oauth2_refresh", func(t *testing.T) { rs := []sql.OAuth2RequestSQL{} - c.RawQuery("SELECT * FROM hydra_oauth2_refresh").All(&rs) + require.NoError(t, c.RawQuery(`SELECT signature, nid, request_id, challenge_id, requested_at, client_id, scope, granted_scope, requested_audience, granted_audience, form_data, subject, active, session_data, expires_at FROM hydra_oauth2_refresh`).All(&rs)) require.Equal(t, 13, len(rs)) for _, r := range rs { - testhelpersuuid.AssertUUID(t, &r.NID) + testhelpersuuid.AssertUUID(t, r.NID) r.NID = uuid.Nil require.False(t, r.RequestedAt.IsZero()) r.RequestedAt = time.Time{} @@ -235,11 +226,11 @@ func TestMigrations(t *testing.T) { t.Run("case=hydra_oauth2_code", func(t *testing.T) { cs := []sql.OAuth2RequestSQL{} - c.RawQuery("SELECT * FROM hydra_oauth2_code").All(&cs) + require.NoError(t, c.RawQuery("SELECT * FROM hydra_oauth2_code").All(&cs)) require.Equal(t, 13, len(cs)) for _, c := range cs { - testhelpersuuid.AssertUUID(t, &c.NID) + testhelpersuuid.AssertUUID(t, c.NID) c.NID = uuid.Nil require.False(t, c.RequestedAt.IsZero()) c.RequestedAt = time.Time{} @@ -251,11 +242,11 @@ func TestMigrations(t *testing.T) { t.Run("case=hydra_oauth2_oidc", func(t *testing.T) { os := []sql.OAuth2RequestSQL{} - c.RawQuery("SELECT * FROM hydra_oauth2_oidc").All(&os) + require.NoError(t, c.RawQuery("SELECT * FROM hydra_oauth2_oidc").All(&os)) require.Equal(t, 13, len(os)) for _, o := range os { - testhelpersuuid.AssertUUID(t, &o.NID) + testhelpersuuid.AssertUUID(t, o.NID) o.NID = uuid.Nil require.False(t, o.RequestedAt.IsZero()) o.RequestedAt = time.Time{} @@ -267,11 +258,11 @@ func TestMigrations(t *testing.T) { t.Run("case=hydra_oauth2_pkce", func(t *testing.T) { ps := []sql.OAuth2RequestSQL{} - c.RawQuery("SELECT * FROM hydra_oauth2_pkce").All(&ps) + require.NoError(t, c.RawQuery("SELECT * FROM hydra_oauth2_pkce").All(&ps)) require.Equal(t, 11, len(ps)) for _, p := range ps { - testhelpersuuid.AssertUUID(t, &p.NID) + testhelpersuuid.AssertUUID(t, p.NID) p.NID = uuid.Nil require.False(t, p.RequestedAt.IsZero()) p.RequestedAt = time.Time{} @@ -283,10 +274,10 @@ func TestMigrations(t *testing.T) { t.Run("case=networks", func(t *testing.T) { ns := []networkx.Network{} - c.RawQuery("SELECT * FROM networks").All(&ns) + require.NoError(t, c.RawQuery("SELECT * FROM networks").All(&ns)) require.Equal(t, 1, len(ns)) for _, n := range ns { - testhelpersuuid.AssertUUID(t, &n.ID) + testhelpersuuid.AssertUUID(t, n.ID) require.NotZero(t, n.CreatedAt) require.NotZero(t, n.UpdatedAt) } diff --git a/persistence/sql/migratest/testdata/20230313112801_testdata.sql b/persistence/sql/migratest/testdata/20230313112801_testdata.sql new file mode 100644 index 00000000000..f41a0eecab6 --- /dev/null +++ b/persistence/sql/migratest/testdata/20230313112801_testdata.sql @@ -0,0 +1,93 @@ +INSERT INTO hydra_oauth2_authentication_session ( + id, + nid, + authenticated_at, + subject, + remember +) VALUES ( + 'auth_session-0016', + (SELECT id FROM networks LIMIT 1), + CURRENT_TIMESTAMP, + 'subject-0016', + true +); + +INSERT INTO hydra_oauth2_flow ( + login_challenge, + nid, + requested_scope, + login_verifier, + login_csrf, + subject, + request_url, + login_skip, + client_id, + requested_at, + oidc_context, + login_session_id, + requested_at_audience, + login_initialized_at, + state, + login_remember, + login_remember_for, + login_error, + acr, + login_authenticated_at, + login_was_used, + forced_subject_identifier, + context, + amr, + consent_challenge_id, + consent_verifier, + consent_skip, + consent_csrf, + granted_scope, + consent_remember, + consent_remember_for, + consent_error, + session_access_token, + session_id_token, + consent_was_used, + granted_at_audience, + consent_handled_at, + login_extend_session_lifespan +) VALUES ( + 'challenge-0016', + (SELECT id FROM networks LIMIT 1), + '["requested_scope-0016_1","requested_scope-0016_2"]', + 'verifier-0016', + 'csrf-0016', + 'subject-0016', + 'http://request/0016', + true, + 'client-21', + CURRENT_TIMESTAMP, + '{"display": "display-0016"}', + 'auth_session-0016', + '["requested_audience-0016_1","requested_audience-0016_2"]', + CURRENT_TIMESTAMP, + 128, + true, + 15, + '{}', + 'acr-0016', + CURRENT_TIMESTAMP, + true, + 'force_subject_id-0016', + '{"context": "0016"}', + '["amr-0016-1","amr-0016-2"]', + 'challenge-0016', + 'verifier-0016', + true, + 'csrf-0016', + '["granted_scope-0016_1","granted_scope-0016_2"]', + true, + 15, + '{}', + '{"session_access_token-0016": "0016"}', + '{"session_id_token-0016": "0016"}', + true, + '["granted_audience-0016_1","granted_audience-0016_2"]', + CURRENT_TIMESTAMP, + true +); diff --git a/persistence/sql/migratest/testdata/20230809122501_testdata.sql b/persistence/sql/migratest/testdata/20230809122501_testdata.sql new file mode 100644 index 00000000000..472700be3db --- /dev/null +++ b/persistence/sql/migratest/testdata/20230809122501_testdata.sql @@ -0,0 +1,97 @@ +INSERT INTO hydra_oauth2_authentication_session ( + id, + nid, + authenticated_at, + subject, + remember, + identity_provider_session_id +) VALUES ( + 'auth_session-0017', + (SELECT id FROM networks LIMIT 1), + CURRENT_TIMESTAMP, + 'subject-0017', + true, + 'identity_provider_session_id-0017' +); + +INSERT INTO hydra_oauth2_flow ( + login_challenge, + nid, + requested_scope, + login_verifier, + login_csrf, + subject, + request_url, + login_skip, + client_id, + requested_at, + oidc_context, + login_session_id, + requested_at_audience, + login_initialized_at, + state, + login_remember, + login_remember_for, + login_error, + acr, + login_authenticated_at, + login_was_used, + forced_subject_identifier, + context, + amr, + consent_challenge_id, + consent_verifier, + consent_skip, + consent_csrf, + granted_scope, + consent_remember, + consent_remember_for, + consent_error, + session_access_token, + session_id_token, + consent_was_used, + granted_at_audience, + consent_handled_at, + login_extend_session_lifespan, + identity_provider_session_id +) VALUES ( + 'challenge-0017', + (SELECT id FROM networks LIMIT 1), + '["requested_scope-0016_1","requested_scope-0016_2"]', + 'verifier-0017', + 'csrf-0017', + 'subject-0017', + 'http://request/0017', + true, + 'client-21', + CURRENT_TIMESTAMP, + '{"display": "display-0017"}', + 'auth_session-0017', + '["requested_audience-0016_1","requested_audience-0016_2"]', + CURRENT_TIMESTAMP, + 128, + true, + 15, + '{}', + 'acr-0017', + CURRENT_TIMESTAMP, + true, + 'force_subject_id-0017', + '{"context": "0017"}', + '["amr-0017-1","amr-0017-2"]', + 'challenge-0017', + 'verifier-0017', + true, + 'csrf-0017', + '["granted_scope-0016_1","granted_scope-0016_2"]', + true, + 15, + '{}', + '{"session_access_token-0017": "0017"}', + '{"session_id_token-0017": "0017"}', + true, + '["granted_audience-0016_1","granted_audience-0016_2"]', + CURRENT_TIMESTAMP, + true, + 'identity_provider_session_id-0017' +); diff --git a/persistence/sql/migratest/testdata/20240129174410_testdata.sql b/persistence/sql/migratest/testdata/20240129174410_testdata.sql new file mode 100644 index 00000000000..b71277553ac --- /dev/null +++ b/persistence/sql/migratest/testdata/20240129174410_testdata.sql @@ -0,0 +1,46 @@ +INSERT INTO hydra_client (id, + nid, + client_name, + client_secret, + redirect_uris, + grant_types, + response_types, + scope, + owner, + policy_uri, + tos_uri, + client_uri, + logo_uri, + contacts, + client_secret_expires_at, + sector_identifier_uri, + jwks, + jwks_uri, + request_uris, + token_endpoint_auth_method, + request_object_signing_alg, + userinfo_signed_response_alg, + subject_type, + allowed_cors_origins, + pk_deprecated, + audience, + created_at, + updated_at, + frontchannel_logout_uri, + frontchannel_logout_session_required, + post_logout_redirect_uris, + backchannel_logout_uri, + backchannel_logout_session_required, + metadata, + token_endpoint_auth_signing_alg, + pk, + registration_access_token_signature, + skip_consent, + skip_logout_consent) +VALUES ('client-22', + (SELECT id FROM networks LIMIT 1), 'Client 22', 'secret-22', '["http://redirect/22_1","http://redirect/22_2"]', '["grant-22_1","grant-22_2"]', + '["response-22_1","response-22_2"]', 'scope-22', 'owner-22', 'http://policy/22', 'http://tos/22', 'http://client/22', 'http://logo/22', + '["contact-22_1","contact-22_2"]', 0, 'http://sector_id/22', '', 'http://jwks/22', '["http://request/22_1","http://request/22_2"]', + 'token_auth-22', 'r_alg-22', 'u_alg-22', 'subject-22', '["http://cors/22_1","http://cors/22_2"]', 0, '["autdience-22_1","autdience-22_2"]', + '2022-02-15 22:20:23.004598', '2022-02-15 22:20:23.004598', 'http://front_logout/22', true, '["http://post_redirect/22_1","http://post_redirect/22_2"]', + 'http://back_logout/22', true, '{"migration": "22"}', '', '2ca3b77b-ee29-4b63-aa07-6384e6c650fb', '', TRUE, TRUE ); diff --git a/persistence/sql/migratest/testdata/20240916105610_testdata.sql b/persistence/sql/migratest/testdata/20240916105610_testdata.sql new file mode 100644 index 00000000000..160017814f7 --- /dev/null +++ b/persistence/sql/migratest/testdata/20240916105610_testdata.sql @@ -0,0 +1,4 @@ +INSERT INTO hydra_oauth2_logout_request (challenge, verifier, subject, sid, client_id, nid, request_url, redir_url, + was_used, accepted, rejected, rp_initiated, expires_at, requested_at) +VALUES ('challenge-20240916105610000001', 'verifier-20240916105610000001', 'subject-0014', 'session_id-0014', 'client-0014', + (SELECT id FROM networks LIMIT 1), 'http://request/0014', 'http://post_logout/0014', true, true, false, true, '2022-02-15 22:20:20', '2022-02-15 22:20:20'); diff --git a/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.cockroach.up.sql b/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.cockroach.up.sql index 93a36be3b9b..c4be8178d7b 100644 --- a/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.cockroach.up.sql +++ b/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.cockroach.up.sql @@ -98,3 +98,27 @@ ON hydra_oauth2_authentication_request.challenge = hydra_oauth2_consent_request. LEFT JOIN hydra_oauth2_consent_request_handled ON hydra_oauth2_consent_request.challenge = hydra_oauth2_consent_request_handled.challenge; +UPDATE hydra_oauth2_access AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_code AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_oidc AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_refresh AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_pkce AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); diff --git a/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.mysql.up.sql b/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.mysql.up.sql index 4d9d58178b1..c1de175de2d 100644 --- a/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.mysql.up.sql +++ b/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.mysql.up.sql @@ -97,3 +97,28 @@ LEFT JOIN hydra_oauth2_consent_request ON hydra_oauth2_authentication_request.challenge = hydra_oauth2_consent_request.login_challenge LEFT JOIN hydra_oauth2_consent_request_handled ON hydra_oauth2_consent_request.challenge = hydra_oauth2_consent_request_handled.challenge; + +UPDATE hydra_oauth2_access AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_code AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_oidc AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_refresh AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_pkce AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); diff --git a/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.postgres.up.sql b/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.postgres.up.sql index 93a36be3b9b..c4be8178d7b 100644 --- a/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.postgres.up.sql +++ b/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.postgres.up.sql @@ -98,3 +98,27 @@ ON hydra_oauth2_authentication_request.challenge = hydra_oauth2_consent_request. LEFT JOIN hydra_oauth2_consent_request_handled ON hydra_oauth2_consent_request.challenge = hydra_oauth2_consent_request_handled.challenge; +UPDATE hydra_oauth2_access AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_code AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_oidc AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_refresh AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_pkce AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); diff --git a/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.sqlite.up.sql b/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.sqlite.up.sql index 0580edef09d..a6ef43cb24c 100644 --- a/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.sqlite.up.sql +++ b/persistence/sql/migrations/20211019000001000001_merge_authentication_request_tables.sqlite.up.sql @@ -98,3 +98,27 @@ ON hydra_oauth2_authentication_request.challenge = hydra_oauth2_consent_request. LEFT JOIN hydra_oauth2_consent_request_handled ON hydra_oauth2_consent_request.challenge = hydra_oauth2_consent_request_handled.challenge; +UPDATE hydra_oauth2_access AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_code AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_oidc AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_refresh AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); + +UPDATE hydra_oauth2_pkce AS t1 +SET challenge_id = NULL +WHERE challenge_id IS NOT NULL + AND NOT exists(SELECT NULL FROM hydra_oauth2_flow t2 WHERE t1.challenge_id = t2.consent_challenge_id); diff --git a/persistence/sql/migrations/20230220000000000000_access_token_strategy.down.sql b/persistence/sql/migrations/20230220000000000000_access_token_strategy.down.sql new file mode 100644 index 00000000000..7ecd6c1cd1d --- /dev/null +++ b/persistence/sql/migrations/20230220000000000000_access_token_strategy.down.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_client DROP COLUMN access_token_strategy; diff --git a/persistence/sql/migrations/20230220000000000000_access_token_strategy.up.sql b/persistence/sql/migrations/20230220000000000000_access_token_strategy.up.sql new file mode 100644 index 00000000000..711c467f8b2 --- /dev/null +++ b/persistence/sql/migrations/20230220000000000000_access_token_strategy.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_client ADD COLUMN access_token_strategy VARCHAR(10) NOT NULL DEFAULT ''; diff --git a/persistence/sql/migrations/20230228000010000001_client_add_skip_consent_column.down.sql b/persistence/sql/migrations/20230228000010000001_client_add_skip_consent_column.down.sql new file mode 100644 index 00000000000..950efade3b7 --- /dev/null +++ b/persistence/sql/migrations/20230228000010000001_client_add_skip_consent_column.down.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_client DROP COLUMN skip_consent; diff --git a/persistence/sql/migrations/20230228000010000001_client_add_skip_consent_column.up.sql b/persistence/sql/migrations/20230228000010000001_client_add_skip_consent_column.up.sql new file mode 100644 index 00000000000..cfa0efe463f --- /dev/null +++ b/persistence/sql/migrations/20230228000010000001_client_add_skip_consent_column.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_client ADD COLUMN skip_consent BOOLEAN NOT NULL DEFAULT false; diff --git a/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.cockroach.down.sql b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.cockroach.down.sql new file mode 100644 index 00000000000..9d5c9db74db --- /dev/null +++ b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.cockroach.down.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_flow DROP COLUMN login_extend_session_lifespan; diff --git a/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.cockroach.up.sql b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.cockroach.up.sql new file mode 100644 index 00000000000..f19f41d875c --- /dev/null +++ b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.cockroach.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_flow ADD login_extend_session_lifespan BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.mysql.down.sql b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.mysql.down.sql new file mode 100644 index 00000000000..9d5c9db74db --- /dev/null +++ b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.mysql.down.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_flow DROP COLUMN login_extend_session_lifespan; diff --git a/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.mysql.up.sql b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.mysql.up.sql new file mode 100644 index 00000000000..91c0f8716ed --- /dev/null +++ b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.mysql.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_flow ADD COLUMN login_extend_session_lifespan BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.postgres.down.sql b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.postgres.down.sql new file mode 100644 index 00000000000..9d5c9db74db --- /dev/null +++ b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.postgres.down.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_flow DROP COLUMN login_extend_session_lifespan; diff --git a/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.postgres.up.sql b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.postgres.up.sql new file mode 100644 index 00000000000..f19f41d875c --- /dev/null +++ b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.postgres.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_flow ADD login_extend_session_lifespan BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.sqlite.down.sql b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.sqlite.down.sql new file mode 100644 index 00000000000..9d5c9db74db --- /dev/null +++ b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.sqlite.down.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_flow DROP COLUMN login_extend_session_lifespan; diff --git a/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.sqlite.up.sql b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.sqlite.up.sql new file mode 100644 index 00000000000..f19f41d875c --- /dev/null +++ b/persistence/sql/migrations/20230313112801000001_support_extend_session_lifespan.sqlite.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_flow ADD login_extend_session_lifespan BOOLEAN NOT NULL DEFAULT FALSE; diff --git a/persistence/sql/migrations/20230512112801000001_refresh_requested_at_index.down.sql b/persistence/sql/migrations/20230512112801000001_refresh_requested_at_index.down.sql new file mode 100644 index 00000000000..cee58284abb --- /dev/null +++ b/persistence/sql/migrations/20230512112801000001_refresh_requested_at_index.down.sql @@ -0,0 +1 @@ +DROP INDEX hydra_oauth2_refresh_requested_at_idx; diff --git a/persistence/sql/migrations/20230512112801000001_refresh_requested_at_index.up.sql b/persistence/sql/migrations/20230512112801000001_refresh_requested_at_index.up.sql new file mode 100644 index 00000000000..e0d1e273ed9 --- /dev/null +++ b/persistence/sql/migrations/20230512112801000001_refresh_requested_at_index.up.sql @@ -0,0 +1 @@ +CREATE INDEX hydra_oauth2_refresh_requested_at_idx ON hydra_oauth2_refresh (nid, requested_at); diff --git a/persistence/sql/migrations/20230606112801000001_remove_flow_indices.down.sql b/persistence/sql/migrations/20230606112801000001_remove_flow_indices.down.sql new file mode 100644 index 00000000000..a391920ba8f --- /dev/null +++ b/persistence/sql/migrations/20230606112801000001_remove_flow_indices.down.sql @@ -0,0 +1,12 @@ +CREATE UNIQUE INDEX hydra_oauth2_flow_login_verifier_idx ON hydra_oauth2_flow (login_verifier); +CREATE UNIQUE INDEX hydra_oauth2_flow_consent_verifier_idx ON hydra_oauth2_flow (consent_verifier); + +CREATE INDEX hydra_oauth2_flow_multi_query_idx + ON hydra_oauth2_flow + ( + consent_error ASC, state ASC, subject ASC, + client_id ASC, consent_skip ASC, consent_remember + ASC, nid ASC + ); + +DROP INDEX hydra_oauth2_flow_previous_consents_idx; diff --git a/persistence/sql/migrations/20230606112801000001_remove_flow_indices.mysql.down.sql b/persistence/sql/migrations/20230606112801000001_remove_flow_indices.mysql.down.sql new file mode 100644 index 00000000000..16d4e470dae --- /dev/null +++ b/persistence/sql/migrations/20230606112801000001_remove_flow_indices.mysql.down.sql @@ -0,0 +1,12 @@ +CREATE UNIQUE INDEX hydra_oauth2_flow_login_verifier_idx ON hydra_oauth2_flow (login_verifier); +CREATE UNIQUE INDEX hydra_oauth2_flow_consent_verifier_idx ON hydra_oauth2_flow (consent_verifier); + +CREATE INDEX hydra_oauth2_flow_multi_query_idx + ON hydra_oauth2_flow + ( + consent_error(2) ASC, state ASC, subject ASC, + client_id ASC, consent_skip ASC, consent_remember + ASC, nid ASC + ); + +DROP INDEX hydra_oauth2_flow_previous_consents_idx ON hydra_oauth2_flow; diff --git a/persistence/sql/migrations/20230606112801000001_remove_flow_indices.mysql.up.sql b/persistence/sql/migrations/20230606112801000001_remove_flow_indices.mysql.up.sql new file mode 100644 index 00000000000..d7f86b61f94 --- /dev/null +++ b/persistence/sql/migrations/20230606112801000001_remove_flow_indices.mysql.up.sql @@ -0,0 +1,6 @@ +DROP INDEX hydra_oauth2_flow_login_verifier_idx ON hydra_oauth2_flow; +DROP INDEX hydra_oauth2_flow_consent_verifier_idx ON hydra_oauth2_flow; +DROP INDEX hydra_oauth2_flow_multi_query_idx ON hydra_oauth2_flow; + +CREATE INDEX hydra_oauth2_flow_previous_consents_idx + ON hydra_oauth2_flow (subject, client_id, nid, consent_skip, consent_error(2), consent_remember); diff --git a/persistence/sql/migrations/20230606112801000001_remove_flow_indices.up.sql b/persistence/sql/migrations/20230606112801000001_remove_flow_indices.up.sql new file mode 100644 index 00000000000..d522d3482f5 --- /dev/null +++ b/persistence/sql/migrations/20230606112801000001_remove_flow_indices.up.sql @@ -0,0 +1,6 @@ +DROP INDEX hydra_oauth2_flow_login_verifier_idx; +DROP INDEX hydra_oauth2_flow_consent_verifier_idx; +DROP INDEX hydra_oauth2_flow_multi_query_idx; + +CREATE INDEX IF NOT EXISTS hydra_oauth2_flow_previous_consents_idx + ON hydra_oauth2_flow (subject, client_id, nid, consent_skip, consent_error, consent_remember); diff --git a/persistence/sql/migrations/20230809122501000001_add_kratos_session_id.down.sql b/persistence/sql/migrations/20230809122501000001_add_kratos_session_id.down.sql new file mode 100644 index 00000000000..b5ab0899249 --- /dev/null +++ b/persistence/sql/migrations/20230809122501000001_add_kratos_session_id.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE hydra_oauth2_flow DROP COLUMN identity_provider_session_id; +ALTER TABLE hydra_oauth2_authentication_session DROP COLUMN identity_provider_session_id; \ No newline at end of file diff --git a/persistence/sql/migrations/20230809122501000001_add_kratos_session_id.up.sql b/persistence/sql/migrations/20230809122501000001_add_kratos_session_id.up.sql new file mode 100644 index 00000000000..1d39c457105 --- /dev/null +++ b/persistence/sql/migrations/20230809122501000001_add_kratos_session_id.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE hydra_oauth2_flow ADD COLUMN identity_provider_session_id VARCHAR(40); +ALTER TABLE hydra_oauth2_authentication_session ADD COLUMN identity_provider_session_id VARCHAR(40); \ No newline at end of file diff --git a/persistence/sql/migrations/20230908104443000000_change_client_pk.cockroach.down.sql b/persistence/sql/migrations/20230908104443000000_change_client_pk.cockroach.down.sql new file mode 100644 index 00000000000..e0325012a57 --- /dev/null +++ b/persistence/sql/migrations/20230908104443000000_change_client_pk.cockroach.down.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_client ALTER PRIMARY KEY USING COLUMNS (pk); diff --git a/persistence/sql/migrations/20230908104443000000_change_client_pk.cockroach.up.sql b/persistence/sql/migrations/20230908104443000000_change_client_pk.cockroach.up.sql new file mode 100644 index 00000000000..5dedcc76bb3 --- /dev/null +++ b/persistence/sql/migrations/20230908104443000000_change_client_pk.cockroach.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_client ALTER PRIMARY KEY USING COLUMNS (id, nid); diff --git a/persistence/sql/migrations/20230908104443000000_change_client_pk.down.sql b/persistence/sql/migrations/20230908104443000000_change_client_pk.down.sql new file mode 100644 index 00000000000..0835302054e --- /dev/null +++ b/persistence/sql/migrations/20230908104443000000_change_client_pk.down.sql @@ -0,0 +1,7 @@ +UPDATE hydra_client SET pk = gen_random_uuid() WHERE pk IS NULL; + +ALTER TABLE hydra_client ALTER COLUMN pk SET NOT NULL; + +ALTER TABLE hydra_client DROP CONSTRAINT hydra_client_pkey; + +ALTER TABLE hydra_client ADD PRIMARY KEY (pk); diff --git a/persistence/sql/migrations/20230908104443000000_change_client_pk.mysql.down.sql b/persistence/sql/migrations/20230908104443000000_change_client_pk.mysql.down.sql new file mode 100644 index 00000000000..0764ae08246 --- /dev/null +++ b/persistence/sql/migrations/20230908104443000000_change_client_pk.mysql.down.sql @@ -0,0 +1,3 @@ +ALTER TABLE hydra_client MODIFY pk CHAR(36) NOT NULL; + +ALTER TABLE hydra_client DROP PRIMARY KEY, ADD PRIMARY KEY (pk); diff --git a/persistence/sql/migrations/20230908104443000000_change_client_pk.mysql.up.sql b/persistence/sql/migrations/20230908104443000000_change_client_pk.mysql.up.sql new file mode 100644 index 00000000000..9a951cefa36 --- /dev/null +++ b/persistence/sql/migrations/20230908104443000000_change_client_pk.mysql.up.sql @@ -0,0 +1,3 @@ +ALTER TABLE hydra_client DROP PRIMARY KEY, ADD PRIMARY KEY (id, nid); + +ALTER TABLE hydra_client MODIFY pk CHAR(36); diff --git a/persistence/sql/migrations/20230908104443000000_change_client_pk.sqlite.down.sql b/persistence/sql/migrations/20230908104443000000_change_client_pk.sqlite.down.sql new file mode 100644 index 00000000000..69a5686c381 --- /dev/null +++ b/persistence/sql/migrations/20230908104443000000_change_client_pk.sqlite.down.sql @@ -0,0 +1,161 @@ +CREATE TABLE "_hydra_client_tmp" +( + id VARCHAR(255) NOT NULL, + client_name TEXT NOT NULL, + client_secret TEXT NOT NULL, + redirect_uris TEXT NOT NULL, + grant_types TEXT NOT NULL, + response_types TEXT NOT NULL, + scope TEXT NOT NULL, + owner TEXT NOT NULL, + policy_uri TEXT NOT NULL, + tos_uri TEXT NOT NULL, + client_uri TEXT NOT NULL, + logo_uri TEXT NOT NULL, + contacts TEXT NOT NULL, + client_secret_expires_at INTEGER NOT NULL DEFAULT 0, + sector_identifier_uri TEXT NOT NULL, + jwks TEXT NOT NULL, + jwks_uri TEXT NOT NULL, + request_uris TEXT NOT NULL, + token_endpoint_auth_method VARCHAR(25) NOT NULL DEFAULT '', + request_object_signing_alg VARCHAR(10) NOT NULL DEFAULT '', + userinfo_signed_response_alg VARCHAR(10) NOT NULL DEFAULT '', + subject_type VARCHAR(15) NOT NULL DEFAULT '', + allowed_cors_origins TEXT NOT NULL, + pk TEXT PRIMARY KEY NOT NULL, + pk_deprecated INTEGER NULL DEFAULT NULL, + audience TEXT NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + frontchannel_logout_uri TEXT NOT NULL DEFAULT '', + frontchannel_logout_session_required INTEGER NOT NULL DEFAULT false, + post_logout_redirect_uris TEXT NOT NULL DEFAULT '', + backchannel_logout_uri TEXT NOT NULL DEFAULT '', + backchannel_logout_session_required INTEGER NOT NULL DEFAULT false, + metadata TEXT NOT NULL DEFAULT '{}', + token_endpoint_auth_signing_alg VARCHAR(10) NOT NULL DEFAULT '', + registration_access_token_signature VARCHAR(128) NOT NULL DEFAULT '', + access_token_strategy VARCHAR(10) NOT NULL DEFAULT '', + authorization_code_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + authorization_code_grant_id_token_lifespan BIGINT NULL DEFAULT NULL, + authorization_code_grant_refresh_token_lifespan BIGINT NULL DEFAULT NULL, + client_credentials_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + implicit_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + implicit_grant_id_token_lifespan BIGINT NULL DEFAULT NULL, + jwt_bearer_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + password_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + password_grant_refresh_token_lifespan BIGINT NULL DEFAULT NULL, + refresh_token_grant_id_token_lifespan BIGINT NULL DEFAULT NULL, + refresh_token_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + refresh_token_grant_refresh_token_lifespan BIGINT NULL DEFAULT NULL, + skip_consent BOOLEAN NOT NULL DEFAULT false, + nid CHAR(36) NOT NULL, + PRIMARY KEY (id, nid) +); +INSERT INTO "_hydra_client_tmp" (id, + client_name, + client_secret, + redirect_uris, + grant_types, + response_types, + scope, + owner, + policy_uri, + tos_uri, + client_uri, + logo_uri, + contacts, + client_secret_expires_at, + sector_identifier_uri, + jwks, + jwks_uri, + request_uris, + token_endpoint_auth_method, + request_object_signing_alg, + userinfo_signed_response_alg, + subject_type, + allowed_cors_origins, + pk, + pk_deprecated, + audience, + created_at, + updated_at, + frontchannel_logout_uri, + frontchannel_logout_session_required, + post_logout_redirect_uris, + backchannel_logout_uri, + backchannel_logout_session_required, + metadata, + token_endpoint_auth_signing_alg, + access_token_strategy, + registration_access_token_signature, + authorization_code_grant_access_token_lifespan, + authorization_code_grant_id_token_lifespan, + authorization_code_grant_refresh_token_lifespan, + client_credentials_grant_access_token_lifespan, + implicit_grant_access_token_lifespan, + implicit_grant_id_token_lifespan, + jwt_bearer_grant_access_token_lifespan, + password_grant_access_token_lifespan, + password_grant_refresh_token_lifespan, + refresh_token_grant_id_token_lifespan, + refresh_token_grant_access_token_lifespan, + refresh_token_grant_refresh_token_lifespan, + skip_consent, + nid) +SELECT id, + client_name, + client_secret, + redirect_uris, + grant_types, + response_types, + scope, + owner, + policy_uri, + tos_uri, + client_uri, + logo_uri, + contacts, + client_secret_expires_at, + sector_identifier_uri, + jwks, + jwks_uri, + request_uris, + token_endpoint_auth_method, + request_object_signing_alg, + userinfo_signed_response_alg, + subject_type, + allowed_cors_origins, + id, + pk, + pk_deprecated, + audience, + created_at, + updated_at, + frontchannel_logout_uri, + frontchannel_logout_session_required, + post_logout_redirect_uris, + backchannel_logout_uri, + backchannel_logout_session_required, + metadata, + token_endpoint_auth_signing_alg, + access_token_strategy, + registration_access_token_signature, + authorization_code_grant_access_token_lifespan, + authorization_code_grant_id_token_lifespan, + authorization_code_grant_refresh_token_lifespan, + client_credentials_grant_access_token_lifespan, + implicit_grant_access_token_lifespan, + implicit_grant_id_token_lifespan, + jwt_bearer_grant_access_token_lifespan, + password_grant_access_token_lifespan, + password_grant_refresh_token_lifespan, + refresh_token_grant_id_token_lifespan, + refresh_token_grant_access_token_lifespan, + refresh_token_grant_refresh_token_lifespan, + skip_consent, + nid +FROM "hydra_client"; +DROP TABLE "hydra_client"; +ALTER TABLE "_hydra_client_tmp" RENAME TO "hydra_client"; diff --git a/persistence/sql/migrations/20230908104443000000_change_client_pk.sqlite.up.sql b/persistence/sql/migrations/20230908104443000000_change_client_pk.sqlite.up.sql new file mode 100644 index 00000000000..4c348c2ba41 --- /dev/null +++ b/persistence/sql/migrations/20230908104443000000_change_client_pk.sqlite.up.sql @@ -0,0 +1,158 @@ +CREATE TABLE "_hydra_client_tmp" +( + id VARCHAR(255) NOT NULL, + client_name TEXT NOT NULL, + client_secret TEXT NOT NULL, + redirect_uris TEXT NOT NULL, + grant_types TEXT NOT NULL, + response_types TEXT NOT NULL, + scope TEXT NOT NULL, + owner TEXT NOT NULL, + policy_uri TEXT NOT NULL, + tos_uri TEXT NOT NULL, + client_uri TEXT NOT NULL, + logo_uri TEXT NOT NULL, + contacts TEXT NOT NULL, + client_secret_expires_at INTEGER NOT NULL DEFAULT 0, + sector_identifier_uri TEXT NOT NULL, + jwks TEXT NOT NULL, + jwks_uri TEXT NOT NULL, + request_uris TEXT NOT NULL, + token_endpoint_auth_method VARCHAR(25) NOT NULL DEFAULT '', + request_object_signing_alg VARCHAR(10) NOT NULL DEFAULT '', + userinfo_signed_response_alg VARCHAR(10) NOT NULL DEFAULT '', + subject_type VARCHAR(15) NOT NULL DEFAULT '', + allowed_cors_origins TEXT NOT NULL, + pk TEXT NULL, + pk_deprecated INTEGER NULL DEFAULT NULL, + audience TEXT NOT NULL, + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + frontchannel_logout_uri TEXT NOT NULL DEFAULT '', + frontchannel_logout_session_required INTEGER NOT NULL DEFAULT false, + post_logout_redirect_uris TEXT NOT NULL DEFAULT '', + backchannel_logout_uri TEXT NOT NULL DEFAULT '', + backchannel_logout_session_required INTEGER NOT NULL DEFAULT false, + metadata TEXT NOT NULL DEFAULT '{}', + token_endpoint_auth_signing_alg VARCHAR(10) NOT NULL DEFAULT '', + registration_access_token_signature VARCHAR(128) NOT NULL DEFAULT '', + access_token_strategy VARCHAR(10) NOT NULL DEFAULT '', + authorization_code_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + authorization_code_grant_id_token_lifespan BIGINT NULL DEFAULT NULL, + authorization_code_grant_refresh_token_lifespan BIGINT NULL DEFAULT NULL, + client_credentials_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + implicit_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + implicit_grant_id_token_lifespan BIGINT NULL DEFAULT NULL, + jwt_bearer_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + password_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + password_grant_refresh_token_lifespan BIGINT NULL DEFAULT NULL, + refresh_token_grant_id_token_lifespan BIGINT NULL DEFAULT NULL, + refresh_token_grant_access_token_lifespan BIGINT NULL DEFAULT NULL, + refresh_token_grant_refresh_token_lifespan BIGINT NULL DEFAULT NULL, + skip_consent BOOLEAN NOT NULL DEFAULT false, + nid CHAR(36) NOT NULL, + PRIMARY KEY (id, nid) +); +INSERT INTO "_hydra_client_tmp" (id, + client_name, + client_secret, + redirect_uris, + grant_types, + response_types, + scope, + owner, + policy_uri, + tos_uri, + client_uri, + logo_uri, + contacts, + client_secret_expires_at, + sector_identifier_uri, + jwks, + jwks_uri, + request_uris, + token_endpoint_auth_method, + request_object_signing_alg, + userinfo_signed_response_alg, + subject_type, + allowed_cors_origins, + pk, + pk_deprecated, + audience, + created_at, + updated_at, + frontchannel_logout_uri, + frontchannel_logout_session_required, + post_logout_redirect_uris, + backchannel_logout_uri, + backchannel_logout_session_required, + metadata, + token_endpoint_auth_signing_alg, + registration_access_token_signature, + authorization_code_grant_access_token_lifespan, + authorization_code_grant_id_token_lifespan, + authorization_code_grant_refresh_token_lifespan, + client_credentials_grant_access_token_lifespan, + implicit_grant_access_token_lifespan, + implicit_grant_id_token_lifespan, + jwt_bearer_grant_access_token_lifespan, + password_grant_access_token_lifespan, + password_grant_refresh_token_lifespan, + refresh_token_grant_id_token_lifespan, + refresh_token_grant_access_token_lifespan, + refresh_token_grant_refresh_token_lifespan, + skip_consent, + nid) +SELECT id, + client_name, + client_secret, + redirect_uris, + grant_types, + response_types, + scope, + owner, + policy_uri, + tos_uri, + client_uri, + logo_uri, + contacts, + client_secret_expires_at, + sector_identifier_uri, + jwks, + jwks_uri, + request_uris, + token_endpoint_auth_method, + request_object_signing_alg, + userinfo_signed_response_alg, + subject_type, + allowed_cors_origins, + pk, + pk_deprecated, + audience, + created_at, + updated_at, + frontchannel_logout_uri, + frontchannel_logout_session_required, + post_logout_redirect_uris, + backchannel_logout_uri, + backchannel_logout_session_required, + metadata, + token_endpoint_auth_signing_alg, + registration_access_token_signature, + authorization_code_grant_access_token_lifespan, + authorization_code_grant_id_token_lifespan, + authorization_code_grant_refresh_token_lifespan, + client_credentials_grant_access_token_lifespan, + implicit_grant_access_token_lifespan, + implicit_grant_id_token_lifespan, + jwt_bearer_grant_access_token_lifespan, + password_grant_access_token_lifespan, + password_grant_refresh_token_lifespan, + refresh_token_grant_id_token_lifespan, + refresh_token_grant_access_token_lifespan, + refresh_token_grant_refresh_token_lifespan, + skip_consent, + nid +FROM "hydra_client"; +DROP TABLE "hydra_client"; +ALTER TABLE "_hydra_client_tmp" RENAME TO "hydra_client"; diff --git a/persistence/sql/migrations/20230908104443000000_change_client_pk.up.sql b/persistence/sql/migrations/20230908104443000000_change_client_pk.up.sql new file mode 100644 index 00000000000..a22b8c6c305 --- /dev/null +++ b/persistence/sql/migrations/20230908104443000000_change_client_pk.up.sql @@ -0,0 +1,5 @@ +ALTER TABLE hydra_client DROP CONSTRAINT hydra_client_pkey; + +ALTER TABLE hydra_client ALTER COLUMN pk DROP NOT NULL; + +ALTER TABLE hydra_client ADD PRIMARY KEY (id, nid); diff --git a/persistence/sql/migrations/20230908104443000001_change_client_pk.cockroach.down.sql b/persistence/sql/migrations/20230908104443000001_change_client_pk.cockroach.down.sql new file mode 100644 index 00000000000..bfee76d222c --- /dev/null +++ b/persistence/sql/migrations/20230908104443000001_change_client_pk.cockroach.down.sql @@ -0,0 +1,3 @@ +UPDATE hydra_client SET pk = gen_random_uuid() WHERE pk IS NULL; + +ALTER TABLE hydra_client ALTER COLUMN pk SET NOT NULL; diff --git a/persistence/sql/migrations/20230908104443000001_change_client_pk.cockroach.up.sql b/persistence/sql/migrations/20230908104443000001_change_client_pk.cockroach.up.sql new file mode 100644 index 00000000000..d56f3d514cf --- /dev/null +++ b/persistence/sql/migrations/20230908104443000001_change_client_pk.cockroach.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_client ALTER COLUMN pk DROP NOT NULL; diff --git a/persistence/sql/migrations/20230908104443000001_change_client_pk.down.sql b/persistence/sql/migrations/20230908104443000001_change_client_pk.down.sql new file mode 100644 index 00000000000..11c36dee1b6 --- /dev/null +++ b/persistence/sql/migrations/20230908104443000001_change_client_pk.down.sql @@ -0,0 +1 @@ +-- only for crdb diff --git a/persistence/sql/migrations/20230908104443000001_change_client_pk.up.sql b/persistence/sql/migrations/20230908104443000001_change_client_pk.up.sql new file mode 100644 index 00000000000..11c36dee1b6 --- /dev/null +++ b/persistence/sql/migrations/20230908104443000001_change_client_pk.up.sql @@ -0,0 +1 @@ +-- only for crdb diff --git a/persistence/sql/migrations/20240104181300000001_jwk_index.down.sql b/persistence/sql/migrations/20240104181300000001_jwk_index.down.sql new file mode 100644 index 00000000000..2f6ee7479fe --- /dev/null +++ b/persistence/sql/migrations/20240104181300000001_jwk_index.down.sql @@ -0,0 +1,2 @@ +DROP INDEX hydra_jwk_nid_sid_created_at_idx; +DROP INDEX hydra_jwk_nid_sid_kid_created_at_idx; diff --git a/persistence/sql/migrations/20240104181300000001_jwk_index.up.sql b/persistence/sql/migrations/20240104181300000001_jwk_index.up.sql new file mode 100644 index 00000000000..8ec5ed97302 --- /dev/null +++ b/persistence/sql/migrations/20240104181300000001_jwk_index.up.sql @@ -0,0 +1,2 @@ +CREATE INDEX hydra_jwk_nid_sid_created_at_idx ON hydra_jwk (nid, sid, created_at); +CREATE INDEX hydra_jwk_nid_sid_kid_created_at_idx ON hydra_jwk (nid, sid, kid, created_at); diff --git a/persistence/sql/migrations/20240129174410000001_client_add_logout_skip_consent_column.down.sql b/persistence/sql/migrations/20240129174410000001_client_add_logout_skip_consent_column.down.sql new file mode 100644 index 00000000000..98258eecc43 --- /dev/null +++ b/persistence/sql/migrations/20240129174410000001_client_add_logout_skip_consent_column.down.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_client DROP COLUMN skip_logout_consent; diff --git a/persistence/sql/migrations/20240129174410000001_client_add_logout_skip_consent_column.up.sql b/persistence/sql/migrations/20240129174410000001_client_add_logout_skip_consent_column.up.sql new file mode 100644 index 00000000000..96a8e3ec0c2 --- /dev/null +++ b/persistence/sql/migrations/20240129174410000001_client_add_logout_skip_consent_column.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_client ADD COLUMN skip_logout_consent BOOLEAN NULL; diff --git a/persistence/sql/migrations/20240403121110000001_add_expire_columns.down.sql b/persistence/sql/migrations/20240403121110000001_add_expire_columns.down.sql new file mode 100644 index 00000000000..539996e4efc --- /dev/null +++ b/persistence/sql/migrations/20240403121110000001_add_expire_columns.down.sql @@ -0,0 +1,5 @@ +ALTER TABLE hydra_oauth2_oidc DROP COLUMN expires_at; +ALTER TABLE hydra_oauth2_access DROP COLUMN expires_at; +ALTER TABLE hydra_oauth2_refresh DROP COLUMN expires_at; +ALTER TABLE hydra_oauth2_code DROP COLUMN expires_at; +ALTER TABLE hydra_oauth2_pkce DROP COLUMN expires_at; diff --git a/persistence/sql/migrations/20240403121110000001_add_expire_columns.up.sql b/persistence/sql/migrations/20240403121110000001_add_expire_columns.up.sql new file mode 100644 index 00000000000..e3814953e96 --- /dev/null +++ b/persistence/sql/migrations/20240403121110000001_add_expire_columns.up.sql @@ -0,0 +1,11 @@ +ALTER TABLE hydra_oauth2_oidc ADD COLUMN expires_at TIMESTAMP NULL; +ALTER TABLE hydra_oauth2_access ADD COLUMN expires_at TIMESTAMP NULL; +ALTER TABLE hydra_oauth2_refresh ADD COLUMN expires_at TIMESTAMP NULL; +ALTER TABLE hydra_oauth2_code ADD COLUMN expires_at TIMESTAMP NULL; +ALTER TABLE hydra_oauth2_pkce ADD COLUMN expires_at TIMESTAMP NULL; + +CREATE INDEX hydra_oauth2_oidc_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX hydra_oauth2_access_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX hydra_oauth2_refresh_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX hydra_oauth2_code_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX hydra_oauth2_pkce_expires_at_idx ON hydra_oauth2_oidc (expires_at); diff --git a/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.down.sql b/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.down.sql new file mode 100644 index 00000000000..89adb722a78 --- /dev/null +++ b/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.down.sql @@ -0,0 +1,9 @@ +CREATE INDEX IF NOT EXISTS hydra_oauth2_access_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX IF NOT EXISTS hydra_oauth2_refresh_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX IF NOT EXISTS hydra_oauth2_code_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX IF NOT EXISTS hydra_oauth2_pkce_expires_at_idx ON hydra_oauth2_oidc (expires_at); + +DROP INDEX hydra_oauth2_access_expires_at_v2_idx; +DROP INDEX hydra_oauth2_refresh_expires_at_v2_idx; +DROP INDEX hydra_oauth2_code_expires_at_v2_idx; +DROP INDEX hydra_oauth2_pkce_expires_at_v2_idx; diff --git a/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.mysql.down.sql b/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.mysql.down.sql new file mode 100644 index 00000000000..d76d2b4f10b --- /dev/null +++ b/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.mysql.down.sql @@ -0,0 +1,9 @@ +CREATE INDEX IF NOT EXISTS hydra_oauth2_access_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX IF NOT EXISTS hydra_oauth2_refresh_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX IF NOT EXISTS hydra_oauth2_code_expires_at_idx ON hydra_oauth2_oidc (expires_at); +CREATE INDEX IF NOT EXISTS hydra_oauth2_pkce_expires_at_idx ON hydra_oauth2_oidc (expires_at); + +DROP INDEX hydra_oauth2_access_expires_at_v2_idx ON hydra_oauth2_access; +DROP INDEX hydra_oauth2_refresh_expires_at_v2_idx ON hydra_oauth2_refresh; +DROP INDEX hydra_oauth2_code_expires_at_v2_idx ON hydra_oauth2_code; +DROP INDEX hydra_oauth2_pkce_expires_at_v2_idx ON hydra_oauth2_pkce; diff --git a/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.mysql.up.sql b/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.mysql.up.sql new file mode 100644 index 00000000000..71c9b49bf81 --- /dev/null +++ b/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.mysql.up.sql @@ -0,0 +1,9 @@ +CREATE INDEX hydra_oauth2_access_expires_at_v2_idx ON hydra_oauth2_access (expires_at); +CREATE INDEX hydra_oauth2_refresh_expires_at_v2_idx ON hydra_oauth2_refresh (expires_at); +CREATE INDEX hydra_oauth2_code_expires_at_v2_idx ON hydra_oauth2_code (expires_at); +CREATE INDEX hydra_oauth2_pkce_expires_at_v2_idx ON hydra_oauth2_pkce (expires_at); + +DROP INDEX hydra_oauth2_access_expires_at_idx ON hydra_oauth2_oidc; +DROP INDEX hydra_oauth2_refresh_expires_at_idx ON hydra_oauth2_oidc; +DROP INDEX hydra_oauth2_code_expires_at_idx ON hydra_oauth2_oidc; +DROP INDEX hydra_oauth2_pkce_expires_at_idx ON hydra_oauth2_oidc; diff --git a/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.up.sql b/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.up.sql new file mode 100644 index 00000000000..8928b89454c --- /dev/null +++ b/persistence/sql/migrations/20240612222110000001_add_oauth2_expires_at_indices.up.sql @@ -0,0 +1,9 @@ +CREATE INDEX IF NOT EXISTS hydra_oauth2_access_expires_at_v2_idx ON hydra_oauth2_access (expires_at); +CREATE INDEX IF NOT EXISTS hydra_oauth2_refresh_expires_at_v2_idx ON hydra_oauth2_refresh (expires_at); +CREATE INDEX IF NOT EXISTS hydra_oauth2_code_expires_at_v2_idx ON hydra_oauth2_code (expires_at); +CREATE INDEX IF NOT EXISTS hydra_oauth2_pkce_expires_at_v2_idx ON hydra_oauth2_pkce (expires_at); + +DROP INDEX hydra_oauth2_access_expires_at_idx; +DROP INDEX hydra_oauth2_refresh_expires_at_idx; +DROP INDEX hydra_oauth2_code_expires_at_idx; +DROP INDEX hydra_oauth2_pkce_expires_at_idx; diff --git a/persistence/sql/migrations/20240916105610000001_add_logout_request_timestamps.down.sql b/persistence/sql/migrations/20240916105610000001_add_logout_request_timestamps.down.sql new file mode 100644 index 00000000000..a435c6af599 --- /dev/null +++ b/persistence/sql/migrations/20240916105610000001_add_logout_request_timestamps.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE hydra_oauth2_logout_request DROP expires_at; +ALTER TABLE hydra_oauth2_logout_request DROP requested_at; diff --git a/persistence/sql/migrations/20240916105610000001_add_logout_request_timestamps.up.sql b/persistence/sql/migrations/20240916105610000001_add_logout_request_timestamps.up.sql new file mode 100644 index 00000000000..8bcd8c3e789 --- /dev/null +++ b/persistence/sql/migrations/20240916105610000001_add_logout_request_timestamps.up.sql @@ -0,0 +1,2 @@ +ALTER TABLE hydra_oauth2_logout_request ADD expires_at timestamp NULL; +ALTER TABLE hydra_oauth2_logout_request ADD requested_at timestamp NULL; diff --git a/persistence/sql/migrations/20241012144910000001_unused_indices.down.sql b/persistence/sql/migrations/20241012144910000001_unused_indices.down.sql new file mode 100644 index 00000000000..16cb58bb35d --- /dev/null +++ b/persistence/sql/migrations/20241012144910000001_unused_indices.down.sql @@ -0,0 +1,14 @@ +-- CREATE INDEX IF NOT EXISTS hydra_oauth2_access_client_id_subject_idx ON hydra_oauth2_access (client_id ASC, subject ASC, nid ASC); +CREATE INDEX IF NOT EXISTS hydra_oauth2_access_expires_at_v2_idx ON hydra_oauth2_access (expires_at ASC); + +CREATE INDEX IF NOT EXISTS hydra_oauth2_refresh_client_id_subject_idx ON hydra_oauth2_refresh (client_id ASC, subject ASC); +CREATE INDEX IF NOT EXISTS hydra_oauth2_refresh_expires_at_v2_idx ON hydra_oauth2_refresh (expires_at ASC); + +CREATE INDEX IF NOT EXISTS hydra_oauth2_pkce_request_id_idx ON hydra_oauth2_pkce (request_id ASC, nid ASC); +CREATE INDEX IF NOT EXISTS hydra_oauth2_pkce_expires_at_v2_idx ON hydra_oauth2_pkce (expires_at ASC); + +CREATE INDEX IF NOT EXISTS hydra_oauth2_oidc_request_id_idx ON hydra_oauth2_oidc (request_id ASC, nid ASC); +CREATE INDEX IF NOT EXISTS hydra_oauth2_oidc_expires_at_idx ON hydra_oauth2_oidc (expires_at ASC); + +CREATE INDEX IF NOT EXISTS hydra_oauth2_code_request_id_idx ON hydra_oauth2_code (request_id ASC, nid ASC); +CREATE INDEX IF NOT EXISTS hydra_oauth2_code_expires_at_v2_idx ON hydra_oauth2_code (expires_at ASC); diff --git a/persistence/sql/migrations/20241012144910000001_unused_indices.mysql.up.sql b/persistence/sql/migrations/20241012144910000001_unused_indices.mysql.up.sql new file mode 100644 index 00000000000..83ae09f7edf --- /dev/null +++ b/persistence/sql/migrations/20241012144910000001_unused_indices.mysql.up.sql @@ -0,0 +1,14 @@ +-- DROP INDEX hydra_oauth2_access_client_id_subject_idx ON hydra_oauth2_access; +DROP INDEX hydra_oauth2_access_expires_at_v2_idx ON hydra_oauth2_access; -- janitor still uses requested_at index + +DROP INDEX hydra_oauth2_refresh_client_id_subject_idx ON hydra_oauth2_refresh; +DROP INDEX hydra_oauth2_refresh_expires_at_v2_idx ON hydra_oauth2_refresh; -- janitor still uses requested_at index + +DROP INDEX hydra_oauth2_pkce_request_id_idx ON hydra_oauth2_pkce; +DROP INDEX hydra_oauth2_pkce_expires_at_v2_idx ON hydra_oauth2_pkce; -- janitor still uses requested_at index + +DROP INDEX hydra_oauth2_oidc_request_id_idx ON hydra_oauth2_oidc; +DROP INDEX hydra_oauth2_oidc_expires_at_idx ON hydra_oauth2_oidc; -- janitor still uses requested_at index + +DROP INDEX hydra_oauth2_code_request_id_idx ON hydra_oauth2_code; +DROP INDEX hydra_oauth2_code_expires_at_v2_idx ON hydra_oauth2_code; -- janitor still uses requested_at index diff --git a/persistence/sql/migrations/20241012144910000001_unused_indices.up.sql b/persistence/sql/migrations/20241012144910000001_unused_indices.up.sql new file mode 100644 index 00000000000..ac2ba6ebf8b --- /dev/null +++ b/persistence/sql/migrations/20241012144910000001_unused_indices.up.sql @@ -0,0 +1,14 @@ +DROP INDEX IF EXISTS hydra_oauth2_access_client_id_subject_idx; +DROP INDEX IF EXISTS hydra_oauth2_access_expires_at_v2_idx; -- janitor still uses requested_at index + +DROP INDEX IF EXISTS hydra_oauth2_refresh_client_id_subject_idx; +DROP INDEX IF EXISTS hydra_oauth2_refresh_expires_at_v2_idx; -- janitor still uses requested_at index + +DROP INDEX IF EXISTS hydra_oauth2_pkce_request_id_idx; +DROP INDEX IF EXISTS hydra_oauth2_pkce_expires_at_v2_idx; -- janitor still uses requested_at index + +DROP INDEX IF EXISTS hydra_oauth2_oidc_request_id_idx; +DROP INDEX IF EXISTS hydra_oauth2_oidc_expires_at_idx; -- janitor still uses requested_at index + +DROP INDEX IF EXISTS hydra_oauth2_code_request_id_idx; +DROP INDEX IF EXISTS hydra_oauth2_code_expires_at_v2_idx; -- janitor still uses requested_at index diff --git a/persistence/sql/migrations/20241014121000000000_add_refresh_token_in_grace_period_flag.down.sql b/persistence/sql/migrations/20241014121000000000_add_refresh_token_in_grace_period_flag.down.sql new file mode 100644 index 00000000000..a30a127e902 --- /dev/null +++ b/persistence/sql/migrations/20241014121000000000_add_refresh_token_in_grace_period_flag.down.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_refresh DROP COLUMN first_used_at; diff --git a/persistence/sql/migrations/20241014121000000000_add_refresh_token_in_grace_period_flag.up.sql b/persistence/sql/migrations/20241014121000000000_add_refresh_token_in_grace_period_flag.up.sql new file mode 100644 index 00000000000..8ae823047f7 --- /dev/null +++ b/persistence/sql/migrations/20241014121000000000_add_refresh_token_in_grace_period_flag.up.sql @@ -0,0 +1 @@ +ALTER TABLE hydra_oauth2_refresh ADD first_used_at TIMESTAMP DEFAULT NULL; diff --git a/persistence/sql/persister.go b/persistence/sql/persister.go index 2f1b2adf3be..ba2647393a5 100644 --- a/persistence/sql/persister.go +++ b/persistence/sql/persister.go @@ -6,24 +6,26 @@ package sql import ( "context" "database/sql" + "io/fs" "reflect" "github.com/gobuffalo/pop/v6" - "github.com/gobuffalo/x/randx" "github.com/gofrs/uuid" - "github.com/pkg/errors" "github.com/ory/fosite" "github.com/ory/fosite/storage" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/persistence" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/aead" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal/kratos" + "github.com/ory/hydra/v2/persistence" + "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" "github.com/ory/x/errorsx" + "github.com/ory/x/fsx" "github.com/ory/x/logrusx" "github.com/ory/x/networkx" + "github.com/ory/x/otelx" "github.com/ory/x/popx" ) @@ -31,10 +33,14 @@ var _ persistence.Persister = new(Persister) var _ storage.Transactional = new(Persister) var ( - ErrTransactionOpen = errors.New("There is already a transaction in this context.") - ErrNoTransactionOpen = errors.New("There is no transaction in this context.") + ErrTransactionOpen = errors.New("There is already a Transaction in this context.") + ErrNoTransactionOpen = errors.New("There is no Transaction in this context.") ) +type skipCommitContextKey int + +const skipCommitKey skipCommitContextKey = 0 + type ( Persister struct { conn *pop.Connection @@ -48,20 +54,23 @@ type ( } Dependencies interface { ClientHasher() fosite.Hasher - KeyCipher() *jwk.AEAD + KeyCipher() *aead.AESGCM + FlowCipher() *aead.XChaCha20Poly1305 + Kratos() kratos.Client contextx.Provider x.RegistryLogger x.TracingProvider + config.Provider } ) -func (p *Persister) BeginTX(ctx context.Context) (context.Context, error) { +func (p *Persister) BeginTX(ctx context.Context) (_ context.Context, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.BeginTX") - defer span.End() + defer otelx.End(span, &err) fallback := &pop.Connection{TX: &pop.Tx{}} if popx.GetConnection(ctx, fallback).TX != fallback.TX { - return ctx, errorsx.WithStack(ErrTransactionOpen) + return context.WithValue(ctx, skipCommitKey, true), nil // no-op } tx, err := p.conn.Store.TransactionContextOptions(ctx, &sql.TxOptions{ @@ -71,15 +80,19 @@ func (p *Persister) BeginTX(ctx context.Context) (context.Context, error) { c := &pop.Connection{ TX: tx, Store: tx, - ID: randx.String(30), + ID: uuid.Must(uuid.NewV4()).String(), Dialect: p.conn.Dialect, } return popx.WithTransaction(ctx, c), err } -func (p *Persister) Commit(ctx context.Context) error { +func (p *Persister) Commit(ctx context.Context) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.Commit") - defer span.End() + defer otelx.End(span, &err) + + if skip, ok := ctx.Value(skipCommitKey).(bool); ok && skip { + return nil // we skipped BeginTX, so we also skip Commit + } fallback := &pop.Connection{TX: &pop.Tx{}} tx := popx.GetConnection(ctx, fallback) @@ -90,9 +103,13 @@ func (p *Persister) Commit(ctx context.Context) error { return errorsx.WithStack(tx.TX.Commit()) } -func (p *Persister) Rollback(ctx context.Context) error { +func (p *Persister) Rollback(ctx context.Context) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.Rollback") - defer span.End() + defer otelx.End(span, &err) + + if skip, ok := ctx.Value(skipCommitKey).(bool); ok && skip { + return nil // we skipped BeginTX, so we also skip Rollback + } fallback := &pop.Connection{TX: &pop.Tx{}} tx := popx.GetConnection(ctx, fallback) @@ -103,8 +120,11 @@ func (p *Persister) Rollback(ctx context.Context) error { return errorsx.WithStack(tx.TX.Rollback()) } -func NewPersister(ctx context.Context, c *pop.Connection, r Dependencies, config *config.DefaultProvider, l *logrusx.Logger) (*Persister, error) { - mb, err := popx.NewMigrationBox(migrations, popx.NewMigrator(c, r.Logger(), r.Tracer(ctx), 0)) +func NewPersister(ctx context.Context, c *pop.Connection, r Dependencies, config *config.DefaultProvider, extraMigrations []fs.FS, goMigrations []popx.Migration) (*Persister, error) { + mb, err := popx.NewMigrationBox( + fsx.Merge(append([]fs.FS{Migrations}, extraMigrations...)...), + popx.NewMigrator(c, r.Logger(), r.Tracer(ctx), 0), + popx.WithGoMigrations(goMigrations)) if err != nil { return nil, errorsx.WithStack(err) } @@ -114,7 +134,7 @@ func NewPersister(ctx context.Context, c *pop.Connection, r Dependencies, config mb: mb, r: r, config: config, - l: l, + l: r.Logger(), p: networkx.NewManager(c, r.Logger(), r.Tracer(ctx)), }, nil } @@ -158,9 +178,12 @@ func (p *Persister) Connection(ctx context.Context) *pop.Connection { return popx.GetConnection(ctx, p.conn) } -func (p *Persister) Ping() error { - type pinger interface{ Ping() error } - return p.conn.Store.(pinger).Ping() +func (p *Persister) Ping(ctx context.Context) error { + return p.conn.Store.SQLDB().PingContext(ctx) +} +func (p *Persister) PingContext(ctx context.Context) error { + type pinger interface{ PingContext(context.Context) error } + return p.conn.Store.(pinger).PingContext(ctx) } func (p *Persister) mustSetNetwork(nid uuid.UUID, v interface{}) interface{} { @@ -177,6 +200,6 @@ func (p *Persister) mustSetNetwork(nid uuid.UUID, v interface{}) interface{} { return v } -func (p *Persister) transaction(ctx context.Context, f func(ctx context.Context, c *pop.Connection) error) error { +func (p *Persister) Transaction(ctx context.Context, f func(ctx context.Context, c *pop.Connection) error) error { return popx.Transaction(ctx, p.conn, f) } diff --git a/persistence/sql/persister_authenticate.go b/persistence/sql/persister_authenticate.go new file mode 100644 index 00000000000..013ccc30051 --- /dev/null +++ b/persistence/sql/persister_authenticate.go @@ -0,0 +1,16 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql + +import ( + "context" +) + +func (p *Persister) Authenticate(ctx context.Context, name, secret string) (subject string, err error) { + session, err := p.r.Kratos().Authenticate(ctx, name, secret) + if err != nil { + return "", err + } + return session.Identity.Id, nil +} diff --git a/persistence/sql/persister_client.go b/persistence/sql/persister_client.go index 9f82843dc53..b3a484af564 100644 --- a/persistence/sql/persister_client.go +++ b/persistence/sql/persister_client.go @@ -6,20 +6,26 @@ package sql import ( "context" - "github.com/gofrs/uuid" + "go.opentelemetry.io/otel/trace" + + "github.com/ory/hydra/v2/x/events" "github.com/gobuffalo/pop/v6" + "github.com/gofrs/uuid" "github.com/ory/x/errorsx" + "github.com/ory/x/otelx" "github.com/ory/fosite" - "github.com/ory/hydra/client" + "github.com/ory/hydra/v2/client" "github.com/ory/x/sqlcon" ) -func (p *Persister) GetConcreteClient(ctx context.Context, id string) (*client.Client, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetConcreteClient") - defer span.End() +func (p *Persister) GetConcreteClient(ctx context.Context, id string) (c *client.Client, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetConcreteClient", + trace.WithAttributes(events.ClientID(id)), + ) + defer otelx.End(span, &err) var cl client.Client if err := p.QueryWithNetwork(ctx).Where("id = ?", id).First(&cl); err != nil { @@ -32,11 +38,13 @@ func (p *Persister) GetClient(ctx context.Context, id string) (fosite.Client, er return p.GetConcreteClient(ctx, id) } -func (p *Persister) UpdateClient(ctx context.Context, cl *client.Client) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateClient") - defer span.End() +func (p *Persister) UpdateClient(ctx context.Context, cl *client.Client) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateClient", + trace.WithAttributes(events.ClientID(cl.ID)), + ) + defer otelx.End(span, &err) - return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { + return p.Transaction(ctx, func(ctx context.Context, c *pop.Connection) error { o, err := p.GetConcreteClient(ctx, cl.GetID()) if err != nil { return err @@ -51,11 +59,9 @@ func (p *Persister) UpdateClient(ctx context.Context, cl *client.Client) error { } cl.Secret = string(h) } - // set the internal primary key - cl.ID = o.ID - // Set the legacy client ID - cl.LegacyClientID = o.LegacyClientID + // Ensure ID is the same + cl.ID = o.ID if err = cl.BeforeSave(c); err != nil { return sqlcon.HandleError(err) @@ -67,13 +73,20 @@ func (p *Persister) UpdateClient(ctx context.Context, cl *client.Client) error { } else if count == 0 { return sqlcon.HandleError(sqlcon.ErrNoRows) } + + events.Trace(ctx, events.ClientUpdated, + events.WithClientID(cl.ID), + events.WithClientName(cl.Name)) + return sqlcon.HandleError(err) }) } -func (p *Persister) Authenticate(ctx context.Context, id string, secret []byte) (*client.Client, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.Authenticate") - defer span.End() +func (p *Persister) AuthenticateClient(ctx context.Context, id string, secret []byte) (_ *client.Client, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.AuthenticateClient", + trace.WithAttributes(events.ClientID(id)), + ) + defer otelx.End(span, &err) c, err := p.GetConcreteClient(ctx, id) if err != nil { @@ -87,9 +100,9 @@ func (p *Persister) Authenticate(ctx context.Context, id string, secret []byte) return c, nil } -func (p *Persister) CreateClient(ctx context.Context, c *client.Client) error { +func (p *Persister) CreateClient(ctx context.Context, c *client.Client) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateClient") - defer span.End() + defer otelx.End(span, &err) h, err := p.r.ClientHasher().Hash(ctx, []byte(c.Secret)) if err != nil { @@ -97,36 +110,51 @@ func (p *Persister) CreateClient(ctx context.Context, c *client.Client) error { } c.Secret = string(h) - if c.ID == uuid.Nil { - c.ID = uuid.Must(uuid.NewV4()) + if c.ID == "" { + c.ID = uuid.Must(uuid.NewV4()).String() } - if c.LegacyClientID == "" { - c.LegacyClientID = c.ID.String() + if err := sqlcon.HandleError(p.CreateWithNetwork(ctx, c)); err != nil { + return err } - return sqlcon.HandleError(p.CreateWithNetwork(ctx, c)) + + events.Trace(ctx, events.ClientCreated, + events.WithClientID(c.ID), + events.WithClientName(c.Name)) + + return nil } -func (p *Persister) DeleteClient(ctx context.Context, id string) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteClient") - defer span.End() +func (p *Persister) DeleteClient(ctx context.Context, id string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteClient", + trace.WithAttributes(events.ClientID(id)), + ) + defer otelx.End(span, &err) - _, err := p.GetConcreteClient(ctx, id) + c, err := p.GetConcreteClient(ctx, id) if err != nil { return err } - return sqlcon.HandleError(p.QueryWithNetwork(ctx).Where("id = ?", id).Delete(&client.Client{})) + if err := sqlcon.HandleError(p.QueryWithNetwork(ctx).Where("id = ?", id).Delete(&client.Client{})); err != nil { + return err + } + + events.Trace(ctx, events.ClientDeleted, + events.WithClientID(c.ID), + events.WithClientName(c.Name)) + + return nil } -func (p *Persister) GetClients(ctx context.Context, filters client.Filter) ([]client.Client, error) { +func (p *Persister) GetClients(ctx context.Context, filters client.Filter) (_ []client.Client, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetClients") - defer span.End() + defer otelx.End(span, &err) cs := make([]client.Client, 0) query := p.QueryWithNetwork(ctx). Paginate(filters.Offset/filters.Limit+1, filters.Limit). - Order("pk") + Order("id") if filters.Name != "" { query.Where("client_name = ?", filters.Name) @@ -141,10 +169,10 @@ func (p *Persister) GetClients(ctx context.Context, filters client.Filter) ([]cl return cs, nil } -func (p *Persister) CountClients(ctx context.Context) (int, error) { +func (p *Persister) CountClients(ctx context.Context) (n int, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CountClients") - defer span.End() + defer otelx.End(span, &err) - n, err := p.QueryWithNetwork(ctx).Count(&client.Client{}) + n, err = p.QueryWithNetwork(ctx).Count(&client.Client{}) return n, sqlcon.HandleError(err) } diff --git a/persistence/sql/persister_consent.go b/persistence/sql/persister_consent.go index a93f60a7705..ad3c25b3d72 100644 --- a/persistence/sql/persister_consent.go +++ b/persistence/sql/persister_consent.go @@ -11,35 +11,37 @@ import ( "time" "github.com/gobuffalo/pop/v6" - - "github.com/ory/x/sqlxx" - - "github.com/ory/x/errorsx" - + "github.com/gofrs/uuid" "github.com/pkg/errors" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "github.com/ory/fosite" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/flow" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/oauth2/flowctx" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/errorsx" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" + "github.com/ory/x/sqlxx" ) var _ consent.Manager = &Persister{} -func (p *Persister) RevokeSubjectConsentSession(ctx context.Context, user string) error { +func (p *Persister) RevokeSubjectConsentSession(ctx context.Context, user string) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeSubjectConsentSession") - defer span.End() + defer otelx.End(span, &err) - return p.transaction(ctx, p.revokeConsentSession("consent_challenge_id IS NOT NULL AND subject = ?", user)) + return p.Transaction(ctx, p.revokeConsentSession("consent_challenge_id IS NOT NULL AND subject = ?", user)) } -func (p *Persister) RevokeSubjectClientConsentSession(ctx context.Context, user, client string) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeSubjectClientConsentSession") - defer span.End() +func (p *Persister) RevokeSubjectClientConsentSession(ctx context.Context, user, client string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeSubjectClientConsentSession", trace.WithAttributes(attribute.String("client", client))) + defer otelx.End(span, &err) - return p.transaction(ctx, p.revokeConsentSession("consent_challenge_id IS NOT NULL AND subject = ? AND client_id = ?", user, client)) + return p.Transaction(ctx, p.revokeConsentSession("consent_challenge_id IS NOT NULL AND subject = ? AND client_id = ?", user, client)) } func (p *Persister) revokeConsentSession(whereStmt string, whereArgs ...interface{}) func(context.Context, *pop.Connection) error { @@ -48,54 +50,58 @@ func (p *Persister) revokeConsentSession(whereStmt string, whereArgs ...interfac if err := p.QueryWithNetwork(ctx). Where(whereStmt, whereArgs...). Select("consent_challenge_id"). - All(&fs); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return errorsx.WithStack(x.ErrNotFound) - } - + All(&fs); errors.Is(err, sql.ErrNoRows) { + return errorsx.WithStack(x.ErrNotFound) + } else if err != nil { return sqlcon.HandleError(err) } - var count int + ids := make([]interface{}, 0, len(fs)) + nid := p.NetworkID(ctx) for _, f := range fs { - if err := p.RevokeAccessToken(ctx, f.ConsentChallengeID.String()); errors.Is(err, fosite.ErrNotFound) { - // do nothing - } else if err != nil { - return err - } - - if err := p.RevokeRefreshToken(ctx, f.ConsentChallengeID.String()); errors.Is(err, fosite.ErrNotFound) { - // do nothing - } else if err != nil { - return err - } - - localCount, err := c.RawQuery("DELETE FROM hydra_oauth2_flow WHERE consent_challenge_id = ? AND nid = ?", f.ConsentChallengeID, p.NetworkID(ctx)).ExecWithCount() - if err != nil { - if errors.Is(err, sql.ErrNoRows) { - return errorsx.WithStack(x.ErrNotFound) - } - return sqlcon.HandleError(err) - } - - // If there are no sessions to revoke we should return an error to indicate to the caller - // that the request failed. - count += localCount + ids = append(ids, f.ConsentChallengeID.String()) } - if count == 0 { + if len(ids) == 0 { + return nil + } + + if err := p.QueryWithNetwork(ctx). + Where("nid = ?", nid). + Where("request_id IN (?)", ids...). + Delete(&OAuth2RequestSQL{Table: sqlTableAccess}); errors.Is(err, fosite.ErrNotFound) { + // do nothing + } else if err != nil { + return err + } + + if err := p.QueryWithNetwork(ctx). + Where("nid = ?", nid). + Where("request_id IN (?)", ids...). + Delete(&OAuth2RequestSQL{Table: sqlTableRefresh}); errors.Is(err, fosite.ErrNotFound) { + // do nothing + } else if err != nil { + return err + } + + if err := p.QueryWithNetwork(ctx). + Where("nid = ?", nid). + Where("consent_challenge_id IN (?)", ids...). + Delete(new(flow.Flow)); errors.Is(err, sql.ErrNoRows) { return errorsx.WithStack(x.ErrNotFound) + } else if err != nil { + return sqlcon.HandleError(err) } return nil } } -func (p *Persister) RevokeSubjectLoginSession(ctx context.Context, subject string) error { +func (p *Persister) RevokeSubjectLoginSession(ctx context.Context, subject string) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeSubjectLoginSession") - defer span.End() + defer otelx.End(span, &err) - err := p.QueryWithNetwork(ctx).Where("subject = ?", subject).Delete(&consent.LoginSession{}) + err = p.QueryWithNetwork(ctx).Where("subject = ?", subject).Delete(&flow.LoginSession{}) if err != nil { return sqlcon.HandleError(err) } @@ -110,11 +116,11 @@ func (p *Persister) RevokeSubjectLoginSession(ctx context.Context, subject strin return nil } -func (p *Persister) CreateForcedObfuscatedLoginSession(ctx context.Context, session *consent.ForcedObfuscatedLoginSession) error { +func (p *Persister) CreateForcedObfuscatedLoginSession(ctx context.Context, session *consent.ForcedObfuscatedLoginSession) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateForcedObfuscatedLoginSession") - defer span.End() + defer otelx.End(span, &err) - return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { + return p.Transaction(ctx, func(ctx context.Context, c *pop.Connection) error { nid := p.NetworkID(ctx) if err := c.RawQuery( "DELETE FROM hydra_oauth2_obfuscated_authentication_session WHERE nid = ? AND client_id = ? AND subject = ?", @@ -135,9 +141,9 @@ func (p *Persister) CreateForcedObfuscatedLoginSession(ctx context.Context, sess }) } -func (p *Persister) GetForcedObfuscatedLoginSession(ctx context.Context, client, obfuscated string) (*consent.ForcedObfuscatedLoginSession, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetForcedObfuscatedLoginSession") - defer span.End() +func (p *Persister) GetForcedObfuscatedLoginSession(ctx context.Context, client, obfuscated string) (_ *consent.ForcedObfuscatedLoginSession, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetForcedObfuscatedLoginSession", trace.WithAttributes(attribute.String("client", client))) + defer otelx.End(span, &err) var s consent.ForcedObfuscatedLoginSession @@ -158,53 +164,47 @@ func (p *Persister) GetForcedObfuscatedLoginSession(ctx context.Context, client, // CreateConsentRequest configures fields that are introduced or changed in the // consent request. It doesn't touch fields that would be copied from the login // request. -func (p *Persister) CreateConsentRequest(ctx context.Context, req *consent.OAuth2ConsentRequest) error { +func (p *Persister) CreateConsentRequest(ctx context.Context, f *flow.Flow, req *flow.OAuth2ConsentRequest) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateConsentRequest") - defer span.End() - - c, err := p.Connection(ctx).RawQuery(` -UPDATE hydra_oauth2_flow -SET - state = ?, - consent_challenge_id = ?, - consent_skip = ?, - consent_verifier = ?, - consent_csrf = ? -WHERE login_challenge = ? AND nid = ?; -`, - flow.FlowStateConsentInitialized, - sqlxx.NullString(req.ID), - req.Skip, - req.Verifier, - req.CSRF, - req.LoginChallenge.String(), - p.NetworkID(ctx), - ).ExecWithCount() - if err != nil { - return sqlcon.HandleError(err) + defer otelx.End(span, &err) + + if f == nil { + return errorsx.WithStack(x.ErrNotFound.WithDebug("Flow is nil")) } - if c != 1 { + if f.ID != req.LoginChallenge.String() || f.NID != p.NetworkID(ctx) { return errorsx.WithStack(x.ErrNotFound) } + f.State = flow.FlowStateConsentInitialized + f.ConsentChallengeID = sqlxx.NullString(req.ID) + f.ConsentSkip = req.Skip + f.ConsentVerifier = sqlxx.NullString(req.Verifier) + f.ConsentCSRF = sqlxx.NullString(req.CSRF) + return nil } -func (p *Persister) GetFlowByConsentChallenge(ctx context.Context, challenge string) (*flow.Flow, error) { +func (p *Persister) GetFlowByConsentChallenge(ctx context.Context, challenge string) (_ *flow.Flow, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetFlowByConsentChallenge") - defer span.End() + defer otelx.End(span, &err) - f := &flow.Flow{} - - if err := sqlcon.HandleError(p.QueryWithNetwork(ctx).Where("consent_challenge_id = ?", challenge).First(f)); err != nil { - return nil, err + // challenge contains the flow. + f, err := flowctx.Decode[flow.Flow](ctx, p.r.FlowCipher(), challenge, flowctx.AsConsentChallenge) + if err != nil { + return nil, errorsx.WithStack(x.ErrNotFound) + } + if f.NID != p.NetworkID(ctx) { + return nil, errorsx.WithStack(x.ErrNotFound) + } + if f.RequestedAt.Add(p.config.ConsentRequestMaxAge(ctx)).Before(time.Now()) { + return nil, errorsx.WithStack(fosite.ErrRequestUnauthorized.WithHint("The consent request has expired, please try again.")) } return f, nil } -func (p *Persister) GetConsentRequest(ctx context.Context, challenge string) (*consent.OAuth2ConsentRequest, error) { +func (p *Persister) GetConsentRequest(ctx context.Context, challenge string) (_ *flow.OAuth2ConsentRequest, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetConsentRequest") - defer span.End() + defer otelx.End(span, &err) f, err := p.GetFlowByConsentChallenge(ctx, challenge) if err != nil { @@ -214,146 +214,157 @@ func (p *Persister) GetConsentRequest(ctx context.Context, challenge string) (*c return nil, err } + // We need to overwrite the ID with the encoded flow (challenge) so that the client is not confused. + f.ConsentChallengeID = sqlxx.NullString(challenge) + return f.GetConsentRequest(), nil } -func (p *Persister) CreateLoginRequest(ctx context.Context, req *consent.LoginRequest) error { +func (p *Persister) CreateLoginRequest(ctx context.Context, req *flow.LoginRequest) (_ *flow.Flow, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateLoginRequest") - defer span.End() + defer otelx.End(span, &err) f := flow.NewFlow(req) - return sqlcon.HandleError(p.CreateWithNetwork(ctx, f)) + nid := p.NetworkID(ctx) + if nid == uuid.Nil { + return nil, errorsx.WithStack(x.ErrNotFound) + } + f.NID = nid + + return f, nil } -func (p *Persister) GetFlow(ctx context.Context, loginChallenge string) (*flow.Flow, error) { +func (p *Persister) GetFlow(ctx context.Context, loginChallenge string) (_ *flow.Flow, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetFlow") - defer span.End() + defer otelx.End(span, &err) var f flow.Flow - return &f, p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - if err := p.QueryWithNetwork(ctx).Where("login_challenge = ?", loginChallenge).First(&f); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return errorsx.WithStack(x.ErrNotFound) - } - return sqlcon.HandleError(err) + if err := p.QueryWithNetwork(ctx).Where("login_challenge = ?", loginChallenge).First(&f); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, errorsx.WithStack(x.ErrNotFound) } - - return nil - }) + return nil, sqlcon.HandleError(err) + } + return &f, nil } -func (p *Persister) GetLoginRequest(ctx context.Context, loginChallenge string) (*consent.LoginRequest, error) { +func (p *Persister) GetLoginRequest(ctx context.Context, loginChallenge string) (_ *flow.LoginRequest, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetLoginRequest") - defer span.End() - - var lr *consent.LoginRequest - return lr, p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - var f flow.Flow - if err := p.QueryWithNetwork(ctx).Where("login_challenge = ?", loginChallenge).First(&f); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return errorsx.WithStack(x.ErrNotFound) - } - return sqlcon.HandleError(err) - } - lr = f.GetLoginRequest() + defer otelx.End(span, &err) - return nil - }) + f, err := flowctx.Decode[flow.Flow](ctx, p.r.FlowCipher(), loginChallenge, flowctx.AsLoginChallenge) + if err != nil { + return nil, errorsx.WithStack(x.ErrNotFound.WithWrap(err)) + } + if f.NID != p.NetworkID(ctx) { + return nil, errorsx.WithStack(x.ErrNotFound) + } + if f.RequestedAt.Add(p.config.ConsentRequestMaxAge(ctx)).Before(time.Now()) { + return nil, errorsx.WithStack(fosite.ErrRequestUnauthorized.WithHint("The login request has expired, please try again.")) + } + lr := f.GetLoginRequest() + // Restore the short challenge ID, which was previously sent to the encoded flow, + // to make sure that the challenge ID in the returned flow matches the param. + lr.ID = loginChallenge + + return lr, nil } -func (p *Persister) HandleConsentRequest(ctx context.Context, r *consent.AcceptOAuth2ConsentRequest) (*consent.OAuth2ConsentRequest, error) { +func (p *Persister) HandleConsentRequest(ctx context.Context, f *flow.Flow, r *flow.AcceptOAuth2ConsentRequest) (_ *flow.OAuth2ConsentRequest, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.HandleConsentRequest") - defer span.End() + defer otelx.End(span, &err) - f := &flow.Flow{} - - if err := sqlcon.HandleError(p.QueryWithNetwork(ctx).Where("consent_challenge_id = ?", r.ID).First(f)); errors.Is(err, sqlcon.ErrNoRows) { - return nil, err + if f == nil { + return nil, errorsx.WithStack(fosite.ErrInvalidRequest.WithDebug("Flow was nil")) } - + if f.NID != p.NetworkID(ctx) { + return nil, errorsx.WithStack(x.ErrNotFound) + } + // Restore the short challenge ID, which was previously sent to the encoded flow, + // to make sure that the challenge ID in the returned flow matches the param. + r.ID = f.ConsentChallengeID.String() if err := f.HandleConsentRequest(r); err != nil { return nil, errorsx.WithStack(err) } - _, err := p.UpdateWithNetwork(ctx, f) - if err != nil { - return nil, sqlcon.HandleError(err) - } - - return p.GetConsentRequest(ctx, r.ID) + return f.GetConsentRequest(), nil } -func (p *Persister) VerifyAndInvalidateConsentRequest(ctx context.Context, verifier string) (*consent.AcceptOAuth2ConsentRequest, error) { +func (p *Persister) VerifyAndInvalidateConsentRequest(ctx context.Context, verifier string) (_ *flow.AcceptOAuth2ConsentRequest, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.VerifyAndInvalidateConsentRequest") - defer span.End() + defer otelx.End(span, &err) - var r consent.AcceptOAuth2ConsentRequest - return &r, p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - var f flow.Flow - if err := p.QueryWithNetwork(ctx).Where("consent_verifier = ?", verifier).First(&f); err != nil { - return sqlcon.HandleError(err) - } + f, err := flowctx.Decode[flow.Flow](ctx, p.r.FlowCipher(), verifier, flowctx.AsConsentVerifier) + if err != nil { + return nil, errorsx.WithStack(fosite.ErrAccessDenied.WithHint("The consent verifier has already been used, has not been granted, or is invalid.")) + } + if f.NID != p.NetworkID(ctx) { + return nil, errorsx.WithStack(sqlcon.ErrNoRows) + } - if err := f.InvalidateConsentRequest(); err != nil { - return errorsx.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error())) - } + if err = f.InvalidateConsentRequest(); err != nil { + return nil, errorsx.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error())) + } - r = *f.GetHandledConsentRequest() - _, err := p.UpdateWithNetwork(ctx, &f) - return err - }) + // We set the consent challenge ID to a new UUID that we can use as a foreign key in the database + // without encoding the whole flow. + f.ConsentChallengeID = sqlxx.NullString(uuid.Must(uuid.NewV4()).String()) + + if err = p.Connection(ctx).Create(f); err != nil { + return nil, sqlcon.HandleError(err) + } + + return f.GetHandledConsentRequest(), nil } -func (p *Persister) HandleLoginRequest(ctx context.Context, challenge string, r *consent.HandledLoginRequest) (lr *consent.LoginRequest, err error) { +func (p *Persister) HandleLoginRequest(ctx context.Context, f *flow.Flow, challenge string, r *flow.HandledLoginRequest) (lr *flow.LoginRequest, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.HandleLoginRequest") - defer span.End() - - return lr, p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - f, err := p.GetFlow(ctx, challenge) - if err != nil { - return sqlcon.HandleError(err) - } - err = f.HandleLoginRequest(r) - if err != nil { - return err - } + defer otelx.End(span, &err) - _, err = p.UpdateWithNetwork(ctx, f) - if err != nil { - return sqlcon.HandleError(err) - } + if f == nil { + return nil, errorsx.WithStack(fosite.ErrInvalidRequest.WithDebug("Flow was nil")) + } + if f.NID != p.NetworkID(ctx) { + return nil, errorsx.WithStack(x.ErrNotFound) + } + r.ID = f.ID + err = f.HandleLoginRequest(r) + if err != nil { + return nil, err + } - lr, err = p.GetLoginRequest(ctx, challenge) - return sqlcon.HandleError(err) - }) + return p.GetLoginRequest(ctx, challenge) } -func (p *Persister) VerifyAndInvalidateLoginRequest(ctx context.Context, verifier string) (*consent.HandledLoginRequest, error) { +func (p *Persister) VerifyAndInvalidateLoginRequest(ctx context.Context, verifier string) (_ *flow.HandledLoginRequest, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.VerifyAndInvalidateLoginRequest") - defer span.End() + defer otelx.End(span, &err) - var d consent.HandledLoginRequest - return &d, p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - var f flow.Flow - if err := p.QueryWithNetwork(ctx).Where("login_verifier = ?", verifier).First(&f); err != nil { - return sqlcon.HandleError(err) - } + f, err := flowctx.Decode[flow.Flow](ctx, p.r.FlowCipher(), verifier, flowctx.AsLoginVerifier) + if err != nil { + return nil, errorsx.WithStack(sqlcon.ErrNoRows) + } + if f.NID != p.NetworkID(ctx) { + return nil, errorsx.WithStack(sqlcon.ErrNoRows) + } - if err := f.InvalidateLoginRequest(); err != nil { - return errorsx.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error())) - } + if err := f.InvalidateLoginRequest(); err != nil { + return nil, errorsx.WithStack(fosite.ErrInvalidRequest.WithDebug(err.Error())) + } + d := f.GetHandledLoginRequest() - d = f.GetHandledLoginRequest() - _, err := p.UpdateWithNetwork(ctx, &f) - return sqlcon.HandleError(err) - }) + return &d, nil } -func (p *Persister) GetRememberedLoginSession(ctx context.Context, id string) (*consent.LoginSession, error) { +func (p *Persister) GetRememberedLoginSession(ctx context.Context, loginSessionFromCookie *flow.LoginSession, id string) (_ *flow.LoginSession, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetRememberedLoginSession") - defer span.End() + defer otelx.End(span, &err) - var s consent.LoginSession + if s := loginSessionFromCookie; s != nil && s.NID == p.NetworkID(ctx) && s.ID == id && s.Remember { + return s, nil + } + + var s flow.LoginSession if err := p.QueryWithNetwork(ctx).Where("remember = TRUE").Find(&s, id); errors.Is(err, sql.ErrNoRows) { return nil, errorsx.WithStack(x.ErrNotFound) @@ -364,49 +375,119 @@ func (p *Persister) GetRememberedLoginSession(ctx context.Context, id string) (* return &s, nil } -func (p *Persister) ConfirmLoginSession(ctx context.Context, id string, authenticatedAt time.Time, subject string, remember bool) error { +// ConfirmLoginSession creates or updates the login session. The NID will be set to the network ID of the context. +func (p *Persister) ConfirmLoginSession(ctx context.Context, loginSession *flow.LoginSession) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ConfirmLoginSession") - defer span.End() + defer otelx.End(span, &err) + + loginSession.NID = p.NetworkID(ctx) + loginSession.AuthenticatedAt = sqlxx.NullTime(time.Time(loginSession.AuthenticatedAt).Truncate(time.Second)) + + if p.Connection(ctx).Dialect.Name() == "mysql" { + // MySQL does not support UPSERT. + return p.mySQLConfirmLoginSession(ctx, loginSession) + } - _, err := p.Connection(ctx).Where("id = ? AND nid = ?", id, p.NetworkID(ctx)).UpdateQuery(&consent.LoginSession{ - AuthenticatedAt: sqlxx.NullTime(authenticatedAt), - Subject: subject, - Remember: remember, - }, "authenticated_at", "subject", "remember") - return sqlcon.HandleError(err) + res, err := p.Connection(ctx).Store.NamedExecContext(ctx, ` +INSERT INTO hydra_oauth2_authentication_session (id, nid, authenticated_at, subject, remember, identity_provider_session_id) +VALUES (:id, :nid, :authenticated_at, :subject, :remember, :identity_provider_session_id) +ON CONFLICT(id) DO +UPDATE SET + authenticated_at = :authenticated_at, + subject = :subject, + remember = :remember, + identity_provider_session_id = :identity_provider_session_id +WHERE hydra_oauth2_authentication_session.id = :id AND hydra_oauth2_authentication_session.nid = :nid +`, loginSession) + if err != nil { + return sqlcon.HandleError(err) + } + n, err := res.RowsAffected() + if err != nil { + return sqlcon.HandleError(err) + } + if n == 0 { + return errorsx.WithStack(x.ErrNotFound) + } + return nil } -func (p *Persister) CreateLoginSession(ctx context.Context, session *consent.LoginSession) error { +func (p *Persister) CreateLoginSession(ctx context.Context, session *flow.LoginSession) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateLoginSession") - defer span.End() + defer otelx.End(span, &err) - return sqlcon.HandleError(p.CreateWithNetwork(ctx, session)) + nid := p.NetworkID(ctx) + if nid == uuid.Nil { + return errorsx.WithStack(x.ErrNotFound) + } + session.NID = nid + + return nil } -func (p *Persister) DeleteLoginSession(ctx context.Context, id string) error { +func (p *Persister) DeleteLoginSession(ctx context.Context, id string) (deletedSession *flow.LoginSession, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteLoginSession") - defer span.End() + defer otelx.End(span, &err) - count, err := p.Connection(ctx).RawQuery("DELETE FROM hydra_oauth2_authentication_session WHERE id=? AND nid = ?", id, p.NetworkID(ctx)).ExecWithCount() - if count == 0 { - return errorsx.WithStack(x.ErrNotFound) - } else { - return sqlcon.HandleError(err) + if p.Connection(ctx).Dialect.Name() == "mysql" { + // MySQL does not support RETURNING. + return p.mySQLDeleteLoginSession(ctx, id) + } + + var session flow.LoginSession + + err = p.Connection(ctx).RawQuery( + `DELETE FROM hydra_oauth2_authentication_session + WHERE id = ? AND nid = ? + RETURNING *`, + id, + p.NetworkID(ctx), + ).First(&session) + if err != nil { + return nil, sqlcon.HandleError(err) } + + return &session, nil } -func (p *Persister) FindGrantedAndRememberedConsentRequests(ctx context.Context, client, subject string) ([]consent.AcceptOAuth2ConsentRequest, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindGrantedAndRememberedConsentRequests") - defer span.End() +func (p *Persister) mySQLDeleteLoginSession(ctx context.Context, id string) (*flow.LoginSession, error) { + var session flow.LoginSession - rs := make([]consent.AcceptOAuth2ConsentRequest, 0) + err := p.Connection(ctx).Transaction(func(tx *pop.Connection) error { + err := tx.RawQuery(` +SELECT * FROM hydra_oauth2_authentication_session +WHERE id = ? AND nid = ?`, + id, + p.NetworkID(ctx), + ).First(&session) + if err != nil { + return err + } - return rs, p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - f := &flow.Flow{} + return p.Connection(ctx).RawQuery(` +DELETE FROM hydra_oauth2_authentication_session +WHERE id = ? AND nid = ?`, + id, + p.NetworkID(ctx), + ).Exec() + }) - if err := c. - Where( - strings.TrimSpace(fmt.Sprintf(` + if err != nil { + return nil, sqlcon.HandleError(err) + } + + return &session, nil + +} + +func (p *Persister) FindGrantedAndRememberedConsentRequests(ctx context.Context, client, subject string) (rs []flow.AcceptOAuth2ConsentRequest, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindGrantedAndRememberedConsentRequests") + defer otelx.End(span, &err) + + var f flow.Flow + if err = p.Connection(ctx). + Where( + strings.TrimSpace(fmt.Sprintf(` (state = %d OR state = %d) AND subject = ? AND client_id = ? AND @@ -414,26 +495,24 @@ consent_skip=FALSE AND consent_error='{}' AND consent_remember=TRUE AND nid = ?`, flow.FlowStateConsentUsed, flow.FlowStateConsentUnused, - )), - subject, client, p.NetworkID(ctx)). - Order("requested_at DESC"). - Limit(1). - First(f); err != nil { - if errors.Is(err, sql.ErrNoRows) { - return errorsx.WithStack(consent.ErrNoPreviousConsentFound) - } - return sqlcon.HandleError(err) + )), + subject, client, p.NetworkID(ctx)). + Order("requested_at DESC"). + Limit(1). + First(&f); err != nil { + if errors.Is(err, sql.ErrNoRows) { + return nil, errorsx.WithStack(consent.ErrNoPreviousConsentFound) } + return nil, sqlcon.HandleError(err) + } - var err error - rs, err = p.filterExpiredConsentRequests(ctx, []consent.AcceptOAuth2ConsentRequest{*f.GetHandledConsentRequest()}) - return err - }) + return p.filterExpiredConsentRequests(ctx, []flow.AcceptOAuth2ConsentRequest{*f.GetHandledConsentRequest()}) } -func (p *Persister) FindSubjectsGrantedConsentRequests(ctx context.Context, subject string, limit, offset int) ([]consent.AcceptOAuth2ConsentRequest, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindSubjectsGrantedConsentRequests") - defer span.End() +func (p *Persister) FindSubjectsGrantedConsentRequests(ctx context.Context, subject string, limit, offset int) (_ []flow.AcceptOAuth2ConsentRequest, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindSubjectsGrantedConsentRequests", + trace.WithAttributes(attribute.Int("limit", limit), attribute.Int("offset", offset))) + defer otelx.End(span, &err) var fs []flow.Flow c := p.Connection(ctx) @@ -457,7 +536,7 @@ nid = ?`, flow.FlowStateConsentUsed, flow.FlowStateConsentUnused, return nil, sqlcon.HandleError(err) } - var rs []consent.AcceptOAuth2ConsentRequest + var rs []flow.AcceptOAuth2ConsentRequest for _, f := range fs { rs = append(rs, *f.GetHandledConsentRequest()) } @@ -465,9 +544,10 @@ nid = ?`, flow.FlowStateConsentUsed, flow.FlowStateConsentUnused, return p.filterExpiredConsentRequests(ctx, rs) } -func (p *Persister) FindSubjectsSessionGrantedConsentRequests(ctx context.Context, subject, sid string, limit, offset int) ([]consent.AcceptOAuth2ConsentRequest, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindSubjectsSessionGrantedConsentRequests") - defer span.End() +func (p *Persister) FindSubjectsSessionGrantedConsentRequests(ctx context.Context, subject, sid string, limit, offset int) (_ []flow.AcceptOAuth2ConsentRequest, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FindSubjectsSessionGrantedConsentRequests", + trace.WithAttributes(attribute.String("sid", sid), attribute.Int("limit", limit), attribute.Int("offset", offset))) + defer otelx.End(span, &err) var fs []flow.Flow c := p.Connection(ctx) @@ -492,7 +572,7 @@ nid = ?`, flow.FlowStateConsentUsed, flow.FlowStateConsentUnused, return nil, sqlcon.HandleError(err) } - var rs []consent.AcceptOAuth2ConsentRequest + var rs []flow.AcceptOAuth2ConsentRequest for _, f := range fs { rs = append(rs, *f.GetHandledConsentRequest()) } @@ -500,11 +580,14 @@ nid = ?`, flow.FlowStateConsentUsed, flow.FlowStateConsentUnused, return p.filterExpiredConsentRequests(ctx, rs) } -func (p *Persister) CountSubjectsGrantedConsentRequests(ctx context.Context, subject string) (int, error) { +func (p *Persister) CountSubjectsGrantedConsentRequests(ctx context.Context, subject string) (n int, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CountSubjectsGrantedConsentRequests") - defer span.End() + defer otelx.End(span, &err) + defer func() { + span.SetAttributes(attribute.Int("count", n)) + }() - n, err := p.Connection(ctx). + n, err = p.Connection(ctx). Where( strings.TrimSpace(fmt.Sprintf(` (state = %d OR state = %d) AND @@ -518,11 +601,11 @@ nid = ?`, flow.FlowStateConsentUsed, flow.FlowStateConsentUnused, return n, sqlcon.HandleError(err) } -func (p *Persister) filterExpiredConsentRequests(ctx context.Context, requests []consent.AcceptOAuth2ConsentRequest) ([]consent.AcceptOAuth2ConsentRequest, error) { +func (p *Persister) filterExpiredConsentRequests(ctx context.Context, requests []flow.AcceptOAuth2ConsentRequest) (_ []flow.AcceptOAuth2ConsentRequest, err error) { _, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.filterExpiredConsentRequests") - defer span.End() + defer otelx.End(span, &err) - var result []consent.AcceptOAuth2ConsentRequest + var result []flow.AcceptOAuth2ConsentRequest for _, v := range requests { if v.RememberFor > 0 && v.RequestedAt.Add(time.Duration(v.RememberFor)*time.Second).Before(time.Now().UTC()) { continue @@ -535,62 +618,61 @@ func (p *Persister) filterExpiredConsentRequests(ctx context.Context, requests [ return result, nil } -func (p *Persister) ListUserAuthenticatedClientsWithFrontChannelLogout(ctx context.Context, subject, sid string) ([]client.Client, error) { +func (p *Persister) ListUserAuthenticatedClientsWithFrontChannelLogout(ctx context.Context, subject, sid string) (_ []client.Client, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListUserAuthenticatedClientsWithFrontChannelLogout") - defer span.End() + defer otelx.End(span, &err) return p.listUserAuthenticatedClients(ctx, subject, sid, "front") } -func (p *Persister) ListUserAuthenticatedClientsWithBackChannelLogout(ctx context.Context, subject, sid string) ([]client.Client, error) { +func (p *Persister) ListUserAuthenticatedClientsWithBackChannelLogout(ctx context.Context, subject, sid string) (_ []client.Client, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ListUserAuthenticatedClientsWithBackChannelLogout") - defer span.End() + defer otelx.End(span, &err) + return p.listUserAuthenticatedClients(ctx, subject, sid, "back") } -func (p *Persister) listUserAuthenticatedClients(ctx context.Context, subject, sid, channel string) ([]client.Client, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.listUserAuthenticatedClients") - defer span.End() +func (p *Persister) listUserAuthenticatedClients(ctx context.Context, subject, sid, channel string) (cs []client.Client, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.listUserAuthenticatedClients", + trace.WithAttributes(attribute.String("sid", sid))) + defer otelx.End(span, &err) - var cs []client.Client - return cs, p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - if err := c.RawQuery( - /* #nosec G201 - channel can either be "front" or "back" */ - fmt.Sprintf(` + if err := p.Connection(ctx).RawQuery( + /* #nosec G201 - channel can either be "front" or "back" */ + fmt.Sprintf(` SELECT DISTINCT c.* FROM hydra_client as c -JOIN hydra_oauth2_flow as f ON (c.id = f.client_id) +JOIN hydra_oauth2_flow as f ON (c.id = f.client_id AND c.nid = f.nid) WHERE f.subject=? AND - c.%schannel_logout_uri!='' AND + c.%schannel_logout_uri != '' AND c.%schannel_logout_uri IS NOT NULL AND f.login_session_id = ? AND f.nid = ? AND c.nid = ?`, - channel, - channel, - ), - subject, - sid, - p.NetworkID(ctx), - p.NetworkID(ctx), - ).All(&cs); err != nil { - return sqlcon.HandleError(err) - } + channel, + channel, + ), + subject, + sid, + p.NetworkID(ctx), + p.NetworkID(ctx), + ).All(&cs); err != nil { + return nil, sqlcon.HandleError(err) + } - return nil - }) + return cs, nil } -func (p *Persister) CreateLogoutRequest(ctx context.Context, request *consent.LogoutRequest) error { +func (p *Persister) CreateLogoutRequest(ctx context.Context, request *flow.LogoutRequest) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateLogoutRequest") - defer span.End() + defer otelx.End(span, &err) return errorsx.WithStack(p.CreateWithNetwork(ctx, request)) } -func (p *Persister) AcceptLogoutRequest(ctx context.Context, challenge string) (*consent.LogoutRequest, error) { +func (p *Persister) AcceptLogoutRequest(ctx context.Context, challenge string) (_ *flow.LogoutRequest, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.AcceptLogoutRequest") - defer span.End() + defer otelx.End(span, &err) if err := p.Connection(ctx).RawQuery("UPDATE hydra_oauth2_logout_request SET accepted=true, rejected=false WHERE challenge=? AND nid = ?", challenge, p.NetworkID(ctx)).Exec(); err != nil { return nil, sqlcon.HandleError(err) @@ -599,9 +681,9 @@ func (p *Persister) AcceptLogoutRequest(ctx context.Context, challenge string) ( return p.GetLogoutRequest(ctx, challenge) } -func (p *Persister) RejectLogoutRequest(ctx context.Context, challenge string) error { +func (p *Persister) RejectLogoutRequest(ctx context.Context, challenge string) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RejectLogoutRequest") - defer span.End() + defer otelx.End(span, &err) count, err := p.Connection(ctx). RawQuery("UPDATE hydra_oauth2_logout_request SET rejected=true, accepted=false WHERE challenge=? AND nid = ?", challenge, p.NetworkID(ctx)). @@ -613,42 +695,52 @@ func (p *Persister) RejectLogoutRequest(ctx context.Context, challenge string) e } } -func (p *Persister) GetLogoutRequest(ctx context.Context, challenge string) (*consent.LogoutRequest, error) { +func (p *Persister) GetLogoutRequest(ctx context.Context, challenge string) (_ *flow.LogoutRequest, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetLogoutRequest") - defer span.End() + defer otelx.End(span, &err) - var lr consent.LogoutRequest + var lr flow.LogoutRequest return &lr, sqlcon.HandleError(p.QueryWithNetwork(ctx).Where("challenge = ? AND rejected = FALSE", challenge).First(&lr)) } -func (p *Persister) VerifyAndInvalidateLogoutRequest(ctx context.Context, verifier string) (*consent.LogoutRequest, error) { +func (p *Persister) VerifyAndInvalidateLogoutRequest(ctx context.Context, verifier string) (_ *flow.LogoutRequest, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.VerifyAndInvalidateLogoutRequest") - defer span.End() + defer otelx.End(span, &err) + + var lr flow.LogoutRequest + if count, err := p.Connection(ctx).RawQuery(` +UPDATE hydra_oauth2_logout_request + SET was_used = TRUE +WHERE nid = ? + AND verifier = ? + AND accepted = TRUE + AND rejected = FALSE`, + p.NetworkID(ctx), + verifier, + ).ExecWithCount(); count == 0 && err == nil { + return nil, errorsx.WithStack(x.ErrNotFound) + } else if err != nil { + return nil, sqlcon.HandleError(err) + } - var lr consent.LogoutRequest - return &lr, p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - if count, err := c.RawQuery( - "UPDATE hydra_oauth2_logout_request SET was_used=TRUE WHERE nid = ? AND verifier=? AND was_used=FALSE AND accepted=TRUE AND rejected=FALSE", - p.NetworkID(ctx), - verifier, - ).ExecWithCount(); count == 0 && err == nil { - return errorsx.WithStack(x.ErrNotFound) - } else if err != nil { - return sqlcon.HandleError(err) - } + err = sqlcon.HandleError(p.QueryWithNetwork(ctx).Where("verifier = ?", verifier).First(&lr)) + if err != nil { + return nil, err + } - err := sqlcon.HandleError(p.QueryWithNetwork(ctx).Where("verifier=?", verifier).First(&lr)) - if err != nil { - return err - } + if expiry := time.Time(lr.ExpiresAt); + // If the expiry is unset, we are in a legacy use case (allow logout). + // TODO: Remove this in the future. + !expiry.IsZero() && expiry.Before(time.Now().UTC()) { + return nil, errorsx.WithStack(flow.ErrorLogoutFlowExpired) + } - return nil - }) + return &lr, nil } -func (p *Persister) FlushInactiveLoginConsentRequests(ctx context.Context, notAfter time.Time, limit int, batchSize int) error { +func (p *Persister) FlushInactiveLoginConsentRequests(ctx context.Context, notAfter time.Time, limit int, batchSize int) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FlushInactiveLoginConsentRequests") - defer span.End() + defer otelx.End(span, &err) /* #nosec G201 table is static */ var f flow.Flow @@ -707,3 +799,26 @@ func (p *Persister) FlushInactiveLoginConsentRequests(ctx context.Context, notAf return nil } + +func (p *Persister) mySQLConfirmLoginSession(ctx context.Context, session *flow.LoginSession) error { + err := sqlcon.HandleError(p.Connection(ctx).Create(session)) + if err == nil { + return nil + } + + if !errors.Is(err, sqlcon.ErrUniqueViolation) { + return err + } + + n, err := p.Connection(ctx). + Where("id = ? and nid = ?", session.ID, session.NID). + UpdateQuery(session, "authenticated_at", "subject", "identity_provider_session_id", "remember") + if err != nil { + return errors.WithStack(sqlcon.HandleError(err)) + } + if n == 0 { + return errorsx.WithStack(x.ErrNotFound) + } + + return nil +} diff --git a/persistence/sql/persister_grant_jwk.go b/persistence/sql/persister_grant_jwk.go index 3c1c668cfb7..acbf0e38766 100644 --- a/persistence/sql/persister_grant_jwk.go +++ b/persistence/sql/persister_grant_jwk.go @@ -8,12 +8,15 @@ import ( "strings" "time" + "github.com/ory/hydra/v2/jwk" + "github.com/pkg/errors" + "github.com/go-jose/go-jose/v3" "github.com/gobuffalo/pop/v6" - "gopkg.in/square/go-jose.v2" - "github.com/ory/hydra/oauth2/trust" + "github.com/ory/hydra/v2/oauth2/trust" + "github.com/ory/x/otelx" "github.com/ory/x/stringsx" "github.com/ory/x/sqlcon" @@ -21,11 +24,11 @@ import ( var _ trust.GrantManager = &Persister{} -func (p *Persister) CreateGrant(ctx context.Context, g trust.Grant, publicKey jose.JSONWebKey) error { +func (p *Persister) CreateGrant(ctx context.Context, g trust.Grant, publicKey jose.JSONWebKey) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateGrant") - defer span.End() + defer otelx.End(span, &err) - return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { + return p.Transaction(ctx, func(ctx context.Context, c *pop.Connection) error { // add key, if it doesn't exist if _, err := p.GetKey(ctx, g.PublicKey.Set, g.PublicKey.KeyID); err != nil { if !errors.Is(err, sqlcon.ErrNoRows) { @@ -42,9 +45,9 @@ func (p *Persister) CreateGrant(ctx context.Context, g trust.Grant, publicKey jo }) } -func (p *Persister) GetConcreteGrant(ctx context.Context, id string) (trust.Grant, error) { +func (p *Persister) GetConcreteGrant(ctx context.Context, id string) (_ trust.Grant, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetConcreteGrant") - defer span.End() + defer otelx.End(span, &err) var data trust.SQLData if err := p.QueryWithNetwork(ctx).Where("id = ?", id).First(&data); err != nil { @@ -54,11 +57,11 @@ func (p *Persister) GetConcreteGrant(ctx context.Context, id string) (trust.Gran return p.jwtGrantFromSQlData(data), nil } -func (p *Persister) DeleteGrant(ctx context.Context, id string) error { +func (p *Persister) DeleteGrant(ctx context.Context, id string) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteGrant") - defer span.End() + defer otelx.End(span, &err) - return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { + return p.Transaction(ctx, func(ctx context.Context, c *pop.Connection) error { grant, err := p.GetConcreteGrant(ctx, id) if err != nil { return sqlcon.HandleError(err) @@ -72,9 +75,9 @@ func (p *Persister) DeleteGrant(ctx context.Context, id string) error { }) } -func (p *Persister) GetGrants(ctx context.Context, limit, offset int, optionalIssuer string) ([]trust.Grant, error) { +func (p *Persister) GetGrants(ctx context.Context, limit, offset int, optionalIssuer string) (_ []trust.Grant, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetGrants") - defer span.End() + defer otelx.End(span, &err) grantsData := make([]trust.SQLData, 0) @@ -97,23 +100,23 @@ func (p *Persister) GetGrants(ctx context.Context, limit, offset int, optionalIs return grants, nil } -func (p *Persister) CountGrants(ctx context.Context) (int, error) { +func (p *Persister) CountGrants(ctx context.Context) (n int, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CountGrants") - defer span.End() + defer otelx.End(span, &err) - n, err := p.QueryWithNetwork(ctx). + n, err = p.QueryWithNetwork(ctx). Count(&trust.SQLData{}) return n, sqlcon.HandleError(err) } -func (p *Persister) GetPublicKey(ctx context.Context, issuer string, subject string, keyId string) (*jose.JSONWebKey, error) { +func (p *Persister) GetPublicKey(ctx context.Context, issuer string, subject string, keyId string) (_ *jose.JSONWebKey, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetPublicKey") - defer span.End() + defer otelx.End(span, &err) var data trust.SQLData query := p.QueryWithNetwork(ctx). Where("issuer = ?", issuer). - Where("subject = ? OR allow_any_subject IS TRUE", subject). + Where("(subject = ? OR allow_any_subject IS TRUE)", subject). Where("key_id = ?", keyId). Where("nid = ?", p.NetworkID(ctx)) if err := query.First(&data); err != nil { @@ -128,15 +131,23 @@ func (p *Persister) GetPublicKey(ctx context.Context, issuer string, subject str return &keySet.Keys[0], nil } -func (p *Persister) GetPublicKeys(ctx context.Context, issuer string, subject string) (*jose.JSONWebKeySet, error) { +func (p *Persister) GetPublicKeys(ctx context.Context, issuer string, subject string) (_ *jose.JSONWebKeySet, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetPublicKeys") - defer span.End() + defer otelx.End(span, &err) + + expiresAt := "expires_at > NOW()" + if p.conn.Dialect.Name() == "sqlite3" { + expiresAt = "expires_at > datetime('now')" + } grantsData := make([]trust.SQLData, 0) query := p.QueryWithNetwork(ctx). + Select("key_id"). + Where(expiresAt). Where("issuer = ?", issuer). - Where("subject = ? OR allow_any_subject IS TRUE", subject). - Where("nid = ?", p.NetworkID(ctx)) + Where("(subject = ? OR allow_any_subject IS TRUE)", subject). + Order("created_at DESC"). + Limit(100) // Load maximum of 100 keys if err := query.All(&grantsData); err != nil { return nil, sqlcon.HandleError(err) @@ -146,31 +157,48 @@ func (p *Persister) GetPublicKeys(ctx context.Context, issuer string, subject st return &jose.JSONWebKeySet{}, nil } - // because keys must be grouped by issuer, we can retrieve set name from first grant - keySet, err := p.GetKeySet(ctx, grantsData[0].KeySet) - if err != nil { - return nil, err + keyIDs := make([]interface{}, len(grantsData)) + for k, d := range grantsData { + keyIDs[k] = d.KeyID } - // find keys, that belong to grants - filteredKeySet := &jose.JSONWebKeySet{} - for _, data := range grantsData { - if keys := keySet.Key(data.KeyID); len(keys) > 0 { - filteredKeySet.Keys = append(filteredKeySet.Keys, keys...) - } + var js jwk.SQLDataRows + if err := p.QueryWithNetwork(ctx). + // key_set and issuer are set to the same value on creation: + // + // grant := Grant{ + // ID: uuid.New().String(), + // Issuer: grantRequest.Issuer, + // Subject: grantRequest.Subject, + // AllowAnySubject: grantRequest.AllowAnySubject, + // Scope: grantRequest.Scope, + // PublicKey: PublicKey{ + // Set: grantRequest.Issuer, // group all keys by issuer, so set=issuer + // KeyID: grantRequest.PublicKeyJWK.KeyID, + // }, + // CreatedAt: time.Now().UTC().Round(time.Second), + // ExpiresAt: grantRequest.ExpiresAt.UTC().Round(time.Second), + // } + // + // Therefore it is fine if we only look for the issuer here instead of the key set id. + Where("sid = ?", issuer). + Where("kid IN (?)", keyIDs). + Order("created_at DESC"). + All(&js); err != nil { + return nil, sqlcon.HandleError(err) } - return filteredKeySet, nil + return js.ToJWK(ctx, p.r) } -func (p *Persister) GetPublicKeyScopes(ctx context.Context, issuer string, subject string, keyId string) ([]string, error) { +func (p *Persister) GetPublicKeyScopes(ctx context.Context, issuer string, subject string, keyId string) (_ []string, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetPublicKeyScopes") - defer span.End() + defer otelx.End(span, &err) var data trust.SQLData query := p.QueryWithNetwork(ctx). Where("issuer = ?", issuer). - Where("subject = ? OR allow_any_subject IS TRUE", subject). + Where("(subject = ? OR allow_any_subject IS TRUE)", subject). Where("key_id = ?", keyId). Where("nid = ?", p.NetworkID(ctx)) @@ -181,11 +209,11 @@ func (p *Persister) GetPublicKeyScopes(ctx context.Context, issuer string, subje return p.jwtGrantFromSQlData(data).Scope, nil } -func (p *Persister) IsJWTUsed(ctx context.Context, jti string) (bool, error) { +func (p *Persister) IsJWTUsed(ctx context.Context, jti string) (ok bool, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.IsJWTUsed") - defer span.End() + defer otelx.End(span, &err) - err := p.ClientAssertionJWTValid(ctx, jti) + err = p.ClientAssertionJWTValid(ctx, jti) if err != nil { return true, nil } @@ -193,9 +221,9 @@ func (p *Persister) IsJWTUsed(ctx context.Context, jti string) (bool, error) { return false, nil } -func (p *Persister) MarkJWTUsedForTime(ctx context.Context, jti string, exp time.Time) error { +func (p *Persister) MarkJWTUsedForTime(ctx context.Context, jti string, exp time.Time) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.MarkJWTUsedForTime") - defer span.End() + defer otelx.End(span, &err) return p.SetClientAssertionJWT(ctx, jti, exp) } @@ -230,9 +258,9 @@ func (p *Persister) jwtGrantFromSQlData(data trust.SQLData) trust.Grant { } } -func (p *Persister) FlushInactiveGrants(ctx context.Context, notAfter time.Time, limit int, batchSize int) error { +func (p *Persister) FlushInactiveGrants(ctx context.Context, notAfter time.Time, _ int, _ int) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FlushInactiveGrants") - defer span.End() + defer otelx.End(span, &err) deleteUntil := time.Now().UTC() if deleteUntil.After(notAfter) { diff --git a/persistence/sql/persister_jwk.go b/persistence/sql/persister_jwk.go index ad4e8dc3bde..27a6e184a2b 100644 --- a/persistence/sql/persister_jwk.go +++ b/persistence/sql/persister_jwk.go @@ -7,23 +7,29 @@ import ( "context" "encoding/json" + "github.com/go-jose/go-jose/v3" "github.com/gobuffalo/pop/v6" - "gopkg.in/square/go-jose.v2" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "github.com/ory/x/errorsx" + "github.com/ory/x/otelx" "github.com/pkg/errors" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/jwk" "github.com/ory/x/sqlcon" ) var _ jwk.Manager = &Persister{} -func (p *Persister) GenerateAndPersistKeySet(ctx context.Context, set, kid, alg, use string) (*jose.JSONWebKeySet, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GenerateAndPersistKey") - defer span.End() +func (p *Persister) GenerateAndPersistKeySet(ctx context.Context, set, kid, alg, use string) (_ *jose.JSONWebKeySet, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GenerateAndPersistKeySet", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", kid), + attribute.String("alg", alg))) + defer otelx.End(span, &err) keys, err := jwk.GenerateJWK(ctx, jose.SignatureAlgorithm(alg), kid, use) if err != nil { @@ -38,16 +44,20 @@ func (p *Persister) GenerateAndPersistKeySet(ctx context.Context, set, kid, alg, return keys, nil } -func (p *Persister) AddKey(ctx context.Context, set string, key *jose.JSONWebKey) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.AddKey") - defer span.End() +func (p *Persister) AddKey(ctx context.Context, set string, key *jose.JSONWebKey) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.AddKey", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", key.KeyID))) + + defer otelx.End(span, &err) out, err := json.Marshal(key) if err != nil { return errorsx.WithStack(err) } - encrypted, err := p.r.KeyCipher().Encrypt(ctx, out) + encrypted, err := p.r.KeyCipher().Encrypt(ctx, out, nil) if err != nil { return errorsx.WithStack(err) } @@ -60,18 +70,18 @@ func (p *Persister) AddKey(ctx context.Context, set string, key *jose.JSONWebKey })) } -func (p *Persister) AddKeySet(ctx context.Context, set string, keys *jose.JSONWebKeySet) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.AddKey") - defer span.End() +func (p *Persister) AddKeySet(ctx context.Context, set string, keys *jose.JSONWebKeySet) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.AddKeySet", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) - return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { + return p.Transaction(ctx, func(ctx context.Context, c *pop.Connection) error { for _, key := range keys.Keys { out, err := json.Marshal(key) if err != nil { return errorsx.WithStack(err) } - encrypted, err := p.r.KeyCipher().Encrypt(ctx, out) + encrypted, err := p.r.KeyCipher().Encrypt(ctx, out, nil) if err != nil { return err } @@ -90,11 +100,14 @@ func (p *Persister) AddKeySet(ctx context.Context, set string, keys *jose.JSONWe } // UpdateKey updates or creates the key. -func (p *Persister) UpdateKey(ctx context.Context, set string, key *jose.JSONWebKey) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateKey") - defer span.End() - - return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { +func (p *Persister) UpdateKey(ctx context.Context, set string, key *jose.JSONWebKey) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateKey", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", key.KeyID))) + defer otelx.End(span, &err) + + return p.Transaction(ctx, func(ctx context.Context, c *pop.Connection) error { if err := p.DeleteKey(ctx, set, key.KeyID); err != nil { return err } @@ -106,11 +119,11 @@ func (p *Persister) UpdateKey(ctx context.Context, set string, key *jose.JSONWeb } // UpdateKeySet updates or creates the key set. -func (p *Persister) UpdateKeySet(ctx context.Context, set string, keySet *jose.JSONWebKeySet) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateKeySet") - defer span.End() +func (p *Persister) UpdateKeySet(ctx context.Context, set string, keySet *jose.JSONWebKeySet) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.UpdateKeySet", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) - return p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { + return p.Transaction(ctx, func(ctx context.Context, c *pop.Connection) error { if err := p.DeleteKeySet(ctx, set); err != nil { return err } @@ -121,9 +134,12 @@ func (p *Persister) UpdateKeySet(ctx context.Context, set string, keySet *jose.J }) } -func (p *Persister) GetKey(ctx context.Context, set, kid string) (*jose.JSONWebKeySet, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetKey") - defer span.End() +func (p *Persister) GetKey(ctx context.Context, set, kid string) (_ *jose.JSONWebKeySet, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetKey", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", kid))) + defer otelx.End(span, &err) var j jwk.SQLData if err := p.QueryWithNetwork(ctx). @@ -133,7 +149,7 @@ func (p *Persister) GetKey(ctx context.Context, set, kid string) (*jose.JSONWebK return nil, sqlcon.HandleError(err) } - key, err := p.r.KeyCipher().Decrypt(ctx, j.Key) + key, err := p.r.KeyCipher().Decrypt(ctx, j.Key, nil) if err != nil { return nil, errorsx.WithStack(err) } @@ -148,11 +164,11 @@ func (p *Persister) GetKey(ctx context.Context, set, kid string) (*jose.JSONWebK }, nil } -func (p *Persister) GetKeySet(ctx context.Context, set string) (*jose.JSONWebKeySet, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetKeySet") - defer span.End() +func (p *Persister) GetKeySet(ctx context.Context, set string) (keys *jose.JSONWebKeySet, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetKeySet", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) - var js []jwk.SQLData + var js jwk.SQLDataRows if err := p.QueryWithNetwork(ctx). Where("sid = ?", set). Order("created_at DESC"). @@ -160,43 +176,24 @@ func (p *Persister) GetKeySet(ctx context.Context, set string) (*jose.JSONWebKey return nil, sqlcon.HandleError(err) } - if len(js) == 0 { - return nil, errors.Wrap(x.ErrNotFound, "") - } - - keys := &jose.JSONWebKeySet{Keys: []jose.JSONWebKey{}} - for _, d := range js { - key, err := p.r.KeyCipher().Decrypt(ctx, d.Key) - if err != nil { - return nil, errorsx.WithStack(err) - } - - var c jose.JSONWebKey - if err := json.Unmarshal(key, &c); err != nil { - return nil, errorsx.WithStack(err) - } - keys.Keys = append(keys.Keys, c) - } - - if len(keys.Keys) == 0 { - return nil, errorsx.WithStack(x.ErrNotFound) - } - - return keys, nil + return js.ToJWK(ctx, p.r) } -func (p *Persister) DeleteKey(ctx context.Context, set, kid string) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteKey") - defer span.End() +func (p *Persister) DeleteKey(ctx context.Context, set, kid string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteKey", + trace.WithAttributes( + attribute.String("set", set), + attribute.String("kid", kid))) + defer otelx.End(span, &err) - err := p.QueryWithNetwork(ctx).Where("sid=? AND kid=?", set, kid).Delete(&jwk.SQLData{}) + err = p.QueryWithNetwork(ctx).Where("sid=? AND kid=?", set, kid).Delete(&jwk.SQLData{}) return sqlcon.HandleError(err) } -func (p *Persister) DeleteKeySet(ctx context.Context, set string) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteKeySet") - defer span.End() +func (p *Persister) DeleteKeySet(ctx context.Context, set string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteKeySet", trace.WithAttributes(attribute.String("set", set))) + defer otelx.End(span, &err) - err := p.QueryWithNetwork(ctx).Where("sid=?", set).Delete(&jwk.SQLData{}) + err = p.QueryWithNetwork(ctx).Where("sid=?", set).Delete(&jwk.SQLData{}) return sqlcon.HandleError(err) } diff --git a/persistence/sql/persister_migration.go b/persistence/sql/persister_migration.go index f82605c90b4..419bb3c835a 100644 --- a/persistence/sql/persister_migration.go +++ b/persistence/sql/persister_migration.go @@ -21,7 +21,7 @@ import ( ) //go:embed migrations/*.sql -var migrations embed.FS +var Migrations embed.FS func (p *Persister) MigrationStatus(ctx context.Context) (popx.MigrationStatuses, error) { if p.mbs != nil { diff --git a/persistence/sql/persister_nid_test.go b/persistence/sql/persister_nid_test.go index ae4410a4af4..5d556d44b4d 100644 --- a/persistence/sql/persister_nid_test.go +++ b/persistence/sql/persister_nid_test.go @@ -6,29 +6,35 @@ package sql_test import ( "context" "database/sql" + "encoding/json" "testing" "time" + "github.com/ory/fosite/handler/openid" + + "github.com/stretchr/testify/assert" + + "github.com/ory/hydra/v2/persistence" "github.com/ory/x/uuidx" "github.com/ory/x/assertx" + "github.com/go-jose/go-jose/v3" "github.com/gofrs/uuid" - "github.com/instana/testify/require" + "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" - "gopkg.in/square/go-jose.v2" "github.com/ory/fosite" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/flow" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/jwk" - "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/oauth2/trust" - persistencesql "github.com/ory/hydra/persistence/sql" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/consent" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/flow" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/jwk" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/oauth2/trust" + persistencesql "github.com/ory/hydra/v2/persistence/sql" + "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" "github.com/ory/x/dbal" "github.com/ory/x/networkx" @@ -38,14 +44,16 @@ import ( type PersisterTestSuite struct { suite.Suite registries map[string]driver.Registry - clean func(*testing.T) t1 context.Context t2 context.Context t1NID uuid.UUID t2NID uuid.UUID } -var _ PersisterTestSuite = PersisterTestSuite{} +var _ interface { + suite.SetupAllSuite + suite.TearDownTestSuite +} = (*PersisterTestSuite)(nil) func (s *PersisterTestSuite) SetupSuite() { s.registries = map[string]driver.Registry{ @@ -53,7 +61,7 @@ func (s *PersisterTestSuite) SetupSuite() { } if !testing.Short() { - s.registries["postgres"], s.registries["mysql"], s.registries["cockroach"], s.clean = internal.ConnectDatabases(s.T(), true, &contextx.Default{}) + s.registries["postgres"], s.registries["mysql"], s.registries["cockroach"], _ = internal.ConnectDatabases(s.T(), true, &contextx.Default{}) } s.t1NID, s.t2NID = uuid.Must(uuid.NewV4()), uuid.Must(uuid.NewV4()) @@ -88,7 +96,7 @@ func (s *PersisterTestSuite) TestAcceptLogoutRequest() { lrAccepted, err := r.ConsentManager().AcceptLogoutRequest(s.t2, lr.ID) require.Error(t, err) - require.Equal(t, &consent.LogoutRequest{}, lrAccepted) + require.Equal(t, &flow.LogoutRequest{}, lrAccepted) actual, err := r.ConsentManager().GetLogoutRequest(s.t1, lr.ID) require.NoError(t, err) @@ -149,14 +157,14 @@ func (s *PersisterTestSuite) TestAuthenticate() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id", Secret: "secret"} + client := &client.Client{ID: "client-id", Secret: "secret"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) - actual, err := r.Persister().Authenticate(s.t2, "client-id", []byte("secret")) + actual, err := r.Persister().AuthenticateClient(s.t2, "client-id", []byte("secret")) require.Error(t, err) require.Nil(t, actual) - actual, err = r.Persister().Authenticate(s.t1, "client-id", []byte("secret")) + actual, err = r.Persister().AuthenticateClient(s.t1, "client-id", []byte("secret")) require.NoError(t, err) require.NotNil(t, actual) }) @@ -179,20 +187,25 @@ func (s *PersisterTestSuite) TestClientAssertionJWTValid() { func (s *PersisterTestSuite) TestConfirmLoginSession() { t := s.T() ls := newLoginSession() + ls.AuthenticatedAt = sqlxx.NullTime(time.Now().UTC()) + ls.Remember = true for k, r := range s.registries { t.Run(k, func(t *testing.T) { require.NoError(t, r.Persister().CreateLoginSession(s.t1, ls)) - expected := &consent.LoginSession{} - require.NoError(t, r.Persister().Connection(context.Background()).Find(expected, ls.ID)) - require.NoError(t, r.Persister().ConfirmLoginSession(s.t2, expected.ID, time.Now(), expected.Subject, !expected.Remember)) - actual := &consent.LoginSession{} + // Expects the login session to be confirmed in the correct context. + require.NoError(t, r.Persister().ConfirmLoginSession(s.t1, ls)) + actual := &flow.LoginSession{} require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, ls.ID)) - require.Equal(t, expected, actual) + exp, _ := json.Marshal(ls) + act, _ := json.Marshal(actual) + require.JSONEq(t, string(exp), string(act)) - require.NoError(t, r.Persister().ConfirmLoginSession(s.t1, expected.ID, time.Now(), expected.Subject, !expected.Remember)) - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, ls.ID)) - require.NotEqual(t, expected, actual) + // Can't find the login session in the wrong context. + require.ErrorIs(t, + r.Persister().ConfirmLoginSession(s.t2, ls), + x.ErrNotFound, + ) }) } } @@ -202,8 +215,8 @@ func (s *PersisterTestSuite) TestCreateSession() { ls := newLoginSession() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - require.NoError(t, r.Persister().CreateLoginSession(s.t1, ls)) - actual := &consent.LoginSession{} + persistLoginSession(s.t1, t, r.Persister(), ls) + actual := &flow.LoginSession{} require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, ls.ID)) require.Equal(t, s.t1NID, actual.NID) ls.NID = actual.NID @@ -280,12 +293,12 @@ func (s *PersisterTestSuite) TestCountSubjectsGrantedConsentRequests() { require.Equal(t, 0, count) sessionID := uuid.Must(uuid.NewV4()).String() - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) - client := &client.Client{LegacyClientID: "client-id"} + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) - f := newFlow(s.t1NID, client.LegacyClientID, sub, sqlxx.NullString(sessionID)) + f := newFlow(s.t1NID, client.ID, sub, sqlxx.NullString(sessionID)) f.ConsentSkip = false - f.ConsentError = &consent.RequestDeniedError{} + f.ConsentError = &flow.RequestDeniedError{} f.State = flow.FlowStateConsentUnused require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) @@ -304,17 +317,18 @@ func (s *PersisterTestSuite) TestCreateAccessTokenSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - c1 := &client.Client{LegacyClientID: "client-id"} + c1 := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, c1)) - c2 := &client.Client{LegacyClientID: "client-id"} + c2 := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t2, c2)) sig := uuid.Must(uuid.NewV4()).String() fr := fosite.NewRequest() - fr.Client = &fosite.DefaultClient{ID: c1.LegacyClientID} + fr.Client = &fosite.DefaultClient{ID: c1.ID} + fr.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} require.NoError(t, r.Persister().CreateAccessTokenSession(s.t1, sig, fr)) actual := persistencesql.OAuth2RequestSQL{Table: "access"} - require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) + require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, x.SignatureHash(sig))) require.Equal(t, s.t1NID, actual.NID) }) } @@ -324,13 +338,14 @@ func (s *PersisterTestSuite) TestCreateAuthorizeCodeSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - c1 := &client.Client{LegacyClientID: "client-id"} + c1 := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, c1)) - c2 := &client.Client{LegacyClientID: "client-id"} + c2 := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t2, c2)) sig := uuid.Must(uuid.NewV4()).String() fr := fosite.NewRequest() - fr.Client = &fosite.DefaultClient{ID: c1.LegacyClientID} + fr.Client = &fosite.DefaultClient{ID: c1.ID} + fr.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} require.NoError(t, r.Persister().CreateAuthorizeCodeSession(s.t1, sig, fr)) actual := persistencesql.OAuth2RequestSQL{Table: "code"} require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) @@ -343,7 +358,7 @@ func (s *PersisterTestSuite) TestCreateClient() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - expected := &client.Client{LegacyClientID: "client-id"} + expected := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, expected)) actual := client.Client{} require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, expected.ID)) @@ -357,20 +372,20 @@ func (s *PersisterTestSuite) TestCreateConsentRequest() { for k, r := range s.registries { t.Run(k, func(t *testing.T) { sessionID := uuid.Must(uuid.NewV4()).String() - client := &client.Client{LegacyClientID: "client-id"} - f := newFlow(s.t1NID, client.LegacyClientID, "sub", sqlxx.NullString(sessionID)) - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) + client := &client.Client{ID: "client-id"} + f := newFlow(s.t1NID, client.ID, "sub", sqlxx.NullString(sessionID)) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) - req := &consent.OAuth2ConsentRequest{ + req := &flow.OAuth2ConsentRequest{ ID: "consent-request-id", LoginChallenge: sqlxx.NullString(f.ID), Skip: false, Verifier: "verifier", CSRF: "csrf", } - require.NoError(t, r.Persister().CreateConsentRequest(s.t1, req)) + require.NoError(t, r.Persister().CreateConsentRequest(s.t1, f, req)) actual := flow.Flow{} require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, f.ID)) @@ -383,11 +398,11 @@ func (s *PersisterTestSuite) TestCreateForcedObfuscatedLoginSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} - session := &consent.ForcedObfuscatedLoginSession{ClientID: client.LegacyClientID} + client := &client.Client{ID: "client-id"} + session := &consent.ForcedObfuscatedLoginSession{ClientID: client.ID} require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().CreateForcedObfuscatedLoginSession(s.t1, session)) - actual, err := r.Persister().GetForcedObfuscatedLoginSession(s.t1, client.LegacyClientID, "") + actual, err := r.Persister().GetForcedObfuscatedLoginSession(s.t1, client.ID, "") require.NoError(t, err) require.Equal(t, s.t1NID, actual.NID) }) @@ -417,13 +432,12 @@ func (s *PersisterTestSuite) TestCreateLoginRequest() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} - lr := consent.LoginRequest{ID: "lr-id", ClientID: client.LegacyClientID, RequestedAt: time.Now()} + client := &client.Client{ID: "client-id"} + lr := flow.LoginRequest{ID: "lr-id", ClientID: client.ID, RequestedAt: time.Now()} require.NoError(t, r.Persister().CreateClient(s.t1, client)) - require.NoError(t, r.ConsentManager().CreateLoginRequest(s.t1, &lr)) - f := flow.Flow{} - require.NoError(t, r.Persister().Connection(context.Background()).Find(&f, lr.ID)) + f, err := r.ConsentManager().CreateLoginRequest(s.t1, &lr) + require.NoError(t, err) require.Equal(t, s.t1NID, f.NID) }) } @@ -433,9 +447,9 @@ func (s *PersisterTestSuite) TestCreateLoginSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - ls := consent.LoginSession{ID: uuid.Must(uuid.NewV4()).String(), Remember: true} + ls := flow.LoginSession{ID: uuid.Must(uuid.NewV4()).String(), Remember: true} require.NoError(t, r.Persister().CreateLoginSession(s.t1, &ls)) - actual, err := r.Persister().GetRememberedLoginSession(s.t1, ls.ID) + actual, err := r.Persister().GetRememberedLoginSession(s.t1, &ls, ls.ID) require.NoError(t, err) require.Equal(t, s.t1NID, actual.NID) }) @@ -446,11 +460,11 @@ func (s *PersisterTestSuite) TestCreateLogoutRequest() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} - lr := consent.LogoutRequest{ + client := &client.Client{ID: "client-id"} + lr := flow.LogoutRequest{ // TODO there is not FK for SessionID so we don't need it here; TODO make sure the missing FK is intentional ID: uuid.Must(uuid.NewV4()).String(), - ClientID: sql.NullString{Valid: true, String: client.LegacyClientID}, + ClientID: sql.NullString{Valid: true, String: client.ID}, } require.NoError(t, r.Persister().CreateClient(s.t1, client)) @@ -466,11 +480,12 @@ func (s *PersisterTestSuite) TestCreateOpenIDConnectSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) request := fosite.NewRequest() request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} authorizeCode := uuid.Must(uuid.NewV4()).String() require.NoError(t, r.Persister().CreateOpenIDConnectSession(s.t1, authorizeCode, request)) @@ -486,11 +501,12 @@ func (s *PersisterTestSuite) TestCreatePKCERequestSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) request := fosite.NewRequest() request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} authorizeCode := uuid.Must(uuid.NewV4()).String() @@ -507,11 +523,12 @@ func (s *PersisterTestSuite) TestCreateRefreshTokenSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) request := fosite.NewRequest() request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} authorizeCode := uuid.Must(uuid.NewV4()).String() actual := persistencesql.OAuth2RequestSQL{Table: "refresh"} @@ -527,7 +544,7 @@ func (s *PersisterTestSuite) TestCreateWithNetwork() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - expected := &client.Client{LegacyClientID: "client-id"} + expected := &client.Client{ID: "client-id"} store, ok := r.OAuth2Storage().(*persistencesql.Persister) if !ok { t.Fatal("type assertion failed") @@ -535,7 +552,7 @@ func (s *PersisterTestSuite) TestCreateWithNetwork() { store.CreateWithNetwork(s.t1, expected) actual := &client.Client{} - require.NoError(t, r.Persister().Connection(context.Background()).Where("id = ?", expected.LegacyClientID).First(actual)) + require.NoError(t, r.Persister().Connection(context.Background()).Where("id = ?", expected.ID).First(actual)) require.Equal(t, s.t1NID, actual.NID) }) } @@ -545,20 +562,21 @@ func (s *PersisterTestSuite) DeleteAccessTokenSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) sig := uuid.Must(uuid.NewV4()).String() fr := fosite.NewRequest() - fr.Client = &fosite.DefaultClient{ID: client.LegacyClientID} + fr.Client = &fosite.DefaultClient{ID: client.ID} + fr.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} require.NoError(t, r.Persister().CreateAccessTokenSession(s.t1, sig, fr)) require.NoError(t, r.Persister().DeleteAccessTokenSession(s.t2, sig)) actual := persistencesql.OAuth2RequestSQL{Table: "access"} - require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) + require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, x.SignatureHash(sig))) require.Equal(t, s.t1NID, actual.NID) require.NoError(t, r.Persister().DeleteAccessTokenSession(s.t1, sig)) - require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) + require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, x.SignatureHash(sig))) }) } } @@ -567,20 +585,21 @@ func (s *PersisterTestSuite) TestDeleteAccessTokens() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) sig := uuid.Must(uuid.NewV4()).String() fr := fosite.NewRequest() - fr.Client = &fosite.DefaultClient{ID: client.LegacyClientID} + fr.Client = &fosite.DefaultClient{ID: client.ID} + fr.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} require.NoError(t, r.Persister().CreateAccessTokenSession(s.t1, sig, fr)) - require.NoError(t, r.Persister().DeleteAccessTokens(s.t2, client.LegacyClientID)) + require.NoError(t, r.Persister().DeleteAccessTokens(s.t2, client.ID)) actual := persistencesql.OAuth2RequestSQL{Table: "access"} - require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) + require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, x.SignatureHash(sig))) require.Equal(t, s.t1NID, actual.NID) - require.NoError(t, r.Persister().DeleteAccessTokens(s.t1, client.LegacyClientID)) - require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) + require.NoError(t, r.Persister().DeleteAccessTokens(s.t1, client.ID)) + require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, x.SignatureHash(sig))) }) } } @@ -589,12 +608,12 @@ func (s *PersisterTestSuite) TestDeleteClient() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - c := &client.Client{LegacyClientID: "client-id"} + c := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, c)) actual := client.Client{} - require.Error(t, r.Persister().DeleteClient(s.t2, c.LegacyClientID)) + require.Error(t, r.Persister().DeleteClient(s.t2, c.ID)) require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, c.ID)) - require.NoError(t, r.Persister().DeleteClient(s.t1, c.LegacyClientID)) + require.NoError(t, r.Persister().DeleteClient(s.t1, c.ID)) require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, c.ID)) }) } @@ -626,15 +645,23 @@ func (s *PersisterTestSuite) TestDeleteLoginSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - ls := consent.LoginSession{ID: uuid.Must(uuid.NewV4()).String(), Remember: true} - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &ls)) + ls := flow.LoginSession{ + ID: uuid.Must(uuid.NewV4()).String(), + Remember: true, + IdentityProviderSessionID: sqlxx.NullString(uuid.Must(uuid.NewV4()).String()), + } + persistLoginSession(s.t1, t, r.Persister(), &ls) - require.Error(t, r.Persister().DeleteLoginSession(s.t2, ls.ID)) - _, err := r.Persister().GetRememberedLoginSession(s.t1, ls.ID) + deletedLS, err := r.Persister().DeleteLoginSession(s.t2, ls.ID) + require.Error(t, err) + assert.Nil(t, deletedLS) + _, err = r.Persister().GetRememberedLoginSession(s.t1, nil, ls.ID) require.NoError(t, err) - require.NoError(t, r.Persister().DeleteLoginSession(s.t1, ls.ID)) - _, err = r.Persister().GetRememberedLoginSession(s.t1, ls.ID) + deletedLS, err = r.Persister().DeleteLoginSession(s.t1, ls.ID) + require.NoError(t, err) + assert.Equal(t, ls, *deletedLS) + _, err = r.Persister().GetRememberedLoginSession(s.t1, nil, ls.ID) require.Error(t, err) }) } @@ -644,11 +671,12 @@ func (s *PersisterTestSuite) TestDeleteOpenIDConnectSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) request := fosite.NewRequest() request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} authorizeCode := uuid.Must(uuid.NewV4()).String() require.NoError(t, r.Persister().CreateOpenIDConnectSession(s.t1, authorizeCode, request)) @@ -667,14 +695,15 @@ func (s *PersisterTestSuite) TestDeletePKCERequestSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) request := fosite.NewRequest() request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} authorizeCode := uuid.Must(uuid.NewV4()).String() - r.Persister().CreatePKCERequestSession(s.t1, authorizeCode, request) + require.NoError(t, r.Persister().CreatePKCERequestSession(s.t1, authorizeCode, request)) actual := persistencesql.OAuth2RequestSQL{Table: "pkce"} @@ -690,11 +719,12 @@ func (s *PersisterTestSuite) TestDeleteRefreshTokenSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) request := fosite.NewRequest() request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} signature := uuid.Must(uuid.NewV4()).String() require.NoError(t, r.Persister().CreateRefreshTokenSession(s.t1, signature, request)) @@ -732,13 +762,12 @@ func (s *PersisterTestSuite) TestFindGrantedAndRememberedConsentRequests() { for k, r := range s.registries { t.Run(k, func(t *testing.T) { sessionID := uuid.Must(uuid.NewV4()).String() - client := &client.Client{LegacyClientID: "client-id"} - f := newFlow(s.t1NID, client.LegacyClientID, "sub", sqlxx.NullString(sessionID)) - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) + client := &client.Client{ID: "client-id"} + f := newFlow(s.t1NID, client.ID, "sub", sqlxx.NullString(sessionID)) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) require.NoError(t, r.Persister().CreateClient(s.t1, client)) - require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) - req := &consent.OAuth2ConsentRequest{ + req := &flow.OAuth2ConsentRequest{ ID: "consent-request-id", LoginChallenge: sqlxx.NullString(f.ID), Skip: false, @@ -746,20 +775,21 @@ func (s *PersisterTestSuite) TestFindGrantedAndRememberedConsentRequests() { CSRF: "csrf", } - hcr := &consent.AcceptOAuth2ConsentRequest{ + hcr := &flow.AcceptOAuth2ConsentRequest{ ID: req.ID, HandledAt: sqlxx.NullTime(time.Now()), Remember: true, } - require.NoError(t, r.Persister().CreateConsentRequest(s.t1, req)) - _, err := r.Persister().HandleConsentRequest(s.t1, hcr) + require.NoError(t, r.Persister().CreateConsentRequest(s.t1, f, req)) + _, err := r.Persister().HandleConsentRequest(s.t1, f, hcr) require.NoError(t, err) + require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) - actual, err := r.Persister().FindGrantedAndRememberedConsentRequests(s.t2, client.LegacyClientID, f.Subject) + actual, err := r.Persister().FindGrantedAndRememberedConsentRequests(s.t2, client.ID, f.Subject) require.Error(t, err) require.Equal(t, 0, len(actual)) - actual, err = r.Persister().FindGrantedAndRememberedConsentRequests(s.t1, client.LegacyClientID, f.Subject) + actual, err = r.Persister().FindGrantedAndRememberedConsentRequests(s.t1, client.ID, f.Subject) require.NoError(t, err) require.Equal(t, 1, len(actual)) }) @@ -771,13 +801,13 @@ func (s *PersisterTestSuite) TestFindSubjectsGrantedConsentRequests() { for k, r := range s.registries { t.Run(k, func(t *testing.T) { sessionID := uuid.Must(uuid.NewV4()).String() - client := &client.Client{LegacyClientID: "client-id"} - f := newFlow(s.t1NID, client.LegacyClientID, "sub", sqlxx.NullString(sessionID)) - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) + client := &client.Client{ID: "client-id"} + f := newFlow(s.t1NID, client.ID, "sub", sqlxx.NullString(sessionID)) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) - req := &consent.OAuth2ConsentRequest{ + req := &flow.OAuth2ConsentRequest{ ID: "consent-request-id", LoginChallenge: sqlxx.NullString(f.ID), Skip: false, @@ -785,13 +815,13 @@ func (s *PersisterTestSuite) TestFindSubjectsGrantedConsentRequests() { CSRF: "csrf", } - hcr := &consent.AcceptOAuth2ConsentRequest{ + hcr := &flow.AcceptOAuth2ConsentRequest{ ID: req.ID, HandledAt: sqlxx.NullTime(time.Now()), Remember: true, } - require.NoError(t, r.Persister().CreateConsentRequest(s.t1, req)) - _, err := r.Persister().HandleConsentRequest(s.t1, hcr) + require.NoError(t, r.Persister().CreateConsentRequest(s.t1, f, req)) + _, err := r.Persister().HandleConsentRequest(s.t1, f, hcr) require.NoError(t, err) actual, err := r.Persister().FindSubjectsGrantedConsentRequests(s.t2, f.Subject, 100, 0) @@ -809,20 +839,21 @@ func (s *PersisterTestSuite) TestFlushInactiveAccessTokens() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) sig := uuid.Must(uuid.NewV4()).String() fr := fosite.NewRequest() fr.RequestedAt = time.Now().UTC().Add(-24 * time.Hour) - fr.Client = &fosite.DefaultClient{ID: client.LegacyClientID} + fr.Client = &fosite.DefaultClient{ID: client.ID} + fr.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} require.NoError(t, r.Persister().CreateAccessTokenSession(s.t1, sig, fr)) actual := persistencesql.OAuth2RequestSQL{Table: "access"} require.NoError(t, r.Persister().FlushInactiveAccessTokens(s.t2, time.Now().Add(time.Hour), 100, 100)) - require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) + require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, x.SignatureHash(sig))) require.NoError(t, r.Persister().FlushInactiveAccessTokens(s.t1, time.Now().Add(time.Hour), 100, 100)) - require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) + require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, x.SignatureHash(sig))) }) } } @@ -873,10 +904,10 @@ func (s *PersisterTestSuite) TestFlushInactiveLoginConsentRequests() { for k, r := range s.registries { t.Run(k, func(t *testing.T) { sessionID := uuid.Must(uuid.NewV4()).String() - client := &client.Client{LegacyClientID: "client-id"} - f := newFlow(s.t1NID, client.LegacyClientID, "sub", sqlxx.NullString(sessionID)) + client := &client.Client{ID: "client-id"} + f := newFlow(s.t1NID, client.ID, "sub", sqlxx.NullString(sessionID)) f.RequestedAt = time.Now().Add(-24 * time.Hour) - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) @@ -894,10 +925,11 @@ func (s *PersisterTestSuite) TestFlushInactiveRefreshTokens() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} request := fosite.NewRequest() request.RequestedAt = time.Now().Add(-240 * 365 * time.Hour) request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} signature := uuid.Must(uuid.NewV4()).String() require.NoError(t, r.Persister().CreateClient(s.t1, client)) @@ -917,11 +949,12 @@ func (s *PersisterTestSuite) TestGetAccessTokenSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) sig := uuid.Must(uuid.NewV4()).String() fr := fosite.NewRequest() - fr.Client = &fosite.DefaultClient{ID: client.LegacyClientID} + fr.Client = &fosite.DefaultClient{ID: client.ID} + fr.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} require.NoError(t, r.Persister().CreateAccessTokenSession(s.t1, sig, fr)) actual, err := r.Persister().GetAccessTokenSession(s.t2, sig, &fosite.DefaultSession{}) @@ -938,11 +971,12 @@ func (s *PersisterTestSuite) TestGetAuthorizeCodeSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) sig := uuid.Must(uuid.NewV4()).String() fr := fosite.NewRequest() - fr.Client = &fosite.DefaultClient{ID: client.LegacyClientID} + fr.Client = &fosite.DefaultClient{ID: client.ID} + fr.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} require.NoError(t, r.Persister().CreateAuthorizeCodeSession(s.t1, sig, fr)) actual, err := r.Persister().GetAuthorizeCodeSession(s.t2, sig, &fosite.DefaultSession{}) @@ -959,15 +993,15 @@ func (s *PersisterTestSuite) TestGetClient() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - expected := &client.Client{LegacyClientID: "client-id"} + expected := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, expected)) - actual, err := r.Persister().GetClient(s.t2, expected.LegacyClientID) + actual, err := r.Persister().GetClient(s.t2, expected.ID) require.Error(t, err) require.Nil(t, actual) - actual, err = r.Persister().GetClient(s.t1, expected.LegacyClientID) + actual, err = r.Persister().GetClient(s.t1, expected.ID) require.NoError(t, err) - require.Equal(t, expected.LegacyClientID, actual.GetID()) + require.Equal(t, expected.ID, actual.GetID()) }) } } @@ -995,7 +1029,7 @@ func (s *PersisterTestSuite) TestGetClients() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - c := &client.Client{LegacyClientID: "client-id"} + c := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, c)) actual, err := r.Persister().GetClients(s.t2, client.Filter{Offset: 0, Limit: 100}) @@ -1012,15 +1046,15 @@ func (s *PersisterTestSuite) TestGetConcreteClient() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - expected := &client.Client{LegacyClientID: "client-id"} + expected := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, expected)) - actual, err := r.Persister().GetConcreteClient(s.t2, expected.LegacyClientID) + actual, err := r.Persister().GetConcreteClient(s.t2, expected.ID) require.Error(t, err) require.Nil(t, actual) - actual, err = r.Persister().GetConcreteClient(s.t1, expected.LegacyClientID) + actual, err = r.Persister().GetConcreteClient(s.t1, expected.ID) require.NoError(t, err) - require.Equal(t, expected.LegacyClientID, actual.GetID()) + require.Equal(t, expected.ID, actual.GetID()) }) } } @@ -1054,20 +1088,20 @@ func (s *PersisterTestSuite) TestGetConsentRequest() { for k, r := range s.registries { t.Run(k, func(t *testing.T) { sessionID := uuid.Must(uuid.NewV4()).String() - client := &client.Client{LegacyClientID: "client-id"} - f := newFlow(s.t1NID, client.LegacyClientID, "sub", sqlxx.NullString(sessionID)) - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) + client := &client.Client{ID: "client-id"} + f := newFlow(s.t1NID, client.ID, "sub", sqlxx.NullString(sessionID)) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) - req := &consent.OAuth2ConsentRequest{ - ID: "consent-request-id", + req := &flow.OAuth2ConsentRequest{ + ID: x.Must(f.ToConsentChallenge(s.t1, r)), LoginChallenge: sqlxx.NullString(f.ID), Skip: false, Verifier: "verifier", CSRF: "csrf", } - require.NoError(t, r.Persister().CreateConsentRequest(s.t1, req)) + require.NoError(t, r.Persister().CreateConsentRequest(s.t1, f, req)) actual, err := r.Persister().GetConsentRequest(s.t2, req.ID) require.Error(t, err) @@ -1085,9 +1119,9 @@ func (s *PersisterTestSuite) TestGetFlow() { for k, r := range s.registries { t.Run(k, func(t *testing.T) { sessionID := uuid.Must(uuid.NewV4()).String() - client := &client.Client{LegacyClientID: "client-id"} - f := newFlow(s.t1NID, client.LegacyClientID, "sub", sqlxx.NullString(sessionID)) - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) + client := &client.Client{ID: "client-id"} + f := newFlow(s.t1NID, client.ID, "sub", sqlxx.NullString(sessionID)) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) @@ -1110,21 +1144,22 @@ func (s *PersisterTestSuite) TestGetFlowByConsentChallenge() { for k, r := range s.registries { t.Run(k, func(t *testing.T) { sessionID := uuid.Must(uuid.NewV4()).String() - client := &client.Client{LegacyClientID: "client-id"} - f := newFlow(s.t1NID, client.LegacyClientID, "sub", sqlxx.NullString(sessionID)) - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) + client := &client.Client{ID: "client-id"} + f := newFlow(s.t1NID, client.ID, "sub", sqlxx.NullString(sessionID)) + require.NoError(t, r.Persister().CreateLoginSession(s.t1, &flow.LoginSession{ID: sessionID})) require.NoError(t, r.Persister().CreateClient(s.t1, client)) - require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) store, ok := r.Persister().(*persistencesql.Persister) if !ok { t.Fatal("type assertion failed") } - _, err := store.GetFlowByConsentChallenge(s.t2, f.ConsentChallengeID.String()) + challenge := x.Must(f.ToConsentChallenge(s.t1, r)) + + _, err := store.GetFlowByConsentChallenge(s.t2, challenge) require.Error(t, err) - _, err = store.GetFlowByConsentChallenge(s.t1, f.ConsentChallengeID.String()) + _, err = store.GetFlowByConsentChallenge(s.t1, challenge) require.NoError(t, err) }) } @@ -1134,16 +1169,16 @@ func (s *PersisterTestSuite) TestGetForcedObfuscatedLoginSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} - session := &consent.ForcedObfuscatedLoginSession{ClientID: client.LegacyClientID} + client := &client.Client{ID: "client-id"} + session := &consent.ForcedObfuscatedLoginSession{ClientID: client.ID} require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().CreateForcedObfuscatedLoginSession(s.t1, session)) - actual, err := r.Persister().GetForcedObfuscatedLoginSession(s.t2, client.LegacyClientID, "") + actual, err := r.Persister().GetForcedObfuscatedLoginSession(s.t2, client.ID, "") require.Error(t, err) require.Nil(t, actual) - actual, err = r.Persister().GetForcedObfuscatedLoginSession(s.t1, client.LegacyClientID, "") + actual, err = r.Persister().GetForcedObfuscatedLoginSession(s.t1, client.ID, "") require.NoError(t, err) require.NotNil(t, actual) }) @@ -1178,20 +1213,21 @@ func (s *PersisterTestSuite) TestGetLoginRequest() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} - lr := consent.LoginRequest{ID: "lr-id", ClientID: client.LegacyClientID, RequestedAt: time.Now()} + client := &client.Client{ID: "client-id"} + lr := flow.LoginRequest{ID: "lr-id", ClientID: client.ID, RequestedAt: time.Now()} require.NoError(t, r.Persister().CreateClient(s.t1, client)) - require.NoError(t, r.ConsentManager().CreateLoginRequest(s.t1, &lr)) - f := flow.Flow{} - require.NoError(t, r.Persister().Connection(context.Background()).Find(&f, lr.ID)) + f, err := r.ConsentManager().CreateLoginRequest(s.t1, &lr) + require.NoError(t, err) require.Equal(t, s.t1NID, f.NID) - actual, err := r.Persister().GetLoginRequest(s.t2, lr.ID) + challenge := x.Must(f.ToLoginChallenge(s.t1, r)) + + actual, err := r.Persister().GetLoginRequest(s.t2, challenge) require.Error(t, err) require.Nil(t, actual) - actual, err = r.Persister().GetLoginRequest(s.t1, lr.ID) + actual, err = r.Persister().GetLoginRequest(s.t1, challenge) require.NoError(t, err) require.NotNil(t, actual) }) @@ -1202,10 +1238,10 @@ func (s *PersisterTestSuite) TestGetLogoutRequest() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} - lr := consent.LogoutRequest{ + client := &client.Client{ID: "client-id"} + lr := flow.LogoutRequest{ ID: uuid.Must(uuid.NewV4()).String(), - ClientID: sql.NullString{Valid: true, String: client.LegacyClientID}, + ClientID: sql.NullString{Valid: true, String: client.ID}, } require.NoError(t, r.Persister().CreateClient(s.t1, client)) @@ -1213,11 +1249,11 @@ func (s *PersisterTestSuite) TestGetLogoutRequest() { actual, err := r.Persister().GetLogoutRequest(s.t2, lr.ID) require.Error(t, err) - require.Equal(t, &consent.LogoutRequest{}, actual) + require.Equal(t, &flow.LogoutRequest{}, actual) actual, err = r.Persister().GetLogoutRequest(s.t1, lr.ID) require.NoError(t, err) - require.NotEqual(t, &consent.LogoutRequest{}, actual) + require.NotEqual(t, &flow.LogoutRequest{}, actual) }) } } @@ -1226,10 +1262,11 @@ func (s *PersisterTestSuite) TestGetOpenIDConnectSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} request := fosite.NewRequest() request.SetID("request-id") request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} authorizeCode := uuid.Must(uuid.NewV4()).String() require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().CreateOpenIDConnectSession(s.t1, authorizeCode, request)) @@ -1249,10 +1286,11 @@ func (s *PersisterTestSuite) TestGetPKCERequestSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} request := fosite.NewRequest() request.SetID("request-id") request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} sig := uuid.Must(uuid.NewV4()).String() require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().CreatePKCERequestSession(s.t1, sig, request)) @@ -1321,13 +1359,15 @@ func (s *PersisterTestSuite) TestGetPublicKeys() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - ks := newKeySet("ks-id", "use") + const issuer = "ks-id" + ks := newKeySet(issuer, "use") grant := trust.Grant{ ID: uuid.Must(uuid.NewV4()).String(), ExpiresAt: time.Now().Add(time.Hour), - PublicKey: trust.PublicKey{Set: "ks-id", KeyID: ks.Keys[0].KeyID}, + Issuer: issuer, + PublicKey: trust.PublicKey{Set: issuer, KeyID: ks.Keys[0].KeyID}, } - require.NoError(t, r.Persister().AddKeySet(s.t1, "ks-id", ks)) + require.NoError(t, r.Persister().AddKeySet(s.t1, issuer, ks)) require.NoError(t, r.Persister().CreateGrant(s.t1, grant, ks.Keys[0])) actual, err := r.Persister().GetPublicKeys(s.t2, grant.Issuer, grant.Subject) @@ -1345,10 +1385,11 @@ func (s *PersisterTestSuite) TestGetRefreshTokenSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} request := fosite.NewRequest() request.SetID("request-id") request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} sig := uuid.Must(uuid.NewV4()).String() require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().CreateRefreshTokenSession(s.t1, sig, request)) @@ -1368,14 +1409,14 @@ func (s *PersisterTestSuite) TestGetRememberedLoginSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - ls := consent.LoginSession{ID: uuid.Must(uuid.NewV4()).String(), Remember: true} + ls := flow.LoginSession{ID: uuid.Must(uuid.NewV4()).String(), Remember: true} require.NoError(t, r.Persister().CreateLoginSession(s.t1, &ls)) - actual, err := r.Persister().GetRememberedLoginSession(s.t2, ls.ID) + actual, err := r.Persister().GetRememberedLoginSession(s.t2, &ls, ls.ID) require.Error(t, err) require.Nil(t, actual) - actual, err = r.Persister().GetRememberedLoginSession(s.t1, ls.ID) + actual, err = r.Persister().GetRememberedLoginSession(s.t1, &ls, ls.ID) require.NoError(t, err) require.NotNil(t, actual) }) @@ -1387,15 +1428,13 @@ func (s *PersisterTestSuite) TestHandleConsentRequest() { for k, r := range s.registries { t.Run(k, func(t *testing.T) { sessionID := uuid.Must(uuid.NewV4()).String() - c1 := &client.Client{LegacyClientID: uuidx.NewV4().String()} - f := newFlow(s.t1NID, c1.LegacyClientID, "sub", sqlxx.NullString(sessionID)) - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) + c1 := &client.Client{ID: uuidx.NewV4().String()} + f := newFlow(s.t1NID, c1.ID, "sub", sqlxx.NullString(sessionID)) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) require.NoError(t, r.Persister().CreateClient(s.t1, c1)) - c1.ID = uuid.Nil require.NoError(t, r.Persister().CreateClient(s.t2, c1)) - require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) - req := &consent.OAuth2ConsentRequest{ + req := &flow.OAuth2ConsentRequest{ ID: "consent-request-id", LoginChallenge: sqlxx.NullString(f.ID), Skip: false, @@ -1403,24 +1442,25 @@ func (s *PersisterTestSuite) TestHandleConsentRequest() { CSRF: "csrf", } - hcr := &consent.AcceptOAuth2ConsentRequest{ + hcr := &flow.AcceptOAuth2ConsentRequest{ ID: req.ID, HandledAt: sqlxx.NullTime(time.Now()), Remember: true, } - require.NoError(t, r.Persister().CreateConsentRequest(s.t1, req)) + require.NoError(t, r.Persister().CreateConsentRequest(s.t1, f, req)) - actualCR, err := r.Persister().HandleConsentRequest(s.t2, hcr) + actualCR, err := r.Persister().HandleConsentRequest(s.t2, f, hcr) require.Error(t, err) require.Nil(t, actualCR) - actual, err := r.Persister().FindGrantedAndRememberedConsentRequests(s.t1, c1.LegacyClientID, f.Subject) + actual, err := r.Persister().FindGrantedAndRememberedConsentRequests(s.t1, c1.ID, f.Subject) require.Error(t, err) require.Equal(t, 0, len(actual)) - actualCR, err = r.Persister().HandleConsentRequest(s.t1, hcr) + actualCR, err = r.Persister().HandleConsentRequest(s.t1, f, hcr) require.NoError(t, err) require.NotNil(t, actualCR) - actual, err = r.Persister().FindGrantedAndRememberedConsentRequests(s.t1, c1.LegacyClientID, f.Subject) + require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) + actual, err = r.Persister().FindGrantedAndRememberedConsentRequests(s.t1, c1.ID, f.Subject) require.NoError(t, err) require.Equal(t, 1, len(actual)) }) @@ -1431,13 +1471,13 @@ func (s *PersisterTestSuite) TestInvalidateAuthorizeCodeSession() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: uuidx.NewV4().String()} - require.NoError(t, r.Persister().CreateClient(s.t1, client)) - client.ID = uuid.Nil - require.NoError(t, r.Persister().CreateClient(s.t2, client)) + cl := &client.Client{ID: uuidx.NewV4().String()} + require.NoError(t, r.Persister().CreateClient(s.t1, cl)) + require.NoError(t, r.Persister().CreateClient(s.t2, cl)) sig := uuid.Must(uuid.NewV4()).String() fr := fosite.NewRequest() - fr.Client = &fosite.DefaultClient{ID: client.LegacyClientID} + fr.Client = &fosite.DefaultClient{ID: cl.ID} + fr.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} require.NoError(t, r.Persister().CreateAuthorizeCodeSession(s.t1, sig, fr)) require.NoError(t, r.Persister().InvalidateAuthorizeCodeSession(s.t2, sig)) @@ -1475,43 +1515,72 @@ func (s *PersisterTestSuite) TestListUserAuthenticatedClientsWithBackChannelLogo t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - c1 := &client.Client{LegacyClientID: "client-1", BackChannelLogoutURI: "not-null"} - c2 := &client.Client{LegacyClientID: "client-2", BackChannelLogoutURI: "not-null"} + c1 := &client.Client{ID: "client-1", BackChannelLogoutURI: "not-null"} + c2 := &client.Client{ID: "client-2", BackChannelLogoutURI: "not-null"} require.NoError(t, r.Persister().CreateClient(s.t1, c1)) - c1.ID = uuid.Nil require.NoError(t, r.Persister().CreateClient(s.t2, c1)) require.NoError(t, r.Persister().CreateClient(s.t2, c2)) - t1f1 := newFlow(s.t1NID, c1.LegacyClientID, "sub", sqlxx.NullString(uuid.Must(uuid.NewV4()).String())) + t1f1 := newFlow(s.t1NID, c1.ID, "sub", sqlxx.NullString(uuid.Must(uuid.NewV4()).String())) t1f1.ConsentChallengeID = "t1f1-consent-challenge" t1f1.LoginVerifier = "t1f1-login-verifier" t1f1.ConsentVerifier = "t1f1-consent-verifier" - t2f1 := newFlow(s.t2NID, c1.LegacyClientID, "sub", t1f1.SessionID) + t2f1 := newFlow(s.t2NID, c1.ID, "sub", t1f1.SessionID) t2f1.ConsentChallengeID = "t2f1-consent-challenge" t2f1.LoginVerifier = "t2f1-login-verifier" t2f1.ConsentVerifier = "t2f1-consent-verifier" - t2f2 := newFlow(s.t2NID, c2.LegacyClientID, "sub", t1f1.SessionID) + t2f2 := newFlow(s.t2NID, c2.ID, "sub", t1f1.SessionID) t2f2.ConsentChallengeID = "t2f2-consent-challenge" t2f2.LoginVerifier = "t2f2-login-verifier" t2f2.ConsentVerifier = "t2f2-consent-verifier" - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: t1f1.SessionID.String()})) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: t1f1.SessionID.String()}) require.NoError(t, r.Persister().Connection(context.Background()).Create(t1f1)) require.NoError(t, r.Persister().Connection(context.Background()).Create(t2f1)) require.NoError(t, r.Persister().Connection(context.Background()).Create(t2f2)) - require.NoError(t, r.Persister().CreateConsentRequest(s.t1, &consent.OAuth2ConsentRequest{ID: t1f1.ID, LoginChallenge: sqlxx.NullString(t1f1.ID), Skip: false, Verifier: t1f1.ConsentVerifier.String(), CSRF: "csrf"})) - require.NoError(t, r.Persister().CreateConsentRequest(s.t2, &consent.OAuth2ConsentRequest{ID: t2f1.ID, LoginChallenge: sqlxx.NullString(t2f1.ID), Skip: false, Verifier: t2f1.ConsentVerifier.String(), CSRF: "csrf"})) - require.NoError(t, r.Persister().CreateConsentRequest(s.t2, &consent.OAuth2ConsentRequest{ID: t2f2.ID, LoginChallenge: sqlxx.NullString(t2f2.ID), Skip: false, Verifier: t2f2.ConsentVerifier.String(), CSRF: "csrf"})) + require.NoError(t, r.Persister().CreateConsentRequest(s.t1, t1f1, &flow.OAuth2ConsentRequest{ + ID: t1f1.ID, + LoginChallenge: sqlxx.NullString(t1f1.ID), + Skip: false, + Verifier: t1f1.ConsentVerifier.String(), + CSRF: "csrf", + })) + require.NoError(t, r.Persister().CreateConsentRequest(s.t2, t2f1, &flow.OAuth2ConsentRequest{ + ID: t2f1.ID, + LoginChallenge: sqlxx.NullString(t2f1.ID), + Skip: false, + Verifier: t2f1.ConsentVerifier.String(), + CSRF: "csrf", + })) + require.NoError(t, r.Persister().CreateConsentRequest(s.t2, t2f2, &flow.OAuth2ConsentRequest{ + ID: t2f2.ID, + LoginChallenge: sqlxx.NullString(t2f2.ID), + Skip: false, + Verifier: t2f2.ConsentVerifier.String(), + CSRF: "csrf", + })) - _, err := r.Persister().HandleConsentRequest(s.t1, &consent.AcceptOAuth2ConsentRequest{ID: t1f1.ID, HandledAt: sqlxx.NullTime(time.Now()), Remember: true}) + _, err := r.Persister().HandleConsentRequest(s.t1, t1f1, &flow.AcceptOAuth2ConsentRequest{ + ID: t1f1.ID, + HandledAt: sqlxx.NullTime(time.Now()), + Remember: true, + }) require.NoError(t, err) - _, err = r.Persister().HandleConsentRequest(s.t2, &consent.AcceptOAuth2ConsentRequest{ID: t2f1.ID, HandledAt: sqlxx.NullTime(time.Now()), Remember: true}) + _, err = r.Persister().HandleConsentRequest(s.t2, t2f1, &flow.AcceptOAuth2ConsentRequest{ + ID: t2f1.ID, + HandledAt: sqlxx.NullTime(time.Now()), + Remember: true, + }) require.NoError(t, err) - _, err = r.Persister().HandleConsentRequest(s.t2, &consent.AcceptOAuth2ConsentRequest{ID: t2f2.ID, HandledAt: sqlxx.NullTime(time.Now()), Remember: true}) + _, err = r.Persister().HandleConsentRequest(s.t2, t2f2, &flow.AcceptOAuth2ConsentRequest{ + ID: t2f2.ID, + HandledAt: sqlxx.NullTime(time.Now()), + Remember: true, + }) require.NoError(t, err) cs, err := r.Persister().ListUserAuthenticatedClientsWithBackChannelLogout(s.t1, "sub", t1f1.SessionID.String()) @@ -1529,43 +1598,72 @@ func (s *PersisterTestSuite) TestListUserAuthenticatedClientsWithFrontChannelLog t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - c1 := &client.Client{LegacyClientID: "client-1", FrontChannelLogoutURI: "not-null"} - c2 := &client.Client{LegacyClientID: "client-2", FrontChannelLogoutURI: "not-null"} + c1 := &client.Client{ID: "client-1", FrontChannelLogoutURI: "not-null"} + c2 := &client.Client{ID: "client-2", FrontChannelLogoutURI: "not-null"} require.NoError(t, r.Persister().CreateClient(s.t1, c1)) - c1.ID = uuid.Nil require.NoError(t, r.Persister().CreateClient(s.t2, c1)) require.NoError(t, r.Persister().CreateClient(s.t2, c2)) - t1f1 := newFlow(s.t1NID, c1.LegacyClientID, "sub", sqlxx.NullString(uuid.Must(uuid.NewV4()).String())) + t1f1 := newFlow(s.t1NID, c1.ID, "sub", sqlxx.NullString(uuid.Must(uuid.NewV4()).String())) t1f1.ConsentChallengeID = "t1f1-consent-challenge" t1f1.LoginVerifier = "t1f1-login-verifier" t1f1.ConsentVerifier = "t1f1-consent-verifier" - t2f1 := newFlow(s.t2NID, c1.LegacyClientID, "sub", t1f1.SessionID) + t2f1 := newFlow(s.t2NID, c1.ID, "sub", t1f1.SessionID) t2f1.ConsentChallengeID = "t2f1-consent-challenge" t2f1.LoginVerifier = "t2f1-login-verifier" t2f1.ConsentVerifier = "t2f1-consent-verifier" - t2f2 := newFlow(s.t2NID, c2.LegacyClientID, "sub", t1f1.SessionID) + t2f2 := newFlow(s.t2NID, c2.ID, "sub", t1f1.SessionID) t2f2.ConsentChallengeID = "t2f2-consent-challenge" t2f2.LoginVerifier = "t2f2-login-verifier" t2f2.ConsentVerifier = "t2f2-consent-verifier" - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: t1f1.SessionID.String()})) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: t1f1.SessionID.String()}) require.NoError(t, r.Persister().Connection(context.Background()).Create(t1f1)) require.NoError(t, r.Persister().Connection(context.Background()).Create(t2f1)) require.NoError(t, r.Persister().Connection(context.Background()).Create(t2f2)) - require.NoError(t, r.Persister().CreateConsentRequest(s.t1, &consent.OAuth2ConsentRequest{ID: t1f1.ID, LoginChallenge: sqlxx.NullString(t1f1.ID), Skip: false, Verifier: t1f1.ConsentVerifier.String(), CSRF: "csrf"})) - require.NoError(t, r.Persister().CreateConsentRequest(s.t2, &consent.OAuth2ConsentRequest{ID: t2f1.ID, LoginChallenge: sqlxx.NullString(t2f1.ID), Skip: false, Verifier: t2f1.ConsentVerifier.String(), CSRF: "csrf"})) - require.NoError(t, r.Persister().CreateConsentRequest(s.t2, &consent.OAuth2ConsentRequest{ID: t2f2.ID, LoginChallenge: sqlxx.NullString(t2f2.ID), Skip: false, Verifier: t2f2.ConsentVerifier.String(), CSRF: "csrf"})) + require.NoError(t, r.Persister().CreateConsentRequest(s.t1, t1f1, &flow.OAuth2ConsentRequest{ + ID: t1f1.ID, + LoginChallenge: sqlxx.NullString(t1f1.ID), + Skip: false, + Verifier: t1f1.ConsentVerifier.String(), + CSRF: "csrf", + })) + require.NoError(t, r.Persister().CreateConsentRequest(s.t2, t2f1, &flow.OAuth2ConsentRequest{ + ID: t2f1.ID, + LoginChallenge: sqlxx.NullString(t2f1.ID), + Skip: false, + Verifier: t2f1.ConsentVerifier.String(), + CSRF: "csrf", + })) + require.NoError(t, r.Persister().CreateConsentRequest(s.t2, t2f2, &flow.OAuth2ConsentRequest{ + ID: t2f2.ID, + LoginChallenge: sqlxx.NullString(t2f2.ID), + Skip: false, + Verifier: t2f2.ConsentVerifier.String(), + CSRF: "csrf", + })) - _, err := r.Persister().HandleConsentRequest(s.t1, &consent.AcceptOAuth2ConsentRequest{ID: t1f1.ID, HandledAt: sqlxx.NullTime(time.Now()), Remember: true}) + _, err := r.Persister().HandleConsentRequest(s.t1, t1f1, &flow.AcceptOAuth2ConsentRequest{ + ID: t1f1.ID, + HandledAt: sqlxx.NullTime(time.Now()), + Remember: true, + }) require.NoError(t, err) - _, err = r.Persister().HandleConsentRequest(s.t2, &consent.AcceptOAuth2ConsentRequest{ID: t2f1.ID, HandledAt: sqlxx.NullTime(time.Now()), Remember: true}) + _, err = r.Persister().HandleConsentRequest(s.t2, t2f1, &flow.AcceptOAuth2ConsentRequest{ + ID: t2f1.ID, + HandledAt: sqlxx.NullTime(time.Now()), + Remember: true, + }) require.NoError(t, err) - _, err = r.Persister().HandleConsentRequest(s.t2, &consent.AcceptOAuth2ConsentRequest{ID: t2f2.ID, HandledAt: sqlxx.NullTime(time.Now()), Remember: true}) + _, err = r.Persister().HandleConsentRequest(s.t2, t2f2, &flow.AcceptOAuth2ConsentRequest{ + ID: t2f2.ID, + HandledAt: sqlxx.NullTime(time.Now()), + Remember: true, + }) require.NoError(t, err) cs, err := r.Persister().ListUserAuthenticatedClientsWithFrontChannelLogout(s.t1, "sub", t1f1.SessionID.String()) @@ -1608,7 +1706,7 @@ func (s *PersisterTestSuite) TestQueryWithNetwork() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - r.Persister().CreateClient(s.t1, &client.Client{LegacyClientID: "client-1", FrontChannelLogoutURI: "not-null"}) + r.Persister().CreateClient(s.t1, &client.Client{ID: "client-1", FrontChannelLogoutURI: "not-null"}) store, ok := r.Persister().(*persistencesql.Persister) if !ok { @@ -1639,7 +1737,7 @@ func (s *PersisterTestSuite) TestRejectLogoutRequest() { require.NoError(t, r.ConsentManager().RejectLogoutRequest(s.t1, lr.ID)) actual, err = r.ConsentManager().GetLogoutRequest(s.t1, lr.ID) require.Error(t, err) - require.Equal(t, &consent.LogoutRequest{}, actual) + require.Equal(t, &flow.LogoutRequest{}, actual) }) } } @@ -1648,20 +1746,21 @@ func (s *PersisterTestSuite) TestRevokeAccessToken() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) sig := uuid.Must(uuid.NewV4()).String() fr := fosite.NewRequest() - fr.Client = &fosite.DefaultClient{ID: client.LegacyClientID} + fr.Client = &fosite.DefaultClient{ID: client.ID} + fr.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} require.NoError(t, r.Persister().CreateAccessTokenSession(s.t1, sig, fr)) require.NoError(t, r.Persister().RevokeAccessToken(s.t2, fr.ID)) actual := persistencesql.OAuth2RequestSQL{Table: "access"} - require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) + require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, x.SignatureHash(sig))) require.Equal(t, s.t1NID, actual.NID) require.NoError(t, r.Persister().RevokeAccessToken(s.t1, fr.ID)) - require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, sig)) + require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, x.SignatureHash(sig))) }) } } @@ -1670,11 +1769,12 @@ func (s *PersisterTestSuite) TestRevokeRefreshToken() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) request := fosite.NewRequest() request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} signature := uuid.Must(uuid.NewV4()).String() require.NoError(t, r.Persister().CreateRefreshTokenSession(s.t1, signature, request)) @@ -1695,11 +1795,12 @@ func (s *PersisterTestSuite) TestRevokeRefreshTokenMaybeGracePeriod() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - client := &client.Client{LegacyClientID: "client-id"} + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) request := fosite.NewRequest() request.Client = &fosite.DefaultClient{ID: "client-id"} + request.Session = &oauth2.Session{DefaultSession: &openid.DefaultSession{Subject: "sub"}} signature := uuid.Must(uuid.NewV4()).String() require.NoError(t, r.Persister().CreateRefreshTokenSession(s.t1, signature, request)) @@ -1726,18 +1827,18 @@ func (s *PersisterTestSuite) TestRevokeSubjectClientConsentSession() { for k, r := range s.registries { t.Run(k, func(t *testing.T) { sessionID := uuid.Must(uuid.NewV4()).String() - client := &client.Client{LegacyClientID: "client-id"} - f := newFlow(s.t1NID, client.LegacyClientID, "sub", sqlxx.NullString(sessionID)) + client := &client.Client{ID: "client-id"} + f := newFlow(s.t1NID, client.ID, "sub", sqlxx.NullString(sessionID)) f.RequestedAt = time.Now().Add(-24 * time.Hour) - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) require.NoError(t, r.Persister().CreateClient(s.t1, client)) require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) actual := flow.Flow{} - require.Error(t, r.Persister().RevokeSubjectClientConsentSession(s.t2, "sub", client.LegacyClientID)) + require.NoError(t, r.Persister().RevokeSubjectClientConsentSession(s.t2, "sub", client.ID), "should not error if nothing was found") require.NoError(t, r.Persister().Connection(context.Background()).Find(&actual, f.ID)) - require.NoError(t, r.Persister().RevokeSubjectClientConsentSession(s.t1, "sub", client.LegacyClientID)) + require.NoError(t, r.Persister().RevokeSubjectClientConsentSession(s.t1, "sub", client.ID)) require.Error(t, r.Persister().Connection(context.Background()).Find(&actual, f.ID)) }) } @@ -1780,37 +1881,51 @@ func (s *PersisterTestSuite) TestUpdateClient() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - t1c1 := &client.Client{LegacyClientID: "client-id", Name: "original", Secret: "original-secret"} - t2c1 := &client.Client{LegacyClientID: "client-id", Name: "original", Secret: "original-secret"} + t1c1 := &client.Client{ID: "client-id", Name: "original", Secret: "original-secret"} + t2c1 := &client.Client{ID: "client-id", Name: "original", Secret: "original-secret"} require.NoError(t, r.Persister().CreateClient(s.t1, t1c1)) require.NoError(t, r.Persister().CreateClient(s.t2, t2c1)) - expectedHash := t1c1.Secret + t1Hash, t2Hash := t1c1.Secret, t2c1.Secret u1 := *t1c1 u1.Name = "updated" u1.Secret = "" require.NoError(t, r.Persister().UpdateClient(s.t2, &u1)) - actual := &client.Client{} - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, t1c1.ID)) + actual, err := r.Persister().GetConcreteClient(s.t1, t1c1.ID) + require.NoError(t, err) require.Equal(t, "original", actual.Name) - require.Equal(t, expectedHash, actual.Secret) + require.Equal(t, t1Hash, actual.Secret) + + actual, err = r.Persister().GetConcreteClient(s.t2, t1c1.ID) + require.NoError(t, err) + require.Equal(t, "updated", actual.Name) + require.Equal(t, t2Hash, actual.Secret) u2 := *t1c1 u2.Name = "updated" u2.Secret = "" require.NoError(t, r.Persister().UpdateClient(s.t1, &u2)) - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, t1c1.ID)) + + actual, err = r.Persister().GetConcreteClient(s.t1, t1c1.ID) + require.NoError(t, err) require.Equal(t, "updated", actual.Name) - require.Equal(t, expectedHash, actual.Secret) + require.Equal(t, t1Hash, actual.Secret) u3 := *t1c1 u3.Name = "updated" u3.Secret = "updated-secret" require.NoError(t, r.Persister().UpdateClient(s.t1, &u3)) - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, t1c1.ID)) + + actual, err = r.Persister().GetConcreteClient(s.t1, t1c1.ID) + require.NoError(t, err) require.Equal(t, "updated", actual.Name) - require.NotEqual(t, expectedHash, actual.Secret) + require.NotEqual(t, t1Hash, actual.Secret) + + actual, err = r.Persister().GetConcreteClient(s.t2, t2c1.ID) + require.NoError(t, err) + require.Equal(t, "updated", actual.Name) + require.Equal(t, t2Hash, actual.Secret) }) } } @@ -1869,8 +1984,8 @@ func (s *PersisterTestSuite) TestUpdateWithNetwork() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - t1c1 := &client.Client{LegacyClientID: "client-id", Name: "original", Secret: "original-secret"} - t2c1 := &client.Client{LegacyClientID: "client-id", Name: "original", Secret: "original-secret", Owner: "erase-me"} + t1c1 := &client.Client{ID: "client-id", Name: "original", Secret: "original-secret"} + t2c1 := &client.Client{ID: "client-id", Name: "original", Secret: "original-secret", Owner: "erase-me"} require.NoError(t, r.Persister().CreateClient(s.t1, t1c1)) require.NoError(t, r.Persister().CreateClient(s.t2, t2c1)) @@ -1879,7 +1994,7 @@ func (s *PersisterTestSuite) TestUpdateWithNetwork() { t.Fatal("type assertion failed") } - count, err := store.UpdateWithNetwork(s.t1, &client.Client{ID: t1c1.ID, LegacyClientID: "client-id", Name: "updated", Secret: "original-secret"}) + count, err := store.UpdateWithNetwork(s.t1, &client.Client{ID: "client-id", Name: "updated", Secret: "original-secret"}) require.NoError(t, err) require.Equal(t, int64(1), count) actualt1, err := store.GetConcreteClient(s.t1, "client-id") @@ -1900,33 +2015,30 @@ func (s *PersisterTestSuite) TestVerifyAndInvalidateConsentRequest() { t.Run(k, func(t *testing.T) { sub := uuid.Must(uuid.NewV4()).String() sessionID := uuid.Must(uuid.NewV4()).String() - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) - client := &client.Client{LegacyClientID: "client-id"} + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) - f := newFlow(s.t1NID, client.LegacyClientID, sub, sqlxx.NullString(sessionID)) + f := newFlow(s.t1NID, client.ID, sub, sqlxx.NullString(sessionID)) f.ConsentSkip = false f.GrantedScope = sqlxx.StringSliceJSONFormat{} f.ConsentRemember = false crf := 86400 f.ConsentRememberFor = &crf - f.ConsentError = &consent.RequestDeniedError{} + f.ConsentError = &flow.RequestDeniedError{} f.SessionAccessToken = map[string]interface{}{} f.SessionIDToken = map[string]interface{}{} f.ConsentWasHandled = false f.State = flow.FlowStateConsentUnused - require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) - actual := &flow.Flow{} - _, err := r.ConsentManager().VerifyAndInvalidateConsentRequest(s.t2, f.ConsentVerifier.String()) + consentVerifier := x.Must(f.ToConsentVerifier(s.t1, r)) + + _, err := r.ConsentManager().VerifyAndInvalidateConsentRequest(s.t2, consentVerifier) require.Error(t, err) - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, f.ID)) - require.Equal(t, flow.FlowStateConsentUnused, actual.State) - require.Equal(t, false, actual.ConsentWasHandled) - _, err = r.ConsentManager().VerifyAndInvalidateConsentRequest(s.t1, f.ConsentVerifier.String()) + require.Equal(t, flow.FlowStateConsentUnused, f.State) + require.Equal(t, false, f.ConsentWasHandled) + _, err = r.ConsentManager().VerifyAndInvalidateConsentRequest(s.t1, consentVerifier) require.NoError(t, err) - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, f.ID)) - require.Equal(t, flow.FlowStateConsentUsed, actual.State) - require.Equal(t, true, actual.ConsentWasHandled) + require.Equal(t, flow.FlowStateConsentUnused, f.State) // TODO: Delegate reuse detection to external service. }) } } @@ -1937,24 +2049,20 @@ func (s *PersisterTestSuite) TestVerifyAndInvalidateLoginRequest() { t.Run(k, func(t *testing.T) { sub := uuid.Must(uuid.NewV4()).String() sessionID := uuid.Must(uuid.NewV4()).String() - require.NoError(t, r.Persister().CreateLoginSession(s.t1, &consent.LoginSession{ID: sessionID})) - client := &client.Client{LegacyClientID: "client-id"} + persistLoginSession(s.t1, t, r.Persister(), &flow.LoginSession{ID: sessionID}) + client := &client.Client{ID: "client-id"} require.NoError(t, r.Persister().CreateClient(s.t1, client)) - f := newFlow(s.t1NID, client.LegacyClientID, sub, sqlxx.NullString(sessionID)) + f := newFlow(s.t1NID, client.ID, sub, sqlxx.NullString(sessionID)) f.State = flow.FlowStateLoginUnused - require.NoError(t, r.Persister().Connection(context.Background()).Create(f)) - actual := &flow.Flow{} - _, err := r.ConsentManager().VerifyAndInvalidateLoginRequest(s.t2, f.LoginVerifier) + loginVerifier := x.Must(f.ToLoginVerifier(s.t1, r)) + _, err := r.ConsentManager().VerifyAndInvalidateLoginRequest(s.t2, loginVerifier) require.Error(t, err) - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, f.ID)) - require.Equal(t, flow.FlowStateLoginUnused, actual.State) - require.Equal(t, false, actual.LoginWasUsed) - _, err = r.ConsentManager().VerifyAndInvalidateLoginRequest(s.t1, f.LoginVerifier) + require.Equal(t, flow.FlowStateLoginUnused, f.State) + require.Equal(t, false, f.LoginWasUsed) + _, err = r.ConsentManager().VerifyAndInvalidateLoginRequest(s.t1, loginVerifier) require.NoError(t, err) - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, f.ID)) - require.Equal(t, flow.FlowStateLoginUsed, actual.State) - require.Equal(t, true, actual.LoginWasUsed) + require.Equal(t, flow.FlowStateLoginUnused, f.State) // TODO: Delegate reuse detection to external service. }) } } @@ -1963,27 +2071,54 @@ func (s *PersisterTestSuite) TestVerifyAndInvalidateLogoutRequest() { t := s.T() for k, r := range s.registries { t.Run(k, func(t *testing.T) { - lr := newLogoutRequest() - lr.Verifier = uuid.Must(uuid.NewV4()).String() - lr.Accepted = true - lr.Rejected = false - require.NoError(t, r.ConsentManager().CreateLogoutRequest(s.t1, lr)) + run := func(t *testing.T, lr *flow.LogoutRequest) { + lr.Verifier = uuid.Must(uuid.NewV4()).String() + lr.Accepted = true + lr.Rejected = false + require.NoError(t, r.ConsentManager().CreateLogoutRequest(s.t1, lr)) - expected, err := r.ConsentManager().GetLogoutRequest(s.t1, lr.ID) - require.NoError(t, err) + expected, err := r.ConsentManager().GetLogoutRequest(s.t1, lr.ID) + require.NoError(t, err) - lrInvalidated, err := r.ConsentManager().VerifyAndInvalidateLogoutRequest(s.t2, lr.Verifier) - require.Error(t, err) - require.Equal(t, &consent.LogoutRequest{}, lrInvalidated) - actual := &consent.LogoutRequest{} - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, lr.ID)) - require.Equal(t, expected, actual) + lrInvalidated, err := r.ConsentManager().VerifyAndInvalidateLogoutRequest(s.t2, lr.Verifier) + require.Error(t, err) + require.Nil(t, lrInvalidated) + actual := &flow.LogoutRequest{} + require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, lr.ID)) + require.Equal(t, expected, actual) - lrInvalidated, err = r.ConsentManager().VerifyAndInvalidateLogoutRequest(s.t1, lr.Verifier) - require.NoError(t, err) - require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, lr.ID)) - require.Equal(t, lrInvalidated, actual) - require.Equal(t, true, actual.WasHandled) + lrInvalidated, err = r.ConsentManager().VerifyAndInvalidateLogoutRequest(s.t1, lr.Verifier) + require.NoError(t, err) + require.NoError(t, r.Persister().Connection(context.Background()).Find(actual, lr.ID)) + require.Equal(t, lrInvalidated, actual) + require.Equal(t, true, actual.WasHandled) + } + + t.Run("case=legacy logout request without expiry", func(t *testing.T) { + lr := newLogoutRequest() + run(t, lr) + }) + + t.Run("case=logout request with expiry", func(t *testing.T) { + lr := newLogoutRequest() + lr.ExpiresAt = sqlxx.NullTime(time.Now().Add(time.Hour)) + run(t, lr) + }) + + t.Run("case=logout request that expired returns error", func(t *testing.T) { + lr := newLogoutRequest() + lr.ExpiresAt = sqlxx.NullTime(time.Now().Add(-time.Hour)) + lr.Verifier = uuid.Must(uuid.NewV4()).String() + lr.Accepted = true + lr.Rejected = false + require.NoError(t, r.ConsentManager().CreateLogoutRequest(s.t1, lr)) + + _, err := r.ConsentManager().VerifyAndInvalidateLogoutRequest(s.t2, lr.Verifier) + require.ErrorIs(t, err, x.ErrNotFound) + + _, err = r.ConsentManager().VerifyAndInvalidateLogoutRequest(s.t1, lr.Verifier) + require.ErrorIs(t, err, flow.ErrorLogoutFlowExpired) + }) }) } } @@ -2016,7 +2151,7 @@ func TestPersisterTestSuite(t *testing.T) { func newClient() *client.Client { return &client.Client{ - ID: uuid.Must(uuid.NewV4()), + ID: uuid.Must(uuid.NewV4()).String(), } } @@ -2026,9 +2161,9 @@ func newFlow(nid uuid.UUID, clientID string, subject string, sessionID sqlxx.Nul ID: uuid.Must(uuid.NewV4()).String(), ClientID: clientID, Subject: subject, - ConsentError: &consent.RequestDeniedError{}, + ConsentError: &flow.RequestDeniedError{}, State: flow.FlowStateConsentUnused, - LoginError: &consent.RequestDeniedError{}, + LoginError: &flow.RequestDeniedError{}, Context: sqlxx.JSONRawMessage{}, AMR: sqlxx.StringSliceJSONFormat{}, ConsentChallengeID: sqlxx.NullString("not-null"), @@ -2050,8 +2185,8 @@ func newGrant(keySet string, keyID string) trust.Grant { } } -func newLogoutRequest() *consent.LogoutRequest { - return &consent.LogoutRequest{ +func newLogoutRequest() *flow.LogoutRequest { + return &flow.LogoutRequest{ ID: uuid.Must(uuid.NewV4()).String(), } } @@ -2065,15 +2200,11 @@ func newKey(ksID string, use string) jose.JSONWebKey { } func newKeySet(id string, use string) *jose.JSONWebKeySet { - ks, err := jwk.GenerateJWK(context.Background(), jose.RS256, id, use) - if err != nil { - panic(err) - } - return ks + return x.Must(jwk.GenerateJWK(context.Background(), jose.RS256, id, use)) } -func newLoginSession() *consent.LoginSession { - return &consent.LoginSession{ +func newLoginSession() *flow.LoginSession { + return &flow.LoginSession{ ID: uuid.Must(uuid.NewV4()).String(), AuthenticatedAt: sqlxx.NullTime(time.Time{}), Subject: uuid.Must(uuid.NewV4()).String(), @@ -2084,3 +2215,9 @@ func newLoginSession() *consent.LoginSession { func requireKeySetEqual(t *testing.T, expected *jose.JSONWebKeySet, actual *jose.JSONWebKeySet) { assertx.EqualAsJSON(t, expected, actual) } + +func persistLoginSession(ctx context.Context, t *testing.T, p persistence.Persister, session *flow.LoginSession) { + t.Helper() + require.NoError(t, p.CreateLoginSession(ctx, session)) + require.NoError(t, p.Connection(ctx).Create(session)) +} diff --git a/persistence/sql/persister_nonce.go b/persistence/sql/persister_nonce.go new file mode 100644 index 00000000000..3610a43d95a --- /dev/null +++ b/persistence/sql/persister_nonce.go @@ -0,0 +1,49 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql + +import ( + "context" + "time" + + "github.com/ory/fosite" + "github.com/ory/hydra/v2/x" + "github.com/ory/x/errorsx" + "github.com/ory/x/otelx" +) + +// Set the aadAccessTokenPrefix to something unique to avoid ciphertext confusion with other usages of the AEAD cipher. +var aadAccessTokenPrefix = "vc-nonce-at:" // nolint:gosec + +func (p *Persister) NewNonce(ctx context.Context, accessToken string, expiresIn time.Time) (res string, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.NewNonce") + defer otelx.End(span, &err) + + plaintext := x.IntToBytes(expiresIn.Unix()) + aad := []byte(aadAccessTokenPrefix + accessToken) + + return p.r.FlowCipher().Encrypt(ctx, plaintext, aad) +} + +func (p *Persister) IsNonceValid(ctx context.Context, accessToken, nonce string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.IsNonceValid") + defer otelx.End(span, &err) + + aad := []byte(aadAccessTokenPrefix + accessToken) + plaintext, err := p.r.FlowCipher().Decrypt(ctx, nonce, aad) + if err != nil { + return errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The nonce is invalid.")) + } + + exp, err := x.BytesToInt(plaintext) + if err != nil { + return errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The nonce is invalid.")) // should never happen + } + + if exp < time.Now().Unix() { + return errorsx.WithStack(fosite.ErrInvalidRequest.WithHintf("The nonce has expired.")) + } + + return nil +} diff --git a/persistence/sql/persister_nonce_test.go b/persistence/sql/persister_nonce_test.go new file mode 100644 index 00000000000..1de7eda543a --- /dev/null +++ b/persistence/sql/persister_nonce_test.go @@ -0,0 +1,62 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package sql_test + +import ( + "context" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/ory/fosite" + "github.com/ory/hydra/v2/internal" + "github.com/ory/x/contextx" + "github.com/ory/x/randx" +) + +func TestPersister_Nonce(t *testing.T) { + ctx := context.Background() + p := internal.NewMockedRegistry(t, new(contextx.Default)).Persister() + + accessToken := randx.MustString(100, randx.AlphaNum) + anotherToken := randx.MustString(100, randx.AlphaNum) + validNonce, err := p.NewNonce(ctx, accessToken, time.Now().Add(1*time.Hour)) + require.NoError(t, err) + + expiredNonce, err := p.NewNonce(ctx, accessToken, time.Now().Add(-1*time.Hour)) + require.NoError(t, err) + + nonceForAnotherAccessToken, err := p.NewNonce(ctx, anotherToken, time.Now().Add(-1*time.Hour)) + require.NoError(t, err) + + for _, tc := range []struct { + name string + nonce string + assertErr assert.ErrorAssertionFunc + }{{ + name: "valid nonce", + nonce: validNonce, + assertErr: assert.NoError, + }, { + name: "expired nonce", + nonce: expiredNonce, + assertErr: assertInvalidRequest, + }, { + name: "nonce for another access token", + nonce: nonceForAnotherAccessToken, + assertErr: assertInvalidRequest, + }, + } { + t.Run("case="+tc.name, func(t *testing.T) { + err := p.IsNonceValid(ctx, accessToken, tc.nonce) + tc.assertErr(t, err) + }) + } +} + +func assertInvalidRequest(t assert.TestingT, err error, i ...interface{}) bool { + return assert.ErrorIs(t, err, fosite.ErrInvalidRequest) +} diff --git a/persistence/sql/persister_oauth2.go b/persistence/sql/persister_oauth2.go index 5d3acc585af..80246afed72 100644 --- a/persistence/sql/persister_oauth2.go +++ b/persistence/sql/persister_oauth2.go @@ -5,29 +5,33 @@ package sql import ( "context" - "crypto/sha512" + "crypto/sha256" "database/sql" + "encoding/hex" "encoding/json" "fmt" "net/url" "strings" "time" - "github.com/gobuffalo/pop/v6" - "github.com/gofrs/uuid" + "github.com/ory/hydra/v2/x" - "github.com/ory/x/errorsx" + "github.com/ory/x/sqlxx" - "github.com/ory/fosite/storage" + "go.opentelemetry.io/otel/trace" + "github.com/gofrs/uuid" "github.com/pkg/errors" "github.com/tidwall/gjson" "github.com/ory/fosite" + "github.com/ory/fosite/storage" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/x/events" + "github.com/ory/x/errorsx" + "github.com/ory/x/otelx" "github.com/ory/x/sqlcon" "github.com/ory/x/stringsx" - - "github.com/ory/hydra/oauth2" ) var _ oauth2.AssertionJWTReader = &Persister{} @@ -51,6 +55,12 @@ type ( Active bool `db:"active"` Session []byte `db:"session_data"` Table tableName `db:"-"` + // InternalExpiresAt denormalizes the expiry from the session to additionally store it as a row. + InternalExpiresAt sqlxx.NullTime `db:"expires_at" json:"-"` + } + OAuth2RefreshTable struct { + OAuth2RequestSQL + FirstUsedAt sql.NullTime `db:"first_used_at"` } ) @@ -66,7 +76,11 @@ func (r OAuth2RequestSQL) TableName() string { return "hydra_oauth2_" + string(r.Table) } -func (p *Persister) sqlSchemaFromRequest(ctx context.Context, rawSignature string, r fosite.Requester, table tableName) (*OAuth2RequestSQL, error) { +func (r OAuth2RefreshTable) TableName() string { + return "hydra_oauth2_refresh" +} + +func (p *Persister) sqlSchemaFromRequest(ctx context.Context, signature string, r fosite.Requester, table tableName, expiresAt time.Time) (*OAuth2RequestSQL, error) { subject := "" if r.GetSession() == nil { p.l.Debugf("Got an empty session in sqlSchemaFromRequest") @@ -80,7 +94,7 @@ func (p *Persister) sqlSchemaFromRequest(ctx context.Context, rawSignature strin } if p.config.EncryptSessionData(ctx) { - ciphertext, err := p.r.KeyCipher().Encrypt(ctx, session) + ciphertext, err := p.r.KeyCipher().Encrypt(ctx, session, nil) if err != nil { return nil, errorsx.WithStack(err) } @@ -100,8 +114,9 @@ func (p *Persister) sqlSchemaFromRequest(ctx context.Context, rawSignature strin return &OAuth2RequestSQL{ Request: r.GetID(), ConsentChallenge: challenge, - ID: p.hashSignature(ctx, rawSignature, table), + ID: signature, RequestedAt: r.GetRequestedAt(), + InternalExpiresAt: sqlxx.NullTime(expiresAt), Client: r.GetClient().GetID(), Scopes: strings.Join(r.GetRequestedScopes(), "|"), GrantedScope: strings.Join(r.GetGrantedScopes(), "|"), @@ -115,14 +130,32 @@ func (p *Persister) sqlSchemaFromRequest(ctx context.Context, rawSignature strin }, nil } -func (r *OAuth2RequestSQL) toRequest(ctx context.Context, session fosite.Session, p *Persister) (*fosite.Request, error) { +func (p *Persister) marshalSession(ctx context.Context, session fosite.Session) ([]byte, error) { + sessionBytes, err := json.Marshal(session) + if err != nil { + return nil, err + } + + if !p.config.EncryptSessionData(ctx) { + return sessionBytes, nil + } + + ciphertext, err := p.r.KeyCipher().Encrypt(ctx, sessionBytes, nil) + if err != nil { + return nil, err + } + + return []byte(ciphertext), nil +} + +func (r *OAuth2RequestSQL) toRequest(ctx context.Context, session fosite.Session, p *Persister) (_ *fosite.Request, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.toRequest") - defer span.End() + defer otelx.End(span, &err) sess := r.Session if !gjson.ValidBytes(sess) { var err error - sess, err = p.r.KeyCipher().Decrypt(ctx, string(sess)) + sess, err = p.r.KeyCipher().Decrypt(ctx, string(sess), nil) if err != nil { return nil, errorsx.WithStack(err) } @@ -147,8 +180,9 @@ func (r *OAuth2RequestSQL) toRequest(ctx context.Context, session fosite.Session } return &fosite.Request{ - ID: r.Request, - RequestedAt: r.RequestedAt, + ID: r.Request, + RequestedAt: r.RequestedAt, + // ExpiresAt does not need to be populated as we get the expiry time from the session. Client: c, RequestedScope: stringsx.Splitx(r.Scopes, "|"), GrantedScope: stringsx.Splitx(r.GrantedScope, "|"), @@ -159,17 +193,9 @@ func (r *OAuth2RequestSQL) toRequest(ctx context.Context, session fosite.Session }, nil } -// hashSignature prevents errors where the signature is longer than 128 characters (and thus doesn't fit into the pk). -func (p *Persister) hashSignature(ctx context.Context, signature string, table tableName) string { - if table == sqlTableAccess && p.config.IsUsingJWTAsAccessTokens(ctx) { - return fmt.Sprintf("%x", sha512.Sum384([]byte(signature))) - } - return signature -} - -func (p *Persister) ClientAssertionJWTValid(ctx context.Context, jti string) error { +func (p *Persister) ClientAssertionJWTValid(ctx context.Context, jti string) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.ClientAssertionJWTValid") - defer span.End() + defer otelx.End(span, &err) j, err := p.GetClientAssertionJWT(ctx, jti) if errors.Is(err, sqlcon.ErrNoRows) { @@ -186,9 +212,9 @@ func (p *Persister) ClientAssertionJWTValid(ctx context.Context, jti string) err return nil } -func (p *Persister) SetClientAssertionJWT(ctx context.Context, jti string, exp time.Time) error { +func (p *Persister) SetClientAssertionJWT(ctx context.Context, jti string, exp time.Time) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.SetClientAssertionJWT") - defer span.End() + defer otelx.End(span, &err) // delete expired; this cleanup spares us the need for a background worker if err := p.QueryWithNetwork(ctx).Where("expires_at < CURRENT_TIMESTAMP").Delete(&oauth2.BlacklistedJTI{}); err != nil { @@ -206,31 +232,28 @@ func (p *Persister) SetClientAssertionJWT(ctx context.Context, jti string, exp t return nil } -func (p *Persister) GetClientAssertionJWT(ctx context.Context, j string) (*oauth2.BlacklistedJTI, error) { +func (p *Persister) GetClientAssertionJWT(ctx context.Context, j string) (_ *oauth2.BlacklistedJTI, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetClientAssertionJWT") - defer span.End() + defer otelx.End(span, &err) jti := oauth2.NewBlacklistedJTI(j, time.Time{}) return jti, sqlcon.HandleError(p.QueryWithNetwork(ctx).Find(jti, jti.ID)) } -func (p *Persister) SetClientAssertionJWTRaw(ctx context.Context, jti *oauth2.BlacklistedJTI) error { +func (p *Persister) SetClientAssertionJWTRaw(ctx context.Context, jti *oauth2.BlacklistedJTI) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.SetClientAssertionJWTRaw") - defer span.End() + defer otelx.End(span, &err) return sqlcon.HandleError(p.CreateWithNetwork(ctx, jti)) } -func (p *Persister) createSession(ctx context.Context, signature string, requester fosite.Requester, table tableName) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.createSession") - defer span.End() - - req, err := p.sqlSchemaFromRequest(ctx, signature, requester, table) +func (p *Persister) createSession(ctx context.Context, signature string, requester fosite.Requester, table tableName, expiresAt time.Time) error { + req, err := p.sqlSchemaFromRequest(ctx, signature, requester, table, expiresAt) if err != nil { return err } - if err := sqlcon.HandleError(p.CreateWithNetwork(ctx, req)); errors.Is(err, sqlcon.ErrConcurrentUpdate) { + if err = sqlcon.HandleError(p.CreateWithNetwork(ctx, req)); errors.Is(err, sqlcon.ErrConcurrentUpdate) { return errors.Wrap(fosite.ErrSerializationFailure, err.Error()) } else if err != nil { return err @@ -238,71 +261,58 @@ func (p *Persister) createSession(ctx context.Context, signature string, request return nil } -func (p *Persister) findSessionBySignature(ctx context.Context, rawSignature string, session fosite.Session, table tableName) (fosite.Requester, error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.findSessionBySignature") - defer span.End() - - rawSignature = p.hashSignature(ctx, rawSignature, table) - +func (p *Persister) findSessionBySignature(ctx context.Context, signature string, session fosite.Session, table tableName) (fosite.Requester, error) { r := OAuth2RequestSQL{Table: table} - var fr fosite.Requester - - return fr, p.transaction(ctx, func(ctx context.Context, c *pop.Connection) error { - err := p.QueryWithNetwork(ctx).Where("signature = ?", rawSignature).First(&r) - if errors.Is(err, sql.ErrNoRows) { - return errorsx.WithStack(fosite.ErrNotFound) - } else if err != nil { - return sqlcon.HandleError(err) - } else if !r.Active { - fr, err = r.toRequest(ctx, session, p) - if err != nil { - return err - } else if table == sqlTableCode { - return errorsx.WithStack(fosite.ErrInvalidatedAuthorizeCode) - } - - return errorsx.WithStack(fosite.ErrInactiveToken) + err := p.QueryWithNetwork(ctx).Where("signature = ?", signature).First(&r) + if errors.Is(err, sql.ErrNoRows) { + return nil, errorsx.WithStack(fosite.ErrNotFound) + } + if err != nil { + return nil, sqlcon.HandleError(err) + } + if !r.Active { + fr, err := r.toRequest(ctx, session, p) + if err != nil { + return nil, err } + if table == sqlTableCode { + return fr, errorsx.WithStack(fosite.ErrInvalidatedAuthorizeCode) + } + return fr, errorsx.WithStack(fosite.ErrInactiveToken) + } - fr, err = r.toRequest(ctx, session, p) - return err - }) + return r.toRequest(ctx, session, p) } func (p *Persister) deleteSessionBySignature(ctx context.Context, signature string, table tableName) error { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.deleteSessionBySignature") - defer span.End() - - signature = p.hashSignature(ctx, signature, table) - err := sqlcon.HandleError( p.QueryWithNetwork(ctx). - Where("signature=?", signature). + Where("signature = ?", signature). Delete(&OAuth2RequestSQL{Table: table})) - if errors.Is(err, sqlcon.ErrNoRows) { return errorsx.WithStack(fosite.ErrNotFound) - } else if errors.Is(err, sqlcon.ErrConcurrentUpdate) { + } + if errors.Is(err, sqlcon.ErrConcurrentUpdate) { return errors.Wrap(fosite.ErrSerializationFailure, err.Error()) - } else if err != nil { - return err } - return nil + return err } -func (p *Persister) deleteSessionByRequestID(ctx context.Context, id string, table tableName) error { +func (p *Persister) deleteSessionByRequestID(ctx context.Context, id string, table tableName) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.deleteSessionByRequestID") - defer span.End() + defer otelx.End(span, &err) - /* #nosec G201 table is static */ - if err := p.QueryWithNetwork(ctx). + err = p.QueryWithNetwork(ctx). Where("request_id=?", id). - Delete(&OAuth2RequestSQL{Table: table}); errors.Is(err, sql.ErrNoRows) { + Delete(&OAuth2RequestSQL{Table: table}) + if errors.Is(err, sql.ErrNoRows) { return errorsx.WithStack(fosite.ErrNotFound) - } else if err := sqlcon.HandleError(err); err != nil { + } + if err := sqlcon.HandleError(err); err != nil { if errors.Is(err, sqlcon.ErrConcurrentUpdate) { return errors.Wrap(fosite.ErrSerializationFailure, err.Error()) - } else if strings.Contains(err.Error(), "Error 1213") { // InnoDB Deadlock? + } + if strings.Contains(err.Error(), "Error 1213") { // InnoDB Deadlock? return errors.Wrap(fosite.ErrSerializationFailure, err.Error()) } return err @@ -310,9 +320,9 @@ func (p *Persister) deleteSessionByRequestID(ctx context.Context, id string, tab return nil } -func (p *Persister) deactivateSessionByRequestID(ctx context.Context, id string, table tableName) error { +func (p *Persister) deactivateSessionByRequestID(ctx context.Context, id string, table tableName) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.deactivateSessionByRequestID") - defer span.End() + defer otelx.End(span, &err) /* #nosec G201 table is static */ return sqlcon.HandleError( @@ -326,29 +336,28 @@ func (p *Persister) deactivateSessionByRequestID(ctx context.Context, id string, ) } -func (p *Persister) CreateAuthorizeCodeSession(ctx context.Context, signature string, requester fosite.Requester) (err error) { - ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateAuthorizeCodeSession") - defer span.End() - - return p.createSession(ctx, signature, requester, sqlTableCode) +func (p *Persister) CreateAuthorizeCodeSession(ctx context.Context, signature string, requester fosite.Requester) error { + return otelx.WithSpan(ctx, "persistence.sql.CreateAuthorizeCodeSession", func(ctx context.Context) error { + return p.createSession(ctx, signature, requester, sqlTableCode, requester.GetSession().GetExpiresAt(fosite.AuthorizeCode).UTC()) + }) } func (p *Persister) GetAuthorizeCodeSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetAuthorizeCodeSession") - defer span.End() + defer otelx.End(span, &err) return p.findSessionBySignature(ctx, signature, session, sqlTableCode) } func (p *Persister) InvalidateAuthorizeCodeSession(ctx context.Context, signature string) (err error) { ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.InvalidateAuthorizeCodeSession") - defer span.End() + defer otelx.End(span, &err) /* #nosec G201 table is static */ return sqlcon.HandleError( p.Connection(ctx). RawQuery( - fmt.Sprintf("UPDATE %s SET active=false WHERE signature=? AND nid = ?", OAuth2RequestSQL{Table: sqlTableCode}.TableName()), + fmt.Sprintf("UPDATE %s SET active = false WHERE signature = ? AND nid = ?", OAuth2RequestSQL{Table: sqlTableCode}.TableName()), signature, p.NetworkID(ctx), ). @@ -357,66 +366,215 @@ func (p *Persister) InvalidateAuthorizeCodeSession(ctx context.Context, signatur } func (p *Persister) CreateAccessTokenSession(ctx context.Context, signature string, requester fosite.Requester) (err error) { - return p.createSession(ctx, signature, requester, sqlTableAccess) + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateAccessTokenSession", + trace.WithAttributes(events.AccessTokenSignature(signature)), + ) + defer otelx.End(span, &err) + + events.Trace(ctx, events.AccessTokenIssued, + append(toEventOptions(requester), events.WithGrantType(requester.GetRequestForm().Get("grant_type")))..., + ) + + return p.createSession(ctx, x.SignatureHash(signature), requester, sqlTableAccess, requester.GetSession().GetExpiresAt(fosite.AccessToken).UTC()) } func (p *Persister) GetAccessTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) { - return p.findSessionBySignature(ctx, signature, session, sqlTableAccess) + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetAccessTokenSession", + trace.WithAttributes(events.AccessTokenSignature(signature)), + ) + defer otelx.End(span, &err) + + r := OAuth2RequestSQL{Table: sqlTableAccess} + err = p.QueryWithNetwork(ctx).Where("signature = ?", x.SignatureHash(signature)).First(&r) + if errors.Is(err, sql.ErrNoRows) { + // Backwards compatibility: we previously did not always hash the + // signature before inserting. In case there are still very old (but + // valid) access tokens in the database, this should get them. + err = p.QueryWithNetwork(ctx).Where("signature = ?", signature).First(&r) + if errors.Is(err, sql.ErrNoRows) { + return nil, errorsx.WithStack(fosite.ErrNotFound) + } + } + if err != nil { + return nil, sqlcon.HandleError(err) + } + if !r.Active { + fr, err := r.toRequest(ctx, session, p) + if err != nil { + return nil, err + } + return fr, errorsx.WithStack(fosite.ErrInactiveToken) + } + + return r.toRequest(ctx, session, p) } func (p *Persister) DeleteAccessTokenSession(ctx context.Context, signature string) (err error) { - return p.deleteSessionBySignature(ctx, signature, sqlTableAccess) + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteAccessTokenSession", + trace.WithAttributes(events.AccessTokenSignature(signature)), + ) + defer otelx.End(span, &err) + + err = sqlcon.HandleError( + p.QueryWithNetwork(ctx). + Where("signature = ?", x.SignatureHash(signature)). + Delete(&OAuth2RequestSQL{Table: sqlTableAccess})) + if errors.Is(err, sqlcon.ErrNoRows) { + // Backwards compatibility: we previously did not always hash the + // signature before inserting. In case there are still very old (but + // valid) access tokens in the database, this should get them. + err = sqlcon.HandleError( + p.QueryWithNetwork(ctx). + Where("signature = ?", signature). + Delete(&OAuth2RequestSQL{Table: sqlTableAccess})) + if errors.Is(err, sqlcon.ErrNoRows) { + return errorsx.WithStack(fosite.ErrNotFound) + } + } + if errors.Is(err, sqlcon.ErrConcurrentUpdate) { + return errors.Wrap(fosite.ErrSerializationFailure, err.Error()) + } + return err +} + +func toEventOptions(requester fosite.Requester) []trace.EventOption { + sub := "" + if requester.GetSession() != nil { + hash := sha256.Sum256([]byte(requester.GetSession().GetSubject())) + sub = hex.EncodeToString(hash[:]) + } + return []trace.EventOption{ + events.WithGrantType(requester.GetRequestForm().Get("grant_type")), + events.WithSubject(sub), + events.WithRequest(requester), + events.WithClientID(requester.GetClient().GetID()), + } } func (p *Persister) CreateRefreshTokenSession(ctx context.Context, signature string, requester fosite.Requester) (err error) { - return p.createSession(ctx, signature, requester, sqlTableRefresh) + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateRefreshTokenSession", + trace.WithAttributes(events.RefreshTokenSignature(signature)), + ) + defer otelx.End(span, &err) + events.Trace(ctx, events.RefreshTokenIssued, toEventOptions(requester)...) + return p.createSession(ctx, signature, requester, sqlTableRefresh, requester.GetSession().GetExpiresAt(fosite.RefreshToken).UTC()) } func (p *Persister) GetRefreshTokenSession(ctx context.Context, signature string, session fosite.Session) (request fosite.Requester, err error) { - return p.findSessionBySignature(ctx, signature, session, sqlTableRefresh) + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetRefreshTokenSession", + trace.WithAttributes(events.RefreshTokenSignature(signature)), + ) + defer otelx.End(span, &err) + + r := OAuth2RefreshTable{OAuth2RequestSQL: OAuth2RequestSQL{Table: sqlTableRefresh}} + err = p.QueryWithNetwork(ctx).Where("signature = ?", signature).First(&r) + if errors.Is(err, sql.ErrNoRows) { + return nil, errorsx.WithStack(fosite.ErrNotFound) + } else if err != nil { + return nil, sqlcon.HandleError(err) + } + + fositeRequest, err := r.toRequest(ctx, session, p) + if err != nil { + return nil, err + } + + if r.Active { + return fositeRequest, nil + } + + if gracePeriod := p.r.Config().RefreshTokenRotationGracePeriod(ctx); gracePeriod > 0 && r.FirstUsedAt.Valid { + if r.FirstUsedAt.Time.Add(gracePeriod).Before(time.Now()) { + return fositeRequest, errors.WithStack(fosite.ErrInactiveToken) + } + + r.Active = true // We set active to true because we are in the grace period. + return r.toRequest(ctx, session, p) // And re-generate the request + } + + return fositeRequest, errors.WithStack(fosite.ErrInactiveToken) } func (p *Persister) DeleteRefreshTokenSession(ctx context.Context, signature string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteRefreshTokenSession", + trace.WithAttributes(events.RefreshTokenSignature(signature)), + ) + defer otelx.End(span, &err) return p.deleteSessionBySignature(ctx, signature, sqlTableRefresh) } -func (p *Persister) CreateOpenIDConnectSession(ctx context.Context, signature string, requester fosite.Requester) error { - return p.createSession(ctx, signature, requester, sqlTableOpenID) +func (p *Persister) CreateOpenIDConnectSession(ctx context.Context, signature string, requester fosite.Requester) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreateOpenIDConnectSession") + defer otelx.End(span, &err) + events.Trace(ctx, events.IdentityTokenIssued, toEventOptions(requester)...) + // The expiry of an OIDC session is equal to the expiry of the authorization code. If the code is invalid, so is this OIDC request. + return p.createSession(ctx, signature, requester, sqlTableOpenID, requester.GetSession().GetExpiresAt(fosite.AuthorizeCode).UTC()) } -func (p *Persister) GetOpenIDConnectSession(ctx context.Context, signature string, requester fosite.Requester) (fosite.Requester, error) { +func (p *Persister) GetOpenIDConnectSession(ctx context.Context, signature string, requester fosite.Requester) (_ fosite.Requester, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetOpenIDConnectSession") + defer otelx.End(span, &err) return p.findSessionBySignature(ctx, signature, requester.GetSession(), sqlTableOpenID) } -func (p *Persister) DeleteOpenIDConnectSession(ctx context.Context, signature string) error { +func (p *Persister) DeleteOpenIDConnectSession(ctx context.Context, signature string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteOpenIDConnectSession") + defer otelx.End(span, &err) return p.deleteSessionBySignature(ctx, signature, sqlTableOpenID) } -func (p *Persister) GetPKCERequestSession(ctx context.Context, signature string, session fosite.Session) (fosite.Requester, error) { +func (p *Persister) GetPKCERequestSession(ctx context.Context, signature string, session fosite.Session) (_ fosite.Requester, err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.GetPKCERequestSession") + defer otelx.End(span, &err) return p.findSessionBySignature(ctx, signature, session, sqlTablePKCE) } -func (p *Persister) CreatePKCERequestSession(ctx context.Context, signature string, requester fosite.Requester) error { - return p.createSession(ctx, signature, requester, sqlTablePKCE) +func (p *Persister) CreatePKCERequestSession(ctx context.Context, signature string, requester fosite.Requester) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.CreatePKCERequestSession") + defer otelx.End(span, &err) + // The expiry of a PKCE session is equal to the expiry of the authorization code. If the code is invalid, so is this PKCE request. + return p.createSession(ctx, signature, requester, sqlTablePKCE, requester.GetSession().GetExpiresAt(fosite.AuthorizeCode).UTC()) } -func (p *Persister) DeletePKCERequestSession(ctx context.Context, signature string) error { +func (p *Persister) DeletePKCERequestSession(ctx context.Context, signature string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeletePKCERequestSession") + defer otelx.End(span, &err) return p.deleteSessionBySignature(ctx, signature, sqlTablePKCE) } -func (p *Persister) RevokeRefreshToken(ctx context.Context, id string) error { +func (p *Persister) RevokeRefreshToken(ctx context.Context, id string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeRefreshToken", + trace.WithAttributes(events.ConsentRequestID(id)), + ) + defer otelx.End(span, &err) return p.deactivateSessionByRequestID(ctx, id, sqlTableRefresh) } -func (p *Persister) RevokeRefreshTokenMaybeGracePeriod(ctx context.Context, id string, _ string) error { - return p.deactivateSessionByRequestID(ctx, id, sqlTableRefresh) +func (p *Persister) RevokeRefreshTokenMaybeGracePeriod(ctx context.Context, id string, _ string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeRefreshTokenMaybeGracePeriod") + defer otelx.End(span, &err) + + /* #nosec G201 table is static */ + return sqlcon.HandleError( + p.Connection(ctx). + RawQuery( + fmt.Sprintf("UPDATE %s SET active=false, first_used_at = CURRENT_TIMESTAMP WHERE request_id=? AND nid = ? AND active", OAuth2RequestSQL{Table: sqlTableRefresh}.TableName()), + id, + p.NetworkID(ctx), + ). + Exec(), + ) } -func (p *Persister) RevokeAccessToken(ctx context.Context, id string) error { +func (p *Persister) RevokeAccessToken(ctx context.Context, id string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.RevokeAccessToken", + trace.WithAttributes(events.ConsentRequestID(id)), + ) + defer otelx.End(span, &err) return p.deleteSessionByRequestID(ctx, id, sqlTableAccess) } -func (p *Persister) flushInactiveTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int, table tableName, lifespan time.Duration) error { +func (p *Persister) flushInactiveTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int, table tableName, lifespan time.Duration) (err error) { /* #nosec G201 table is static */ // The value of notAfter should be the minimum between input parameter and token max expire based on its configured age requestMaxExpire := time.Now().Add(-lifespan) @@ -424,8 +582,6 @@ func (p *Persister) flushInactiveTokens(ctx context.Context, notAfter time.Time, notAfter = requestMaxExpire } - var err error - totalDeletedCount := 0 for deletedRecords := batchSize; totalDeletedCount < limit && deletedRecords == batchSize; { d := batchSize @@ -436,7 +592,7 @@ func (p *Persister) flushInactiveTokens(ctx context.Context, notAfter time.Time, // The outer SELECT is necessary because our version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery deletedRecords, err = p.Connection(ctx).RawQuery( fmt.Sprintf(`DELETE FROM %s WHERE signature in ( - SELECT signature FROM (SELECT signature FROM %s hoa WHERE requested_at < ? and nid = ? ORDER BY signature LIMIT %d ) as s + SELECT signature FROM (SELECT signature FROM %s hoa WHERE requested_at < ? and nid = ? ORDER BY requested_at LIMIT %d ) as s )`, OAuth2RequestSQL{Table: table}.TableName(), OAuth2RequestSQL{Table: table}.TableName(), d), notAfter, p.NetworkID(ctx), @@ -452,15 +608,23 @@ func (p *Persister) flushInactiveTokens(ctx context.Context, notAfter time.Time, return sqlcon.HandleError(err) } -func (p *Persister) FlushInactiveAccessTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int) error { +func (p *Persister) FlushInactiveAccessTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FlushInactiveAccessTokens") + defer otelx.End(span, &err) return p.flushInactiveTokens(ctx, notAfter, limit, batchSize, sqlTableAccess, p.config.GetAccessTokenLifespan(ctx)) } -func (p *Persister) FlushInactiveRefreshTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int) error { +func (p *Persister) FlushInactiveRefreshTokens(ctx context.Context, notAfter time.Time, limit int, batchSize int) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.FlushInactiveRefreshTokens") + defer otelx.End(span, &err) return p.flushInactiveTokens(ctx, notAfter, limit, batchSize, sqlTableRefresh, p.config.GetRefreshTokenLifespan(ctx)) } -func (p *Persister) DeleteAccessTokens(ctx context.Context, clientID string) error { +func (p *Persister) DeleteAccessTokens(ctx context.Context, clientID string) (err error) { + ctx, span := p.r.Tracer(ctx).Tracer().Start(ctx, "persistence.sql.DeleteAccessTokens", + trace.WithAttributes(events.ClientID(clientID)), + ) + defer otelx.End(span, &err) /* #nosec G201 table is static */ return sqlcon.HandleError( p.QueryWithNetwork(ctx).Where("client_id=?", clientID).Delete(&OAuth2RequestSQL{Table: sqlTableAccess}), diff --git a/persistence/sql/persister_test.go b/persistence/sql/persister_test.go index f870e4a81dc..a4818a3e69d 100644 --- a/persistence/sql/persister_test.go +++ b/persistence/sql/persister_test.go @@ -8,26 +8,27 @@ import ( "testing" "time" - "gopkg.in/square/go-jose.v2" + "github.com/ory/hydra/v2/consent/test" + + "github.com/go-jose/go-jose/v3" "github.com/gobuffalo/pop/v6" "github.com/gofrs/uuid" - "github.com/instana/testify/assert" - "github.com/instana/testify/require" "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" - "github.com/ory/hydra/client" - "github.com/ory/hydra/consent" - "github.com/ory/hydra/internal/testhelpers" - "github.com/ory/hydra/oauth2/trust" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/internal/testhelpers" + "github.com/ory/hydra/v2/oauth2/trust" "github.com/ory/x/contextx" "github.com/ory/x/dbal" "github.com/ory/x/networkx" - "github.com/ory/hydra/jwk" + "github.com/ory/hydra/v2/jwk" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/internal" + "github.com/ory/hydra/v2/driver" + "github.com/ory/hydra/v2/internal" ) func init() { @@ -52,12 +53,12 @@ func testRegistry(t *testing.T, ctx context.Context, k string, t1 driver.Registr parallel = false } - t.Run("package=consent/manager="+k, consent.ManagerTests(t1.ConsentManager(), t1.ClientManager(), t1.OAuth2Storage(), "t1", parallel)) - t.Run("package=consent/manager="+k, consent.ManagerTests(t2.ConsentManager(), t2.ClientManager(), t2.OAuth2Storage(), "t2", parallel)) + t.Run("package=consent/manager="+k, test.ManagerTests(t1, t1.ConsentManager(), t1.ClientManager(), t1.OAuth2Storage(), "t1", parallel)) + t.Run("package=consent/manager="+k, test.ManagerTests(t2, t2.ConsentManager(), t2.ClientManager(), t2.OAuth2Storage(), "t2", parallel)) t.Run("parallel-boundary", func(t *testing.T) { - t.Run("package=consent/janitor="+k, testhelpers.JanitorTests(t1.Config(), t1.ConsentManager(), t1.ClientManager(), t1.OAuth2Storage(), "t1", parallel)) - t.Run("package=consent/janitor="+k, testhelpers.JanitorTests(t2.Config(), t2.ConsentManager(), t2.ClientManager(), t2.OAuth2Storage(), "t2", parallel)) + t.Run("package=consent/janitor="+k, testhelpers.JanitorTests(t1, "t1", parallel)) + t.Run("package=consent/janitor="+k, testhelpers.JanitorTests(t2, "t2", parallel)) }) t.Run("package=jwk/manager="+k, func(t *testing.T) { @@ -186,7 +187,7 @@ func TestManagers(t *testing.T) { ) } t.Run("package=consent/manager="+k+"/case=nid", - consent.TestHelperNID(t1.ClientManager(), t1.ConsentManager(), t2.ConsentManager()), + test.TestHelperNID(t1, t1.ConsentManager(), t2.ConsentManager()), ) } } diff --git a/quickstart-cockroach.yml b/quickstart-cockroach.yml index 339f317866b..ebb9218f495 100644 --- a/quickstart-cockroach.yml +++ b/quickstart-cockroach.yml @@ -9,7 +9,6 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### -version: "3.7" services: hydra-migrate: environment: @@ -18,7 +17,7 @@ services: environment: - DSN=cockroach://root@cockroachd:26257/defaultdb?sslmode=disable&max_conns=20&max_idle_conns=4 cockroachd: - image: cockroachdb/cockroach:v22.1.10 + image: cockroachdb/cockroach:latest-v24.1 ports: - "26257:26257" command: start-single-node --insecure diff --git a/quickstart-cors.yml b/quickstart-cors.yml index 0bde8012573..8bc137897ff 100644 --- a/quickstart-cors.yml +++ b/quickstart-cors.yml @@ -9,9 +9,6 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### - -version: "3.7" - services: hydra: environment: diff --git a/quickstart-debug.yml b/quickstart-debug.yml index a64b28efc2e..40780f7260d 100644 --- a/quickstart-debug.yml +++ b/quickstart-debug.yml @@ -9,9 +9,6 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### - -version: "3.7" - services: hydra: environment: diff --git a/quickstart-hsm.yml b/quickstart-hsm.yml index 709ab55e81b..c5822f9ae64 100644 --- a/quickstart-hsm.yml +++ b/quickstart-hsm.yml @@ -9,9 +9,6 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### - -version: "3.7" - services: hydra: build: diff --git a/quickstart-jwt.yml b/quickstart-jwt.yml index 0262dd29c0c..8227be78998 100644 --- a/quickstart-jwt.yml +++ b/quickstart-jwt.yml @@ -9,9 +9,6 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### - -version: "3.7" - services: hydra: environment: diff --git a/quickstart-mysql.yml b/quickstart-mysql.yml index b693d1812b2..28a97b92b1b 100644 --- a/quickstart-mysql.yml +++ b/quickstart-mysql.yml @@ -9,7 +9,6 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### -version: "3.7" services: hydra-migrate: environment: @@ -18,7 +17,7 @@ services: environment: - DSN=mysql://root:secret@tcp(mysqld:3306)/mysql?max_conns=20&max_idle_conns=4 mysqld: - image: mysql:8.0.26 + image: mysql:8.0 ports: - "3306:3306" environment: diff --git a/quickstart-postgres.yml b/quickstart-postgres.yml index a5e845cb948..331ca81c57c 100644 --- a/quickstart-postgres.yml +++ b/quickstart-postgres.yml @@ -9,7 +9,6 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### -version: "3.7" services: hydra-migrate: environment: @@ -18,7 +17,7 @@ services: environment: - DSN=postgres://hydra:secret@postgresd:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4 postgresd: - image: postgres:11.8 + image: postgres:16 ports: - "5432:5432" environment: diff --git a/quickstart-prometheus.yml b/quickstart-prometheus.yml index 89b2455b755..ba944436aad 100644 --- a/quickstart-prometheus.yml +++ b/quickstart-prometheus.yml @@ -9,9 +9,6 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### - -version: "3.7" - services: prometheus: image: prom/prometheus:v2.12.0 diff --git a/quickstart-tracing.yml b/quickstart-tracing.yml index 19bb8657c06..ae7758e4a23 100644 --- a/quickstart-tracing.yml +++ b/quickstart-tracing.yml @@ -9,9 +9,6 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### - -version: "3.7" - services: hydra: depends_on: @@ -22,18 +19,19 @@ services: # - TRACING_SERVICE_NAME="Ory Hydra" - TRACING_PROVIDER=jaeger # - TRACING_PROVIDER=zipkin - # - TRACING_PROVIDER=datadog + # - TRACING_PROVIDER=otel # datadog # - TRACING_PROVIDER=elastic-apm ### Jaeger ### - TRACING_PROVIDERS_JAEGER_SAMPLING_SERVER_URL=http://jaeger:5778/sampling - TRACING_PROVIDERS_JAEGER_LOCAL_AGENT_ADDRESS=jaeger:6831 - - TRACING_PROVIDERS_JAEGER_SAMPLING_TYPE=const - - TRACING_PROVIDERS_JAEGER_SAMPLING_VALUE=1 + - TRACING_PROVIDERS_JAEGER_SAMPLING_TRACE_ID_RATIO=1 ### Zipkin ### # - TRACING_PROVIDERS_ZIPKIN_SERVER_URL=http://zipkin:9411/api/v2/spans ### DataDog ### ### See env vars here: https://docs.datadoghq.com/tracing/setup/go/#configuration) ### - # - DD_SERVICE=Hydra + # - TRACING_PROVIDERS_OTLP_INSECURE=true + # - TRACING_PROVIDERS_OTLP_SAMPLING_SAMPLING_RATIO=1.0 + # - TRACING_PROVIDERS_OTLP_SERVER_URL=localhost:4318 ### Elastic APM ### ### See env vars here: https://www.elastic.co/guide/en/apm/agent/go/1.x/configuration.html) ### # - ELASTIC_APM_SERVER_URL="http://apm-server:8200" @@ -61,3 +59,4 @@ services: # - DD_API_KEY= # Replace it with your DataDog API key # - DD_APM_ENABLED=true # - DD_APM_NON_LOCAL_TRAFFIC=true +# - DD_OTLP_CONFIG_RECEIVER_PROTOCOLS_HTTP_ENDPOINT=0.0.0.0:4318 diff --git a/quickstart.yml b/quickstart.yml index 53087bace2d..c521a273f9d 100644 --- a/quickstart.yml +++ b/quickstart.yml @@ -9,10 +9,9 @@ # endpoint can only be used if you follow the steps in the tutorial. # # # ########################################################################### -version: "3.7" services: hydra: - image: oryd/hydra:v2.0.2 + image: oryd/hydra:v2.2.0 ports: - "4444:4444" # Public port - "4445:4445" # Admin port @@ -34,7 +33,7 @@ services: networks: - intranet hydra-migrate: - image: oryd/hydra:v2.0.2 + image: oryd/hydra:v2.2.0 environment: - DSN=sqlite:///var/lib/sqlite/db.sqlite?_fk=true command: migrate -c /etc/config/hydra/hydra.yml sql -e --yes @@ -52,7 +51,7 @@ services: consent: environment: - HYDRA_ADMIN_URL=http://hydra:4445 - image: oryd/hydra-login-consent-node:v2.0.2 + image: oryd/hydra-login-consent-node:v2.2.0 ports: - "3000:3000" restart: unless-stopped diff --git a/script/render-schemas.sh b/script/render-schemas.sh new file mode 100755 index 00000000000..4946152e1a3 --- /dev/null +++ b/script/render-schemas.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +set -euxo pipefail + +ory_x_version="$(go list -f '{{.Version}}' -m github.com/ory/x)" + +sed "s!ory://tracing-config!https://raw.githubusercontent.com/ory/x/$ory_x_version/otelx/config.schema.json!g;" spec/config.json > .schema/config.schema.json + +git commit --author="ory-bot <60093411+ory-bot@users.noreply.github.com>" -m "autogen: render config schema" .schema/config.schema.json || true diff --git a/scripts/5min-tutorial.sh b/scripts/5min-tutorial.sh index f6ec624e3a2..d5b6c8bb242 100755 --- a/scripts/5min-tutorial.sh +++ b/scripts/5min-tutorial.sh @@ -4,7 +4,7 @@ DB=${DB:-postgres} TRACING=${TRACING:-false} PROMETHEUS=${PROMETHEUS:-false} -DC="docker-compose -f quickstart.yml" +DC="docker compose -f quickstart.yml" if [[ $DB == "mysql" ]]; then DC+=" -f quickstart-mysql.yml" fi @@ -20,4 +20,3 @@ fi DC+=" up --build" $DC - diff --git a/scripts/db-diff.sh b/scripts/db-diff.sh index eee37fec8d4..52e77387ff7 100755 --- a/scripts/db-diff.sh +++ b/scripts/db-diff.sh @@ -81,7 +81,7 @@ function dump_pg { make test-resetdb >/dev/null 2>&1 sleep 4 - go run . migrate sql "$TEST_DATABASE_POSTGRESQL" --yes >&2 || true + go run . migrate sql up "$TEST_DATABASE_POSTGRESQL" --yes >&2 || true sleep 1 pg_dump -s "$TEST_DATABASE_POSTGRESQL" | sed '/^--/d' } @@ -94,9 +94,9 @@ function dump_cockroach { make test-resetdb >/dev/null 2>&1 sleep 4 - go run . migrate sql "$TEST_DATABASE_COCKROACHDB" --yes > /dev/null || true + go run . migrate sql up "$TEST_DATABASE_COCKROACHDB" --yes > /dev/null || true hydra::util::parse-connection-url "${TEST_DATABASE_COCKROACHDB}" - docker run --rm --net=host -it cockroachdb/cockroach:v20.2.6 dump --dump-all --dump-mode=schema --insecure --user="${DB_USER}" --host="${DB_HOST}" --port="${DB_PORT}" + docker run --rm --net=host -it cockroachdb/cockroach:latest-v24.1 dump --dump-all --dump-mode=schema --insecure --user="${DB_USER}" --host="${DB_HOST}" --port="${DB_PORT}" } function dump_sqlite { @@ -107,7 +107,7 @@ function dump_sqlite { hydra::util::ensure-sqlite rm "$SQLITE_PATH" > /dev/null 2>&1 || true - go run -tags sqlite,json1 . migrate sql "sqlite://$SQLITE_PATH?_fk=true" --yes > /dev/null 2>&1 || true + go run -tags sqlite,sqlite_omit_load_extension . migrate sql up "sqlite://$SQLITE_PATH?_fk=true" --yes > /dev/null 2>&1 || true echo '.dump' | sqlite3 "$SQLITE_PATH" } @@ -120,7 +120,7 @@ function dump_mysql { hydra::util::ensure-mysqldump make test-resetdb >/dev/null 2>&1 sleep 10 - go run . migrate sql "$TEST_DATABASE_MYSQL" --yes > /dev/null || true + go run . migrate sql up "$TEST_DATABASE_MYSQL" --yes > /dev/null || true hydra::util::parse-connection-url "${TEST_DATABASE_MYSQL}" mysqldump --user="$DB_USER" --password="$DB_PASSWORD" --host="$DB_HOST" --port="$DB_PORT" "$DB_DB" --no-data } diff --git a/scripts/render-schemas.sh b/scripts/render-schemas.sh new file mode 100755 index 00000000000..4946152e1a3 --- /dev/null +++ b/scripts/render-schemas.sh @@ -0,0 +1,9 @@ +#!/bin/sh + +set -euxo pipefail + +ory_x_version="$(go list -f '{{.Version}}' -m github.com/ory/x)" + +sed "s!ory://tracing-config!https://raw.githubusercontent.com/ory/x/$ory_x_version/otelx/config.schema.json!g;" spec/config.json > .schema/config.schema.json + +git commit --author="ory-bot <60093411+ory-bot@users.noreply.github.com>" -m "autogen: render config schema" .schema/config.schema.json || true diff --git a/spec/api.json b/spec/api.json index d439715e270..26ab8b4dfbf 100644 --- a/spec/api.json +++ b/spec/api.json @@ -2,7 +2,7 @@ "components": { "responses": { "emptyResponse": { - "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 201." + "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 204." }, "errorOAuth2BadRequest": { "content": { @@ -49,6 +49,25 @@ } }, "schemas": { + "CreateVerifiableCredentialRequestBody": { + "properties": { + "format": { + "type": "string" + }, + "proof": { + "$ref": "#/components/schemas/VerifiableCredentialProof" + }, + "types": { + "items": { + "type": "string" + }, + "type": "array" + } + }, + "title": "CreateVerifiableCredentialRequestBody contains the request body to request a verifiable credential.", + "type": "object" + }, + "DefaultError": {}, "JSONRawMessage": { "title": "JSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger." }, @@ -80,6 +99,28 @@ "nullable": true, "type": "string" }, + "RFC6749ErrorJson": { + "properties": { + "error": { + "type": "string" + }, + "error_debug": { + "type": "string" + }, + "error_description": { + "type": "string" + }, + "error_hint": { + "type": "string" + }, + "status_code": { + "format": "int64", + "type": "integer" + } + }, + "title": "RFC6749ErrorJson is a helper struct for JSON encoding/decoding of RFC6749Error.", + "type": "object" + }, "StringSliceJSONFormat": { "items": { "type": "string" @@ -95,8 +136,23 @@ "format": "uuid4", "type": "string" }, + "VerifiableCredentialProof": { + "properties": { + "jwt": { + "type": "string" + }, + "proof_type": { + "type": "string" + } + }, + "title": "VerifiableCredentialProof contains the proof of a verifiable credential.", + "type": "object" + }, "acceptOAuth2ConsentRequest": { "properties": { + "context": { + "$ref": "#/components/schemas/JSONRawMessage" + }, "grant_access_token_audience": { "$ref": "#/components/schemas/StringSliceJSONFormat" }, @@ -146,10 +202,18 @@ "context": { "$ref": "#/components/schemas/JSONRawMessage" }, + "extend_session_lifespan": { + "description": "Extend OAuth2 authentication session lifespan\n\nIf set to `true`, the OAuth2 authentication cookie lifespan is extended. This is for example useful if you want the user to be able to use `prompt=none` continuously.\n\nThis value can only be set to `true` if the user has an authentication, which is the case if the `skip` value is `true`.", + "type": "boolean" + }, "force_subject_identifier": { "description": "ForceSubjectIdentifier forces the \"pairwise\" user ID of the end-user that authenticated. The \"pairwise\" user ID refers to the\n(Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg] of the OpenID\nConnect specification. It allows you to set an obfuscated subject (\"user\") identifier that is unique to the client.\n\nPlease note that this changes the user ID on endpoint /userinfo and sub claim of the ID Token. It does not change the\nsub claim in the OAuth 2.0 Introspection.\n\nPer default, ORY Hydra handles this value with its own algorithm. In case you want to set this yourself\nyou can use this field. Please note that setting this field has no effect if `pairwise` is not configured in\nORY Hydra or the OAuth 2.0 Client does not expect a pairwise identifier (set via `subject_type` key in the client's\nconfiguration).\n\nPlease also be aware that ORY Hydra is unable to properly compute this value during authentication. This implies\nthat you have to compute this value on every authentication process (probably depending on the client ID or some\nother unique value).\n\nIf you fail to compute the proper value, then authentication processes which have id_token_hint set might fail.", "type": "string" }, + "identity_provider_session_id": { + "description": "IdentityProviderSessionID is the session ID of the end-user that authenticated.\nIf specified, we will use this value to propagate the logout.", + "type": "string" + }, "remember": { "description": "Remember, if set to true, tells ORY Hydra to remember this user by telling the user agent (browser) to store\na cookie with authentication data. If the same user performs another OAuth 2.0 Authorization Request, he/she\nwill not be asked to log in again.", "type": "boolean" @@ -193,6 +257,38 @@ ], "type": "object" }, + "credentialSupportedDraft00": { + "description": "Includes information about the supported verifiable credentials.", + "properties": { + "cryptographic_binding_methods_supported": { + "description": "OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported\n\nContains a list of cryptographic binding methods supported for signing the proof.", + "items": { + "type": "string" + }, + "type": "array" + }, + "cryptographic_suites_supported": { + "description": "OpenID Connect Verifiable Credentials Cryptographic Suites Supported\n\nContains a list of cryptographic suites methods supported for signing the proof.", + "items": { + "type": "string" + }, + "type": "array" + }, + "format": { + "description": "OpenID Connect Verifiable Credentials Format\n\nContains the format that is supported by this authorization server.", + "type": "string" + }, + "types": { + "description": "OpenID Connect Verifiable Credentials Types\n\nContains the types of verifiable credentials supported.", + "items": { + "type": "string" + }, + "type": "array" + } + }, + "title": "Verifiable Credentials Metadata (Draft 00)", + "type": "object" + }, "errorOAuth2": { "description": "Error", "properties": { @@ -278,6 +374,7 @@ "type": "object" } }, + "title": "The not ready status of the service.", "type": "object" }, "healthStatus": { @@ -287,6 +384,7 @@ "type": "string" } }, + "title": "The health status of the service.", "type": "object" }, "introspectedOAuth2Token": { @@ -513,6 +611,10 @@ "oAuth2Client": { "description": "OAuth 2.0 Clients are used to perform OAuth 2.0 and OpenID Connect flows. Usually, OAuth 2.0 clients are\ngenerated for applications which want to consume your OAuth 2.0 or OpenID Connect capabilities.", "properties": { + "access_token_strategy": { + "description": "OAuth 2.0 Access Token Strategy\n\nAccessTokenStrategy is the strategy used to generate access tokens.\nValid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens\nSetting the stragegy here overrides the global setting in `strategies.access_token`.", + "type": "string" + }, "allowed_cors_origins": { "$ref": "#/components/schemas/StringSliceJSONFormat" }, @@ -540,7 +642,7 @@ "$ref": "#/components/schemas/NullDuration" }, "client_id": { - "description": "OAuth 2.0 Client ID\n\nThe ID is autogenerated and immutable.", + "description": "OAuth 2.0 Client ID\n\nThe ID is immutable. If no ID is provided, a UUID4 will be generated.", "type": "string" }, "client_name": { @@ -652,12 +754,21 @@ "description": "OpenID Connect Sector Identifier URI\n\nURL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. The URL references a\nfile with a single JSON array of redirect_uri values.", "type": "string" }, + "skip_consent": { + "description": "SkipConsent skips the consent screen for this client. This field can only\nbe set from the admin API.", + "type": "boolean" + }, + "skip_logout_consent": { + "description": "SkipLogoutConsent skips the logout consent screen for this client. This field can only\nbe set from the admin API.", + "type": "boolean" + }, "subject_type": { "description": "OpenID Connect Subject Type\n\nThe `subject_types_supported` Discovery parameter contains a\nlist of the supported subject_type values for this server. Valid types include `pairwise` and `public`.", "type": "string" }, "token_endpoint_auth_method": { - "description": "OAuth 2.0 Token Endpoint Authentication Method\n\nRequested Client Authentication method for the Token Endpoint. The options are:\n\n`client_secret_post`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body.\n`client_secret_basic`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header.\n`private_key_jwt`: Use JSON Web Tokens to authenticate the client.\n`none`: Used for public clients (native apps, mobile apps) which can not have secrets.", + "default": "client_secret_basic", + "description": "OAuth 2.0 Token Endpoint Authentication Method\n\nRequested Client Authentication method for the Token Endpoint. The options are:\n\n`client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header.\n`client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body.\n`private_key_jwt`: Use JSON Web Tokens to authenticate the client.\n`none`: Used for public clients (native apps, mobile apps) which can not have secrets.", "type": "string" }, "token_endpoint_auth_signing_alg": { @@ -812,6 +923,9 @@ "consent_request": { "$ref": "#/components/schemas/oAuth2ConsentRequest" }, + "context": { + "$ref": "#/components/schemas/JSONRawMessage" + }, "expires_at": { "properties": { "access_token": { @@ -906,8 +1020,6 @@ }, "required": [ "challenge", - "requested_scope", - "requested_access_token_audience", "skip", "subject", "client", @@ -973,8 +1085,7 @@ }, "id_token": { "description": "To retrieve a refresh token request the id_token scope.", - "format": "int64", - "type": "integer" + "type": "string" }, "refresh_token": { "description": "The refresh token, which can be used to obtain new\naccess tokens. To retrieve it add the scope \"offline\" to your access token request.", @@ -1025,6 +1136,17 @@ }, "type": "array" }, + "credentials_endpoint_draft_00": { + "description": "OpenID Connect Verifiable Credentials Endpoint\n\nContains the URL of the Verifiable Credentials Endpoint.", + "type": "string" + }, + "credentials_supported_draft_00": { + "description": "OpenID Connect Verifiable Credentials Supported\n\nJSON array containing a list of the Verifiable Credentials supported by this authorization server.", + "items": { + "$ref": "#/components/schemas/credentialSupportedDraft00" + }, + "type": "array" + }, "end_session_endpoint": { "description": "OpenID Connect End-Session Endpoint\n\nURL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP.", "type": "string" @@ -1496,6 +1618,53 @@ }, "type": "object" }, + "unexpectedError": { + "type": "string" + }, + "verifiableCredentialPrimingResponse": { + "properties": { + "c_nonce": { + "type": "string" + }, + "c_nonce_expires_in": { + "format": "int64", + "type": "integer" + }, + "error": { + "type": "string" + }, + "error_debug": { + "type": "string" + }, + "error_description": { + "type": "string" + }, + "error_hint": { + "type": "string" + }, + "format": { + "type": "string" + }, + "status_code": { + "format": "int64", + "type": "integer" + } + }, + "title": "VerifiableCredentialPrimingResponse contains the nonce to include in the proof-of-possession JWT.", + "type": "object" + }, + "verifiableCredentialResponse": { + "properties": { + "credential_draft_00": { + "type": "string" + }, + "format": { + "type": "string" + } + }, + "title": "VerifiableCredentialResponse contains the verifiable credential.", + "type": "object" + }, "version": { "properties": { "version": { @@ -1546,7 +1715,7 @@ "paths": { "/.well-known/jwks.json": { "get": { - "description": "This endpoint returns JSON Web Keys required to verifying OpenID Connect ID Tokens and,\nif enabled, OAuth 2.0 JWT Access Tokens. This endpoint can be used with client libraries like\n[node-jwks-rsa](https://github.com/auth0/node-jwks-rsa) among others.", + "description": "This endpoint returns JSON Web Keys required to verifying OpenID Connect ID Tokens and,\nif enabled, OAuth 2.0 JWT Access Tokens. This endpoint can be used with client libraries like\n[node-jwks-rsa](https://github.com/auth0/node-jwks-rsa) among others.\n\nAdding custom keys requires first creating a keyset via the createJsonWebKeySet operation,\nand then configuring the webfinger.jwks.broadcast_keys configuration value to include the keyset name.", "operationId": "discoverJsonWebKeys", "responses": { "200": { @@ -2836,14 +3005,21 @@ }, "/admin/oauth2/auth/sessions/login": { "delete": { - "description": "This endpoint invalidates a subject's authentication session. After revoking the authentication session, the subject\nhas to re-authenticate at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens and\ndoes not work with OpenID Connect Front- or Back-channel logout.", + "description": "This endpoint invalidates authentication sessions. After revoking the authentication session(s), the subject\nhas to re-authenticate at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens.\n\nIf you send the subject in a query param, all authentication sessions that belong to that subject are revoked.\nNo OpenID Connect Front- or Back-channel logout is performed in this case.\n\nAlternatively, you can send a SessionID via `sid` query param, in which case, only the session that is connected\nto that SessionID is revoked. OpenID Connect Back-channel logout is performed in this case.", "operationId": "revokeOAuth2LoginSessions", "parameters": [ { "description": "OAuth 2.0 Subject\n\nThe subject to revoke authentication sessions for.", "in": "query", "name": "subject", - "required": true, + "schema": { + "type": "string" + } + }, + { + "description": "Login Session ID\n\nThe login session to revoke.", + "in": "query", + "name": "sid", "schema": { "type": "string" } @@ -2864,7 +3040,7 @@ "description": "errorOAuth2" } }, - "summary": "Revokes All OAuth 2.0 Login Sessions of a Subject", + "summary": "Revokes OAuth 2.0 Login Sessions by either a Subject or a SessionID", "tags": [ "oAuth2" ] @@ -3140,6 +3316,58 @@ ] } }, + "/credentials": { + "post": { + "description": "This endpoint creates a verifiable credential that attests that the user\nauthenticated with the provided access token owns a certain public/private key\npair.\n\nMore information can be found at\nhttps://openid.net/specs/openid-connect-userinfo-vc-1_0.html.", + "operationId": "createVerifiableCredential", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateVerifiableCredentialRequestBody" + } + } + }, + "x-originalParamName": "Body" + }, + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/verifiableCredentialResponse" + } + } + }, + "description": "verifiableCredentialResponse" + }, + "400": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/verifiableCredentialPrimingResponse" + } + } + }, + "description": "verifiableCredentialPrimingResponse" + }, + "default": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/errorOAuth2" + } + } + }, + "description": "errorOAuth2" + } + }, + "summary": "Issues a Verifiable Credential", + "tags": [ + "oidc" + ] + } + }, "/health/alive": { "get": { "description": "This endpoint returns a HTTP 200 status code when Ory Hydra is accepting incoming\nHTTP requests. This status does currently not include checks whether the database connection is working.\n\nIf the service supports TLS Edge Termination, this endpoint does not require the\n`X-Forwarded-Proto` header to be set.\n\nBe aware that if you are running multiple nodes of this service, the health status will never\nrefer to the cluster state, only to a single instance.", @@ -3221,7 +3449,7 @@ }, "/oauth2/auth": { "get": { - "description": "Use open source libraries to perform OAuth 2.0 and OpenID Connect\navailable for any programming language. You can find a list of libraries at https://oauth.net/code/\n\nThe Ory SDK is not yet able to this endpoint properly.", + "description": "Use open source libraries to perform OAuth 2.0 and OpenID Connect\navailable for any programming language. You can find a list of libraries at https://oauth.net/code/\n\nThis endpoint should not be used via the Ory SDK and is only included for technical reasons.\nInstead, use one of the libraries linked above.", "operationId": "oAuth2Authorize", "responses": { "302": { @@ -3497,7 +3725,7 @@ }, "/oauth2/token": { "post": { - "description": "Use open source libraries to perform OAuth 2.0 and OpenID Connect\navailable for any programming language. You can find a list of libraries here https://oauth.net/code/\n\nThe Ory SDK is not yet able to this endpoint properly.", + "description": "Use open source libraries to perform OAuth 2.0 and OpenID Connect\navailable for any programming language. You can find a list of libraries here https://oauth.net/code/\n\nThis endpoint should not be used via the Ory SDK and is only included for technical reasons.\nInstead, use one of the libraries linked above.", "operationId": "oauth2TokenExchange", "requestBody": { "content": { diff --git a/spec/config.go b/spec/config.go index 36fda6188dd..01089975937 100644 --- a/spec/config.go +++ b/spec/config.go @@ -13,7 +13,7 @@ import ( "github.com/tidwall/gjson" "github.com/ory/x/logrusx" - "github.com/ory/x/tracing" + "github.com/ory/x/otelx" ) //go:embed config.json @@ -32,7 +32,7 @@ func init() { func AddConfigSchema(compiler interface { AddResource(url string, r io.Reader) error }) error { - if err := tracing.AddConfigSchema(compiler); err != nil { + if err := otelx.AddConfigSchema(compiler); err != nil { return err } if err := logrusx.AddConfigSchema(compiler); err != nil { diff --git a/spec/config.json b/spec/config.json index d0a02bbc6cd..72f81534c66 100644 --- a/spec/config.json +++ b/spec/config.json @@ -1,5 +1,5 @@ { - "$id": "https://github.com/ory/hydra/docs/config.schema.json", + "$id": "https://github.com/ory/hydra/spec/config.json", "$schema": "http://json-schema.org/draft-07/schema#", "title": "Ory Hydra Configuration", "type": "object", @@ -40,7 +40,7 @@ }, "mode": { "type": "integer", - "description": "Mode of unix socket in numeric form", + "description": "Mode of unix socket in numeric form, base 10.", "default": 493, "minimum": 0, "maximum": 511 @@ -248,6 +248,47 @@ } } } + }, + "webhook_config": { + "type": "object", + "additionalProperties": false, + "description": "Configures a webhook.", + "required": ["url"], + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The URL to send the webhook to." + }, + "auth": { + "type": "object", + "additionalProperties": false, + "required": ["type", "config"], + "properties": { + "type": { + "const": "api_key" + }, + "config": { + "type": "object", + "additionalProperties": false, + "required": ["name", "value"], + "properties": { + "in": { + "enum": ["header", "cookie"] + }, + "name": { + "description": "The header or cookie name.", + "type": "string" + }, + "value": { + "description": "The header or cookie value.", + "type": "string" + } + } + } + } + } + } } }, "properties": { @@ -439,6 +480,18 @@ "default": "ory_hydra_session" } } + }, + "paths": { + "title": "Cookie Paths", + "description": "Sets the path for which session cookie is scoped. Use with care!", + "type": "object", + "properties": { + "session": { + "type": "string", + "title": "Session Cookie Path", + "default": "/" + } + } } } } @@ -465,6 +518,16 @@ "description": "Disallow all outgoing HTTP calls to private IP ranges. This feature can help protect against SSRF attacks.", "type": "boolean", "default": false + }, + "private_ip_exception_urls": { + "title": "Add exempt URLs to private IP ranges", + "description": "Allows the given URLs to be called despite them being in the private IP range. URLs need to have an exact and case-sensitive match to be excempt.", + "type": "array", + "items": { + "type": "string", + "format": "uri-reference" + }, + "default": [] } } } @@ -713,6 +776,15 @@ "/ui/login" ] }, + "registration": { + "type": "string", + "description": "Sets the OAuth2 Registration Endpoint URL of the OAuth2 User Login & Consent flow. Defaults to the same value as `login`. The registration URL is used if the authorization request was started with the `prompt=registration` parameter.", + "format": "uri-reference", + "examples": [ + "https://my-login.app/registration", + "/ui/registration" + ] + }, "consent": { "type": "string", "description": "Sets the consent endpoint of the User Login & Consent flow. Defaults to an internal fallback URL showing an error.", @@ -748,6 +820,42 @@ "https://my-example.app/logout-successful", "/ui" ] + }, + "identity_provider": { + "type": "object", + "additionalProperties": false, + "properties": { + "url": { + "title": "The admin URL of the ORY Kratos instance.", + "description": "If set, ORY Hydra will use this URL to log out the user in addition to removing the Hydra session.", + "type": "string", + "format": "uri", + "examples": [ + "https://kratos.example.com/admin" + ] + }, + "publicUrl": { + "title": "The public URL of the ORY Kratos instance.", + "type": "string", + "format": "uri", + "examples": [ + "https://kratos.example.com/public" + ] + }, + "headers": { + "title": "HTTP Request Headers", + "description": "These headers will be passed in HTTP requests to the Identity Provider.", + "type": "object", + "additionalProperties": { + "type": "string" + }, + "examples": [ + { + "Authorization": "Bearer some-token" + } + ] + } + } } } }, @@ -769,6 +877,18 @@ "description": "Defines access token type. jwt is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens", "enum": ["opaque", "jwt"], "default": "opaque" + }, + "jwt": { + "type": "object", + "additionalProperties": false, + "properties": { + "scope_claim": { + "type": "string", + "description": "Defines how the scope claim is represented within a JWT access token", + "enum": ["list", "string", "both"], + "default": "list" + } + } } } }, @@ -865,6 +985,12 @@ }, "examples": [["username", "email", "user_uuid"]] }, + "mirror_top_level_claims": { + "type": "boolean", + "description": "Set to false if you don't want to mirror custom claims under 'ext'", + "default": true, + "examples": [false] + }, "hashers": { "type": "object", "additionalProperties": false, @@ -942,6 +1068,21 @@ "type": "object", "additionalProperties": false, "properties": { + "refresh_token": { + "type": "object", + "properties": { + "grace_period": { + "title": "Refresh Token Rotation Grace Period", + "description": "Configures how long a Refresh Token remains valid after it has been used. The maximum value is one hour.", + "default": "0s", + "allOf": [ + { + "$ref": "#/definitions/duration" + } + ] + } + } + }, "jwt": { "type": "object", "additionalProperties": false, @@ -971,13 +1112,33 @@ } }, "refresh_token_hook": { - "type": "string", "description": "Sets the refresh token hook endpoint. If set it will be called during token refresh to receive updated token claims.", - "format": "uri", - "examples": ["https://my-example.app/token-refresh-hook"] + "examples": ["https://my-example.app/token-refresh-hook"], + "oneOf": [ + { + "type": "string", + "format": "uri" + }, + { + "$ref": "#/definitions/webhook_config" + } + ] + }, + "token_hook": { + "description": "Sets the token hook endpoint for all grant types. If set it will be called while providing token to customize claims.", + "examples": ["https://my-example.app/token-hook"], + "oneOf": [ + { + "type": "string", + "format": "uri" + }, + { + "$ref": "#/definitions/webhook_config" + } + ] } - } - }, + } + }, "secrets": { "type": "object", "additionalProperties": false, @@ -1022,154 +1183,7 @@ "examples": ["cpu"] }, "tracing": { - "type": "object", - "additionalProperties": false, - "description": "Ory Hydra supports distributed tracing.", - "properties": { - "provider": { - "type": "string", - "description": "Set this to the tracing backend you wish to use. Supports Jaeger, Zipkin DataDog, Elastic APM and Instana. If omitted or empty, tracing will be disabled. Use environment variables to configure DataDog (see https://docs.datadoghq.com/tracing/setup/go/#configuration).", - "enum": [ - "jaeger", - "zipkin", - "datadog", - "elastic-apm", - "instana", - "otel" - ], - "examples": ["jaeger"] - }, - "service_name": { - "type": "string", - "description": "Specifies the service name to use on the tracer.", - "examples": ["Ory Hydra"] - }, - "providers": { - "type": "object", - "additionalProperties": false, - "properties": { - "jaeger": { - "type": "object", - "additionalProperties": false, - "description": "Configures the jaeger tracing backend.", - "properties": { - "local_agent_address": { - "type": "string", - "description": "The address of the jaeger-agent where spans should be sent to.", - "oneOf": [ - { - "pattern": "^\\[(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))]:([0-9]*)$" - }, - { - "pattern": "^([0-9]{1,3}\\.){3}[0-9]{1,3}:([0-9]*)$" - }, - { - "format": "uri" - } - ], - "examples": ["127.0.0.1:6831"] - }, - "propagation": { - "type": "string", - "description": "The tracing header format", - "examples": ["jaeger"] - }, - "max_tag_value_length": { - "type": "integer", - "description": "The value passed to the max tag value length that has been configured.", - "minimum": 0 - }, - "sampling": { - "type": "object", - "propertyNames": { - "enum": ["type", "value", "server_url"] - }, - "allOf": [ - { - "oneOf": [ - { - "properties": { - "type": { - "description": "The type of the sampler you want to use.", - "const": "const" - }, - "value": { - "type": "integer", - "description": "The value passed to the sampler type that has been configured.", - "minimum": 0, - "maximum": 1 - } - } - }, - { - "properties": { - "type": { - "description": "The type of the sampler you want to use.", - "const": "rateLimiting" - }, - "value": { - "type": "integer", - "description": "The value passed to the sampler type that has been configured.", - "minimum": 0 - } - } - }, - { - "properties": { - "type": { - "description": "The type of the sampler you want to use.", - "const": "probabilistic" - }, - "value": { - "type": "number", - "description": "The value passed to the sampler type that has been configured.", - "minimum": 0, - "maximum": 1 - } - } - } - ] - }, - { - "properties": { - "server_url": { - "type": "string", - "description": "The address of jaeger-agent's HTTP sampling server", - "format": "uri" - } - } - } - ], - "examples": [ - { - "type": "const", - "value": 1, - "server_url": "http://localhost:5778/sampling" - } - ] - } - } - }, - "zipkin": { - "type": "object", - "additionalProperties": false, - "description": "Configures the zipkin tracing backend.", - "properties": { - "server_url": { - "type": "string", - "description": "The address of Zipkin server where spans should be sent to.", - "format": "uri" - } - }, - "examples": [ - { - "server_url": "http://localhost:9411/api/v2/spans" - } - ] - } - } - } - } + "$ref": "ory://tracing-config" }, "sqa": { "type": "object", @@ -1220,6 +1234,11 @@ "title": "Enable development mode", "description": "If true, disables critical security measures to allow easier local development. Do not use in production.", "default": false + }, + "feature_flags": { + "title": "Feature flags", + "type": "object", + "additionalProperties": true } }, "additionalProperties": false diff --git a/spec/swagger.json b/spec/swagger.json index a1921533f02..734ff1e4b99 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -20,7 +20,7 @@ "paths": { "/.well-known/jwks.json": { "get": { - "description": "This endpoint returns JSON Web Keys required to verifying OpenID Connect ID Tokens and,\nif enabled, OAuth 2.0 JWT Access Tokens. This endpoint can be used with client libraries like\n[node-jwks-rsa](https://github.com/auth0/node-jwks-rsa) among others.", + "description": "This endpoint returns JSON Web Keys required to verifying OpenID Connect ID Tokens and,\nif enabled, OAuth 2.0 JWT Access Tokens. This endpoint can be used with client libraries like\n[node-jwks-rsa](https://github.com/auth0/node-jwks-rsa) among others.\n\nAdding custom keys requires first creating a keyset via the createJsonWebKeySet operation,\nand then configuring the webfinger.jwks.broadcast_keys configuration value to include the keyset name.", "consumes": [ "application/json" ], @@ -1280,7 +1280,7 @@ }, "/admin/oauth2/auth/sessions/login": { "delete": { - "description": "This endpoint invalidates a subject's authentication session. After revoking the authentication session, the subject\nhas to re-authenticate at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens and\ndoes not work with OpenID Connect Front- or Back-channel logout.", + "description": "This endpoint invalidates authentication sessions. After revoking the authentication session(s), the subject\nhas to re-authenticate at the Ory OAuth2 Provider. This endpoint does not invalidate any tokens.\n\nIf you send the subject in a query param, all authentication sessions that belong to that subject are revoked.\nNo OpenID Connect Front- or Back-channel logout is performed in this case.\n\nAlternatively, you can send a SessionID via `sid` query param, in which case, only the session that is connected\nto that SessionID is revoked. OpenID Connect Back-channel logout is performed in this case.", "consumes": [ "application/json" ], @@ -1294,15 +1294,20 @@ "tags": [ "oAuth2" ], - "summary": "Revokes All OAuth 2.0 Login Sessions of a Subject", + "summary": "Revokes OAuth 2.0 Login Sessions by either a Subject or a SessionID", "operationId": "revokeOAuth2LoginSessions", "parameters": [ { "type": "string", "description": "OAuth 2.0 Subject\n\nThe subject to revoke authentication sessions for.", "name": "subject", - "in": "query", - "required": true + "in": "query" + }, + { + "type": "string", + "description": "Login Session ID\n\nThe login session to revoke.", + "name": "sid", + "in": "query" } ], "responses": { @@ -1580,6 +1585,52 @@ } } }, + "/credentials": { + "post": { + "description": "This endpoint creates a verifiable credential that attests that the user\nauthenticated with the provided access token owns a certain public/private key\npair.\n\nMore information can be found at\nhttps://openid.net/specs/openid-connect-userinfo-vc-1_0.html.", + "consumes": [ + "application/json" + ], + "schemes": [ + "http", + "https" + ], + "tags": [ + "oidc" + ], + "summary": "Issues a Verifiable Credential", + "operationId": "createVerifiableCredential", + "parameters": [ + { + "name": "Body", + "in": "body", + "schema": { + "$ref": "#/definitions/CreateVerifiableCredentialRequestBody" + } + } + ], + "responses": { + "200": { + "description": "verifiableCredentialResponse", + "schema": { + "$ref": "#/definitions/verifiableCredentialResponse" + } + }, + "400": { + "description": "verifiableCredentialPrimingResponse", + "schema": { + "$ref": "#/definitions/verifiableCredentialPrimingResponse" + } + }, + "default": { + "description": "errorOAuth2", + "schema": { + "$ref": "#/definitions/errorOAuth2" + } + } + } + } + }, "/health/alive": { "get": { "description": "This endpoint returns a 200 status code when the HTTP server is up running.\nThis status does currently not include checks whether the database connection is working.\n\nIf the service supports TLS Edge Termination, this endpoint does not require the\n`X-Forwarded-Proto` header to be set.\n\nBe aware that if you are running multiple nodes of this service, the health status will never\nrefer to the cluster state, only to a single instance.", @@ -1636,7 +1687,7 @@ }, "/oauth2/auth": { "get": { - "description": "Use open source libraries to perform OAuth 2.0 and OpenID Connect\navailable for any programming language. You can find a list of libraries at https://oauth.net/code/\n\nThe Ory SDK is not yet able to this endpoint properly.", + "description": "Use open source libraries to perform OAuth 2.0 and OpenID Connect\navailable for any programming language. You can find a list of libraries at https://oauth.net/code/\n\nThis endpoint should not be used via the Ory SDK and is only included for technical reasons.\nInstead, use one of the libraries linked above.", "consumes": [ "application/x-www-form-urlencoded" ], @@ -1930,7 +1981,7 @@ "oauth2": [] } ], - "description": "Use open source libraries to perform OAuth 2.0 and OpenID Connect\navailable for any programming language. You can find a list of libraries here https://oauth.net/code/\n\nThe Ory SDK is not yet able to this endpoint properly.", + "description": "Use open source libraries to perform OAuth 2.0 and OpenID Connect\navailable for any programming language. You can find a list of libraries here https://oauth.net/code/\n\nThis endpoint should not be used via the Ory SDK and is only included for technical reasons.\nInstead, use one of the libraries linked above.", "consumes": [ "application/x-www-form-urlencoded" ], @@ -2049,6 +2100,25 @@ } }, "definitions": { + "CreateVerifiableCredentialRequestBody": { + "type": "object", + "title": "CreateVerifiableCredentialRequestBody contains the request body to request a verifiable credential.", + "properties": { + "format": { + "type": "string" + }, + "proof": { + "$ref": "#/definitions/VerifiableCredentialProof" + }, + "types": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "DefaultError": {}, "JSONRawMessage": { "type": "object", "title": "JSONRawMessage represents a json.RawMessage that works well with JSON, SQL, and Swagger." @@ -2058,6 +2128,28 @@ "type": "string", "title": "NullDuration represents a nullable JSON and SQL compatible time.Duration." }, + "RFC6749ErrorJson": { + "type": "object", + "title": "RFC6749ErrorJson is a helper struct for JSON encoding/decoding of RFC6749Error.", + "properties": { + "error": { + "type": "string" + }, + "error_debug": { + "type": "string" + }, + "error_description": { + "type": "string" + }, + "error_hint": { + "type": "string" + }, + "status_code": { + "type": "integer", + "format": "int64" + } + } + }, "StringSliceJSONFormat": { "type": "array", "title": "StringSliceJSONFormat represents []string{} which is encoded to/from JSON for SQL storage.", @@ -2065,10 +2157,25 @@ "type": "string" } }, + "VerifiableCredentialProof": { + "type": "object", + "title": "VerifiableCredentialProof contains the proof of a verifiable credential.", + "properties": { + "jwt": { + "type": "string" + }, + "proof_type": { + "type": "string" + } + } + }, "acceptOAuth2ConsentRequest": { "type": "object", "title": "The request payload used to accept a consent request.", "properties": { + "context": { + "$ref": "#/definitions/JSONRawMessage" + }, "grant_access_token_audience": { "$ref": "#/definitions/StringSliceJSONFormat" }, @@ -2125,10 +2232,18 @@ "context": { "$ref": "#/definitions/JSONRawMessage" }, + "extend_session_lifespan": { + "description": "Extend OAuth2 authentication session lifespan\n\nIf set to `true`, the OAuth2 authentication cookie lifespan is extended. This is for example useful if you want the user to be able to use `prompt=none` continuously.\n\nThis value can only be set to `true` if the user has an authentication, which is the case if the `skip` value is `true`.", + "type": "boolean" + }, "force_subject_identifier": { "description": "ForceSubjectIdentifier forces the \"pairwise\" user ID of the end-user that authenticated. The \"pairwise\" user ID refers to the\n(Pairwise Identifier Algorithm)[http://openid.net/specs/openid-connect-core-1_0.html#PairwiseAlg] of the OpenID\nConnect specification. It allows you to set an obfuscated subject (\"user\") identifier that is unique to the client.\n\nPlease note that this changes the user ID on endpoint /userinfo and sub claim of the ID Token. It does not change the\nsub claim in the OAuth 2.0 Introspection.\n\nPer default, ORY Hydra handles this value with its own algorithm. In case you want to set this yourself\nyou can use this field. Please note that setting this field has no effect if `pairwise` is not configured in\nORY Hydra or the OAuth 2.0 Client does not expect a pairwise identifier (set via `subject_type` key in the client's\nconfiguration).\n\nPlease also be aware that ORY Hydra is unable to properly compute this value during authentication. This implies\nthat you have to compute this value on every authentication process (probably depending on the client ID or some\nother unique value).\n\nIf you fail to compute the proper value, then authentication processes which have id_token_hint set might fail.", "type": "string" }, + "identity_provider_session_id": { + "description": "IdentityProviderSessionID is the session ID of the end-user that authenticated.\nIf specified, we will use this value to propagate the logout.", + "type": "string" + }, "remember": { "description": "Remember, if set to true, tells ORY Hydra to remember this user by telling the user agent (browser) to store\na cookie with authentication data. If the same user performs another OAuth 2.0 Authorization Request, he/she\nwill not be asked to log in again.", "type": "boolean" @@ -2167,6 +2282,38 @@ } } }, + "credentialSupportedDraft00": { + "description": "Includes information about the supported verifiable credentials.", + "type": "object", + "title": "Verifiable Credentials Metadata (Draft 00)", + "properties": { + "cryptographic_binding_methods_supported": { + "description": "OpenID Connect Verifiable Credentials Cryptographic Binding Methods Supported\n\nContains a list of cryptographic binding methods supported for signing the proof.", + "type": "array", + "items": { + "type": "string" + } + }, + "cryptographic_suites_supported": { + "description": "OpenID Connect Verifiable Credentials Cryptographic Suites Supported\n\nContains a list of cryptographic suites methods supported for signing the proof.", + "type": "array", + "items": { + "type": "string" + } + }, + "format": { + "description": "OpenID Connect Verifiable Credentials Format\n\nContains the format that is supported by this authorization server.", + "type": "string" + }, + "types": { + "description": "OpenID Connect Verifiable Credentials Types\n\nContains the types of verifiable credentials supported.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, "errorOAuth2": { "description": "Error", "type": "object", @@ -2246,6 +2393,7 @@ }, "healthNotReadyStatus": { "type": "object", + "title": "The not ready status of the service.", "properties": { "errors": { "description": "Errors contains a list of errors that caused the not ready status.", @@ -2258,6 +2406,7 @@ }, "healthStatus": { "type": "object", + "title": "The health status of the service.", "properties": { "status": { "description": "Status always contains \"ok\".", @@ -2482,6 +2631,10 @@ "type": "object", "title": "OAuth 2.0 Client", "properties": { + "access_token_strategy": { + "description": "OAuth 2.0 Access Token Strategy\n\nAccessTokenStrategy is the strategy used to generate access tokens.\nValid options are `jwt` and `opaque`. `jwt` is a bad idea, see https://www.ory.sh/docs/hydra/advanced#json-web-tokens\nSetting the stragegy here overrides the global setting in `strategies.access_token`.", + "type": "string" + }, "allowed_cors_origins": { "$ref": "#/definitions/StringSliceJSONFormat" }, @@ -2509,7 +2662,7 @@ "$ref": "#/definitions/NullDuration" }, "client_id": { - "description": "OAuth 2.0 Client ID\n\nThe ID is autogenerated and immutable.", + "description": "OAuth 2.0 Client ID\n\nThe ID is immutable. If no ID is provided, a UUID4 will be generated.", "type": "string" }, "client_name": { @@ -2621,13 +2774,22 @@ "description": "OpenID Connect Sector Identifier URI\n\nURL using the https scheme to be used in calculating Pseudonymous Identifiers by the OP. The URL references a\nfile with a single JSON array of redirect_uri values.", "type": "string" }, + "skip_consent": { + "description": "SkipConsent skips the consent screen for this client. This field can only\nbe set from the admin API.", + "type": "boolean" + }, + "skip_logout_consent": { + "description": "SkipLogoutConsent skips the logout consent screen for this client. This field can only\nbe set from the admin API.", + "type": "boolean" + }, "subject_type": { "description": "OpenID Connect Subject Type\n\nThe `subject_types_supported` Discovery parameter contains a\nlist of the supported subject_type values for this server. Valid types include `pairwise` and `public`.", "type": "string" }, "token_endpoint_auth_method": { - "description": "OAuth 2.0 Token Endpoint Authentication Method\n\nRequested Client Authentication method for the Token Endpoint. The options are:\n\n`client_secret_post`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body.\n`client_secret_basic`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header.\n`private_key_jwt`: Use JSON Web Tokens to authenticate the client.\n`none`: Used for public clients (native apps, mobile apps) which can not have secrets.", - "type": "string" + "description": "OAuth 2.0 Token Endpoint Authentication Method\n\nRequested Client Authentication method for the Token Endpoint. The options are:\n\n`client_secret_basic`: (default) Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` encoded in the HTTP Authorization header.\n`client_secret_post`: Send `client_id` and `client_secret` as `application/x-www-form-urlencoded` in the HTTP body.\n`private_key_jwt`: Use JSON Web Tokens to authenticate the client.\n`none`: Used for public clients (native apps, mobile apps) which can not have secrets.", + "type": "string", + "default": "client_secret_basic" }, "token_endpoint_auth_signing_alg": { "description": "OAuth 2.0 Token Endpoint Signing Algorithm\n\nRequested Client Authentication signing algorithm for the Token Endpoint.", @@ -2781,6 +2943,9 @@ "consent_request": { "$ref": "#/definitions/oAuth2ConsentRequest" }, + "context": { + "$ref": "#/definitions/JSONRawMessage" + }, "grant_access_token_audience": { "$ref": "#/definitions/StringSliceJSONFormat" }, @@ -2816,8 +2981,6 @@ "title": "Contains information on an ongoing login request.", "required": [ "challenge", - "requested_scope", - "requested_access_token_audience", "skip", "subject", "client", @@ -2916,8 +3079,7 @@ }, "id_token": { "description": "To retrieve a refresh token request the id_token scope.", - "type": "integer", - "format": "int64" + "type": "string" }, "refresh_token": { "description": "The refresh token, which can be used to obtain new\naccess tokens. To retrieve it add the scope \"offline\" to your access token request.", @@ -2980,6 +3142,17 @@ "type": "string" } }, + "credentials_endpoint_draft_00": { + "description": "OpenID Connect Verifiable Credentials Endpoint\n\nContains the URL of the Verifiable Credentials Endpoint.", + "type": "string" + }, + "credentials_supported_draft_00": { + "description": "OpenID Connect Verifiable Credentials Supported\n\nJSON array containing a list of the Verifiable Credentials supported by this authorization server.", + "type": "array", + "items": { + "$ref": "#/definitions/credentialSupportedDraft00" + } + }, "end_session_endpoint": { "description": "OpenID Connect End-Session Endpoint\n\nURL at the OP to which an RP can perform a redirect to request that the End-User be logged out at the OP.", "type": "string" @@ -3438,6 +3611,53 @@ } } }, + "unexpectedError": { + "type": "string" + }, + "verifiableCredentialPrimingResponse": { + "type": "object", + "title": "VerifiableCredentialPrimingResponse contains the nonce to include in the proof-of-possession JWT.", + "properties": { + "c_nonce": { + "type": "string" + }, + "c_nonce_expires_in": { + "type": "integer", + "format": "int64" + }, + "error": { + "type": "string" + }, + "error_debug": { + "type": "string" + }, + "error_description": { + "type": "string" + }, + "error_hint": { + "type": "string" + }, + "format": { + "type": "string" + }, + "status_code": { + "type": "integer", + "format": "int64" + } + } + }, + "verifiableCredentialResponse": { + "type": "object", + "title": "VerifiableCredentialResponse contains the verifiable credential.", + "properties": { + "credential_draft_00": { + "type": "string" + }, + "format": { + "type": "string" + } + } + }, "version": { "type": "object", "properties": { @@ -3450,7 +3670,7 @@ ,"UUID":{"type": "string", "format": "uuid4"}}, "responses": { "emptyResponse": { - "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 201." + "description": "Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is\ntypically 204." }, "errorOAuth2BadRequest": { "description": "Bad Request Error Response", diff --git a/test/conformance/Dockerfile b/test/conformance/Dockerfile index fcb1130a8ad..ea6f61052c2 100644 --- a/test/conformance/Dockerfile +++ b/test/conformance/Dockerfile @@ -10,7 +10,7 @@ RUN wget https://gitlab.com/openid/conformance-suite/-/archive/release-v4.1.4/co RUN mvn -B clean package -DskipTests && \ apt-get update && apt-get install -y \ - redir ca-certificates && \ + redir ca-certificates COPY ssl/ory-conformity.crt /etc/ssl/certs/ COPY ssl/ory-conformity.key /etc/ssl/private/ diff --git a/test/conformance/hydra/Dockerfile b/test/conformance/hydra/Dockerfile index df86aefa45b..71449925947 100644 --- a/test/conformance/hydra/Dockerfile +++ b/test/conformance/hydra/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.19-buster AS builder +FROM golang:1.22 AS builder RUN apt-get update && \ apt-get install --no-install-recommends -y \ @@ -18,7 +18,7 @@ RUN go mod download COPY . . -RUN go build -tags sqlite,json1 -o /usr/bin/hydra +RUN go build -tags sqlite -o /usr/bin/hydra VOLUME /var/lib/sqlite diff --git a/test/conformance/purge.sh b/test/conformance/purge.sh index caf4491106f..da436588b1d 100755 --- a/test/conformance/purge.sh +++ b/test/conformance/purge.sh @@ -3,4 +3,4 @@ set -euxo pipefail cd "$( dirname "${BASH_SOURCE[0]}" )/../.." -docker-compose -f quickstart.yml -f quickstart-postgres.yml -f test/conformance/docker-compose.yml down -v +docker compose -f quickstart.yml -f quickstart-postgres.yml -f test/conformance/docker-compose.yml down -v diff --git a/test/conformance/run_test.go b/test/conformance/run_test.go index b53de72197b..abab78dbbc2 100644 --- a/test/conformance/run_test.go +++ b/test/conformance/run_test.go @@ -107,24 +107,19 @@ var ( } server = urlx.ParseOrPanic("https://127.0.0.1:8443") config, _ = os.ReadFile("./config.json") - httpClient = httpx.NewResilientClient( - httpx.ResilientClientWithMinxRetryWait(time.Second*5), - httpx.ResilientClientWithClient(&http.Client{ - Timeout: time.Second * 5, - Transport: &http.Transport{ - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: true, - }, - }, - })) - - workdir string + httpClient = httpx.NewResilientClient(httpx.ResilientClientWithMinxRetryWait(time.Second * 5)) + workdir string hydra = hydrac.NewAPIClient(hydrac.NewConfiguration()) ) func init() { - rand.Seed(time.Now().UnixNano()) + httpClient.HTTPClient.Timeout = 5 * time.Second + httpClient.HTTPClient.Transport = &http.Transport{ + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + } hydra.GetConfig().HTTPClient = httpClient.HTTPClient hydra.GetConfig().Servers = hydrac.ServerConfigurations{{URL: "https://127.0.0.1:4445"}} } @@ -224,7 +219,7 @@ func createPlan(t *testing.T, extra url.Values, isParallel bool) { t.Skipf("Test module 'oidcc-server-rotate-keys' can not run in parallel tests and was skipped...") return } else if module != "oidcc-server-rotate-keys" && !isParallel { - t.Skipf("Without paralleism only test module 'oidcc-server-rotate-keys' will be executed.") + t.Skipf("Without parallelism only test module 'oidcc-server-rotate-keys' will be executed.") return } @@ -277,7 +272,7 @@ func createPlan(t *testing.T, extra url.Values, isParallel bool) { bo := conf.NextBackOff() require.NotEqual(t, backoff.Stop, bo, "%+v", err) - _, _, err = hydra.JwkApi.CreateJsonWebKeySet(context.Background(), "hydra.openid.id-token").CreateJsonWebKeySet(hydrac.CreateJsonWebKeySet{ + _, _, err = hydra.JwkAPI.CreateJsonWebKeySet(context.Background(), "hydra.openid.id-token").CreateJsonWebKeySet(hydrac.CreateJsonWebKeySet{ Alg: "RS256", }).Execute() if err == nil { diff --git a/test/conformance/ssl/generate.sh b/test/conformance/ssl/generate.sh index 39779e4c431..363d3ec1792 100755 --- a/test/conformance/ssl/generate.sh +++ b/test/conformance/ssl/generate.sh @@ -4,11 +4,11 @@ set -euxo pipefail cd "$( dirname "${BASH_SOURCE[0]}" )" subj="/C=GB/ST=London/L=London/O=Global Security/OU=IT Department/CN=ory.sh.local" -openssl genrsa -out ory-ca.key 2048 -subj "$subj" +openssl genrsa -out ory-ca.key 2048 openssl req -x509 -new -nodes -key ory-ca.key -sha256 -days 4096 -out ory-ca.pem -subj "$subj" NAME=ory-conformity -openssl genrsa -out $NAME.key 2048 -subj "$subj" +openssl genrsa -out $NAME.key 2048 openssl req -new -key $NAME.key -out $NAME.csr -subj "$subj" cat > $NAME.ext << EOF diff --git a/test/conformance/ssl/ory-ca.key b/test/conformance/ssl/ory-ca.key index ac95905420e..7c86c811b57 100644 --- a/test/conformance/ssl/ory-ca.key +++ b/test/conformance/ssl/ory-ca.key @@ -1,27 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEogIBAAKCAQEAuSTkfDNMsW3lYTQVVtzGR0Uf1b1lrNJuRNT3nDbTGmhR4cUD -Aks3W5cJbZMBm5XS/ym7pLBbCgTj+5N17Mfc6dgTIyzdd1gpFEqTRfmgKZcOfEbQ -EHChMzYPSZS7c2/NTHQX8P4wlvVUjeUi4zA2wZgUqduDwxS+d/BPj/Kqi2samaFm -FVpBxSHgW4MwYKN9WR1KbijIhxaDsqVoypkRPgqmgw3L7HRX0oy2mrd/QFaSfdpi -j2tZPiwL4G1MjHzI3KpWOWWm6RIlkFoI0ihCkS+lIuOZnclW0NIpi0I+xER8X9BR -kzJATJUPTwfxTrVNqFdogjItsqVIYgff4neWzwIDAQABAoIBAHzA3zTRXFwyMN3O -upJNMU3Uxh7AAELziFnZJv+b8aNZp9L5bY2eIS8WFsQ+ylaMHiDRfh76tl2J7hUW -x99EzRbFAiAxmwlP3l5N4e7ExadAogIbtRdezUA0rRhnn+eo7i0WDQvWO+d8Z/00 -6M0tL7hDQakywRYyZCVtSC821LQb0CZ82aA0oRvVO7ZvqCgnD4kCx5LXLkwK+/xe -wVuemjplBVTGZpNhqv73L37eOb1nYxmyYq1Ma9qASP44p1ArR49D+hlvU5w7GLLT -hP//MK00wDLvKEQnVjWv9RSFHHHm5b/Yjg5ibWHvfXmrxqFiVt4dnt3nF8hWvM+a -dC/HxAECgYEA8vbM8j4pMj4l6QveHKX9z686xPKK3xDhtMGJTC/N6w2riFMwor+W -iZaM6agMqJ7iVf9hyePVlrpDLGBY1NMB0mKxJ3cw0xKQNH5l5RRXueEB6gxHgZqU -smASEnoSmxuJlhSXea/EAdpT91lSX1Eg8/VDBSkKOn/ZER+vzO7OX6UCgYEAwxPp -+H7Ou/QeVXssUevnZWh66YgNlKqO6xinQV4iBoH/xM72C7c1AN/KGusq4ZnXetF0 -KkuXGRtmEfeJfZwP+RrtQYKF0Yt6Nuz3hrBvC8UcB6iD0fbfJ/t5WXPo3NjxTTYV -hC81IdpXixtQSBUWQBjN6a50cFOMXxtArZsDEmMCgYA3jbj01sPCqjUu4TjLIiUz -vKRabf7U3F5PX0VOd0vFKB4FkMf5HoeENDlKH9OtJo8oDLnGWOL4kORVHD6Tgx/S -hCBvnrA6Qu9YIWKZC5q3dLxkUKR0/OxtEMxxDxp7/sLp3xF3kHnn1o0GbJUKGFnJ -jlXhsy2UjLEMWktvN1dWxQKBgDgI21c2zZltmN0DAYsSkSgu58d2/jeq+lyLe1eq -e2mVI+vbaw+Yc5ApuDsdO/cLorqzuYOArQlYNmyIxySelHQAiRAdNuUnBFcMoFk/ -Cta9qryEakEAgb9RW90XD1eItV9xXqLWkJOFzUm28cuSyw5kUZmDNA0j4plbEawM -b8hzAoGABhGhbKg7bIWrQM/Y465RL2lKqOt3P+Hs9yXLuVS/q8tTzf6LSus2XD2z -hSeZFEBIE0ufPv1hQD1uW2cLpwckcKts3clFNLaQa4lAgSWRRMkz39IqnmxsgYpx -ZYQtAJrovA79o03ylsgm4LZoLa1LNL09VyqCMMnQhJsGJ1Z9v5I= ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCzxpUrcz4CSi3F +4JCsjIHVe9fZAgax8OWKu+tP6KjnA9nOoF81NEm8etaS1wD071op6MS7qEZ52Ipz +iRjca7dNz0O6rIIZ+Div/4vnQ8zM39hW/nP7x97tGiug+QOh6cN9UiitlzugBuFz ++4N2RNjUfnGUST9080AaTjR4hAp7hyYHmjLFEu/fMQucVDuvUBR7ncMRisclNcj2 +6lMaOp6ohm7GWatJ+MMbZE2Gwi4TlJS8orkFKQ64u/5sKbXpt7NvwjbmGwhLkDj7 +RnNgbY52tyCgogPjF+blwVRH+Noozm5ipxa8CUAzqH3ftbwi2spPJ5TDqlp0HPTP +TeZPMkmBAgMBAAECggEASPCDSVPCju9Fzwkj6b5AVzueAd/+k2en2jgQayV8ke5Q +CrOqrU1/tUcpk/5D1xzdui9E0tadcYZX9jRjr9rMTnePhUfEqYC6jz3hp30stNsF +TZaDvF4FprF9jhw6SxErTcdt1bCMcosYIhSj6/JW/zAmKQHnCy4+je25AESidCdd +NXMqGa/HhmTebjIJcMO3T7iFZ8WAICrVx260iE3Zdw+GyRnybjuHMCtGNVQjeeG1 +G9P6qQKfil07ND9Vvc40h13m7bNuEDuh3oREtWk5LyzL/2HdC/Sk0cyDCrJdjDLz +UE3cJYQUlsSM9rdWL7s6V8BU6W3Y9x8yz1Yg0Bzl2QKBgQDRLPsu16CHuzA2nquS +cuQ/CyiJmx/hPv8h5mj6NtR7TbNLyt5ebKUE31URrYtyASx+grjk6RXjmwkwJLoc +GXxKuYfdxnzM6X5h5pjDJHYVamDW3ZdMeWbL5W2Ci7ux5pLQ0Xmo/Io8x03vc/iH +Z+jJeyewVx/0v9EaAxixlMEUuwKBgQDcBM5ZbrCl0FqraIWGB43bc89ZE7miWsuh +v1bZ2dg6c9PyZSD1Z61h44nFcQUMTwyw/GupqUzyzcgClOUiui9o46WstwASGlPA +EbY52vpk2HGtXj3L+rT35P3CTNVFsdn0/l0BHYSTwNXU6/oVLgBxrKKX+4YKsbH8 +WsjkpJcU8wKBgEcym1CnXmG0ykVdHqMbbiszPhoQbfp6OdctGQBJ12sc2HFs3OGg +805EQi1hN7yXP7DUB+EKoUO2ipsTdTGJTzAUFHXdUK9irnzeQ5Lwfyzs54dbJ1uF +WwL91ZeAvmNgSwq+sj1dsCPd5t4hSC+2o5qoy6qPDTZ+b8r90NLpAgtvAoGALKMM ++jfqvrk2q+/YpwiBTzR/rKLD1px1E6uuAySfKby2E0dRGHigRGvVV6lGTOj8uit7 +7D/czKXTHjL3CcScObt1sUSvTvzoYN83CSXUBwGijnnAL9H9RQ3ALdtIqYsbnQi9 +9av3acKFn10Ar6tVi7pqgksVNrY2VexVNY3u2OECgYA4U/MjlYTrPOEPeSBgxrJ/ +yaX+It1BLrp3iRMygfSGP7jFv+hO6Zok61iBTc7Z/23c97K/kTdxqpf1CoSpjVUg +w7dh1oo3Z3yitT9JQufHPheo9Twp+wD6FuG0eJAfEQGT8rUSMjnhvqrmhjQwIqJn +tHRNAVpIfOKuZFeMVfsNOQ== +-----END PRIVATE KEY----- diff --git a/test/conformance/ssl/ory-ca.pem b/test/conformance/ssl/ory-ca.pem index ff1f45ee072..ca38661e50a 100644 --- a/test/conformance/ssl/ory-ca.pem +++ b/test/conformance/ssl/ory-ca.pem @@ -1,21 +1,23 @@ -----BEGIN CERTIFICATE----- -MIIDbDCCAlQCCQCdoz0sAj5xlzANBgkqhkiG9w0BAQsFADB4MQswCQYDVQQGEwJH -QjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25kb24xGDAWBgNVBAoMD0ds -b2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0bWVudDEVMBMGA1UEAwwM -b3J5LnNoLmxvY2FsMB4XDTIwMTExMDA5MjY1NFoXDTMyMDEyODA5MjY1NFoweDEL -MAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9uZG9uMRgw -FgYDVQQKDA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFydG1lbnQx -FTATBgNVBAMMDG9yeS5zaC5sb2NhbDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC -AQoCggEBALkk5HwzTLFt5WE0FVbcxkdFH9W9ZazSbkTU95w20xpoUeHFAwJLN1uX -CW2TAZuV0v8pu6SwWwoE4/uTdezH3OnYEyMs3XdYKRRKk0X5oCmXDnxG0BBwoTM2 -D0mUu3NvzUx0F/D+MJb1VI3lIuMwNsGYFKnbg8MUvnfwT4/yqotrGpmhZhVaQcUh -4FuDMGCjfVkdSm4oyIcWg7KlaMqZET4KpoMNy+x0V9KMtpq3f0BWkn3aYo9rWT4s -C+BtTIx8yNyqVjllpukSJZBaCNIoQpEvpSLjmZ3JVtDSKYtCPsREfF/QUZMyQEyV -D08H8U61TahXaIIyLbKlSGIH3+J3ls8CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA -ad4IllTfGig/Pcee+hCvYKuFX9n5QbVBUebNzSRIg8LC38jCNTK3dLBeiNel9D0q -TR53s83k9uFfPkmajV1THNIc+phDrrDEAqE7SlUPitdmdZvaFf7Mho5YWca+MpgL -2mawCZZ3ALZ9s4l9Q1v5eA5woZ/AdSJ1ESbVaw1IYV92xvKLRE2Wtr/XMav0eJDQ -ZVBHiXLdYPUcLna5gkfBCCFTliY2FPX6XTAN9u2E/dmva762H15pV2KQmfNmgLVO -wMRygU53w8IoJE79yegLUmMZoGN1KfcxOoCc4Xz58hv1kQo38CE3yCboVtLNoHmv -CuGY6J36+9mQ8bBs26Oinw== +MIID0TCCArmgAwIBAgIUWUAyEMCvpI3KIVx017/mT06RrHkwDQYJKoZIhvcNAQEL +BQAweDELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9u +ZG9uMRgwFgYDVQQKDA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFy +dG1lbnQxFTATBgNVBAMMDG9yeS5zaC5sb2NhbDAeFw0yMzAzMDExMjAzNTlaFw0z +NDA1MTgxMjAzNTlaMHgxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzAN +BgNVBAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQL +DA1JVCBEZXBhcnRtZW50MRUwEwYDVQQDDAxvcnkuc2gubG9jYWwwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCzxpUrcz4CSi3F4JCsjIHVe9fZAgax8OWK +u+tP6KjnA9nOoF81NEm8etaS1wD071op6MS7qEZ52IpziRjca7dNz0O6rIIZ+Div +/4vnQ8zM39hW/nP7x97tGiug+QOh6cN9UiitlzugBuFz+4N2RNjUfnGUST9080Aa +TjR4hAp7hyYHmjLFEu/fMQucVDuvUBR7ncMRisclNcj26lMaOp6ohm7GWatJ+MMb +ZE2Gwi4TlJS8orkFKQ64u/5sKbXpt7NvwjbmGwhLkDj7RnNgbY52tyCgogPjF+bl +wVRH+Noozm5ipxa8CUAzqH3ftbwi2spPJ5TDqlp0HPTPTeZPMkmBAgMBAAGjUzBR +MB0GA1UdDgQWBBR4UYOtflvdNT0SSVnU17OJsMGa6jAfBgNVHSMEGDAWgBR4UYOt +flvdNT0SSVnU17OJsMGa6jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA +A4IBAQCcdZSpSOIUez0yRL7eMqI23XNpaqzm644G9ZvsPijbSJKH8q0OuOF1aC1e +gCBzjkzeJUY83OKav7l/OzP4YeZ71OyHGtMQgFF5p4BDG7WrZWSKKEUHVId+9BET +ZNn3p3HWi0A2G36inNTdOc4dvDBnNYjBMaxRKuG6Mm2YpTcEGseA9u4n3uinz+xY +6A1Q0fFyx9DZP1PA+ZLJLLAuANwmqOMCTNJiLHVEutTjHI000xGBz+hf7tmEZYz+ +cf1+irECFK6+f8XXG4YA+utm4ZrqQ6rpEexyKrU+GkQy9rrxn+dxVEj43xPGbpoJ +G6xXX8xNEXhqL8sDGnTPABucyCLa -----END CERTIFICATE----- diff --git a/test/conformance/ssl/ory-ca.srl b/test/conformance/ssl/ory-ca.srl index 8277e9f8e4d..c781914d726 100644 --- a/test/conformance/ssl/ory-ca.srl +++ b/test/conformance/ssl/ory-ca.srl @@ -1 +1 @@ -DD6B7209999175BD +DD6B7209999175BF diff --git a/test/conformance/ssl/ory-conformity.crt b/test/conformance/ssl/ory-conformity.crt index b926d15bb22..34f396190db 100644 --- a/test/conformance/ssl/ory-conformity.crt +++ b/test/conformance/ssl/ory-conformity.crt @@ -1,26 +1,24 @@ -----BEGIN CERTIFICATE----- -MIIETjCCAzagAwIBAgIJAN1rcgmZkXW9MA0GCSqGSIb3DQEBCwUAMHgxCzAJBgNV +MIID9zCCAt+gAwIBAgIJAN1rcgmZkXW/MA0GCSqGSIb3DQEBCwUAMHgxCzAJBgNV BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRUwEwYD -VQQDDAxvcnkuc2gubG9jYWwwHhcNMjAxMTEwMDkyNjU0WhcNMjMwMjEzMDkyNjU0 +VQQDDAxvcnkuc2gubG9jYWwwHhcNMjMwMzAxMTIwMzU5WhcNMjUwNjAzMTIwMzU5 WjB4MQswCQYDVQQGEwJHQjEPMA0GA1UECAwGTG9uZG9uMQ8wDQYDVQQHDAZMb25k b24xGDAWBgNVBAoMD0dsb2JhbCBTZWN1cml0eTEWMBQGA1UECwwNSVQgRGVwYXJ0 bWVudDEVMBMGA1UEAwwMb3J5LnNoLmxvY2FsMIIBIjANBgkqhkiG9w0BAQEFAAOC -AQ8AMIIBCgKCAQEAweQbhpjij22E/gQo27/mIJIzA5s7Y/PbfRfQXSWQME/UrsKP -6gauioHHN/y+acWinrvM7qjm5t90METdrpGOl1uLSXQcev0SAQWxc6enjIqnBQ7u -dNzg4oEl3SE4IkeXWggdubq6pbch5PxtLnIeO5cXSUaXkRfzEcb7Vk0mY7QGnHTm -kiwQa6B0JKzTps4lT909ueUoTlkRl+xV48vt0igcOAbmm/ONq4GeLucaYOhPOZ2F -Cp20Bx8RzSIOt5+54ziVQWJ2cz6+qamoZTVRqd18sabR5pVAp5z5TB+C8F6CuDxU -NsPX0X12TnDH+MEWzhnEe7Y2cvZU7ez+kxauSwIDAQABo4HaMIHXMIGUBgNVHSME -gYwwgYmhfKR6MHgxCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV -BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J -VCBEZXBhcnRtZW50MRUwEwYDVQQDDAxvcnkuc2gubG9jYWyCCQCdoz0sAj5xlzAJ -BgNVHRMEAjAAMAsGA1UdDwQEAwIE8DAmBgNVHREEHzAdggVodHRwZIIFaHlkcmGC -B2NvbnNlbnSHBH8AAAEwDQYJKoZIhvcNAQELBQADggEBACFr6UqN/9Mx3NuLgFeb -VMfq929BOdbXeRz5lYUsdoBktexDHIRk/zORu6nnsWoGptnk1Swbdq9hj2WLElCS -73GwlDJISCRe65qlhcDPNixOp7R/8ZZMrV4VvhyADXclBsdBVwtYNI42G9MHTxhx -D69JDzbeNRY+aZ5i8DvGh29V+1ZkG9bpwsMIXn1OoF7b3MTQ+s/eajQTnNfvmWXg -jgvFIZZdj5O8apEkO/e6XXAWz5uyVAFzIcWijT+FjyjDdZzVCA1Qx0y2nxAoz2BI -HvdIhX6wXW9p6UBmsuxkVtxLNn/SdGzhl7OA4sWFdJgDmo5/EoKaYvRULxX6Z+sB -qIc= +AQ8AMIIBCgKCAQEAiSU7qDfXU85nV4Uu0vgYGfXNxFhc6Ycyui61LfboP+McczJG +2ldHeQn5v4/ptNhjkVa6WyZ2nrgMNO1cJrVsMJvw0U23gocAvD8u/tUbgwH1bzaE +FUXIhOBLMO/DrKXpimAOwDG4fZ3ywScnwOMyliWcV7U9NpdP7631UKWWpoAB/76c +lM+x5lrOFQ0YqXhQSJDwsZz4Ty8nbRj76ljC/asUzoApyLSpsgBz5GamxXqValnJ +GOiWNbZwBFZi145z1EV8wAYge3QtigITanvIfqZLVw5WXt4fAAdG9HmGheHtgxEY +wtEmdifRyN7t2nppa7cxsD8djxSd0c8283SYDQIDAQABo4GDMIGAMB8GA1UdIwQY +MBaAFHhRg61+W901PRJJWdTXs4mwwZrqMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgTw +MCYGA1UdEQQfMB2CBWh0dHBkggVoeWRyYYIHY29uc2VudIcEfwAAATAdBgNVHQ4E +FgQUnmBi20O87lV+h0snFBa87Us2N2UwDQYJKoZIhvcNAQELBQADggEBABnAsWcK ++YKVLHxoPVJ24SHAH4DwBIOZpzoINWIziL3pWYT56yGZSlPbVrYCaPQi0acmaAnI +IsmtunUbgBzRdKhMlO7vj+PvN0fiV/d5quMlpkIvNSxVNJftXkTm8wbruubFVYMQ +LFeoo1PDHYgZbMAyppjEHQDFd8gqMQcB3msX8hAIlklnPjXvGb0PjJ+ZKcg40FMY +WAqmD23zoqyV5gbPgi+gxvZwLvEG8k2Q9H8iLGiBPQQ9jXFmAIz1bor8ZZTAJ3f1 +wJKoPYAS5qsR1TU3aFfTWiQ+dHqouLUjHXDQjdjU0LewrWi3+QNNaCcWYz7xxiZS +cYbsRyMuKJ/HhRU= -----END CERTIFICATE----- diff --git a/test/conformance/ssl/ory-conformity.csr b/test/conformance/ssl/ory-conformity.csr index f788d77fd1d..b6a2fee2915 100644 --- a/test/conformance/ssl/ory-conformity.csr +++ b/test/conformance/ssl/ory-conformity.csr @@ -2,16 +2,16 @@ MIICvTCCAaUCAQAweDELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0G A1UEBwwGTG9uZG9uMRgwFgYDVQQKDA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsM DUlUIERlcGFydG1lbnQxFTATBgNVBAMMDG9yeS5zaC5sb2NhbDCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMHkG4aY4o9thP4EKNu/5iCSMwObO2Pz230X -0F0lkDBP1K7Cj+oGroqBxzf8vmnFop67zO6o5ubfdDBE3a6Rjpdbi0l0HHr9EgEF -sXOnp4yKpwUO7nTc4OKBJd0hOCJHl1oIHbm6uqW3IeT8bS5yHjuXF0lGl5EX8xHG -+1ZNJmO0Bpx05pIsEGugdCSs06bOJU/dPbnlKE5ZEZfsVePL7dIoHDgG5pvzjauB -ni7nGmDoTzmdhQqdtAcfEc0iDrefueM4lUFidnM+vqmpqGU1UandfLGm0eaVQKec -+UwfgvBegrg8VDbD19F9dk5wx/jBFs4ZxHu2NnL2VO3s/pMWrksCAwEAAaAAMA0G -CSqGSIb3DQEBCwUAA4IBAQC9WyDMh1HO+DH+/KvBgZy1LecI0ScM3K5sNtikDCaJ -KJrbRljUYdJPkFmTO9XCgRYAY3CzlZLj9uURjqRIk7lDUr39bPZzIUBmxYhlkiQ/ -Ivgt52QJYo9RsonQ3g7NoW7IneLJdFn2rBx0Z81qjQV0UNdx/dg5lZVTdeco1JbC -Tj6vO0tKLahBcBwVIcOnHmvf+sp5mwmf12BT6XO13QzOASUssPOGSfXCvA+b6F9Y -bMA3pFgkgzGnAPjPDJdx1oImlg6pRga77scUQNJiVXGP/ZW0lF9GcL44iqcidFnv -MQTqARfG+1hBM87/1JK++On490wvYcy/hKCMb3nwaA3Y +hvcNAQEBBQADggEPADCCAQoCggEBAIklO6g311POZ1eFLtL4GBn1zcRYXOmHMrou +tS326D/jHHMyRtpXR3kJ+b+P6bTYY5FWulsmdp64DDTtXCa1bDCb8NFNt4KHALw/ +Lv7VG4MB9W82hBVFyITgSzDvw6yl6YpgDsAxuH2d8sEnJ8DjMpYlnFe1PTaXT++t +9VCllqaAAf++nJTPseZazhUNGKl4UEiQ8LGc+E8vJ20Y++pYwv2rFM6AKci0qbIA +c+RmpsV6lWpZyRjoljW2cARWYteOc9RFfMAGIHt0LYoCE2p7yH6mS1cOVl7eHwAH +RvR5hoXh7YMRGMLRJnYn0cje7dp6aWu3MbA/HY8UndHPNvN0mA0CAwEAAaAAMA0G +CSqGSIb3DQEBCwUAA4IBAQB2J1BsN8NqGA8v4gtLp3k/35JpFrbGz29K/e/4r7Sl +knFyZl52ImDR4JoQfLNlHZUzTqcVWaas3zFKFyGJ3VoqZA2D1K/3vvMlZbqOmJj7 +TiVNTFTlHzr6eNzK4gkglbIbJItmEDWYUyNdwQrEPJr0ELcFK+ziP67vZ8YIexUb +QMaLgeY64scik/P83bYDLcbDk8ZtbUyc4DmGYu7Wv/qBTY2jZrGSPio5MDceT1Rn +AluxlMCSOHxNDuxmXvpIH9fMl+Msdi7lmQl4FkvcaGvTq0/OnUEr9y6MFYWOHOdh +k2TB7UB5ACBThpclzaSYmNlxzla/DCV5RY0eBKUyhIiO -----END CERTIFICATE REQUEST----- diff --git a/test/conformance/ssl/ory-conformity.key b/test/conformance/ssl/ory-conformity.key index 1728cdca4cd..6e495e49a8f 100644 --- a/test/conformance/ssl/ory-conformity.key +++ b/test/conformance/ssl/ory-conformity.key @@ -1,27 +1,28 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpQIBAAKCAQEAweQbhpjij22E/gQo27/mIJIzA5s7Y/PbfRfQXSWQME/UrsKP -6gauioHHN/y+acWinrvM7qjm5t90METdrpGOl1uLSXQcev0SAQWxc6enjIqnBQ7u -dNzg4oEl3SE4IkeXWggdubq6pbch5PxtLnIeO5cXSUaXkRfzEcb7Vk0mY7QGnHTm -kiwQa6B0JKzTps4lT909ueUoTlkRl+xV48vt0igcOAbmm/ONq4GeLucaYOhPOZ2F -Cp20Bx8RzSIOt5+54ziVQWJ2cz6+qamoZTVRqd18sabR5pVAp5z5TB+C8F6CuDxU -NsPX0X12TnDH+MEWzhnEe7Y2cvZU7ez+kxauSwIDAQABAoIBAE4pGVuJ+BLfkHQh -0yK62hcZOI1kn21smXd1CR7zjIudMtx8PC2YIfZd2KReM5hJ/oNEq5kt5178h0cK -C99aeAPV+HFU6EJAEGjvFZjM5gMGxcuJOGFNxS4p58ybnphbCc1WZj0/5Av3pic8 -BvtpL3zQLKfyWBk6cVciQqGImkgoT57t1HDSkQJFVIAjjx4myxcP7vQvxhj4HouW -1uk40p9sw7I7/VWOycR+Y2A5UKsculVSWNWV9U+pnFWDuDWeorNVBSqanmVznZOi -IiZjP3ipxitFF9OwlPth7mD0DDspTotHa0+ID70tNSosxBxiUhOaFwQr+SarKuEY -bsLZLlECgYEA5yYkOLAPdJW7wvlapHOD0LP1biXhZJuIhlcL/Tf4/KqlXa2ThsI1 -x5oRDTkuAU5Sdkov499l6NbjBxeZTLsh5ViNbn6aSwDVOLsD5tem7/NcvvllpEtI -RdhAgfxg+pzDLiLhU4ewIy0ktcEUekEmrsK1Rwdq46TknRjBG0m50SMCgYEA1ryG -RWFIfxFHr/GY3tMbup3zKtja5iOkkNZyiNRycNs8rL2FHviBf6/cJVY6jDH/GIe9 -Gvt/KVmLMw6aqGk+bO1G03gkV0il8KVOhOXxyHTwIRSd+nIQ2Mdx/+In7cdgq4as -7QX7ohBfDB7qJxTsXqBnV7WOc97lzDfIk5LuBLkCgYEAwxtIu6iwgwHYSMzdG659 -du5PnbfPtnIqHOrgrc5PFkab6qSWv8qyRlbfScAX+vY3WK1qGvf4Nz8axmO+/CuA -guvqBXhLmD+NuqLwuisRN7y9bl1o0/LPgFT2rkFvQlqLzSeX9j+0Bx0VvWzKch8I -Hb8v8FJsgNYwOgIpDXV/qO0CgYEAnVtvZX4hmwP1rWf0pyy6QCmo3PgmiMkLuht7 -uOs9pZfywX7sA0MF2qTrRO0IYF3u2nH10MUFbS6yA8sq6EifN0E1SpfawZ96AnuQ -q3C5mjSfFw69qZ5W3BRjZKi8q9ET9P3u0I421I78p6wr2FHL2JfgwvRHnH91lA44 -zHO6OfkCgYEAnkHD4gOuhJJyb/y1kcOKHduReNZ4Mn49bv6+zI6j5QawrGxf3c6D -u6Xla6bivwjICnsN+cAAPfg86X0yXzlu0YFQYJ2y0idYo3GY8cgCU4Bo5ltF10En -qtR2HQ9oN3HRYZ7hObDgpOj0D2v1lWdGOi4iOofIIE809pLQPDLcBKY= ------END RSA PRIVATE KEY----- +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCJJTuoN9dTzmdX +hS7S+BgZ9c3EWFzphzK6LrUt9ug/4xxzMkbaV0d5Cfm/j+m02GORVrpbJnaeuAw0 +7VwmtWwwm/DRTbeChwC8Py7+1RuDAfVvNoQVRciE4Esw78OspemKYA7AMbh9nfLB +JyfA4zKWJZxXtT02l0/vrfVQpZamgAH/vpyUz7HmWs4VDRipeFBIkPCxnPhPLydt +GPvqWML9qxTOgCnItKmyAHPkZqbFepVqWckY6JY1tnAEVmLXjnPURXzABiB7dC2K +AhNqe8h+pktXDlZe3h8AB0b0eYaF4e2DERjC0SZ2J9HI3u3aemlrtzGwPx2PFJ3R +zzbzdJgNAgMBAAECggEADtDe6QVfVcZuk53nuRLkR6muWQ/SucfJSyPQnu6VmJFI +eYls7hmPtxvEx1UcwlS+LO1ZpI87MVpgtzcNRYFD9txh37qtoIRFKBELWqxbFIQZ +p7IUAthPGUvB07+TPAuQd0p5TXoRnEB8ATHhsYzZ4i6d/TuvKT6ffB0m61d4NvRk +xV0/qgdVgvp5u/QuPb2fP/OPXT9hqki/aZUqlnOLsuvSj54JWnaQia+gJpZD8SpA +2ZYYbcD2gad4fZH8aVKsGPgZZNJ+uxvT/si41rLB5SmiISj7sUUsQIvEw/HkhtPW +RLiMvPeZZLxOHruLJUy24qIZUG69AhPn7kTKO+ILYQKBgQC4Whs3Fy95ySyU4uUq +n46gbm5AaVyDSlXaT0snv4OUn+TI9R8jnBGImUeGeyNuW4fdbezqxEJUp8CnQ68y +qsh0U+pg+mhFc/GmYQIu+KefEQ3lSZPh0AGUeLtYcxHe1w0D2cEGn4RPBp1+q8A6 +8vNzoQD9181Gs+fjc6U5Ectw6wKBgQC+cl2AayYqb1Ualy9fEnN8c1g6O5HHsEvJ +/q/iNeRvN5vdg7wbj9u3gW46/7zo4u0mWL02INISBTXscG/d52IBZQNgJmFFRsQ5 +QNaKgQehL9qqgfCW5jA6fAO2ZfkjdmlpNRIdgk/LITuKivsNH/BkBo3aFOY3cPsw +41hBi5gc5wKBgHkEvcTmdYYPKDL818+pOqnalIm4IMEXNVDAqOeI80nHxRqevzhT +Jbd0V93STCoP8BrOJK7g82I7VV74MbSjJEApLj1HZNfjCwlbuWE4XmEvgt239VpR +gBgFQYcI0vxkU+jpM6uzX9m4z/7tpJ2OC38mfE4nMlxtkZZgvl++bLzNAoGALxLH +p8FUWrLQH1V1QROndgBws1wcCXa7FP+d69UUVKUzIoq4STvCvFYCsBScVhgZNBxF +EIcGRawCCyIzlG7n255jOjXiXyRBxkEPhoakIyRX8UNS+4mELECRDlmgPjK7lWSn +yKF4JaZeOD1oFnNpkN/J2jjGOrfzbr8TBoiBncsCgYEAjRfKBBFy8FjOg1OpixZN +DWBQHFXWAuHeGkSb/enrsyXTxurqmnHyzd0wSd9JE6o7SU/OOWr6yuqmX60YYSTT +NzVG5F2YtErPgE3dapjz2cg8rCjfWVAK8tf7UdDNP/CB2N9BUIJMQ/Quj3NGH19A +N1E6ItYjzbG1BLPg80PkKOI= +-----END PRIVATE KEY----- diff --git a/test/conformance/start.sh b/test/conformance/start.sh index 65080fe2c02..09957271f64 100755 --- a/test/conformance/start.sh +++ b/test/conformance/start.sh @@ -4,4 +4,4 @@ set -euxo pipefail cd "$( dirname "${BASH_SOURCE[0]}" )/../.." # shellcheck disable=SC2086 -docker-compose -f quickstart.yml -f quickstart-postgres.yml -f test/conformance/docker-compose.yml up ${1:-} -d --force-recreate --build +docker compose -f quickstart.yml -f quickstart-postgres.yml -f test/conformance/docker-compose.yml up ${1:-} -d --force-recreate --build diff --git a/test/e2e/circle-ci.bash b/test/e2e/circle-ci.bash index f90ffd15251..03b8f70ac79 100755 --- a/test/e2e/circle-ci.bash +++ b/test/e2e/circle-ci.bash @@ -26,7 +26,7 @@ if [[ ! -d "../../node_modules/" ]]; then (cd ../..; npm ci) fi -(cd ../../; go build -tags sqlite,json1 -o test/e2e/hydra . ) +(cd ../../; go build -tags sqlite -o test/e2e/hydra . ) # Install oauth2-client if [[ ! -d "./oauth2-client/node_modules/" ]]; then @@ -92,7 +92,7 @@ case $i in esac done -./hydra migrate sql --yes $TEST_DATABASE > ./hydra-migrate.e2e.log 2>&1 +./hydra migrate sql up --yes $TEST_DATABASE > ./hydra-migrate.e2e.log 2>&1 DSN=$TEST_DATABASE \ ./hydra serve all --dev --sqa-opt-out > ./hydra.e2e.log 2>&1 & diff --git a/test/e2e/docker-compose.cockroach.yml b/test/e2e/docker-compose.cockroach.yml index 08fd1cd8c2c..de0eee0384c 100644 --- a/test/e2e/docker-compose.cockroach.yml +++ b/test/e2e/docker-compose.cockroach.yml @@ -5,7 +5,7 @@ services: image: oryd/hydra:e2e environment: - DSN=cockroach://root@cockroachd:26257/defaultdb?sslmode=disable&max_conns=20&max_idle_conns=4 - command: migrate sql -e --yes + command: migrate sql up -e --yes restart: on-failure hydra: @@ -15,7 +15,7 @@ services: - DSN=cockroach://root@cockroachd:26257/defaultdb?sslmode=disable&max_conns=20&max_idle_conns=4 cockroachd: - image: cockroachdb/cockroach:v22.1.10 + image: cockroachdb/cockroach:latest-v24.1 ports: - "26257:26257" command: start-single-node --insecure diff --git a/test/e2e/docker-compose.mysql.yml b/test/e2e/docker-compose.mysql.yml index 703e8f3cfef..e8a03d4eb67 100644 --- a/test/e2e/docker-compose.mysql.yml +++ b/test/e2e/docker-compose.mysql.yml @@ -5,7 +5,7 @@ services: image: oryd/hydra:e2e environment: - DSN=mysql://root:secret@tcp(mysqld:3306)/mysql?max_conns=20&max_idle_conns=4 - command: migrate sql -e --yes + command: migrate sql up -e --yes restart: on-failure hydra: @@ -15,8 +15,7 @@ services: - DSN=mysql://root:secret@tcp(mysqld:3306)/mysql?max_conns=20&max_idle_conns=4 mysqld: - image: mysql:8.0.26 - platform: linux/amd64 + image: mysql:8.0 ports: - "3306:3306" environment: diff --git a/test/e2e/docker-compose.postgres.yml b/test/e2e/docker-compose.postgres.yml index 7c1a4f6bee2..72e3ed7443c 100644 --- a/test/e2e/docker-compose.postgres.yml +++ b/test/e2e/docker-compose.postgres.yml @@ -5,7 +5,7 @@ services: image: oryd/hydra:e2e environment: - DSN=postgres://hydra:secret@postgresd:5432/hydra?sslmode=disable&max_conns=20&max_idle_conns=4 - command: migrate sql -e --yes + command: migrate sql up -e --yes restart: on-failure hydra: diff --git a/test/e2e/oauth2-client/package-lock.json b/test/e2e/oauth2-client/package-lock.json index 71812fd7951..ffbd7675356 100644 --- a/test/e2e/oauth2-client/package-lock.json +++ b/test/e2e/oauth2-client/package-lock.json @@ -10,10 +10,10 @@ "dependencies": { "body-parser": "^1.20.1", "dotenv": "^7.0.0", - "express": "^4.18.2", + "express": "^4.21.2", "express-session": "^1.17.0", "express-winston": "^3.4.0", - "hydra-login-consent-logout": "1.4.3", + "hydra-login-consent-logout": "2.0.4-pre.2", "jsonwebtoken": "^8.5.1", "jwks-rsa": "^2.1.4", "node-fetch": "^2.6.0", @@ -24,7 +24,7 @@ }, "devDependencies": { "cross-env": "^5.2.1", - "nodemon": "^1.19.4" + "nodemon": "^2.0.22" } }, "node_modules/@hapi/address": { @@ -66,6 +66,14 @@ "@hapi/hoek": "^8.3.0" } }, + "node_modules/@ory/client": { + "version": "0.2.0-alpha.60", + "resolved": "https://registry.npmjs.org/@ory/client/-/client-0.2.0-alpha.60.tgz", + "integrity": "sha512-fGovJ/xIl7dvJJP9/IL4Xu1yiOCy9pvmkfj2xnHZbPrIbL9c9tqVcC3CSlzBq6zJQZMC3XI7VmZ8uEQ+cF4suw==", + "dependencies": { + "axios": "^0.21.4" + } + }, "node_modules/@panva/asn1.js": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", @@ -112,6 +120,22 @@ "@types/node": "*" } }, + "node_modules/@types/cookie-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/csurf": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@types/csurf/-/csurf-1.11.2.tgz", + "integrity": "sha512-9bc98EnwmC1S0aSJiA8rWwXtgXtXHHOQOsGHptImxFgqm6CeH+mIOunHRg6+/eg2tlmDMX3tY7XrWxo2M/nUNQ==", + "dependencies": { + "@types/express-serve-static-core": "*" + } + }, "node_modules/@types/express": { "version": "4.17.13", "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", @@ -146,6 +170,14 @@ "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, + "node_modules/@types/morgan": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", + "integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "17.0.42", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.42.tgz", @@ -170,6 +202,11 @@ "@types/node": "*" } }, + "node_modules/@types/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-wDXw9LEEUHyV+7UWy7U315nrJGJ7p1BzaCxDpEoLr789Dk1WDVMMlf3iBfbG2F8NdWnYyFbtTxUn2ZNbm1Q4LQ==" + }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -254,24 +291,6 @@ "node": ">=0.10.0" } }, - "node_modules/ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", - "dev": true, - "dependencies": { - "string-width": "^2.0.0" - } - }, - "node_modules/ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -284,52 +303,16 @@ } }, "node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "dependencies": { - "remove-trailing-separator": "^1.0.1" + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, "node_modules/array-flatten": { @@ -337,29 +320,11 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/async": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", @@ -368,22 +333,12 @@ "lodash": "^4.17.14" } }, - "node_modules/async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true, - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" + "node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "dependencies": { + "follow-redirects": "^1.14.0" } }, "node_modules/babel-runtime": { @@ -420,74 +375,6 @@ "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/base64-js": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", @@ -513,39 +400,29 @@ } }, "node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "dependencies": { - "file-uri-to-path": "1.0.0" + "node": ">=8" } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", + "qs": "6.13.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -588,24 +465,6 @@ "integrity": "sha512-b2dgVkTZhkQirNMohgC00rWfpVqEi9y5tKM1k3JvoNx05ODtfQoPPd4js9CYFQoY0IM8LAmnJulEuWv74zjUOg==", "deprecated": "This module has moved and is now available at @hapi/bourne. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." }, - "node_modules/boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "dev": true, - "dependencies": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -617,36 +476,15 @@ } }, "node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/braces/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "fill-range": "^7.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/browserify-zlib": { @@ -679,26 +517,6 @@ "node": ">= 0.8" } }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cacheable-request": { "version": "2.1.4", "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", @@ -722,35 +540,23 @@ } }, "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/capture-stack-trace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", @@ -785,59 +591,30 @@ } }, "node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies", - "dev": true, - "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "optionalDependencies": { - "fsevents": "^1.2.7" - } - }, - "node_modules/ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", - "dev": true - }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/class-utils/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" + "node": ">= 8.10.0" }, - "engines": { - "node": ">=0.10.0" + "optionalDependencies": { + "fsevents": "~2.3.2" } }, "node_modules/clean-css": { @@ -867,15 +644,6 @@ "node": ">=4" } }, - "node_modules/cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cliui": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", @@ -894,19 +662,6 @@ "mimic-response": "^1.0.0" } }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", @@ -960,35 +715,12 @@ "text-hex": "1.0.x" } }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", "dev": true }, - "node_modules/configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", - "dev": true, - "dependencies": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/constantinople": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", @@ -1031,9 +763,9 @@ ] }, "node_modules/content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "engines": { "node": ">= 0.6" } @@ -1063,15 +795,6 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/core-js": { "version": "2.6.11", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", @@ -1084,18 +807,6 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "node_modules/create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "dev": true, - "dependencies": { - "capture-stack-trace": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/cross-env": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.1.tgz", @@ -1128,15 +839,6 @@ "node": ">=4.8" } }, - "node_modules/crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/csrf": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", @@ -1205,9 +907,9 @@ } }, "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==", "engines": { "node": ">=0.10" } @@ -1223,64 +925,20 @@ "node": ">=4" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" + "node": ">= 0.4" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-property/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/depd": { @@ -1315,18 +973,6 @@ "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" }, - "node_modules/dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", - "dev": true, - "dependencies": { - "is-obj": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/dotenv": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", @@ -1362,9 +1008,9 @@ } }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } @@ -1374,6 +1020,25 @@ "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -1408,108 +1073,37 @@ "node": ">= 0.6" } }, - "node_modules/execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "dependencies": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "dependencies": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expand-brackets/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -1518,6 +1112,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express-session": { @@ -1567,9 +1165,9 @@ } }, "node_modules/express/node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -1625,112 +1223,6 @@ "node": ">= 0.8" } }, - "node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend-shallow/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fast-safe-stringify": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", @@ -1741,47 +1233,25 @@ "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, "node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fill-range/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -1811,13 +1281,23 @@ "node": ">= 0.8" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], "engines": { - "node": ">=0.10.0" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } } }, "node_modules/forwarded": { @@ -1828,18 +1308,6 @@ "node": ">= 0.6" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", @@ -1880,928 +1348,788 @@ } }, "node_modules/fsevents": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", - "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", - "bundleDependencies": [ - "node-pre-gyp" - ], - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", "dev": true, "hasInstallScript": true, "optional": true, "os": [ "darwin" ], - "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1", - "node-pre-gyp": "*" - }, "engines": { - "node": ">= 4.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/fsevents/node_modules/abbrev": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, - "node_modules/fsevents/node_modules/ansi-regex": { - "version": "2.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fsevents/node_modules/aproba": { - "version": "1.2.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true + "node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "engines": { + "node": ">=4" + } }, - "node_modules/fsevents/node_modules/are-we-there-yet": { - "version": "1.1.5", + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/fsevents/node_modules/balanced-match": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fsevents/node_modules/chownr": { - "version": "1.1.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/code-point-at": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4.0" } }, - "node_modules/fsevents/node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/console-control-strings": { - "version": "1.1.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } }, - "node_modules/fsevents/node_modules/core-util-is": { + "node_modules/has-property-descriptors": { "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/debug": { - "version": "3.2.6", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dependencies": { - "ms": "^2.1.1" + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fsevents/node_modules/deep-extend": { - "version": "0.6.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", "engines": { - "node": ">=4.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fsevents/node_modules/delegates": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/detect-libc": { - "version": "1.0.3", - "dev": true, - "inBundle": true, - "license": "Apache-2.0", - "optional": true, - "bin": { - "detect-libc": "bin/detect-libc.js" - }, + "node_modules/has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", "engines": { - "node": ">=0.10" + "node": "*" } }, - "node_modules/fsevents/node_modules/fs-minipass": { - "version": "1.2.7", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^2.6.0" + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fsevents/node_modules/fs.realpath": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/gauge": { - "version": "2.7.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, + "node_modules/has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "has-symbol-support-x": "^1.4.1" + }, + "engines": { + "node": "*" } }, - "node_modules/fsevents/node_modules/glob": { - "version": "7.1.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "function-bind": "^1.1.2" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">= 0.4" } }, - "node_modules/fsevents/node_modules/has-unicode": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true + "node_modules/hoek": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", + "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", + "deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." }, - "node_modules/fsevents/node_modules/iconv-lite": { - "version": "0.4.24", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/fsevents/node_modules/ignore-walk": { - "version": "3.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "minimatch": "^3.0.4" + "node_modules/http-errors/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" } }, - "node_modules/fsevents/node_modules/inflight": { - "version": "1.0.6", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } + "node_modules/http-errors/node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "node_modules/fsevents/node_modules/inherits": { - "version": "2.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } }, - "node_modules/fsevents/node_modules/ini": { - "version": "1.3.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, + "node_modules/http-errors/node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "engines": { - "node": "*" + "node": ">=0.6" } }, - "node_modules/fsevents/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "number-is-nan": "^1.0.0" + "node_modules/hydra-login-consent-logout": { + "version": "2.0.4-pre.2", + "resolved": "https://registry.npmjs.org/hydra-login-consent-logout/-/hydra-login-consent-logout-2.0.4-pre.2.tgz", + "integrity": "sha512-nB3JKffjiTyQZzr0DPdkdoUAg7mPlNTv7c/jZrC5IrIyodc3X4s16LzcZJcs/e2U3pZyu3CoWGUrnF//wPzmqQ==", + "dependencies": { + "@ory/client": "^0.2.0-alpha.24", + "@types/cookie-parser": "^1.4.2", + "@types/csurf": "^1.9.36", + "@types/express": "^4.17.7", + "@types/morgan": "^1.9.1", + "@types/url-join": "^4.0.0", + "body-parser": "^1.19.0", + "cookie-parser": "^1.4.5", + "csurf": "^1.11.0", + "debug": "^4.1.1", + "express": "^4.17.1", + "morgan": "^1.10.0", + "node-fetch": "^2.6.7", + "pug": "^2.0.4", + "querystring": "^0.2.0", + "serve-favicon": "^2.5.0", + "typescript": "^3.7.5", + "url-join": "^4.0.1" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "hydra-login-consent-logout": "lib/app.js" } }, - "node_modules/fsevents/node_modules/isarray": { - "version": "1.0.0", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true + "node_modules/hydra-login-consent-logout/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "^2.1.1" + } }, - "node_modules/fsevents/node_modules/minimatch": { - "version": "3.0.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, + "node_modules/hydra-login-consent-logout/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dependencies": { - "brace-expansion": "^1.1.7" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/fsevents/node_modules/minimist": { - "version": "1.2.5", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" }, - "node_modules/fsevents/node_modules/minipass": { - "version": "2.9.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true }, - "node_modules/fsevents/node_modules/minizlib": { - "version": "1.3.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "minipass": "^2.9.0" + "node_modules/indent-string": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", + "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", + "engines": { + "node": ">=4" } }, - "node_modules/fsevents/node_modules/mkdirp": { - "version": "0.5.3", - "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/into-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", "dependencies": { - "minimist": "^1.2.5" + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">=4" } }, - "node_modules/fsevents/node_modules/ms": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/needle": { - "version": "2.3.3", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - }, - "bin": { - "needle": "bin/needle" - }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", "engines": { - "node": ">= 4.4.x" + "node": ">= 0.10" } }, - "node_modules/fsevents/node_modules/node-pre-gyp": { - "version": "0.14.0", + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "inBundle": true, - "license": "BSD-3-Clause", - "optional": true, "dependencies": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" + "binary-extensions": "^2.0.0" }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" + "engines": { + "node": ">=8" } }, - "node_modules/fsevents/node_modules/nopt": { - "version": "4.0.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "abbrev": "1", - "osenv": "^0.1.4" - }, - "bin": { - "nopt": "bin/nopt.js" - } - }, - "node_modules/fsevents/node_modules/npm-bundled": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "node_modules/fsevents/node_modules/npm-normalize-package-bin": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/npm-packlist": { - "version": "1.4.8", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, - "node_modules/fsevents/node_modules/npmlog": { - "version": "4.1.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, + "node_modules/is-expression": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", + "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=", "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "acorn": "~4.0.2", + "object-assign": "^4.0.1" } }, - "node_modules/fsevents/node_modules/number-is-nan": { - "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/is-expression/node_modules/acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", + "bin": { + "acorn": "bin/acorn" + }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/fsevents/node_modules/object-assign": { - "version": "4.1.1", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/fsevents/node_modules/once": { - "version": "1.4.0", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, "dependencies": { - "wrappy": "1" - } - }, - "node_modules/fsevents/node_modules/os-homedir": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "is-extglob": "^2.1.1" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/fsevents/node_modules/os-tmpdir": { - "version": "1.0.2", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.12.0" } }, - "node_modules/fsevents/node_modules/osenv": { - "version": "0.1.5", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "node_modules/fsevents/node_modules/path-is-absolute": { + "node_modules/is-object": { "version": "1.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", "engines": { "node": ">=0.10.0" } }, - "node_modules/fsevents/node_modules/process-nextick-args": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true + "node_modules/is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, - "node_modules/fsevents/node_modules/rc": { - "version": "1.2.8", - "dev": true, - "inBundle": true, - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "optional": true, + "node_modules/is-regex": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", + "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "has": "^1.0.3" }, - "bin": { - "rc": "cli.js" + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fsevents/node_modules/readable-stream": { - "version": "2.3.7", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "node_modules/is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/fsevents/node_modules/rimraf": { - "version": "2.7.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "engines": { + "node": ">=0.10.0" } }, - "node_modules/fsevents/node_modules/safe-buffer": { - "version": "5.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/safer-buffer": { - "version": "2.1.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/fsevents/node_modules/sax": { - "version": "1.2.4", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/semver": { - "version": "5.7.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver" - } + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, - "node_modules/fsevents/node_modules/set-blocking": { + "node_modules/isexe": { "version": "2.0.0", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/signal-exit": { - "version": "3.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/string_decoder": { - "version": "1.1.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, - "node_modules/fsevents/node_modules/string-width": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 4" } }, - "node_modules/fsevents/node_modules/strip-ansi": { - "version": "3.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, + "node_modules/jose": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.7.tgz", + "integrity": "sha512-5hFWIigKqC+e/lRyQhfnirrAqUdIPMB7SJRqflJaO29dW7q5DFvH1XCSTmv6PQ6pb++0k6MJlLRoS0Wv4s38Wg==", "dependencies": { - "ansi-regex": "^2.0.0" + "@panva/asn1.js": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0 < 13 || >=13.7.0" + }, + "funding": { + "url": "https://github.com/sponsors/panva" } }, - "node_modules/fsevents/node_modules/strip-json-comments": { - "version": "2.0.1", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/js-stringify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", + "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" }, - "node_modules/fsevents/node_modules/tar": { - "version": "4.4.13", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", "dependencies": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" }, "engines": { - "node": ">=4.5" + "node": ">=4", + "npm": ">=1.4.28" } }, - "node_modules/fsevents/node_modules/util-deprecate": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "MIT", - "optional": true + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, - "node_modules/fsevents/node_modules/wide-align": { - "version": "1.1.3", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true, + "node_modules/jstransformer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", + "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", "dependencies": { - "string-width": "^1.0.2 || 2" + "is-promise": "^2.0.0", + "promise": "^7.0.1" } }, - "node_modules/fsevents/node_modules/wrappy": { - "version": "1.0.2", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/fsevents/node_modules/yallist": { - "version": "3.1.1", - "dev": true, - "inBundle": true, - "license": "ISC", - "optional": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "node_modules/get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" } }, - "node_modules/get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "node_modules/jwks-rsa": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.1.4.tgz", + "integrity": "sha512-mpArfgPkUpX11lNtGxsF/szkasUcbWHGplZl/uFvFO2NuMHmt0dQXIihh0rkPU2yQd5niQtuUHbXnG/WKiXF6Q==", + "dependencies": { + "@types/express": "^4.17.13", + "@types/jsonwebtoken": "^8.5.8", + "debug": "^4.3.4", + "jose": "^2.0.5", + "limiter": "^1.1.5", + "lru-memoizer": "^2.1.4" + }, "engines": { - "node": ">=4" + "node": ">=10 < 13 || >=14" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true, + "node_modules/jwks-rsa/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, + "node_modules/jwks-rsa/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" } }, - "node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, + "node_modules/keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" + "json-buffer": "3.0.0" } }, - "node_modules/global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", - "dev": true, + "node_modules/kuler": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", + "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", "dependencies": { - "ini": "^1.3.4" - }, - "engines": { - "node": ">=4" + "colornames": "^1.1.1" } }, - "node_modules/got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, - "dependencies": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - }, + "node_modules/lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true + "node_modules/limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "node_modules/lodash": { + "version": "4.17.14", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", + "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, + "node_modules/logform": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", + "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", "dependencies": { - "function-bind": "^1.1.1" - }, + "colors": "^1.2.1", + "fast-safe-stringify": "^2.0.4", + "fecha": "^2.3.3", + "ms": "^2.1.1", + "triple-beam": "^1.3.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "engines": { - "node": ">= 0.4.0" + "node": ">=0.10.0" } }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/has-symbol-support-x": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", - "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "node_modules/lru-cache": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", + "dependencies": { + "pseudomap": "^1.0.1", + "yallist": "^2.0.0" + } + }, + "node_modules/lru-memoizer": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.4.tgz", + "integrity": "sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==", + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "lru-cache": "~4.0.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", "engines": { - "node": "*" + "node": ">= 0.6" } }, - "node_modules/has-symbols": { + "node_modules/merge-descriptors": { "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "engines": { - "node": ">= 0.4" - }, + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/has-to-string-tag-x": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", - "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", - "dependencies": { - "has-symbol-support-x": "^1.4.1" - }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", "engines": { - "node": "*" + "node": ">= 0.6" } }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dependencies": { - "is-buffer": "^1.1.5" + "mime-db": "1.52.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/hoek": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz", - "integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ==", - "deprecated": "This module has moved and is now available at @hapi/hoek. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues." + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } }, - "node_modules/http-cache-semantics": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", - "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } }, - "node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8.0" } }, - "node_modules/http-errors/node_modules/depd": { + "node_modules/morgan/node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", @@ -2809,4196 +2137,2243 @@ "node": ">= 0.8" } }, - "node_modules/http-errors/node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "engines": { - "node": ">= 0.8" + "node": ">= 0.6" } }, - "node_modules/http-errors/node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "engines": { - "node": ">=0.6" - } + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true }, - "node_modules/hydra-login-consent-logout": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/hydra-login-consent-logout/-/hydra-login-consent-logout-1.4.3.tgz", - "integrity": "sha512-q2Y1SBpNnKf869TvloCr0CYL3tIljORDiMsBg/3xG6W+wQXGi7VQ4WJWdQR2hTtkSvYU2dXhLvxsQuFb0+mwlw==", + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", "dependencies": { - "body-parser": "^1.19.0", - "cookie-parser": "^1.4.5", - "csurf": "^1.11.0", - "debug": "^4.1.1", - "express": "^4.17.1", - "morgan": "^1.10.0", - "node-fetch": "^2.6.0", - "pug": "^2.0.4", - "querystring": "^0.2.0", - "serve-favicon": "^2.5.0", - "url-join": "^4.0.1" + "whatwg-url": "^5.0.0" }, - "bin": { - "hydra-login-consent-logout": "bin/www" + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } } }, - "node_modules/hydra-login-consent-logout/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "^2.1.1" + "node_modules/node-forge": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", + "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==", + "engines": { + "node": ">= 4.5.0" } }, - "node_modules/hydra-login-consent-logout/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "node_modules/node-jose": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/node-jose/-/node-jose-1.1.4.tgz", + "integrity": "sha512-L31IFwL3pWWcMHxxidCY51ezqrDXMkvlT/5pLTfNw5sXmmOLJuN6ug7txzF/iuZN55cRpyOmoJrotwBQIoo5Lw==", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" + "base64url": "^3.0.1", + "browserify-zlib": "^0.2.0", + "buffer": "^5.5.0", + "es6-promise": "^4.2.8", + "lodash": "^4.17.15", + "long": "^4.0.0", + "node-forge": "^0.8.5", + "process": "^0.11.10", + "react-zlib-js": "^1.0.4", + "uuid": "^3.3.3" } }, - "node_modules/ieee754": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", - "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "node_modules/node-jose/node_modules/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" }, - "node_modules/ignore-by-default": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", - "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", - "dev": true + "node_modules/node-jose/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } }, - "node_modules/import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true, - "engines": { - "node": ">=4" + "node_modules/node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", + "deprecated": "Use uuid module instead", + "bin": { + "uuid": "bin/uuid" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "node_modules/nodemon": { + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^3.2.7", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, "engines": { - "node": ">=0.8.19" + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" } }, - "node_modules/indent-string": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", - "integrity": "sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=", - "engines": { - "node": ">=4" + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "node_modules/nodemon/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true }, - "node_modules/ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", + "node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, "engines": { "node": "*" } }, - "node_modules/into-stream": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", - "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", "dependencies": { - "from2": "^2.1.1", - "p-is-promise": "^1.1.0" + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" }, "engines": { "node": ">=4" } }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "node_modules/normalize-url/node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "engines": { - "node": ">= 0.10" + "node": ">=4" } }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", "engines": { "node": ">=0.10.0" } }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, + "node_modules/object-hash": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", "engines": { - "node": ">=0.10.0" + "node": ">= 0.10.0" } }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "dependencies": { - "binary-extensions": "^1.0.0" - }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + "node_modules/oidc-token-hash": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-3.0.2.tgz", + "integrity": "sha512-dTzp80/y/da+um+i+sOucNqiPpwRL7M/xPwj7pH1TFA2/bqQ+OK2sJahSXbemEoLtPkHcFLyhLhLWZa9yW5+RA==", + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", - "dev": true, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", "dependencies": { - "ci-info": "^1.5.0" + "ee-first": "1.1.1" }, - "bin": { - "is-ci": "bin.js" + "engines": { + "node": ">= 0.8" } }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, + "node_modules/one-time": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", + "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" + }, + "node_modules/openid-client": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-2.5.0.tgz", + "integrity": "sha512-t3hFD7xEoW1U25RyBcRFaL19fGGs6hNVTysq9pgmiltH0IVUPzH/bQV9w24pM5Q7MunnGv2/5XjIru6BQcWdxg==", "dependencies": { - "is-buffer": "^1.1.5" + "base64url": "^3.0.0", + "got": "^8.3.2", + "lodash": "^4.17.11", + "lru-cache": "^5.1.1", + "node-jose": "^1.1.0", + "object-hash": "^1.3.1", + "oidc-token-hash": "^3.0.1", + "p-any": "^1.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, + "node_modules/openid-client/node_modules/got": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" + "@sindresorhus/is": "^0.7.0", + "cacheable-request": "^2.1.1", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "into-stream": "^3.1.0", + "is-retry-allowed": "^1.1.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "mimic-response": "^1.0.0", + "p-cancelable": "^0.4.0", + "p-timeout": "^2.0.1", + "pify": "^3.0.0", + "safe-buffer": "^5.1.1", + "timed-out": "^4.0.1", + "url-parse-lax": "^3.0.0", + "url-to-options": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-descriptor/node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, + "node_modules/openid-client/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/openid-client/node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-expression": { + "node_modules/openid-client/node_modules/url-parse-lax": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", - "integrity": "sha1-Oayqa+f9HzRx3ELHQW5hwkMXrJ8=", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", "dependencies": { - "acorn": "~4.0.2", - "object-assign": "^4.0.1" + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" } }, - "node_modules/is-expression/node_modules/acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=", - "bin": { - "acorn": "bin/acorn" + "node_modules/openid-client/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/p-any": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-any/-/p-any-1.1.0.tgz", + "integrity": "sha512-Ef0tVa4CZ5pTAmKn+Cg3w8ABBXh+hHO1aV8281dKOoUHfX+3tjG2EaFcC+aZyagg9b4EYGsHEjz21DnEE8Og2g==", + "dependencies": { + "p-some": "^2.0.0" }, "engines": { - "node": ">=0.4.0" + "node": ">=4" } }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, + "node_modules/p-cancelable": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, + "node_modules/p-is-promise": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", "engines": { "node": ">=4" } }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, + "node_modules/p-some": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-some/-/p-some-2.0.1.tgz", + "integrity": "sha1-Zdh8ixVO289SIdFnd4ttLhUPbwY=", "dependencies": { - "is-extglob": "^2.1.1" + "aggregate-error": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", - "dev": true, + "node_modules/p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", "dependencies": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" + "p-finally": "^1.0.0" }, "engines": { "node": ">=4" } }, - "node_modules/is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, - "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, - "node_modules/is-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", - "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, - "node_modules/is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, - "dependencies": { - "path-is-inside": "^1.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6.0" } }, - "node_modules/is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + "node_modules/process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" }, - "node_modules/is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" } }, - "node_modules/is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", "dependencies": { - "has": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-retry-allowed": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", - "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" } }, - "node_modules/is-windows": { + "node_modules/pseudomap": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node_modules/pug": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pug/-/pug-2.0.4.tgz", + "integrity": "sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==", + "dependencies": { + "pug-code-gen": "^2.0.2", + "pug-filters": "^3.1.1", + "pug-lexer": "^4.1.0", + "pug-linker": "^3.0.6", + "pug-load": "^2.0.12", + "pug-parser": "^5.0.1", + "pug-runtime": "^2.0.5", + "pug-strip-comments": "^1.0.4" } }, - "node_modules/isurl": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", - "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "node_modules/pug-attrs": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-2.0.4.tgz", + "integrity": "sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==", "dependencies": { - "has-to-string-tag-x": "^1.2.0", - "is-object": "^1.0.1" - }, - "engines": { - "node": ">= 4" + "constantinople": "^3.0.1", + "js-stringify": "^1.0.1", + "pug-runtime": "^2.0.5" } }, - "node_modules/jose": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz", - "integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==", + "node_modules/pug-code-gen": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-2.0.3.tgz", + "integrity": "sha512-r9sezXdDuZJfW9J91TN/2LFbiqDhmltTFmGpHTsGdrNGp3p4SxAjjXEfnuK2e4ywYsRIVP0NeLbSAMHUcaX1EA==", "dependencies": { - "@panva/asn1.js": "^1.0.0" - }, - "engines": { - "node": ">=10.13.0 < 13 || >=13.7.0" - }, - "funding": { - "url": "https://github.com/sponsors/panva" + "constantinople": "^3.1.2", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.1", + "pug-attrs": "^2.0.4", + "pug-error": "^1.3.3", + "pug-runtime": "^2.0.5", + "void-elements": "^2.0.1", + "with": "^5.0.0" } }, - "node_modules/js-stringify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", - "integrity": "sha1-Fzb939lyTyijaCrcYjCufk6Weds=" + "node_modules/pug-error": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-1.3.3.tgz", + "integrity": "sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==" }, - "node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=" + "node_modules/pug-filters": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.1.1.tgz", + "integrity": "sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==", + "dependencies": { + "clean-css": "^4.1.11", + "constantinople": "^3.0.1", + "jstransformer": "1.0.0", + "pug-error": "^1.3.3", + "pug-walk": "^1.1.8", + "resolve": "^1.1.6", + "uglify-js": "^2.6.1" + } }, - "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "node_modules/pug-lexer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.1.0.tgz", + "integrity": "sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==", "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=4", - "npm": ">=1.4.28" + "character-parser": "^2.1.1", + "is-expression": "^3.0.0", + "pug-error": "^1.3.3" } }, - "node_modules/jsonwebtoken/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "node_modules/pug-linker": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-3.0.6.tgz", + "integrity": "sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==", + "dependencies": { + "pug-error": "^1.3.3", + "pug-walk": "^1.1.8" + } }, - "node_modules/jstransformer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/jstransformer/-/jstransformer-1.0.0.tgz", - "integrity": "sha1-7Yvwkh4vPx7U1cGkT2hwntJHIsM=", + "node_modules/pug-load": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-2.0.12.tgz", + "integrity": "sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==", "dependencies": { - "is-promise": "^2.0.0", - "promise": "^7.0.1" + "object-assign": "^4.1.0", + "pug-walk": "^1.1.8" } }, - "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "node_modules/pug-parser": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.1.tgz", + "integrity": "sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==", "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" + "pug-error": "^1.3.3", + "token-stream": "0.0.1" } }, - "node_modules/jwks-rsa": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/jwks-rsa/-/jwks-rsa-2.1.4.tgz", - "integrity": "sha512-mpArfgPkUpX11lNtGxsF/szkasUcbWHGplZl/uFvFO2NuMHmt0dQXIihh0rkPU2yQd5niQtuUHbXnG/WKiXF6Q==", + "node_modules/pug-runtime": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-2.0.5.tgz", + "integrity": "sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==" + }, + "node_modules/pug-strip-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz", + "integrity": "sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==", "dependencies": { - "@types/express": "^4.17.13", - "@types/jsonwebtoken": "^8.5.8", - "debug": "^4.3.4", - "jose": "^2.0.5", - "limiter": "^1.1.5", - "lru-memoizer": "^2.1.4" - }, - "engines": { - "node": ">=10 < 13 || >=14" + "pug-error": "^1.3.3" } }, - "node_modules/jwks-rsa/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/pug-walk": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz", + "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==" + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "ms": "2.1.2" + "side-channel": "^1.0.6" }, "engines": { - "node": ">=6.0" + "node": ">=0.6" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/jwks-rsa/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - }, - "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "node_modules/query-string": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/keyv": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", - "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", - "dependencies": { - "json-buffer": "3.0.0" + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" } }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/kuler": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", - "integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==", - "dependencies": { - "colornames": "^1.1.1" + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" } }, - "node_modules/latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", - "dev": true, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dependencies": { - "package-json": "^4.0.0" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" }, "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/lazy-cache": { + "node_modules/react-zlib-js": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/limiter": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", - "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==" - }, - "node_modules/lodash": { - "version": "4.17.14", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz", - "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==" - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==" - }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + "resolved": "https://registry.npmjs.org/react-zlib-js/-/react-zlib-js-1.0.4.tgz", + "integrity": "sha512-ynXD9DFxpE7vtGoa3ZwBtPmZrkZYw2plzHGbanUjBOSN4RtuXdektSfABykHtTiWEHMh7WdYj45LHtp228ZF1A==" }, - "node_modules/logform": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz", - "integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==", + "node_modules/readable-stream": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", + "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", "dependencies": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", - "fecha": "^2.3.3", - "ms": "^2.1.1", - "triple-beam": "^1.3.0" - } - }, - "node_modules/logform/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node_modules/long": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" - }, - "node_modules/longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, - "node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8.10.0" } }, - "node_modules/lru-cache": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", - "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", - "dependencies": { - "pseudomap": "^1.0.1", - "yallist": "^2.0.0" - } + "node_modules/regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, - "node_modules/lru-memoizer": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/lru-memoizer/-/lru-memoizer-2.1.4.tgz", - "integrity": "sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==", - "dependencies": { - "lodash.clonedeep": "^4.5.0", - "lru-cache": "~4.0.0" + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "engines": { + "node": ">=0.10" } }, - "node_modules/make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, + "node_modules/resolve": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.0.tgz", + "integrity": "sha512-LarL/PIKJvc09k1jaeT4kQb/8/7P+qV4qSnN2K80AES+OHdfZELAKVOBjxsvtToT/uLOfFbvYvKfZmV8cee7nA==", "dependencies": { - "pify": "^3.0.0" + "path-parse": "^1.0.6" }, - "engines": { - "node": ">=4" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dependencies": { + "lowercase-keys": "^1.0.0" } }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, + "node_modules/right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", "dependencies": { - "object-visit": "^1.0.0" + "align-text": "^0.1.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", - "engines": { - "node": ">= 0.6" - } + "node_modules/rndm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", + "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=" }, - "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "node_modules/methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", - "engines": { - "node": ">= 0.6" + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "bin": { + "semver": "bin/semver" } }, - "node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "bin": { - "mime": "cli.js" - }, + "node_modules/send/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dependencies": { - "mime-db": "1.52.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, - "node_modules/mimic-response": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", - "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, + "node_modules/serve-favicon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", + "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=", "dependencies": { - "brace-expansion": "^1.1.7" + "etag": "~1.8.1", + "fresh": "0.5.2", + "ms": "2.1.1", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.1" }, "engines": { - "node": "*" + "node": ">= 0.8.0" } }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true + "node_modules/serve-favicon/node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } + "node_modules/serve-favicon/node_modules/safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "is-plain-object": "^2.0.4" + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dependencies": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/morgan/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" + "node": ">= 0.4" } }, - "node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "node_modules/nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", "dev": true, "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "shebang-regex": "^1.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/negotiator": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", - "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==", + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, "engines": { - "node": "4.x || >=6.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/node-forge": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.8.5.tgz", - "integrity": "sha512-vFMQIWt+J/7FLNyKouZ9TazT74PRV3wgv9UT4cRjC8BffxFbKXkgIWR42URCPSnHm/QDz6BOlb2Q0U4+VQT67Q==", - "engines": { - "node": ">= 4.5.0" + "node_modules/simple-oauth2": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/simple-oauth2/-/simple-oauth2-2.5.2.tgz", + "integrity": "sha512-8qjf+nHRdSUllFjjfpnonrU1oF/HNVbDle5HIbvXRYiy38C7KUvYe6w0ZZ//g4AFB6VNWuiZ80HmnycR8ZFDyQ==", + "deprecated": "simple-oauth2 v2 is no longer supported. Please upgrade to v3 for further support", + "dependencies": { + "@hapi/joi": "^15.1.1", + "date-fns": "^2.2.1", + "debug": "^4.1.1", + "wreck": "^14.0.2" } }, - "node_modules/node-jose": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/node-jose/-/node-jose-1.1.4.tgz", - "integrity": "sha512-L31IFwL3pWWcMHxxidCY51ezqrDXMkvlT/5pLTfNw5sXmmOLJuN6ug7txzF/iuZN55cRpyOmoJrotwBQIoo5Lw==", + "node_modules/simple-oauth2/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", "dependencies": { - "base64url": "^3.0.1", - "browserify-zlib": "^0.2.0", - "buffer": "^5.5.0", - "es6-promise": "^4.2.8", - "lodash": "^4.17.15", - "long": "^4.0.0", - "node-forge": "^0.8.5", - "process": "^0.11.10", - "react-zlib-js": "^1.0.4", - "uuid": "^3.3.3" + "ms": "^2.1.1" } }, - "node_modules/node-jose/node_modules/lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==" - }, - "node_modules/node-jose/node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "bin": { - "uuid": "bin/uuid" - } + "node_modules/simple-oauth2/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, - "node_modules/node-uuid": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", - "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=", - "deprecated": "Use uuid module instead", - "bin": { - "uuid": "bin/uuid" + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "dependencies": { + "is-arrayish": "^0.3.1" } }, - "node_modules/nodemon": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz", - "integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==", + "node_modules/simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", "dev": true, - "hasInstallScript": true, "dependencies": { - "chokidar": "^2.1.8", - "debug": "^3.2.6", - "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", - "semver": "^5.7.1", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^2.5.0" - }, - "bin": { - "nodemon": "bin/nodemon.js" + "semver": "~7.0.0" }, "engines": { - "node": ">=4" + "node": ">=8.10.0" } }, - "node_modules/nodemon/node_modules/debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/nodemon/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", "dev": true, "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" } }, - "node_modules/nopt": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", - "dev": true, + "node_modules/sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" + "is-plain-obj": "^1.0.0" }, "engines": { - "node": "*" + "node": ">=4" } }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", "engines": { "node": ">=0.10.0" } }, - "node_modules/normalize-url": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", - "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", - "dependencies": { - "prepend-http": "^2.0.0", - "query-string": "^5.0.1", - "sort-keys": "^2.0.0" - }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", "engines": { - "node": ">=4" + "node": "*" } }, - "node_modules/normalize-url/node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", "engines": { - "node": ">=4" + "node": ">= 0.6" } }, - "node_modules/npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "dependencies": { - "path-key": "^2.0.0" - }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "engines": { - "node": ">=0.10.0" + "node_modules/string_decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", + "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", + "dependencies": { + "safe-buffer": "~5.1.0" } }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "has-flag": "^3.0.0" }, + "engines": { + "node": ">=4" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", "engines": { "node": ">=0.10.0" } }, - "node_modules/object-copy/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, + "node_modules/to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", "engines": { "node": ">=0.10.0" } }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "dependencies": { - "is-buffer": "^1.1.5" + "is-number": "^7.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0" } }, - "node_modules/object-hash": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", - "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", "engines": { - "node": ">= 0.10.0" + "node": ">=0.6" } }, - "node_modules/object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "node_modules/token-stream": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz", + "integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=" }, - "node_modules/object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", "dev": true, "dependencies": { - "isobject": "^3.0.0" + "nopt": "~1.0.10" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "nodetouch": "bin/nodetouch.js" } }, - "node_modules/object.pick": { + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/triple-beam": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", + "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "engines": { + "node": ">=0.6.x" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dependencies": { - "isobject": "^3.0.1" + "media-typer": "0.3.0", + "mime-types": "~2.1.24" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/oidc-token-hash": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-3.0.2.tgz", - "integrity": "sha512-dTzp80/y/da+um+i+sOucNqiPpwRL7M/xPwj7pH1TFA2/bqQ+OK2sJahSXbemEoLtPkHcFLyhLhLWZa9yW5+RA==", + "node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, "engines": { - "node": ">=6.9.0" + "node": ">=4.2.0" } }, - "node_modules/on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "node_modules/uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", "dependencies": { - "ee-first": "1.1.1" + "source-map": "~0.5.1", + "yargs": "~3.10.0" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" }, "engines": { - "node": ">= 0.8" + "node": ">=0.8.0" + }, + "optionalDependencies": { + "uglify-to-browserify": "~1.0.0" } }, - "node_modules/on-headers": { + "node_modules/uglify-to-browserify": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, "engines": { "node": ">= 0.8" } }, - "node_modules/one-time": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz", - "integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4=" + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true }, - "node_modules/openid-client": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-2.5.0.tgz", - "integrity": "sha512-t3hFD7xEoW1U25RyBcRFaL19fGGs6hNVTysq9pgmiltH0IVUPzH/bQV9w24pM5Q7MunnGv2/5XjIru6BQcWdxg==", - "dependencies": { - "base64url": "^3.0.0", - "got": "^8.3.2", - "lodash": "^4.17.11", - "lru-cache": "^5.1.1", - "node-jose": "^1.1.0", - "object-hash": "^1.3.1", - "oidc-token-hash": "^3.0.1", - "p-any": "^1.1.0" - }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", "engines": { - "node": ">=6.9.0" + "node": ">= 0.8" } }, - "node_modules/openid-client/node_modules/got": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", - "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", - "dependencies": { - "@sindresorhus/is": "^0.7.0", - "cacheable-request": "^2.1.1", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "into-stream": "^3.1.0", - "is-retry-allowed": "^1.1.0", - "isurl": "^1.0.0-alpha5", - "lowercase-keys": "^1.0.0", - "mimic-response": "^1.0.0", - "p-cancelable": "^0.4.0", - "p-timeout": "^2.0.1", - "pify": "^3.0.0", - "safe-buffer": "^5.1.1", - "timed-out": "^4.0.1", - "url-parse-lax": "^3.0.0", - "url-to-options": "^1.0.1" - }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" + }, + "node_modules/url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", "engines": { - "node": ">=4" + "node": ">= 4" } }, - "node_modules/openid-client/node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dependencies": { - "yallist": "^3.0.2" + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" } }, - "node_modules/openid-client/node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/openid-client/node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", - "dependencies": { - "prepend-http": "^2.0.0" - }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/openid-client/node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, - "node_modules/p-any": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-any/-/p-any-1.1.0.tgz", - "integrity": "sha512-Ef0tVa4CZ5pTAmKn+Cg3w8ABBXh+hHO1aV8281dKOoUHfX+3tjG2EaFcC+aZyagg9b4EYGsHEjz21DnEE8Og2g==", + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", "dependencies": { - "p-some": "^2.0.0" - }, - "engines": { - "node": ">=4" + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" } }, - "node_modules/p-cancelable": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", - "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", - "engines": { - "node": ">=4" + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" } }, - "node_modules/p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "node_modules/window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", "engines": { - "node": ">=4" + "node": ">= 0.8.0" } }, - "node_modules/p-is-promise": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", - "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "node_modules/winston": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", + "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", + "dependencies": { + "async": "^2.6.1", + "diagnostics": "^1.1.1", + "is-stream": "^1.1.0", + "logform": "^2.1.1", + "one-time": "0.0.4", + "readable-stream": "^3.1.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.3.0" + }, "engines": { - "node": ">=4" + "node": ">= 6.4.0" } }, - "node_modules/p-some": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-some/-/p-some-2.0.1.tgz", - "integrity": "sha1-Zdh8ixVO289SIdFnd4ttLhUPbwY=", + "node_modules/winston-transport": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", + "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", "dependencies": { - "aggregate-error": "^1.0.0" + "readable-stream": "^2.3.6", + "triple-beam": "^1.2.0" }, "engines": { - "node": ">=4" + "node": ">= 6.4.0" } }, - "node_modules/p-timeout": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", - "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", "dependencies": { - "p-finally": "^1.0.0" - }, - "engines": { - "node": ">=4" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", - "dev": true, + "node_modules/winston-transport/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dependencies": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - }, - "engines": { - "node": ">=4" + "safe-buffer": "~5.1.0" } }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + "node_modules/with": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/with/-/with-5.1.1.tgz", + "integrity": "sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=", + "dependencies": { + "acorn": "^3.1.0", + "acorn-globals": "^3.0.0" + } }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "node_modules/wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", "engines": { - "node": ">= 0.8" + "node": ">=0.4.0" } }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node_modules/wreck": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/wreck/-/wreck-14.2.0.tgz", + "integrity": "sha512-NFFft3SMgqrJbXEVfYifh+QDWFxni+98/I7ut7rLbz3F0XOypluHsdo3mdEYssGSirMobM3fGlqhyikbWKDn2Q==", + "deprecated": "This module has moved and is now available at @hapi/wreck. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", + "dependencies": { + "boom": "7.x.x", + "bourne": "1.x.x", + "hoek": "6.x.x" } }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node_modules/yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dependencies": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true, + "node_modules/yargs/node_modules/camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", "engines": { - "node": ">=4" + "node": ">=0.10.0" } + } + }, + "dependencies": { + "@hapi/address": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", + "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==" }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + "@hapi/bourne": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", + "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "@hapi/hoek": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", + "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==" }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "engines": { - "node": ">=4" + "@hapi/joi": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", + "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", + "requires": { + "@hapi/address": "2.x.x", + "@hapi/bourne": "1.x.x", + "@hapi/hoek": "8.x.x", + "@hapi/topo": "3.x.x" } }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "@hapi/topo": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", + "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", + "requires": { + "@hapi/hoek": "^8.3.0" } }, - "node_modules/prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "@ory/client": { + "version": "0.2.0-alpha.60", + "resolved": "https://registry.npmjs.org/@ory/client/-/client-0.2.0-alpha.60.tgz", + "integrity": "sha512-fGovJ/xIl7dvJJP9/IL4Xu1yiOCy9pvmkfj2xnHZbPrIbL9c9tqVcC3CSlzBq6zJQZMC3XI7VmZ8uEQ+cF4suw==", + "requires": { + "axios": "^0.21.4" } }, - "node_modules/process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "engines": { - "node": ">= 0.6.0" - } + "@panva/asn1.js": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", + "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==" }, - "node_modules/process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" }, - "node_modules/promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "dependencies": { - "asap": "~2.0.3" - } + "@types/babel-types": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.7.tgz", + "integrity": "sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==" }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" + "@types/babylon": { + "version": "6.16.5", + "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.5.tgz", + "integrity": "sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==", + "requires": { + "@types/babel-types": "*" } }, - "node_modules/pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "node_modules/pstree.remy": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", - "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", - "dev": true - }, - "node_modules/pug": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pug/-/pug-2.0.4.tgz", - "integrity": "sha512-XhoaDlvi6NIzL49nu094R2NA6P37ijtgMDuWE+ofekDChvfKnzFal60bhSdiy8y2PBO6fmz3oMEIcfpBVRUdvw==", - "dependencies": { - "pug-code-gen": "^2.0.2", - "pug-filters": "^3.1.1", - "pug-lexer": "^4.1.0", - "pug-linker": "^3.0.6", - "pug-load": "^2.0.12", - "pug-parser": "^5.0.1", - "pug-runtime": "^2.0.5", - "pug-strip-comments": "^1.0.4" + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "requires": { + "@types/connect": "*", + "@types/node": "*" } }, - "node_modules/pug-attrs": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pug-attrs/-/pug-attrs-2.0.4.tgz", - "integrity": "sha512-TaZ4Z2TWUPDJcV3wjU3RtUXMrd3kM4Wzjbe3EWnSsZPsJ3LDI0F3yCnf2/W7PPFF+edUFQ0HgDL1IoxSz5K8EQ==", - "dependencies": { - "constantinople": "^3.0.1", - "js-stringify": "^1.0.1", - "pug-runtime": "^2.0.5" + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "requires": { + "@types/node": "*" } }, - "node_modules/pug-code-gen": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pug-code-gen/-/pug-code-gen-2.0.3.tgz", - "integrity": "sha512-r9sezXdDuZJfW9J91TN/2LFbiqDhmltTFmGpHTsGdrNGp3p4SxAjjXEfnuK2e4ywYsRIVP0NeLbSAMHUcaX1EA==", - "dependencies": { - "constantinople": "^3.1.2", - "doctypes": "^1.1.0", - "js-stringify": "^1.0.1", - "pug-attrs": "^2.0.4", - "pug-error": "^1.3.3", - "pug-runtime": "^2.0.5", - "void-elements": "^2.0.1", - "with": "^5.0.0" + "@types/cookie-parser": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.3.tgz", + "integrity": "sha512-CqSKwFwefj4PzZ5n/iwad/bow2hTCh0FlNAeWLtQM3JA/NX/iYagIpWG2cf1bQKQ2c9gU2log5VUCrn7LDOs0w==", + "requires": { + "@types/express": "*" } }, - "node_modules/pug-error": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/pug-error/-/pug-error-1.3.3.tgz", - "integrity": "sha512-qE3YhESP2mRAWMFJgKdtT5D7ckThRScXRwkfo+Erqga7dyJdY3ZquspprMCj/9sJ2ijm5hXFWQE/A3l4poMWiQ==" + "@types/csurf": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/@types/csurf/-/csurf-1.11.2.tgz", + "integrity": "sha512-9bc98EnwmC1S0aSJiA8rWwXtgXtXHHOQOsGHptImxFgqm6CeH+mIOunHRg6+/eg2tlmDMX3tY7XrWxo2M/nUNQ==", + "requires": { + "@types/express-serve-static-core": "*" + } }, - "node_modules/pug-filters": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/pug-filters/-/pug-filters-3.1.1.tgz", - "integrity": "sha512-lFfjNyGEyVWC4BwX0WyvkoWLapI5xHSM3xZJFUhx4JM4XyyRdO8Aucc6pCygnqV2uSgJFaJWW3Ft1wCWSoQkQg==", - "dependencies": { - "clean-css": "^4.1.11", - "constantinople": "^3.0.1", - "jstransformer": "1.0.0", - "pug-error": "^1.3.3", - "pug-walk": "^1.1.8", - "resolve": "^1.1.6", - "uglify-js": "^2.6.1" + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" } }, - "node_modules/pug-lexer": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/pug-lexer/-/pug-lexer-4.1.0.tgz", - "integrity": "sha512-i55yzEBtjm0mlplW4LoANq7k3S8gDdfC6+LThGEvsK4FuobcKfDAwt6V4jKPH9RtiE3a2Akfg5UpafZ1OksaPA==", - "dependencies": { - "character-parser": "^2.1.1", - "is-expression": "^3.0.0", - "pug-error": "^1.3.3" + "@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" } }, - "node_modules/pug-linker": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/pug-linker/-/pug-linker-3.0.6.tgz", - "integrity": "sha512-bagfuHttfQOpANGy1Y6NJ+0mNb7dD2MswFG2ZKj22s8g0wVsojpRlqveEQHmgXXcfROB2RT6oqbPYr9EN2ZWzg==", - "dependencies": { - "pug-error": "^1.3.3", - "pug-walk": "^1.1.8" + "@types/jsonwebtoken": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz", + "integrity": "sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==", + "requires": { + "@types/node": "*" } }, - "node_modules/pug-load": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/pug-load/-/pug-load-2.0.12.tgz", - "integrity": "sha512-UqpgGpyyXRYgJs/X60sE6SIf8UBsmcHYKNaOccyVLEuT6OPBIMo6xMPhoJnqtB3Q3BbO4Z3Bjz5qDsUWh4rXsg==", - "dependencies": { - "object-assign": "^4.1.0", - "pug-walk": "^1.1.8" + "@types/mime": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", + "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" + }, + "@types/morgan": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.4.tgz", + "integrity": "sha512-cXoc4k+6+YAllH3ZHmx4hf7La1dzUk6keTR4bF4b4Sc0mZxU/zK4wO7l+ZzezXm/jkYj/qC+uYGZrarZdIVvyQ==", + "requires": { + "@types/node": "*" } }, - "node_modules/pug-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/pug-parser/-/pug-parser-5.0.1.tgz", - "integrity": "sha512-nGHqK+w07p5/PsPIyzkTQfzlYfuqoiGjaoqHv1LjOv2ZLXmGX1O+4Vcvps+P4LhxZ3drYSljjq4b+Naid126wA==", - "dependencies": { - "pug-error": "^1.3.3", - "token-stream": "0.0.1" + "@types/node": { + "version": "17.0.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.42.tgz", + "integrity": "sha512-Q5BPGyGKcvQgAMbsr7qEGN/kIPN6zZecYYABeTDBizOsau+2NMdSVTar9UQw21A2+JyA2KRNDYaYrPB0Rpk2oQ==" + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" + }, + "@types/serve-static": { + "version": "1.13.10", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", + "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "requires": { + "@types/mime": "^1", + "@types/node": "*" } }, - "node_modules/pug-runtime": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/pug-runtime/-/pug-runtime-2.0.5.tgz", - "integrity": "sha512-P+rXKn9un4fQY77wtpcuFyvFaBww7/91f3jHa154qU26qFAnOe6SW1CbIDcxiG5lLK9HazYrMCCuDvNgDQNptw==" + "@types/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-wDXw9LEEUHyV+7UWy7U315nrJGJ7p1BzaCxDpEoLr789Dk1WDVMMlf3iBfbG2F8NdWnYyFbtTxUn2ZNbm1Q4LQ==" }, - "node_modules/pug-strip-comments": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/pug-strip-comments/-/pug-strip-comments-1.0.4.tgz", - "integrity": "sha512-i5j/9CS4yFhSxHp5iKPHwigaig/VV9g+FgReLJWWHEHbvKsbqL0oP/K5ubuLco6Wu3Kan5p7u7qk8A4oLLh6vw==", - "dependencies": { - "pug-error": "^1.3.3" + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, - "node_modules/pug-walk": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/pug-walk/-/pug-walk-1.1.8.tgz", - "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==" + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" + "acorn-globals": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", + "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", + "requires": { + "acorn": "^4.0.4" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "dependencies": { + "acorn": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", + "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" + } } }, - "node_modules/query-string": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", - "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", - "dependencies": { - "decode-uri-component": "^0.2.0", - "object-assign": "^4.1.0", - "strict-uri-encode": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", - "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", - "engines": { - "node": ">=0.4.x" - } - }, - "node_modules/random-bytes": { + "aggregate-error": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", - "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/range-parser": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", - "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz", + "integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=", + "requires": { + "clean-stack": "^1.0.0", + "indent-string": "^3.0.0" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "^3.0.2", + "longest": "^1.0.1", + "repeat-string": "^1.5.2" }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/react-zlib-js": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/react-zlib-js/-/react-zlib-js-1.0.4.tgz", - "integrity": "sha512-ynXD9DFxpE7vtGoa3ZwBtPmZrkZYw2plzHGbanUjBOSN4RtuXdektSfABykHtTiWEHMh7WdYj45LHtp228ZF1A==" - }, - "node_modules/readable-stream": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", - "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } } }, - "node_modules/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10" + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" } }, - "node_modules/readdirp/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" } }, - "node_modules/readdirp/node_modules/string_decoder": { + "array-flatten": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, - "node_modules/regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "requires": { + "lodash": "^4.17.14" } }, - "node_modules/registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", - "dev": true, - "dependencies": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" + "axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "requires": { + "follow-redirects": "^1.14.0" } }, - "node_modules/registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", - "dev": true, - "dependencies": { - "rc": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "^2.4.0", + "regenerator-runtime": "^0.11.0" } }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "requires": { + "babel-runtime": "^6.26.0", + "esutils": "^2.0.2", + "lodash": "^4.17.4", + "to-fast-properties": "^1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", "dev": true }, - "node_modules/repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "engines": { - "node": ">=0.10" - } + "base64url": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", + "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" }, - "node_modules/resolve": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.16.0.tgz", - "integrity": "sha512-LarL/PIKJvc09k1jaeT4kQb/8/7P+qV4qSnN2K80AES+OHdfZELAKVOBjxsvtToT/uLOfFbvYvKfZmV8cee7nA==", - "dependencies": { - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" } }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", "dev": true }, - "node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, "dependencies": { - "lowercase-keys": "^1.0.0" + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + } } }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" + "boom": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", + "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", + "requires": { + "hoek": "6.x.x" } }, - "node_modules/right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "dependencies": { - "align-text": "^0.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rndm": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", - "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=" - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + "bourne": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/bourne/-/bourne-1.1.2.tgz", + "integrity": "sha512-b2dgVkTZhkQirNMohgC00rWfpVqEi9y5tKM1k3JvoNx05ODtfQoPPd4js9CYFQoY0IM8LAmnJulEuWv74zjUOg==" }, - "node_modules/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "node_modules/semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "bin": { - "semver": "bin/semver" + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, - "dependencies": { - "semver": "^5.0.3" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "fill-range": "^7.1.1" } }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" } }, - "node_modules/send/node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "engines": { - "node": ">= 0.8" + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" }, - "node_modules/send/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dependencies": { - "ee-first": "1.1.1" + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" }, - "engines": { - "node": ">= 0.8" + "dependencies": { + "lowercase-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", + "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" + } } }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "engines": { - "node": ">= 0.8" + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" } }, - "node_modules/serve-favicon": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", - "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=", - "dependencies": { - "etag": "~1.8.1", - "fresh": "0.5.2", - "ms": "2.1.1", - "parseurl": "~1.3.2", - "safe-buffer": "5.1.1" - }, - "engines": { - "node": ">= 0.8.0" + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "requires": { + "align-text": "^0.1.3", + "lazy-cache": "^1.0.3" } }, - "node_modules/serve-favicon/node_modules/ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - }, - "node_modules/serve-favicon/node_modules/safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" - }, - "engines": { - "node": ">= 0.8.0" + "character-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", + "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", + "requires": { + "is-regex": "^1.0.3" } }, - "node_modules/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" } }, - "node_modules/set-value/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" + "clean-css": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", + "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "requires": { + "source-map": "~0.6.0" }, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } } }, - "node_modules/setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + "clean-stack": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", + "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE=" }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "requires": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" } }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "requires": { + "mimic-response": "^1.0.0" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "color": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", + "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", + "requires": { + "color-convert": "^1.9.1", + "color-string": "^1.5.2" } }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/simple-oauth2": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/simple-oauth2/-/simple-oauth2-2.5.2.tgz", - "integrity": "sha512-8qjf+nHRdSUllFjjfpnonrU1oF/HNVbDle5HIbvXRYiy38C7KUvYe6w0ZZ//g4AFB6VNWuiZ80HmnycR8ZFDyQ==", - "deprecated": "simple-oauth2 v2 is no longer supported. Please upgrade to v3 for further support", - "dependencies": { - "@hapi/joi": "^15.1.1", - "date-fns": "^2.2.1", - "debug": "^4.1.1", - "wreck": "^14.0.2" + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" } }, - "node_modules/simple-oauth2/node_modules/debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", - "dependencies": { - "ms": "^2.1.1" + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-string": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", + "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, - "node_modules/simple-oauth2/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "colornames": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", + "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dependencies": { - "is-arrayish": "^0.3.1" - } + "colors": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" + "colorspace": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", + "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", + "requires": { + "color": "3.0.x", + "text-hex": "1.0.x" } }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "constantinople": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", + "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==", + "requires": { + "@types/babel-types": "^7.0.0", + "@types/babylon": "^6.16.2", + "babel-types": "^6.26.0", + "babylon": "^6.18.0" } }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" }, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } } }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-parser": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6" } }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" + }, + "core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "cross-env": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.1.tgz", + "integrity": "sha512-1yHhtcfAd1r4nwQgknowuUNfIT9E8dOMMspC36g45dN+iD1blloi7xp8X/xAIDnjHWyt1uQ8PHk2fkNaym7soQ==", "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "cross-spawn": "^6.0.5" } }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" } }, - "node_modules/snapdragon/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" + "csrf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", + "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", + "requires": { + "rndm": "1.2.0", + "tsscmp": "1.0.6", + "uid-safe": "2.1.5" } }, - "node_modules/snapdragon/node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "dependencies": { - "is-extendable": "^0.1.0" + "csurf": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz", + "integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "csrf": "3.1.0", + "http-errors": "~1.7.3" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sort-keys": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", - "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", "dependencies": { - "is-plain-obj": "^1.0.0" - }, - "engines": { - "node": ">=4" + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + } } }, - "node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "engines": { - "node": ">=0.10.0" + "date-fns": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.12.0.tgz", + "integrity": "sha512-qJgn99xxKnFgB1qL4jpxU7Q2t0LOn1p8KMIveef3UZD7kqjT3tpFNNdXJelEHhE+rUgffriXriw/sOSU+cS1Hw==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" } }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "deprecated": "See https://github.com/lydell/source-map-resolve#deprecated", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" }, - "node_modules/source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "deprecated": "See https://github.com/lydell/source-map-url#deprecated", - "dev": true + "decode-uri-component": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.2.tgz", + "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==" }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "requires": { + "mimic-response": "^1.0.0" } }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "engines": { - "node": "*" + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" } }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" }, - "node_modules/static-extend/node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" }, - "node_modules/statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", - "engines": { - "node": ">= 0.6" + "diagnostics": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", + "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", + "requires": { + "colorspace": "1.1.x", + "enabled": "1.0.x", + "kuler": "1.0.x" } }, - "node_modules/strict-uri-encode": { + "doctypes": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", - "engines": { - "node": ">=0.10.0" - } + "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", + "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" }, - "node_modules/string_decoder": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", - "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", - "dependencies": { - "safe-buffer": "~5.1.0" - } + "dotenv": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", + "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==" }, - "node_modules/string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "dependencies": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "engines": { - "node": ">=4" - } + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" }, - "node_modules/strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "dependencies": { - "ansi-regex": "^3.0.0" - }, - "engines": { - "node": ">=4" + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" } }, - "node_modules/strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "engines": { - "node": ">=0.10.0" + "enabled": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", + "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", + "requires": { + "env-variable": "0.0.x" } }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } + "encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==" }, - "node_modules/term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", - "dev": true, - "dependencies": { - "execa": "^0.7.0" - }, - "engines": { - "node": ">=4" - } + "env-variable": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", + "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" }, - "node_modules/text-hex": { + "es-define-property": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/timed-out": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", - "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" } }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" }, - "node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" }, - "node_modules/toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", - "engines": { - "node": ">=0.6" - } + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, - "node_modules/token-stream": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/token-stream/-/token-stream-0.0.1.tgz", - "integrity": "sha1-zu78cXp2xDFvEm0LnbqlXX598Bo=" + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, - "node_modules/touch": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", - "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", - "dev": true, - "dependencies": { - "nopt": "~1.0.10" - }, - "bin": { - "nodetouch": "bin/nodetouch.js" - } + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, - "node_modules/triple-beam": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", - "integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw==" - }, - "node_modules/tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", - "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", - "engines": { - "node": ">=0.6.x" - } - }, - "node_modules/type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dependencies": { - "source-map": "~0.5.1", - "yargs": "~3.10.0" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - }, - "optionalDependencies": { - "uglify-to-browserify": "~1.0.0" - } - }, - "node_modules/uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "optional": true - }, - "node_modules/uid-safe": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", - "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", - "dependencies": { - "random-bytes": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/undefsafe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", - "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", - "dev": true, - "dependencies": { - "debug": "^2.2.0" - } - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", - "dev": true, - "dependencies": { - "crypto-random-string": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "dev": true, - "dependencies": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true - }, - "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" - }, - "node_modules/url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "dependencies": { - "prepend-http": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/url-to-options": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", - "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", - "engines": { - "node": ">= 4" - } - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "node_modules/utils-merge": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", - "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/void-elements": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", - "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", - "dev": true, - "dependencies": { - "string-width": "^2.1.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/winston": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz", - "integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==", - "dependencies": { - "async": "^2.6.1", - "diagnostics": "^1.1.1", - "is-stream": "^1.1.0", - "logform": "^2.1.1", - "one-time": "0.0.4", - "readable-stream": "^3.1.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.3.0" - }, - "engines": { - "node": ">= 6.4.0" - } - }, - "node_modules/winston-transport": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz", - "integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==", - "dependencies": { - "readable-stream": "^2.3.6", - "triple-beam": "^1.2.0" - }, - "engines": { - "node": ">= 6.4.0" - } - }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/winston-transport/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/with": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/with/-/with-5.1.1.tgz", - "integrity": "sha1-+k2qktrzLE6pTtRTyB8EaGtXXf4=", - "dependencies": { - "acorn": "^3.1.0", - "acorn-globals": "^3.0.0" - } - }, - "node_modules/wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/wreck": { - "version": "14.2.0", - "resolved": "https://registry.npmjs.org/wreck/-/wreck-14.2.0.tgz", - "integrity": "sha512-NFFft3SMgqrJbXEVfYifh+QDWFxni+98/I7ut7rLbz3F0XOypluHsdo3mdEYssGSirMobM3fGlqhyikbWKDn2Q==", - "deprecated": "This module has moved and is now available at @hapi/wreck. Please update your dependencies as this version is no longer maintained an may contain bugs and security issues.", - "dependencies": { - "boom": "7.x.x", - "bourne": "1.x.x", - "hoek": "6.x.x" - } - }, - "node_modules/write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "node_modules/xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "node_modules/yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dependencies": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" - } - }, - "node_modules/yargs/node_modules/camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "engines": { - "node": ">=0.10.0" - } - } - }, - "dependencies": { - "@hapi/address": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.4.tgz", - "integrity": "sha512-QD1PhQk+s31P1ixsX0H0Suoupp3VMXzIVMSwobR3F3MSUO2YCV0B7xqLcUw/Bh8yuvd3LhpyqLQWTNcRmp6IdQ==" - }, - "@hapi/bourne": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-1.3.2.tgz", - "integrity": "sha512-1dVNHT76Uu5N3eJNTYcvxee+jzX4Z9lfciqRRHCU27ihbUcYi+iSc2iml5Ke1LXe1SyJCLA0+14Jh4tXJgOppA==" - }, - "@hapi/hoek": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-8.5.1.tgz", - "integrity": "sha512-yN7kbciD87WzLGc5539Tn0sApjyiGHAJgKvG9W8C7O+6c7qmoQMfVs0W4bX17eqz6C78QJqqFrtgdK5EWf6Qow==" - }, - "@hapi/joi": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@hapi/joi/-/joi-15.1.1.tgz", - "integrity": "sha512-entf8ZMOK8sc+8YfeOlM8pCfg3b5+WZIKBfUaaJT8UsjAAPjartzxIYm3TIbjvA4u+u++KbcXD38k682nVHDAQ==", - "requires": { - "@hapi/address": "2.x.x", - "@hapi/bourne": "1.x.x", - "@hapi/hoek": "8.x.x", - "@hapi/topo": "3.x.x" - } - }, - "@hapi/topo": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-3.1.6.tgz", - "integrity": "sha512-tAag0jEcjwH+P2quUfipd7liWCNX2F8NvYjQp2wtInsZxnMlypdw0FtAOLxtvvkO+GSRRbmNi8m/5y42PQJYCQ==", - "requires": { - "@hapi/hoek": "^8.3.0" - } - }, - "@panva/asn1.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@panva/asn1.js/-/asn1.js-1.0.0.tgz", - "integrity": "sha512-UdkG3mLEqXgnlKsWanWcgb6dOjUzJ+XC5f+aWw30qrtjxeNUSfKX1cd5FBzOaXQumoe9nIqeZUvrRJS03HCCtw==" - }, - "@sindresorhus/is": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", - "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==" - }, - "@types/babel-types": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/babel-types/-/babel-types-7.0.7.tgz", - "integrity": "sha512-dBtBbrc+qTHy1WdfHYjBwRln4+LWqASWakLHsWHR2NWHIFkv4W3O070IGoGLEBrJBvct3r0L1BUPuvURi7kYUQ==" - }, - "@types/babylon": { - "version": "6.16.5", - "resolved": "https://registry.npmjs.org/@types/babylon/-/babylon-6.16.5.tgz", - "integrity": "sha512-xH2e58elpj1X4ynnKp9qSnWlsRTIs6n3tgLGNfwAGHwePw0mulHQllV34n0T25uYSu1k0hRKkWXF890B1yS47w==", - "requires": { - "@types/babel-types": "*" - } - }, - "@types/body-parser": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", - "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", - "requires": { - "@types/connect": "*", - "@types/node": "*" - } - }, - "@types/connect": { - "version": "3.4.35", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", - "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", - "requires": { - "@types/node": "*" - } - }, - "@types/express": { - "version": "4.17.13", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", - "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", - "requires": { - "@types/body-parser": "*", - "@types/express-serve-static-core": "^4.17.18", - "@types/qs": "*", - "@types/serve-static": "*" - } - }, - "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", - "requires": { - "@types/node": "*", - "@types/qs": "*", - "@types/range-parser": "*" - } - }, - "@types/jsonwebtoken": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz", - "integrity": "sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==", - "requires": { - "@types/node": "*" - } - }, - "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" - }, - "@types/node": { - "version": "17.0.42", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.42.tgz", - "integrity": "sha512-Q5BPGyGKcvQgAMbsr7qEGN/kIPN6zZecYYABeTDBizOsau+2NMdSVTar9UQw21A2+JyA2KRNDYaYrPB0Rpk2oQ==" - }, - "@types/qs": { - "version": "6.9.7", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", - "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==" - }, - "@types/range-parser": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", - "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" - }, - "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", - "requires": { - "@types/mime": "^1", - "@types/node": "*" - } - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true - }, - "accepts": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", - "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "requires": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - } - }, - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" - }, - "acorn-globals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", - "integrity": "sha1-/YJw9x+7SZawBPqIDuXUZXOnMb8=", - "requires": { - "acorn": "^4.0.4" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" - } - } - }, - "aggregate-error": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-1.0.0.tgz", - "integrity": "sha1-iINE2tAiCnLjr1CQYRf0h3GSX6w=", - "requires": { - "clean-stack": "^1.0.0", - "indent-string": "^3.0.0" - } - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "requires": { - "kind-of": "^3.0.2", - "longest": "^1.0.1", - "repeat-string": "^1.5.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "ansi-align": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", - "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", - "dev": true, - "requires": { - "string-width": "^2.0.0" - } - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "requires": { - "lodash": "^4.17.14" - } - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "^6.26.0", - "esutils": "^2.0.2", - "lodash": "^4.17.4", - "to-fast-properties": "^1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "base64-js": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", - "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" - }, - "base64url": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", - "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==" - }, - "basic-auth": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", - "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "requires": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } - } - } - }, - "boom": { - "version": "7.3.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz", - "integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==", - "requires": { - "hoek": "6.x.x" - } - }, - "bourne": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/bourne/-/bourne-1.1.2.tgz", - "integrity": "sha512-b2dgVkTZhkQirNMohgC00rWfpVqEi9y5tKM1k3JvoNx05ODtfQoPPd4js9CYFQoY0IM8LAmnJulEuWv74zjUOg==" - }, - "boxen": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", - "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", - "dev": true, - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "browserify-zlib": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", - "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", - "requires": { - "pako": "~1.0.5" - } - }, - "buffer": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", - "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", - "requires": { - "base64-js": "^1.0.2", - "ieee754": "^1.1.4" - } - }, - "buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" - }, - "bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cacheable-request": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", - "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", - "requires": { - "clone-response": "1.0.2", - "get-stream": "3.0.0", - "http-cache-semantics": "3.8.1", - "keyv": "3.0.0", - "lowercase-keys": "1.0.0", - "normalize-url": "2.0.1", - "responselike": "1.0.2" - }, - "dependencies": { - "lowercase-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz", - "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=" - } - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", - "dev": true - }, - "capture-stack-trace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", - "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", - "dev": true - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "requires": { - "align-text": "^0.1.3", - "lazy-cache": "^1.0.3" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "character-parser": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/character-parser/-/character-parser-2.2.0.tgz", - "integrity": "sha1-x84o821LzZdE5f/CxfzeHHMmH8A=", - "requires": { - "is-regex": "^1.0.3" - } - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "ci-info": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", - "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", - "requires": { - "source-map": "~0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - }, - "clean-stack": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-1.3.0.tgz", - "integrity": "sha1-noIVAa6XmYbEax1m0tQy2y/UrjE=" - }, - "cli-boxes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", - "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", - "dev": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "requires": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" - } - }, - "clone-response": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", - "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz", - "integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==", - "requires": { - "color-convert": "^1.9.1", - "color-string": "^1.5.2" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "color-string": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", - "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "colornames": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz", - "integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=" - }, - "colors": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", - "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==" - }, - "colorspace": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz", - "integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==", - "requires": { - "color": "3.0.x", - "text-hex": "1.0.x" - } - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "configstore": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", - "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", - "dev": true, - "requires": { - "dot-prop": "^4.1.0", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "constantinople": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", - "integrity": "sha512-yePcBqEFhLOqSBtwYOGGS1exHo/s1xjekXiinh4itpNQGCu4KA1euPh1fg07N2wMITZXQkBz75Ntdt1ctGZouw==", - "requires": { - "@types/babel-types": "^7.0.0", - "@types/babylon": "^6.16.2", - "babel-types": "^6.26.0", - "babylon": "^6.18.0" - } - }, - "content-disposition": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", - "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "requires": { - "safe-buffer": "5.2.1" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" - } - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "cookie": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", - "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" - }, - "cookie-parser": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", - "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", - "requires": { - "cookie": "0.4.0", - "cookie-signature": "1.0.6" - } - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "core-js": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", - "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "create-error-class": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", - "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", - "dev": true, - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, - "cross-env": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.1.tgz", - "integrity": "sha512-1yHhtcfAd1r4nwQgknowuUNfIT9E8dOMMspC36g45dN+iD1blloi7xp8X/xAIDnjHWyt1uQ8PHk2fkNaym7soQ==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.5" - } - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "crypto-random-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", - "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", - "dev": true - }, - "csrf": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", - "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", - "requires": { - "rndm": "1.2.0", - "tsscmp": "1.0.6", - "uid-safe": "2.1.5" - } - }, - "csurf": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz", - "integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==", - "requires": { - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "csrf": "3.1.0", - "http-errors": "~1.7.3" - }, - "dependencies": { - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - } - } - }, - "date-fns": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.12.0.tgz", - "integrity": "sha512-qJgn99xxKnFgB1qL4jpxU7Q2t0LOn1p8KMIveef3UZD7kqjT3tpFNNdXJelEHhE+rUgffriXriw/sOSU+cS1Hw==" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" - }, - "decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", - "requires": { - "mimic-response": "^1.0.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", - "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" - }, - "diagnostics": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz", - "integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==", - "requires": { - "colorspace": "1.1.x", - "enabled": "1.0.x", - "kuler": "1.0.x" - } - }, - "doctypes": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/doctypes/-/doctypes-1.1.0.tgz", - "integrity": "sha1-6oCxBqh1OHdOijpKWv4pPeSJ4Kk=" - }, - "dot-prop": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", - "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==", - "dev": true, - "requires": { - "is-obj": "^1.0.0" - } - }, - "dotenv": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-7.0.0.tgz", - "integrity": "sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g==" - }, - "duplexer3": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", - "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=" - }, - "ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "enabled": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz", - "integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=", - "requires": { - "env-variable": "0.0.x" - } - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" - }, - "env-variable": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz", - "integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==" - }, - "es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "dev": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - } - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" }, "express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "requires": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -7007,9 +4382,9 @@ }, "dependencies": { "cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==" }, "depd": { "version": "2.0.0", @@ -7030,200 +4405,9 @@ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, "setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" - }, - "statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" - } - } - }, - "express-session": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.0.tgz", - "integrity": "sha512-t4oX2z7uoSqATbMfsxWMbNjAL0T5zpvcJCk3Z9wnPPN7ibddhnmDZXHfEcoBMG2ojKXZoCyPMc5FbtK+G7SoDg==", - "requires": { - "cookie": "0.4.0", - "cookie-signature": "1.0.6", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-headers": "~1.0.2", - "parseurl": "~1.3.3", - "safe-buffer": "5.2.0", - "uid-safe": "~2.1.5" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - }, - "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" - } - } - }, - "express-winston": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-3.4.0.tgz", - "integrity": "sha512-CKo4ESwIV4BpNIsGVNiq2GcAwuomL4dVJRIIH/2K/jMpoRI2DakhkVTtaJACzV7n2I1v+knDJkkjZRCymJ7nmA==", - "requires": { - "chalk": "^2.4.1", - "lodash": "^4.17.10" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "fast-safe-stringify": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", - "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" - }, - "fecha": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", - "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "2.4.1", - "parseurl": "~1.3.3", - "statuses": "2.0.1", - "unpipe": "~1.0.0" - }, - "dependencies": { - "on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "requires": { - "ee-first": "1.1.1" - } + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "statuses": { "version": "2.0.1", @@ -7232,481 +4416,118 @@ } } }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "express-session": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.0.tgz", + "integrity": "sha512-t4oX2z7uoSqATbMfsxWMbNjAL0T5zpvcJCk3Z9wnPPN7ibddhnmDZXHfEcoBMG2ojKXZoCyPMc5FbtK+G7SoDg==", "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.0", + "uid-safe": "~2.1.5" }, "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" } } }, - "fsevents": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.12.tgz", - "integrity": "sha512-Ggd/Ktt7E7I8pxZRbGIs7vwqAPscSESMrCSkx2FtWeqmheJgCo2R74fTsZFCifr0VTPwqRpPv17+6b8Zp7th0Q==", - "dev": true, - "optional": true, + "express-winston": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/express-winston/-/express-winston-3.4.0.tgz", + "integrity": "sha512-CKo4ESwIV4BpNIsGVNiq2GcAwuomL4dVJRIIH/2K/jMpoRI2DakhkVTtaJACzV7n2I1v+knDJkkjZRCymJ7nmA==", "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1", - "node-pre-gyp": "*" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "3.2.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.6.0" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.9.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.9.0" - } - }, - "mkdirp": { - "version": "0.5.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "ms": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.14.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4.4.2" - } - }, - "nopt": { - "version": "4.0.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, + "chalk": "^2.4.1", + "lodash": "^4.17.10" + } + }, + "fast-safe-stringify": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.6.tgz", + "integrity": "sha512-q8BZ89jjc+mz08rSxROs8VsrBBcn1SIw1kq9NjolL509tkABRk9io01RAjSaEv1Xb2uFLt8VtRiZbGp5H8iDtg==" + }, + "fecha": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz", + "integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg==" + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "ee-first": "1.1.1" } }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { + "statuses": { "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { "readable-stream": { "version": "2.3.7", - "bundled": true, - "dev": true, - "optional": true, + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7717,143 +4538,38 @@ "util-deprecate": "~1.0.1" } }, - "rimraf": { - "version": "2.7.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.1", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, "string_decoder": { "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "requires": { "safe-buffer": "~5.1.0" } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.13", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.1.1", - "bundled": true, - "dev": true, - "optional": true } } }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" }, "get-intrinsic": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", - "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" } }, "get-stream": { @@ -7861,67 +4577,23 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "global-dirs": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", - "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { - "ini": "^1.3.4" + "is-glob": "^4.0.1" } }, - "got": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", - "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", - "dev": true, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" + "get-intrinsic": "^1.1.3" } }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, "has": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", @@ -7935,6 +4607,19 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + }, "has-symbol-support-x": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", @@ -7953,36 +4638,12 @@ "has-symbol-support-x": "^1.4.1" } }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "function-bind": "^1.1.2" } }, "hoek": { @@ -8030,20 +4691,27 @@ } }, "hydra-login-consent-logout": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/hydra-login-consent-logout/-/hydra-login-consent-logout-1.4.3.tgz", - "integrity": "sha512-q2Y1SBpNnKf869TvloCr0CYL3tIljORDiMsBg/3xG6W+wQXGi7VQ4WJWdQR2hTtkSvYU2dXhLvxsQuFb0+mwlw==", - "requires": { + "version": "2.0.4-pre.2", + "resolved": "https://registry.npmjs.org/hydra-login-consent-logout/-/hydra-login-consent-logout-2.0.4-pre.2.tgz", + "integrity": "sha512-nB3JKffjiTyQZzr0DPdkdoUAg7mPlNTv7c/jZrC5IrIyodc3X4s16LzcZJcs/e2U3pZyu3CoWGUrnF//wPzmqQ==", + "requires": { + "@ory/client": "^0.2.0-alpha.24", + "@types/cookie-parser": "^1.4.2", + "@types/csurf": "^1.9.36", + "@types/express": "^4.17.7", + "@types/morgan": "^1.9.1", + "@types/url-join": "^4.0.0", "body-parser": "^1.19.0", "cookie-parser": "^1.4.5", "csurf": "^1.11.0", "debug": "^4.1.1", "express": "^4.17.1", "morgan": "^1.10.0", - "node-fetch": "^2.6.0", + "node-fetch": "^2.6.7", "pug": "^2.0.4", "querystring": "^0.2.0", "serve-favicon": "^2.5.0", + "typescript": "^3.7.5", "url-join": "^4.0.1" }, "dependencies": { @@ -8083,18 +4751,6 @@ "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", "dev": true }, - "import-lazy": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", - "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", - "dev": true - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, "indent-string": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-3.2.0.tgz", @@ -8105,12 +4761,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", - "dev": true - }, "into-stream": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", @@ -8120,98 +4770,30 @@ "p-is-promise": "^1.1.0" } }, - "ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-ci": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", - "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", - "dev": true, - "requires": { - "ci-info": "^1.5.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } + "binary-extensions": "^2.0.0" } }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, "is-expression": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-expression/-/is-expression-3.0.0.tgz", @@ -8228,73 +4810,25 @@ } } }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true }, "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { "is-extglob": "^2.1.1" } }, - "is-installed-globally": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", - "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", - "dev": true, - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" - } - }, - "is-npm": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", - "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", - "dev": true - }, "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, "is-object": { @@ -8302,40 +4836,16 @@ "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=" }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "dev": true, - "requires": { - "path-is-inside": "^1.0.1" - } - }, "is-plain-obj": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, "is-promise": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" }, - "is-redirect": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", - "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", - "dev": true - }, "is-regex": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", @@ -8354,12 +4864,6 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -8371,12 +4875,6 @@ "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", "dev": true }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, "isurl": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", @@ -8387,9 +4885,9 @@ } }, "jose": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.5.tgz", - "integrity": "sha512-BAiDNeDKTMgk4tvD0BbxJ8xHEHBZgpeRZ1zGPPsitSyMgjoMWiLGYAE7H7NpP5h0lPppQajQs871E8NHUrzVPA==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/jose/-/jose-2.0.7.tgz", + "integrity": "sha512-5hFWIigKqC+e/lRyQhfnirrAqUdIPMB7SJRqflJaO29dW7q5DFvH1XCSTmv6PQ6pb++0k6MJlLRoS0Wv4s38Wg==", "requires": { "@panva/asn1.js": "^1.0.0" } @@ -8492,12 +4990,6 @@ "json-buffer": "3.0.0" } }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, "kuler": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz", @@ -8506,15 +4998,6 @@ "colornames": "^1.1.1" } }, - "latest-version": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", - "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", - "dev": true, - "requires": { - "package-json": "^4.0.0" - } - }, "lazy-cache": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", @@ -8622,66 +5105,21 @@ "lru-cache": "~4.0.0" } }, - "make-dir": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", - "dev": true, - "requires": { - "pify": "^3.0.0" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==" }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -8706,41 +5144,14 @@ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, "morgan": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", @@ -8765,32 +5176,6 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - } - }, "negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", @@ -8803,9 +5188,12 @@ "dev": true }, "node-fetch": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz", - "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA==" + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "requires": { + "whatwg-url": "^5.0.0" + } }, "node-forge": { "version": "0.8.5", @@ -8847,42 +5235,36 @@ "integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc=" }, "nodemon": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.4.tgz", - "integrity": "sha512-VGPaqQBNk193lrJFotBU8nvWZPqEZY2eIzymy2jjY0fJ9qIsxA0sxQ8ATPl0gZC645gijYEc1jtZvpS8QWzJGQ==", + "version": "2.0.22", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", + "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", "dev": true, "requires": { - "chokidar": "^2.1.8", - "debug": "^3.2.6", + "chokidar": "^3.5.2", + "debug": "^3.2.7", "ignore-by-default": "^1.0.1", - "minimatch": "^3.0.4", - "pstree.remy": "^1.1.7", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", "semver": "^5.7.1", + "simple-update-notifier": "^1.0.7", "supports-color": "^5.5.0", "touch": "^3.1.0", - "undefsafe": "^2.0.2", - "update-notifier": "^2.5.0" + "undefsafe": "^2.0.5" }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "requires": { "ms": "^2.1.1" } }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true } } @@ -8919,78 +5301,20 @@ } } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, "object-hash": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==" }, "object-inspect": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", - "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==" - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==" }, "oidc-token-hash": { "version": "3.0.2", @@ -9121,18 +5445,6 @@ "p-finally": "^1.0.0" } }, - "package-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", - "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", - "dev": true, - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - } - }, "pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -9143,30 +5455,6 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", @@ -9179,27 +5467,21 @@ "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" }, "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true }, "pify": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", - "dev": true - }, "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", @@ -9233,9 +5515,9 @@ "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" }, "pstree.remy": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz", - "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", "dev": true }, "pug": { @@ -9353,11 +5635,11 @@ "integrity": "sha512-GMu3M5nUL3fju4/egXwZO0XLi6fW/K3T3VTgFQ14GxNi8btlxgT5qZL//JwZFm/2Fa64J/PNS8AZeys3wiMkVA==" }, "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "requires": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" } }, "query-string": { @@ -9386,125 +5668,44 @@ "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" }, "raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "requires": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "react-zlib-js": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/react-zlib-js/-/react-zlib-js-1.0.4.tgz", - "integrity": "sha512-ynXD9DFxpE7vtGoa3ZwBtPmZrkZYw2plzHGbanUjBOSN4RtuXdektSfABykHtTiWEHMh7WdYj45LHtp228ZF1A==" - }, - "readable-stream": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", - "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" } }, - "registry-auth-token": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", - "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", - "dev": true, + "react-zlib-js": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/react-zlib-js/-/react-zlib-js-1.0.4.tgz", + "integrity": "sha512-ynXD9DFxpE7vtGoa3ZwBtPmZrkZYw2plzHGbanUjBOSN4RtuXdektSfABykHtTiWEHMh7WdYj45LHtp228ZF1A==" + }, + "readable-stream": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.3.0.tgz", + "integrity": "sha512-EsI+s3k3XsW+fU8fQACLN59ky34AZ14LoeVZpYwmZvldCFo0r0gnelwF2TcMjLor/BTL5aDJVBMkss0dthToPw==", "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, - "registry-url": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", - "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "requires": { - "rc": "^1.0.1" + "picomatch": "^2.2.1" } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" }, "repeat-string": { "version": "1.6.1", @@ -9519,12 +5720,6 @@ "path-parse": "^1.0.6" } }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, "responselike": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", @@ -9533,12 +5728,6 @@ "lowercase-keys": "^1.0.0" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -9557,38 +5746,20 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" - }, - "semver-diff": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", - "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", - "dev": true, - "requires": { - "semver": "^5.0.3" - } + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==" }, "send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "requires": { "debug": "2.6.9", "depd": "2.0.0", @@ -9610,6 +5781,11 @@ "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, "ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -9655,37 +5831,27 @@ } }, "serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "requires": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" } }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" } }, "setprototypeof": { @@ -9709,21 +5875,16 @@ "dev": true }, "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" } }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, "simple-oauth2": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/simple-oauth2/-/simple-oauth2-2.5.2.tgz", @@ -9758,110 +5919,20 @@ "is-arrayish": "^0.3.1" } }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "simple-update-notifier": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", + "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", "dev": true, "requires": { - "kind-of": "^3.2.0" + "semver": "~7.0.0" }, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true } } }, @@ -9878,60 +5949,11 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - } - }, "stack-trace": { "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, "statuses": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", @@ -9950,37 +5972,6 @@ "safe-buffer": "~5.1.0" } }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -9989,15 +5980,6 @@ "has-flag": "^3.0.0" } }, - "term-size": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", - "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", - "dev": true, - "requires": { - "execa": "^0.7.0" - } - }, "text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", @@ -10013,46 +5995,13 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - } - }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "toidentifier": { @@ -10074,6 +6023,11 @@ "nopt": "~1.0.10" } }, + "tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "triple-beam": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz", @@ -10093,6 +6047,11 @@ "mime-types": "~2.1.24" } }, + "typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==" + }, "uglify-js": { "version": "2.8.29", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", @@ -10118,141 +6077,26 @@ } }, "undefsafe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", - "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", - "dev": true, - "requires": { - "debug": "^2.2.0" - } - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unique-string": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", - "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", - "dev": true, - "requires": { - "crypto-random-string": "^1.0.0" - } + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "unzip-response": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", - "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", - "dev": true - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true - }, - "update-notifier": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", - "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", - "dev": true, - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, "url-join": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" }, - "url-parse-lax": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", - "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", - "dev": true, - "requires": { - "prepend-http": "^1.0.1" - } - }, "url-to-options": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=" }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -10273,6 +6117,20 @@ "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=" }, + "webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "requires": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", @@ -10282,15 +6140,6 @@ "isexe": "^2.0.0" } }, - "widest-line": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", - "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", - "dev": true, - "requires": { - "string-width": "^2.1.1" - } - }, "window-size": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", @@ -10369,23 +6218,6 @@ "hoek": "6.x.x" } }, - "write-file-atomic": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", - "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "xdg-basedir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", - "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", - "dev": true - }, "yallist": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", diff --git a/test/e2e/oauth2-client/package.json b/test/e2e/oauth2-client/package.json index af9bf036ba6..90412a46396 100644 --- a/test/e2e/oauth2-client/package.json +++ b/test/e2e/oauth2-client/package.json @@ -4,17 +4,17 @@ "private": true, "main": "./src/index.js", "scripts": { - "consent": "hydra-login-consent-logout", + "consent": "node node_modules/hydra-login-consent-logout/lib/app.js", "start": "node ./src/index.js", "watch": "nodemon ./src/index.js" }, "dependencies": { "body-parser": "^1.20.1", "dotenv": "^7.0.0", - "express": "^4.18.2", + "express": "^4.21.2", "express-session": "^1.17.0", "express-winston": "^3.4.0", - "hydra-login-consent-logout": "1.4.3", + "hydra-login-consent-logout": "2.0.4-pre.2", "jsonwebtoken": "^8.5.1", "jwks-rsa": "^2.1.4", "node-fetch": "^2.6.0", @@ -25,6 +25,6 @@ }, "devDependencies": { "cross-env": "^5.2.1", - "nodemon": "^1.19.4" + "nodemon": "^2.0.22" } } diff --git a/test/mock-client/main.go b/test/mock-client/main.go index c09edaca14c..e553c1a951c 100644 --- a/test/mock-client/main.go +++ b/test/mock-client/main.go @@ -22,7 +22,7 @@ import ( "golang.org/x/oauth2" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/ory/x/cmdx" "github.com/ory/x/urlx" ) @@ -181,7 +181,7 @@ func checkTokenResponse(token oauth2token) { } } - intro, resp, err := sdk.OAuth2Api.IntrospectOAuth2Token(context.Background()).Token(token.AccessToken).Execute() + intro, resp, err := sdk.OAuth2API.IntrospectOAuth2Token(context.Background()).Token(token.AccessToken).Execute() defer resp.Body.Close() if err != nil { log.Fatalf("Unable to introspect OAuth2 token: %s", err) diff --git a/test/mock-lcp/main.go b/test/mock-lcp/main.go index a3c3bc13d3a..266c1d8fad2 100644 --- a/test/mock-lcp/main.go +++ b/test/mock-lcp/main.go @@ -24,7 +24,7 @@ func init() { func login(rw http.ResponseWriter, r *http.Request) { challenge := r.URL.Query().Get("login_challenge") - lr, resp, err := client.OAuth2Api.GetOAuth2LoginRequest(r.Context()).LoginChallenge(challenge).Execute() + lr, resp, err := client.OAuth2API.GetOAuth2LoginRequest(r.Context()).LoginChallenge(challenge).Execute() defer resp.Body.Close() if err != nil { log.Fatalf("Unable to fetch clogin request: %s", err) @@ -37,7 +37,7 @@ func login(rw http.ResponseWriter, r *http.Request) { remember = true } - vr, resp, err := client.OAuth2Api.AcceptOAuth2LoginRequest(r.Context()). + vr, resp, err := client.OAuth2API.AcceptOAuth2LoginRequest(r.Context()). LoginChallenge(challenge). AcceptOAuth2LoginRequest(hydra.AcceptOAuth2LoginRequest{ Subject: "the-subject", @@ -49,7 +49,7 @@ func login(rw http.ResponseWriter, r *http.Request) { } redirectTo = vr.RedirectTo } else { - vr, resp, err := client.OAuth2Api.RejectOAuth2LoginRequest(r.Context()). + vr, resp, err := client.OAuth2API.RejectOAuth2LoginRequest(r.Context()). LoginChallenge(challenge). RejectOAuth2Request(hydra.RejectOAuth2Request{ Error: pointerx.String("invalid_request"), @@ -69,7 +69,7 @@ func login(rw http.ResponseWriter, r *http.Request) { func consent(rw http.ResponseWriter, r *http.Request) { challenge := r.URL.Query().Get("consent_challenge") - o, resp, err := client.OAuth2Api.GetOAuth2ConsentRequest(r.Context()).ConsentChallenge(challenge).Execute() + o, resp, err := client.OAuth2API.GetOAuth2ConsentRequest(r.Context()).ConsentChallenge(challenge).Execute() defer resp.Body.Close() if err != nil { log.Fatalf("Unable to fetch consent request: %s", err) @@ -86,7 +86,7 @@ func consent(rw http.ResponseWriter, r *http.Request) { value = "rab" } - v, resp, err := client.OAuth2Api.AcceptOAuth2ConsentRequest(r.Context()). + v, resp, err := client.OAuth2API.AcceptOAuth2ConsentRequest(r.Context()). ConsentChallenge(challenge). AcceptOAuth2ConsentRequest(hydra.AcceptOAuth2ConsentRequest{ GrantScope: o.RequestedScope, @@ -102,7 +102,7 @@ func consent(rw http.ResponseWriter, r *http.Request) { } redirectTo = v.RedirectTo } else { - v, resp, err := client.OAuth2Api.RejectOAuth2ConsentRequest(r.Context()). + v, resp, err := client.OAuth2API.RejectOAuth2ConsentRequest(r.Context()). ConsentChallenge(challenge). RejectOAuth2Request(hydra.RejectOAuth2Request{Error: pointerx.String("invalid_request")}).Execute() defer resp.Body.Close() diff --git a/x/audit_test.go b/x/audit_test.go index 6eecc8dcbf7..0a4061551d2 100644 --- a/x/audit_test.go +++ b/x/audit_test.go @@ -43,8 +43,6 @@ func TestLogAudit(t *testing.T) { l.Logger.Out = buf LogAudit(r, tc.message, l) - t.Logf("%s", string(buf.Bytes())) - assert.Contains(t, buf.String(), "audience=audit") for _, expectContain := range tc.expectContains { assert.Contains(t, buf.String(), expectContain) diff --git a/x/clean_sql.go b/x/clean_sql.go index 59628fb3f97..a02a9a054ce 100644 --- a/x/clean_sql.go +++ b/x/clean_sql.go @@ -10,7 +10,6 @@ import ( ) func DeleteHydraRows(t *testing.T, c *pop.Connection) { - t.Logf("Deleting hydra rows in database: %s", c.Dialect.Name()) for _, tb := range []string{ "hydra_oauth2_access", "hydra_oauth2_refresh", @@ -57,7 +56,7 @@ func CleanSQLPop(t *testing.T, c *pop.Connection) { "schema_migration", } { if err := c.RawQuery("DROP TABLE IF EXISTS " + tb).Exec(); err != nil { - t.Logf(`Unable to clean up table "%s": %s`, tb, err) + t.Fatalf(`Unable to clean up table "%s": %s`, tb, err) } } t.Logf("Successfully cleaned up database: %s", c.Dialect.Name()) diff --git a/x/doc_swagger.go b/x/doc_swagger.go index af7944ca09d..b178ae736da 100644 --- a/x/doc_swagger.go +++ b/x/doc_swagger.go @@ -4,10 +4,10 @@ package x // Empty responses are sent when, for example, resources are deleted. The HTTP status code for empty responses is -// typically 201. +// typically 204. // // swagger:response emptyResponse -type emptyResponse struct{} +type _ struct{} // Error // @@ -40,7 +40,7 @@ type errorOAuth2 struct { // Default Error Response // // swagger:response errorOAuth2Default -type errorOAuth2Default struct { +type _ struct { // in: body Body errorOAuth2 } @@ -48,7 +48,7 @@ type errorOAuth2Default struct { // Bad Request Error Response // // swagger:response errorOAuth2BadRequest -type errorOAuth2BadRequest struct { +type _ struct { // in: body Body errorOAuth2 } @@ -56,7 +56,7 @@ type errorOAuth2BadRequest struct { // Not Found Error Response // // swagger:response errorOAuth2NotFound -type errorOAuth2NotFound struct { +type _ struct { // in: body Body errorOAuth2 } diff --git a/x/errors.go b/x/errors.go index 229884a5d51..f90802bf50a 100644 --- a/x/errors.go +++ b/x/errors.go @@ -31,3 +31,10 @@ func LogError(r *http.Request, err error, logger *logrusx.Logger) { logger.WithRequest(r). WithError(err).Errorln("An error occurred") } + +func Must[T any](t T, err error) T { + if err != nil { + panic(err) + } + return t +} diff --git a/x/errors_test.go b/x/errors_test.go index 71de4e8d3fe..13c311b9aec 100644 --- a/x/errors_test.go +++ b/x/errors_test.go @@ -36,9 +36,9 @@ func TestLogError(t *testing.T) { l.Logger.Out = buf LogError(r, errors.New("asdf"), l) - t.Logf("%s", string(buf.Bytes())) + t.Logf("%s", buf.String()) - assert.True(t, strings.Contains(string(buf.Bytes()), "trace")) + assert.True(t, strings.Contains(buf.String(), "trace")) LogError(r, errors.Wrap(new(errStackTracer), ""), l) } diff --git a/x/events/events.go b/x/events/events.go new file mode 100644 index 00000000000..998892f77d9 --- /dev/null +++ b/x/events/events.go @@ -0,0 +1,132 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package events + +import ( + "context" + + otelattr "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" + + "github.com/ory/fosite" + "github.com/ory/x/otelx/semconv" +) + +const ( + // LoginAccepted will be emitted when the login UI accepts a login request. + LoginAccepted semconv.Event = "OAuth2LoginAccepted" + + // LoginRejected will be emitted when the login UI rejects a login request. + LoginRejected semconv.Event = "OAuth2LoginRejected" + + // ConsentAccepted will be emitted when the consent UI accepts a consent request. + ConsentAccepted semconv.Event = "OAuth2ConsentAccepted" + + // ConsentRejected will be emitted when the consent UI rejects a consent request. + ConsentRejected semconv.Event = "OAuth2ConsentRejected" + + // ConsentRevoked will be emitted when the user revokes a consent request. + ConsentRevoked semconv.Event = "OAuth2ConsentRevoked" + + // ClientCreated will be emitted when a client is created. + ClientCreated semconv.Event = "OAuth2ClientCreated" + + // ClientDeleted will be emitted when a client is deleted. + ClientDeleted semconv.Event = "OAuth2ClientDeleted" + + // ClientUpdated will be emitted when a client is updated. + ClientUpdated semconv.Event = "OAuth2ClientUpdated" + + // AccessTokenIssued will be emitted by requests to POST /oauth2/token in case the request was successful. + AccessTokenIssued semconv.Event = "OAuth2AccessTokenIssued" //nolint:gosec + + // TokenExchangeError will be emitted by requests to POST /oauth2/token in case the request was unsuccessful. + TokenExchangeError semconv.Event = "OAuth2TokenExchangeError" //nolint:gosec + + // AccessTokenInspected will be emitted by requests to POST /admin/oauth2/introspect. + AccessTokenInspected semconv.Event = "OAuth2AccessTokenInspected" //nolint:gosec + + // AccessTokenRevoked will be emitted by requests to POST /oauth2/revoke. + AccessTokenRevoked semconv.Event = "OAuth2AccessTokenRevoked" //nolint:gosec + + // RefreshTokenIssued will be emitted when a refresh token is issued. + RefreshTokenIssued semconv.Event = "OAuth2RefreshTokenIssued" //nolint:gosec + + // IdentityTokenIssued will be emitted when a refresh token is issued. + IdentityTokenIssued semconv.Event = "OIDCIdentityTokenIssued" //nolint:gosec +) + +const ( + attributeKeyOAuth2ClientName = "OAuth2ClientName" + attributeKeyOAuth2ClientID = "OAuth2ClientID" + attributeKeyOAuth2Subject = "OAuth2Subject" + attributeKeyOAuth2GrantType = "OAuth2GrantType" + attributeKeyOAuth2ConsentRequestID = "OAuth2ConsentRequestID" + attributeKeyOAuth2TokenFormat = "OAuth2TokenFormat" //nolint:gosec + attributeKeyOAuth2RefreshTokenSignature = "OAuth2RefreshTokenSignature" //nolint:gosec + attributeKeyOAuth2AccessTokenSignature = "OAuth2AccessTokenSignature" //nolint:gosec +) + +// WithTokenFormat emits the token format as part of the event. +func WithTokenFormat(format string) trace.EventOption { + return trace.WithAttributes(otelattr.String(attributeKeyOAuth2TokenFormat, format)) +} + +// WithGrantType emits the token format as part of the event. +func WithGrantType(grantType string) trace.EventOption { + return trace.WithAttributes(otelattr.String(attributeKeyOAuth2GrantType, grantType)) +} + +func ClientID(clientID string) otelattr.KeyValue { + return otelattr.String(attributeKeyOAuth2ClientID, clientID) +} + +func RefreshTokenSignature(signature string) otelattr.KeyValue { + return otelattr.String(attributeKeyOAuth2RefreshTokenSignature, signature) +} + +func AccessTokenSignature(signature string) otelattr.KeyValue { + return otelattr.String(attributeKeyOAuth2AccessTokenSignature, signature) +} + +func ConsentRequestID(id string) otelattr.KeyValue { + return otelattr.String(attributeKeyOAuth2ConsentRequestID, id) +} + +// WithClientID emits the client ID as part of the event. +func WithClientID(clientID string) trace.EventOption { + return trace.WithAttributes(ClientID(clientID)) +} + +// WithClientName emits the client name as part of the event. +func WithClientName(clientID string) trace.EventOption { + return trace.WithAttributes(otelattr.String(attributeKeyOAuth2ClientName, clientID)) +} + +// WithSubject emits the subject as part of the event. +func WithSubject(subject string) trace.EventOption { + return trace.WithAttributes(otelattr.String(attributeKeyOAuth2Subject, subject)) +} + +// WithRequest emits the subject and client ID from the fosite request as part of the event. +func WithRequest(request fosite.Requester) trace.EventOption { + var attributes []otelattr.KeyValue + if client := request.GetClient(); client != nil { + attributes = append(attributes, otelattr.String(attributeKeyOAuth2ClientID, client.GetID())) + } + if session := request.GetSession(); session != nil { + attributes = append(attributes, otelattr.String(attributeKeyOAuth2Subject, session.GetSubject())) + } + + return trace.WithAttributes(attributes...) +} + +// Trace emits an event with the given attributes. +func Trace(ctx context.Context, event semconv.Event, opts ...trace.EventOption) { + allOpts := append([]trace.EventOption{trace.WithAttributes(semconv.AttributesFromContext(ctx)...)}, opts...) + trace.SpanFromContext(ctx).AddEvent( + string(event), + allOpts..., + ) +} diff --git a/x/fosite_storer.go b/x/fosite_storer.go index 1afec037710..546cfc98870 100644 --- a/x/fosite_storer.go +++ b/x/fosite_storer.go @@ -12,18 +12,18 @@ import ( "github.com/ory/fosite/handler/openid" "github.com/ory/fosite/handler/pkce" "github.com/ory/fosite/handler/rfc7523" + "github.com/ory/fosite/handler/verifiable" ) type FositeStorer interface { fosite.Storage oauth2.CoreStorage + oauth2.TokenRevocationStorage openid.OpenIDConnectRequestStorage pkce.PKCERequestStorage rfc7523.RFC7523KeyStorage - - RevokeRefreshToken(ctx context.Context, requestID string) error - - RevokeAccessToken(ctx context.Context, requestID string) error + verifiable.NonceManager + oauth2.ResourceOwnerPasswordCredentialsGrantStorage // flush the access token requests from the database. // no data will be deleted after the 'notAfter' timeframe. diff --git a/x/hasher.go b/x/hasher.go index 1e7bd37a6b0..34d35023120 100644 --- a/x/hasher.go +++ b/x/hasher.go @@ -8,8 +8,11 @@ import ( "github.com/ory/fosite" "github.com/ory/x/hasherx" + "github.com/ory/x/otelx" "go.opentelemetry.io/otel" + "go.opentelemetry.io/otel/attribute" + "go.opentelemetry.io/otel/trace" "github.com/ory/x/errorsx" ) @@ -51,11 +54,14 @@ func NewHasher(c config) *Hasher { } } -func (b *Hasher) Hash(ctx context.Context, data []byte) ([]byte, error) { - ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "x.hasher.Hash") - defer span.End() +func (b *Hasher) Hash(ctx context.Context, data []byte) (_ []byte, err error) { + h := b.c.GetHasherAlgorithm(ctx) - switch b.c.GetHasherAlgorithm(ctx) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "x.hasher.Hash", + trace.WithAttributes(attribute.Stringer("algorithm", h))) + defer otelx.End(span, &err) + + switch h { case HashAlgorithmBCrypt: return b.bcrypt.Generate(ctx, data) case HashAlgorithmPBKDF2: @@ -65,9 +71,9 @@ func (b *Hasher) Hash(ctx context.Context, data []byte) ([]byte, error) { } } -func (b *Hasher) Compare(ctx context.Context, hash, data []byte) error { - _, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "x.hasher.Hash") - defer span.End() +func (b *Hasher) Compare(ctx context.Context, hash, data []byte) (err error) { + ctx, span := otel.GetTracerProvider().Tracer(tracingComponent).Start(ctx, "x.hasher.Compare") + defer otelx.End(span, &err) if err := hasherx.Compare(ctx, data, hash); err != nil { return errorsx.WithStack(err) diff --git a/x/int_to_bytes.go b/x/int_to_bytes.go new file mode 100644 index 00000000000..08805ae4de2 --- /dev/null +++ b/x/int_to_bytes.go @@ -0,0 +1,26 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package x + +import ( + "encoding/binary" + + "github.com/pkg/errors" +) + +// IntToBytes converts an int64 to a byte slice. It is the inverse of BytesToInt. +func IntToBytes(i int64) []byte { + b := make([]byte, 8) + binary.LittleEndian.PutUint64(b, uint64(i)) //nolint:gosec + + return b +} + +// BytesToInt converts a byte slice to an int64. It is the inverse of IntToBytes. +func BytesToInt(b []byte) (int64, error) { + if len(b) != 8 { + return 0, errors.New("byte slice must be 8 bytes long") + } + return int64(binary.LittleEndian.Uint64(b)), nil //nolint:gosec +} diff --git a/x/int_to_bytes_test.go b/x/int_to_bytes_test.go new file mode 100644 index 00000000000..c67f54cc5db --- /dev/null +++ b/x/int_to_bytes_test.go @@ -0,0 +1,52 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package x + +import ( + "math" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_toBytes_fromBytes(t *testing.T) { + for _, tc := range []struct { + name string + i int64 + }{ + { + name: "zero", + i: 0, + }, + { + name: "positive", + i: 1234567890, + }, + { + name: "negative", + i: -1234567890, + }, + { + name: "now", + i: time.Now().Unix(), + }, + { + name: "max", + i: math.MaxInt64, + }, + { + name: "min", + i: math.MinInt64, + }, + } { + t.Run("case="+tc.name, func(t *testing.T) { + bytes := IntToBytes(tc.i) + i, err := BytesToInt(bytes) + require.NoError(t, err) + assert.Equal(t, tc.i, i) + }) + } +} diff --git a/x/oauth2cors/cors.go b/x/oauth2cors/cors.go index 2069c2b8cd0..5cf21a78bd7 100644 --- a/x/oauth2cors/cors.go +++ b/x/oauth2cors/cors.go @@ -4,15 +4,13 @@ package oauth2cors import ( - "context" - "fmt" "net/http" "strings" - "github.com/ory/hydra/client" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/oauth2" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/oauth2" + "github.com/ory/hydra/v2/x" "github.com/gobwas/glob" "github.com/rs/cors" @@ -21,103 +19,128 @@ import ( ) func Middleware( - ctx context.Context, reg interface { x.RegistryLogger oauth2.Registry client.Registry }) func(h http.Handler) http.Handler { - opts, enabled := reg.Config().CORS(ctx, config.PublicInterface) - if !enabled { - return func(h http.Handler) http.Handler { - return h - } - } - - var alwaysAllow = len(opts.AllowedOrigins) == 0 - var patterns []glob.Glob - for _, o := range opts.AllowedOrigins { - if o == "*" { - alwaysAllow = true - } - // if the protocol (http or https) is specified, but the url is wildcard, use special ** glob, which ignore the '.' separator. - // This way g := glob.Compile("http://**") g.Match("http://google.com") returns true. - if splittedO := strings.Split(o, "://"); len(splittedO) != 1 && splittedO[1] == "*" { - o = fmt.Sprintf("%s://**", splittedO[0]) - } - g, err := glob.Compile(strings.ToLower(o), '.') - if err != nil { - reg.Logger().WithError(err).Fatalf("Unable to parse cors origin: %s", o) - } - - patterns = append(patterns, g) - } - - options := cors.Options{ - AllowedOrigins: opts.AllowedOrigins, - AllowedMethods: opts.AllowedMethods, - AllowedHeaders: opts.AllowedHeaders, - ExposedHeaders: opts.ExposedHeaders, - MaxAge: opts.MaxAge, - AllowCredentials: opts.AllowCredentials, - OptionsPassthrough: opts.OptionsPassthrough, - Debug: opts.Debug, - AllowOriginRequestFunc: func(r *http.Request, origin string) bool { + return func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - if alwaysAllow { - return true - } - origin = strings.ToLower(origin) - for _, p := range patterns { - if p.Match(origin) { - return true - } + opts, enabled := reg.Config().CORS(ctx, config.PublicInterface) + if !enabled { + reg.Logger().Debug("not enhancing CORS per client, as CORS is disabled") + h.ServeHTTP(w, r) + return } - // pre-flight requests do not contain credentials (cookies, HTTP authorization) - // so we return true in all cases here. - if r.Method == http.MethodOptions { - return true - } - - username, _, ok := r.BasicAuth() - if !ok || username == "" { - token := fosite.AccessTokenFromRequest(r) - if token == "" { - return false + alwaysAllow := len(opts.AllowedOrigins) == 0 + patterns := make([]glob.Glob, 0, len(opts.AllowedOrigins)) + for _, o := range opts.AllowedOrigins { + if o == "*" { + alwaysAllow = true + break } - - session := oauth2.NewSessionWithCustomClaims("", reg.Config().AllowedTopLevelClaims(ctx)) - _, ar, err := reg.OAuth2Provider().IntrospectToken(ctx, token, fosite.AccessToken, session) + // if the protocol (http or https) is specified, but the url is wildcard, use special ** glob, which ignore the '.' separator. + // This way g := glob.Compile("http://**") g.Match("http://google.com") returns true. + if scheme, rest, found := strings.Cut(o, "://"); found && rest == "*" { + o = scheme + "://**" + } + g, err := glob.Compile(strings.ToLower(o), '.') if err != nil { - return false + reg.Logger().WithError(err).WithField("pattern", o).Error("Unable to parse CORS origin, ignoring it") + continue } - username = ar.GetClient().GetID() + patterns = append(patterns, g) } - cl, err := reg.ClientManager().GetConcreteClient(ctx, username) - if err != nil { - return false - } + options := cors.Options{ + AllowedOrigins: opts.AllowedOrigins, + AllowedMethods: opts.AllowedMethods, + AllowedHeaders: opts.AllowedHeaders, + ExposedHeaders: opts.ExposedHeaders, + MaxAge: opts.MaxAge, + AllowCredentials: opts.AllowCredentials, + OptionsPassthrough: opts.OptionsPassthrough, + Debug: opts.Debug, + AllowOriginRequestFunc: func(r *http.Request, origin string) bool { + ctx := r.Context() + if alwaysAllow { + return true + } + + origin = strings.ToLower(origin) + for _, p := range patterns { + if p.Match(origin) { + return true + } + } + + // pre-flight requests do not contain credentials (cookies, HTTP authorization) + // so we return true in all cases here. + if r.Method == http.MethodOptions { + return true + } + + var clientID string + + // if the client uses client_secret_post auth it will provide its client ID in form data + clientID = r.PostFormValue("client_id") + + // if the client uses client_secret_basic auth the client ID will be the username component + if clientID == "" { + clientID, _, _ = r.BasicAuth() + } + + // otherwise, this may be a bearer auth request, in which case we can introspect the token + if clientID == "" { + token := fosite.AccessTokenFromRequest(r) + if token == "" { + return false + } + + session := oauth2.NewSessionWithCustomClaims(ctx, reg.Config(), "") + _, ar, err := reg.OAuth2Provider().IntrospectToken(ctx, token, fosite.AccessToken, session) + if err != nil { + return false + } + + clientID = ar.GetClient().GetID() + } + + cl, err := reg.ClientManager().GetConcreteClient(ctx, clientID) + if err != nil { + return false + } + + for _, o := range cl.AllowedCORSOrigins { + if o == "*" { + return true + } + + // if the protocol (http or https) is specified, but the url is wildcard, use special ** glob, which ignore the '.' separator. + // This way g := glob.Compile("http://**") g.Match("http://google.com") returns true. + if scheme, rest, found := strings.Cut(o, "://"); found && rest == "*" { + o = scheme + "://**" + } + + g, err := glob.Compile(strings.ToLower(o), '.') + if err != nil { + return false + } + if g.Match(origin) { + return true + } + } - for _, o := range cl.AllowedCORSOrigins { - if o == "*" { - return true - } - g, err := glob.Compile(strings.ToLower(o), '.') - if err != nil { return false - } - if g.Match(origin) { - return true - } + }, } - return false - }, + reg.Logger().Debug("enhancing CORS per client") + cors.New(options).Handler(h).ServeHTTP(w, r) + }) } - - return cors.New(options).Handler } diff --git a/x/oauth2cors/cors_test.go b/x/oauth2cors/cors_test.go index d083dc5f6bd..d450fe308ab 100644 --- a/x/oauth2cors/cors_test.go +++ b/x/oauth2cors/cors_test.go @@ -4,31 +4,35 @@ package oauth2cors_test import ( + "bytes" "context" "fmt" + "io" "net/http" "net/http/httptest" + "net/url" "testing" "time" - "github.com/ory/hydra/driver" - "github.com/ory/hydra/x/oauth2cors" + "github.com/ory/hydra/v2/driver" "github.com/ory/x/contextx" - "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/x" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/ory/fosite" - "github.com/ory/hydra/client" - "github.com/ory/hydra/internal" - "github.com/ory/hydra/oauth2" + "github.com/ory/hydra/v2/client" + "github.com/ory/hydra/v2/internal" + "github.com/ory/hydra/v2/oauth2" ) func TestOAuth2AwareCORSMiddleware(t *testing.T) { + ctx := context.Background() r := internal.NewRegistryMemory(t, internal.NewConfigurationWithDefaults(), &contextx.Default{}) - token, signature, _ := r.OAuth2HMACStrategy().GenerateAccessToken(nil, nil) + token, signature, _ := r.OAuth2HMACStrategy().GenerateAccessToken(ctx, nil) + for k, tc := range []struct { prep func(*testing.T, driver.Registry) d string @@ -37,6 +41,7 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { header http.Header expectHeader http.Header method string + body io.Reader }{ { d: "should ignore when disabled", @@ -48,21 +53,51 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should reject when basic auth but client does not exist and cors enabled", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo", "bar"))}}, expectHeader: http.Header{"Vary": {"Origin"}}, }, + { + d: "should reject when post auth client exists but origin not allowed", + prep: func(t *testing.T, r driver.Registry) { + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) + + // Ignore unique violations + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-2", Secret: "bar", AllowedCORSOrigins: []string{"http://not-foobar.com"}}) + }, + code: http.StatusNotImplemented, + header: http.Header{"Origin": {"http://foobar.com"}, "Content-Type": {"application/x-www-form-urlencoded"}}, + expectHeader: http.Header{"Vary": {"Origin"}}, + method: http.MethodPost, + body: bytes.NewBufferString(url.Values{"client_id": []string{"foo-2"}}.Encode()), + }, + { + d: "should accept when post auth client exists and origin allowed", + prep: func(t *testing.T, r driver.Registry) { + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) + + // Ignore unique violations + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-3", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}}) + }, + code: http.StatusNotImplemented, + header: http.Header{"Origin": {"http://foobar.com"}, "Content-Type": {"application/x-www-form-urlencoded"}}, + expectHeader: http.Header{"Access-Control-Allow-Credentials": []string{"true"}, "Access-Control-Allow-Origin": []string{"http://foobar.com"}, "Access-Control-Expose-Headers": []string{"Cache-Control, Expires, Last-Modified, Pragma, Content-Length, Content-Language, Content-Type"}, "Vary": []string{"Origin"}}, + method: http.MethodPost, + body: bytes.NewBufferString(url.Values{"client_id": {"foo-3"}}.Encode()), + }, { d: "should reject when basic auth client exists but origin not allowed", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-2", Secret: "bar", AllowedCORSOrigins: []string{"http://not-foobar.com"}}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-2", Secret: "bar", AllowedCORSOrigins: []string{"http://not-foobar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-2", "bar"))}}, @@ -71,10 +106,10 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should accept when basic auth client exists and origin allowed", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-3", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-3", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-3", "bar"))}}, @@ -83,11 +118,11 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should accept when basic auth client exists and origin allowed", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{}) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-3", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-3", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-3", "bar"))}}, @@ -96,11 +131,24 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should accept when basic auth client exists and origin (with partial wildcard) is allowed per client", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{}) + + // Ignore unique violations + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-4", Secret: "bar", AllowedCORSOrigins: []string{"http://*.foobar.com"}}) + }, + code: http.StatusNotImplemented, + header: http.Header{"Origin": {"http://foo.foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-4", "bar"))}}, + expectHeader: http.Header{"Access-Control-Allow-Credentials": []string{"true"}, "Access-Control-Allow-Origin": []string{"http://foo.foobar.com"}, "Access-Control-Expose-Headers": []string{"Cache-Control, Expires, Last-Modified, Pragma, Content-Length, Content-Language, Content-Type"}, "Vary": []string{"Origin"}}, + }, + { + d: "should accept when basic auth client exists and wildcard origin is allowed per client", + prep: func(t *testing.T, r driver.Registry) { + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{}) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-4", Secret: "bar", AllowedCORSOrigins: []string{"http://*.foobar.com"}}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-4", Secret: "bar", AllowedCORSOrigins: []string{"http://*"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foo.foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-4", "bar"))}}, @@ -109,11 +157,11 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should accept when basic auth client exists and origin (with full wildcard) is allowed globally", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"*"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"*"}) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-5", Secret: "bar", AllowedCORSOrigins: []string{"http://barbar.com"}}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-5", Secret: "bar", AllowedCORSOrigins: []string{"http://barbar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"*"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-5", "bar"))}}, @@ -122,11 +170,11 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should accept when basic auth client exists and origin (with partial wildcard) is allowed globally", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://*.foobar.com"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://*.foobar.com"}) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-6", Secret: "bar", AllowedCORSOrigins: []string{"http://barbar.com"}}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-6", Secret: "bar", AllowedCORSOrigins: []string{"http://barbar.com"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foo.foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-6", "bar"))}}, @@ -135,11 +183,11 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should accept when basic auth client exists and origin (with full wildcard) allowed per client", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-7", Secret: "bar", AllowedCORSOrigins: []string{"*"}}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-7", Secret: "bar", AllowedCORSOrigins: []string{"*"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-7", "bar"))}}, @@ -148,8 +196,8 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should succeed on pre-flight request when token introspection fails", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {"Bearer 1234"}}, @@ -159,8 +207,8 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should fail when token introspection fails", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {"Bearer 1234"}}, @@ -169,17 +217,17 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should work when token introspection returns a session", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://not-test-domain.com"}) sess := oauth2.NewSession("foo-9") sess.SetExpiresAt(fosite.AccessToken, time.Now().Add(time.Hour)) ar := fosite.NewAccessRequest(sess) - cl := &client.Client{LegacyClientID: "foo-9", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}} + cl := &client.Client{ID: "foo-9", Secret: "bar", AllowedCORSOrigins: []string{"http://foobar.com"}} ar.Client = cl // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), cl) - _ = r.OAuth2Storage().CreateAccessTokenSession(context.Background(), signature, ar) + _ = r.ClientManager().CreateClient(ctx, cl) + _ = r.OAuth2Storage().CreateAccessTokenSession(ctx, signature, ar) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foobar.com"}, "Authorization": {"Bearer " + token}}, @@ -188,12 +236,12 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should accept any allowed specified origin protocol", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-11", Secret: "bar", AllowedCORSOrigins: []string{"*"}}) - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://*", "https://*"}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-11", Secret: "bar", AllowedCORSOrigins: []string{"*"}}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://*", "https://*"}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://foo.foobar.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-11", "bar"))}}, @@ -202,11 +250,11 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should accept client origin when basic auth client exists and origin is set at the client as well as the server", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://**.example.com"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://**.example.com"}) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-12", Secret: "bar", AllowedCORSOrigins: []string{"http://myapp.example.biz"}}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-12", Secret: "bar", AllowedCORSOrigins: []string{"http://myapp.example.biz"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://myapp.example.biz"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-12", "bar"))}}, @@ -215,11 +263,11 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { { d: "should accept server origin when basic auth client exists and origin is set at the client as well as the server", prep: func(t *testing.T, r driver.Registry) { - r.Config().MustSet(context.Background(), "serve.public.cors.enabled", true) - r.Config().MustSet(context.Background(), "serve.public.cors.allowed_origins", []string{"http://**.example.com"}) + r.Config().MustSet(ctx, "serve.public.cors.enabled", true) + r.Config().MustSet(ctx, "serve.public.cors.allowed_origins", []string{"http://**.example.com"}) // Ignore unique violations - _ = r.ClientManager().CreateClient(context.Background(), &client.Client{LegacyClientID: "foo-13", Secret: "bar", AllowedCORSOrigins: []string{"http://myapp.example.biz"}}) + _ = r.ClientManager().CreateClient(ctx, &client.Client{ID: "foo-13", Secret: "bar", AllowedCORSOrigins: []string{"http://myapp.example.biz"}}) }, code: http.StatusNotImplemented, header: http.Header{"Origin": {"http://client-app.example.com"}, "Authorization": {fmt.Sprintf("Basic %s", x.BasicAuth("foo-13", "bar"))}}, @@ -237,14 +285,14 @@ func TestOAuth2AwareCORSMiddleware(t *testing.T) { if tc.method != "" { method = tc.method } - req, err := http.NewRequest(method, "http://foobar.com/", nil) + req, err := http.NewRequest(method, "http://foobar.com/", tc.body) require.NoError(t, err) for k := range tc.header { req.Header.Set(k, tc.header.Get(k)) } res := httptest.NewRecorder() - oauth2cors.Middleware(context.Background(), r)(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + r.OAuth2AwareMiddleware()(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotImplemented) })).ServeHTTP(res, req) require.NoError(t, err) diff --git a/x/pointer.go b/x/pointer.go deleted file mode 100644 index b415ad115da..00000000000 --- a/x/pointer.go +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright © 2022 Ory Corp -// SPDX-License-Identifier: Apache-2.0 - -package x - -// ToPointer returns the pointer to the value. -func ToPointer[T any](val T) *T { - return &val -} - -// FromPointer returns the dereferenced value or if the pointer is nil the zero value. -func FromPointer[T any, TT *T](val *T) (zero T) { - if val == nil { - return zero - } - return *val -} diff --git a/x/sighash.go b/x/sighash.go new file mode 100644 index 00000000000..00069c6f998 --- /dev/null +++ b/x/sighash.go @@ -0,0 +1,15 @@ +// Copyright © 2024 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package x + +import ( + "crypto/sha512" + "fmt" +) + +// SignatureHash hashes the signature to prevent errors where the signature is +// longer than 128 characters (and thus doesn't fit into the pk). +func SignatureHash(signature string) string { + return fmt.Sprintf("%x", sha512.Sum384([]byte(signature))) +} diff --git a/x/sqlx.go b/x/sqlx.go index 7ca0e5a727d..f2710ada372 100644 --- a/x/sqlx.go +++ b/x/sqlx.go @@ -14,7 +14,7 @@ import ( "github.com/ory/x/errorsx" - jose "gopkg.in/square/go-jose.v2" + jose "github.com/go-jose/go-jose/v3" ) // swagger:type JSONWebKeySet @@ -71,6 +71,8 @@ func (ns *Duration) UnmarshalJSON(data []byte) error { } // swagger:model NullDuration +// +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions type swaggerNullDuration string // NullDuration represents a nullable JSON and SQL compatible time.Duration. diff --git a/x/swagger/genericError.go b/x/swagger/genericError.go new file mode 100644 index 00000000000..43005060b91 --- /dev/null +++ b/x/swagger/genericError.go @@ -0,0 +1,12 @@ +// Copyright © 2023 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +package swagger + +import "github.com/ory/herodot" + +// swagger:model genericError +// +//nolint:deadcode,unused +//lint:ignore U1000 Used to generate Swagger and OpenAPI definitions +type GenericError struct{ herodot.DefaultError } diff --git a/x/tls_termination_test.go b/x/tls_termination_test.go index 92f2fd6f27b..bdb5581ce91 100644 --- a/x/tls_termination_test.go +++ b/x/tls_termination_test.go @@ -12,9 +12,9 @@ import ( "github.com/stretchr/testify/assert" - "github.com/ory/hydra/driver/config" - "github.com/ory/hydra/internal" - . "github.com/ory/hydra/x" + "github.com/ory/hydra/v2/driver/config" + "github.com/ory/hydra/v2/internal" + . "github.com/ory/hydra/v2/x" "github.com/ory/x/contextx" )