diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml deleted file mode 100644 index c767e0d3..00000000 --- a/.github/workflows/go.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Go - -on: - push: - branches: [ master ] - pull_request: - branches: [ master ] - -jobs: - - build: - name: Build - runs-on: ubuntu-latest - steps: - - - name: Set up Go 1.16 - uses: actions/setup-go@v2 - with: - go-version: 1.16 - id: go - - - name: Check out code into the Go module directory - uses: actions/checkout@v2 - - - name: Get dependencies - run: | - go get -v -t -d ./... - if [ -f Gopkg.toml ]; then - curl https://raw.githubusercontent.com/golang/dep/master/install.sh | sh - dep ensure - fi - - - - name: Build Server Setup - run: go build -v github.com/oidc-mytoken/server/cmd/mytoken-server/mytoken-setup - - - name: Build Server - run: go build -v github.com/oidc-mytoken/server/cmd/mytoken-server - - - name: Test - run: go test -v ./... - diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml deleted file mode 100644 index 91099a67..00000000 --- a/.github/workflows/release.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: goreleaser -on: - push: - tags: - - "v*.*.*" - -jobs: - goreleaser: - runs-on: ubuntu-latest - steps: - - - name: Checkout - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Set up Go - uses: actions/setup-go@v2 - with: - go-version: 1.16 - - - name: Docker Login - uses: docker/login-action@v1.12.0 - with: - # Server address of Docker registry. If not set then will default to Docker Hub - # registry: # optional - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - - - name: Run GoReleaser - uses: goreleaser/goreleaser-action@v2 - with: - version: latest - args: release --rm-dist - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index 56f6bfc7..c947f0fd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.idea/ +/.cache/ /mytoken /mytoken-setup /mytoken-server @@ -15,3 +16,4 @@ dist/ /docker/db.env /docker/haproxy/haproxy.cfg /docker/.env +/results/ diff --git a/.gitlab-ci-scripts/goreleaser.sh b/.gitlab-ci-scripts/goreleaser.sh new file mode 100755 index 00000000..fc057386 --- /dev/null +++ b/.gitlab-ci-scripts/goreleaser.sh @@ -0,0 +1,19 @@ +mkdir ../shared +first=$(grep '^## ' -nm1 CHANGELOG.md | cut -d':' -f1); \ + second=$(grep '^## ' -nm2 CHANGELOG.md | tail -n1 | cut -d':' -f1); \ + tail -n+$first CHANGELOG.md | head -n$(($second-$first)) > ../shared/release.md +GORELEASER_CONFIG=".goreleaser.yml" +if [ -n "$CI_COMMIT_TAG" ] && echo "$CI_COMMIT_TAG" | grep -qv '-'; then +GORELEASER_CONFIG=".goreleaser-release.yml" +fi +BASEDIR=/go/src/github.com/oidc-mytoken/server +docker run --rm --privileged \ + -v "$PWD":"$BASEDIR" \ + -w "$BASEDIR" \ + -v "${PWD}/../shared":/tmp/shared \ + -v /var/run/docker.sock:/var/run/docker.sock \ + -e DOCKER_USERNAME -e DOCKER_PASSWORD \ + -e GITHUB_TOKEN \ + -e GORELEASER_CONFIG \ + goreleaser/goreleaser release -f $GORELEASER_CONFIG --release-notes /tmp/shared/release.md +ls -l results \ No newline at end of file diff --git a/.gitlab-ci-scripts/set-prerel-version b/.gitlab-ci-scripts/set-prerel-version new file mode 100755 index 00000000..a756819a --- /dev/null +++ b/.gitlab-ci-scripts/set-prerel-version @@ -0,0 +1,16 @@ +#!/bin/sh + +MASTER_BRANCH=refs/remotes/origin/master +VERSION_FILE=internal/model/version/VERSION + +git config --global --add safe.directory "$PWD" +git config user.email "ci@repo.data.kit.edu" +git config user.name "cicd" + +PREREL=$(git rev-list --count HEAD ^$MASTER_BRANCH) +VERSION=$(cat $VERSION_FILE) +FULL_VERSION="${VERSION}-pr${PREREL}" +echo "$FULL_VERSION" > $VERSION_FILE +git add $VERSION_FILE +git commit -m "dummy prerel version" +git tag "v${FULL_VERSION}" \ No newline at end of file diff --git a/.gitlab-ci-scripts/upload.sh b/.gitlab-ci-scripts/upload.sh new file mode 100755 index 00000000..8eb567b1 --- /dev/null +++ b/.gitlab-ci-scripts/upload.sh @@ -0,0 +1,41 @@ + +REPO_TARGET="/prerel" +if [ -n "$CI_COMMIT_TAG" ] && echo "$CI_COMMIT_TAG" | grep -qv '-'; then + REPO_TARGET="/preprod" +fi + +# ssh-key-script +[ -e /tmp/ssh-private-keys/${REPO_USER} ] && { + eval $(ssh-agent -s) + cat /tmp/ssh-private-keys/${REPO_USER} | tr -d '\r' | ssh-add - + test -d ~/.ssh || mkdir -p ~/.ssh + chmod 700 ~/.ssh +} +[ -e /tmp/ssh-private-keys/known_hosts ] && { + test -d ~/.ssh || mkdir -p ~/.ssh + cp /tmp/ssh-private-keys/known_hosts ~/.ssh/known_hosts + chmod 644 ~/.ssh/known_hosts +} +ssh-add -l +ssh -o StrictHostKeyChecking=no "${REPO_USER}@${REPO_HOST}" "hostname -f" + +# sign-repo function +sign_repos() { + ssh "${REPO_USER}@${REPO_HOST}" "~/ci-voodoo/ci-tools/sign-all-repos.sh -t ${REPO_TARGET}" +} + +upload_files() { + UPLOAD_DIR=/tmp/package-upload + ssh "${REPO_USER}@${REPO_HOST}" "rm -rf $UPLOAD_DIR && mkdir -p $UPLOAD_DIR" + scp results/* "${REPO_USER}@${REPO_HOST}:${UPLOAD_DIR}" +} + +distribute_files() { + ssh "${REPO_USER}@${REPO_HOST}" "~/ci-voodoo/ci-tools/distribute-local-packages.sh -t ${REPO_TARGET} -w mytoken" +} + + +# upload and sign +upload_files +distribute_files +sign_repos diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..f4db3e52 --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,79 @@ +image: golang:1.19 +stages: + - build + - test + - lint + - release + +default: + tags: + - linux + cache: + paths: + - .cache + + +before_script: + - mkdir -p .cache + - export GOPATH=${CI_PROJECT_DIR}/.cache + +test: + stage: test + script: + - go test -v ./... + +test_race: + stage: test + script: + - go test -race -v ./... + +lint: + stage: lint + before_script: + - go install golang.org/x/lint/golint@latest + script: + - golint -set_exit_status ./... + +vet: + stage: lint + script: + - go vet ./... + +build_server: + stage: build + script: + - go build github.com/oidc-mytoken/server/cmd/mytoken-server + +build_setup: + stage: build + script: + - go build github.com/oidc-mytoken/server/cmd/mytoken-server/mytoken-setup + +build_migratedb: + stage: build + script: + - go build github.com/oidc-mytoken/server/cmd/mytoken-server/mytoken-migratedb + +prerelease: + stage: release + image: + name: docker:stable + services: + - docker:dind + only: + refs: + - tags + - prerel + tags: + - linux + variables: + GIT_STRATEGY: clone + GIT_DEPTH: 0 + REPO_HOST: repo.data.kit.edu + REPO_USER: cicd + script: + - docker run --rm -v $PWD:/tmp/mytoken -w /tmp/mytoken bitnami/git .gitlab-ci-scripts/set-prerel-version + - .gitlab-ci-scripts/goreleaser.sh + - .gitlab-ci-scripts/upload.sh + after_script: + - docker run --rm curlimages/curl -d "repo=github.com/oidc-mytoken/server" https://goreportcard.com/checks diff --git a/.goreleaser-release.yml b/.goreleaser-release.yml new file mode 100644 index 00000000..d535f336 --- /dev/null +++ b/.goreleaser-release.yml @@ -0,0 +1,187 @@ +project_name: mytoken-server +before: + hooks: + - go mod tidy +dist: results +builds: + - id: server + main: ./cmd/mytoken-server + binary: mytoken-server + env: + - CGO_ENABLED=0 + goos: + - linux + flags: + - -trimpath + mod_timestamp: '{{ .CommitTimestamp }}' + - id: setup + main: ./cmd/mytoken-server/mytoken-setup + binary: mytoken-setup + env: + - CGO_ENABLED=0 + goos: + - linux + flags: + - -trimpath + mod_timestamp: '{{ .CommitTimestamp }}' + - id: migratedb + main: ./cmd/mytoken-server/mytoken-migratedb + binary: mytoken-migratedb + env: + - CGO_ENABLED=0 + goos: + - linux + flags: + - -trimpath + mod_timestamp: '{{ .CommitTimestamp }}' +archives: + - replacements: + darwin: macOS + 386: 32-bit + amd64: 64-bit + format_overrides: + - goos: windows + format: zip +nfpms: + - id: server-pkg + package_name: mytoken-server + replacements: + 386: i386 + file_name_template: "{{ .PackageName }}_{{ .Version }}_{{ .Arch }}" + builds: + - server + homepage: https://mytoken-docs.data.kit.edu/server + maintainer: Gabriel Zachmann + description: Mytoken is a central web service with the goal to easily obtain OpenID Connect access tokens across devices. + license: MIT + formats: + - deb + - rpm + release: "1" + section: misc + bindir: /usr/bin + contents: + - src: config/example-config.yaml + dst: /etc/mytoken/example-config.yaml + type: config + - src: config/mytoken.service + dst: /etc/systemd/system/mytoken.service + - dst: /var/log/mytoken + type: dir + overrides: + rpm: + replacements: + amd64: x86_64 + file_name_template: "{{ .PackageName }}-{{ .Version }}.{{ .Arch }}" + - id: setup-pkg + package_name: mytoken-server-setup + replacements: + 386: i386 + file_name_template: "{{ .PackageName }}_{{ .Version }}_{{ .Arch }}" + builds: + - setup + homepage: https://mytoken-docs.data.kit.edu/server + maintainer: Gabriel Zachmann + description: A setup utility for the mytoken-server + license: MIT + formats: + - deb + - rpm + release: "1" + section: misc + bindir: /usr/bin + overrides: + rpm: + replacements: + amd64: x86_64 + file_name_template: "{{ .PackageName }}-{{ .Version }}.{{ .Arch }}" + - id: migratedb-pkg + package_name: mytoken-server-migratedb + replacements: + 386: i386 + file_name_template: "{{ .PackageName }}_{{ .Version }}_{{ .Arch }}" + builds: + - migratedb + homepage: https://mytoken-docs.data.kit.edu/server + maintainer: Gabriel Zachmann + description: A tool for migrating the database between versions + license: MIT + dependencies: + - mariadb-client + formats: + - deb + - rpm + release: "1" + section: misc + bindir: /usr/bin + overrides: + rpm: + replacements: + amd64: x86_64 + file_name_template: "{{ .PackageName }}-{{ .Version }}.{{ .Arch }}" +dockers: + - goos: linux + goarch: amd64 + ids: + - server + image_templates: + - "oidcmytoken/mytoken-server:latest" + - "oidcmytoken/mytoken-server:{{ .Tag }}" + - "oidcmytoken/mytoken-server:v{{ .Major }}" + - "oidcmytoken/mytoken-server:v{{ .Major }}.{{ .Minor }}" + dockerfile: cmd/mytoken-server/Dockerfile + build_flag_templates: + - "--pull" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.title=mytoken-server" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - goos: linux + goarch: amd64 + ids: + - setup + image_templates: + - "oidcmytoken/mytoken-setup:latest" + - "oidcmytoken/mytoken-setup:{{ .Tag }}" + - "oidcmytoken/mytoken-setup:v{{ .Major }}" + - "oidcmytoken/mytoken-setup:v{{ .Major }}.{{ .Minor }}" + dockerfile: cmd/mytoken-server/mytoken-setup/Dockerfile + build_flag_templates: + - "--pull" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.title=mytoken-setup" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" + - goos: linux + goarch: amd64 + ids: + - migratedb + image_templates: + - "oidcmytoken/mytoken-migratedb:latest" + - "oidcmytoken/mytoken-migratedb:{{ .Tag }}" + - "oidcmytoken/mytoken-migratedb:v{{ .Major }}" + - "oidcmytoken/mytoken-migratedb:v{{ .Major }}.{{ .Minor }}" + dockerfile: cmd/mytoken-server/mytoken-migratedb/Dockerfile + build_flag_templates: + - "--pull" + - "--label=org.opencontainers.image.created={{.Date}}" + - "--label=org.opencontainers.image.title=mytoken-migratedb" + - "--label=org.opencontainers.image.revision={{.FullCommit}}" + - "--label=org.opencontainers.image.version={{.Version}}" +checksum: + name_template: 'checksums.txt' +snapshot: + name_template: "{{ .Tag }}-next" +release: + prerelease: auto + draft: true + github: + owner: oidc-mytoken + name: server + name_template: "{{.ProjectName}} {{.Version}}" +changelog: + sort: asc + filters: + exclude: + - '^docs:' + - '^test:' diff --git a/.goreleaser.yml b/.goreleaser.yml index 60c69025..9827db9a 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -2,6 +2,7 @@ project_name: mytoken-server before: hooks: - go mod tidy +dist: results builds: - id: server main: ./cmd/mytoken-server @@ -10,6 +11,9 @@ builds: - CGO_ENABLED=0 goos: - linux + flags: + - -trimpath + mod_timestamp: '{{ .CommitTimestamp }}' - id: setup main: ./cmd/mytoken-server/mytoken-setup binary: mytoken-setup @@ -17,6 +21,9 @@ builds: - CGO_ENABLED=0 goos: - linux + flags: + - -trimpath + mod_timestamp: '{{ .CommitTimestamp }}' - id: migratedb main: ./cmd/mytoken-server/mytoken-migratedb binary: mytoken-migratedb @@ -24,15 +31,17 @@ builds: - CGO_ENABLED=0 goos: - linux + flags: + - -trimpath + mod_timestamp: '{{ .CommitTimestamp }}' archives: - - - replacements: - darwin: macOS - 386: 32-bit - amd64: 64-bit - format_overrides: - - goos: windows - format: zip + - replacements: + darwin: macOS + 386: 32-bit + amd64: 64-bit + format_overrides: + - goos: windows + format: zip nfpms: - id: server-pkg package_name: mytoken-server @@ -41,14 +50,14 @@ nfpms: file_name_template: "{{ .PackageName }}_{{ .Version }}_{{ .Arch }}" builds: - server - homepage: https://mytoken-doc.data.kit.edu/server/intro + homepage: https://mytoken-docs.data.kit.edu/server maintainer: Gabriel Zachmann description: Mytoken is a central web service with the goal to easily obtain OpenID Connect access tokens across devices. license: MIT formats: - deb - rpm - release: 1 + release: "1" section: misc bindir: /usr/bin contents: @@ -71,14 +80,14 @@ nfpms: file_name_template: "{{ .PackageName }}_{{ .Version }}_{{ .Arch }}" builds: - setup - homepage: https://mytoken-doc.data.kit.edu/server/intro + homepage: https://mytoken-docs.data.kit.edu/server maintainer: Gabriel Zachmann description: A setup utility for the mytoken-server license: MIT formats: - deb - rpm - release: 1 + release: "1" section: misc bindir: /usr/bin overrides: @@ -93,7 +102,7 @@ nfpms: file_name_template: "{{ .PackageName }}_{{ .Version }}_{{ .Arch }}" builds: - migratedb - homepage: https://mytoken-doc.data.kit.edu/server/intro + homepage: https://mytoken-docs.data.kit.edu/server maintainer: Gabriel Zachmann description: A tool for migrating the database between versions license: MIT @@ -102,7 +111,7 @@ nfpms: formats: - deb - rpm - release: 1 + release: "1" section: misc bindir: /usr/bin overrides: @@ -116,11 +125,8 @@ dockers: ids: - server image_templates: - - "oidcmytoken/mytoken-server:latest" + - "oidcmytoken/mytoken-server:unstable" - "oidcmytoken/mytoken-server:{{ .Tag }}" - - "oidcmytoken/mytoken-server:v{{ .Major }}" - - "oidcmytoken/mytoken-server:v{{ .Major }}.{{ .Minor }}" -# skip_push: true dockerfile: cmd/mytoken-server/Dockerfile build_flag_templates: - "--pull" @@ -133,11 +139,8 @@ dockers: ids: - setup image_templates: - - "oidcmytoken/mytoken-setup:latest" + - "oidcmytoken/mytoken-setup:unstable" - "oidcmytoken/mytoken-setup:{{ .Tag }}" - - "oidcmytoken/mytoken-setup:v{{ .Major }}" - - "oidcmytoken/mytoken-setup:v{{ .Major }}.{{ .Minor }}" -# skip_push: true dockerfile: cmd/mytoken-server/mytoken-setup/Dockerfile build_flag_templates: - "--pull" @@ -150,11 +153,8 @@ dockers: ids: - migratedb image_templates: - - "oidcmytoken/mytoken-migratedb:latest" + - "oidcmytoken/mytoken-migratedb:unstable" - "oidcmytoken/mytoken-migratedb:{{ .Tag }}" - - "oidcmytoken/mytoken-migratedb:v{{ .Major }}" - - "oidcmytoken/mytoken-migratedb:v{{ .Major }}.{{ .Minor }}" -# skip_push: true dockerfile: cmd/mytoken-server/mytoken-migratedb/Dockerfile build_flag_templates: - "--pull" @@ -167,7 +167,12 @@ checksum: snapshot: name_template: "{{ .Tag }}-next" release: + disable: true + prerelease: auto draft: true + github: + owner: oidc-mytoken + name: server name_template: "{{.ProjectName}} {{.Version}}" changelog: sort: asc diff --git a/CHANGELOG.md b/CHANGELOG.md index eaaf274c..2409c907 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,38 @@ +## mytoken 0.6.1 + +### API + +- Changed the restriction `ip` key to `hosts`: + - Backward compatibility is preserved. The legacy key `ip` is still accepted. + - The `hosts` entry can contain: + - Single ip address + - Subnet address + - Host name (with or without wildcard) + - To compare against this, on request a reverse dns lookup is done for the request's ip address + +### Enhancements + +- Location restriction can now be done with host names, not only plain ip addresses, see above for more details. +- Webinterface: Added message to tokeninfo after MT creation and TC exchange to indicate that users must copy the + mytoken to persist it. +- Improved code quality + +### Bugfixes + +- Fixed a bug in the web interface where the scope selection indicator for access tokens where not updated. + +### Dependencies + +- Bump go version to 1.19 +- Bump golang.org/x/mod from 0.5.1 to 0.7.0 +- Bump golang.org/x/crypto to 0.2.0 +- Bump golang.org/x/term to 0.2.0 +- Bump github.com/gofiber/fiber/v2 from 2.37.1 to 2.39.0 +- Bump github.com/gofiber/helmet/v2 from 2.2.16 to 2.2.18 + ## mytoken 0.6.0 ### API diff --git a/cmd/mytoken-server/main.go b/cmd/mytoken-server/main.go index 433dd230..9fd35950 100644 --- a/cmd/mytoken-server/main.go +++ b/cmd/mytoken-server/main.go @@ -12,6 +12,7 @@ import ( "github.com/oidc-mytoken/server/internal/endpoints/settings" "github.com/oidc-mytoken/server/internal/model/version" "github.com/oidc-mytoken/server/internal/utils/cookies" + "github.com/oidc-mytoken/server/shared/httpclient" "github.com/oidc-mytoken/server/internal/config" "github.com/oidc-mytoken/server/internal/db" @@ -21,7 +22,6 @@ import ( "github.com/oidc-mytoken/server/internal/server" "github.com/oidc-mytoken/server/internal/utils/geoip" loggerUtils "github.com/oidc-mytoken/server/internal/utils/logger" - "github.com/oidc-mytoken/server/shared/httpClient" ) func main() { @@ -33,7 +33,7 @@ func main() { authcode.Init() versionrepo.ConnectToVersion() jws.LoadKey() - httpClient.Init(config.Get().IssuerURL, fmt.Sprintf("mytoken-server %s", version.VERSION())) + httpclient.Init(config.Get().IssuerURL, fmt.Sprintf("mytoken-server %s", version.VERSION)) geoip.Init() settings.InitSettings() cookies.Init() @@ -42,7 +42,7 @@ func main() { } func handleSignals() { - signals := make(chan os.Signal) + signals := make(chan os.Signal, 1) signal.Notify(signals, syscall.SIGHUP, syscall.SIGUSR1) go func() { for { diff --git a/cmd/mytoken-server/mytoken-migratedb/main.go b/cmd/mytoken-server/mytoken-migratedb/main.go index 9c61b863..6d66488b 100644 --- a/cmd/mytoken-server/mytoken-migratedb/main.go +++ b/cmd/mytoken-server/mytoken-migratedb/main.go @@ -28,7 +28,7 @@ var dbConfig struct { var app = &cli.App{ Name: "mytoken-migratedb", Usage: "Command line client for easy database migration between mytoken versions", - Version: version.VERSION(), + Version: version.VERSION, Compiled: time.Time{}, Authors: []*cli.Author{ { diff --git a/cmd/mytoken-server/mytoken-migratedb/version.go b/cmd/mytoken-server/mytoken-migratedb/version.go index 6811f45a..725e1488 100644 --- a/cmd/mytoken-server/mytoken-migratedb/version.go +++ b/cmd/mytoken-server/mytoken-migratedb/version.go @@ -40,7 +40,7 @@ func getDoneMap(state versionrepo.DBVersionState) (map[string]bool, map[string]b } func migrateDB(mytokenNodes []string) error { - v := "v" + version.VERSION() + v := "v" + version.VERSION dbState, err := versionrepo.GetVersionState(log.StandardLogger(), nil) if err != nil { return err diff --git a/cmd/mytoken-server/mytoken-setup/setup.go b/cmd/mytoken-server/mytoken-setup/setup.go index 6e4af2ce..000a2de9 100644 --- a/cmd/mytoken-server/mytoken-setup/setup.go +++ b/cmd/mytoken-server/mytoken-setup/setup.go @@ -3,7 +3,6 @@ package main import ( "embed" "fmt" - "io/ioutil" "os" "time" @@ -40,8 +39,12 @@ func (cred _rootDBCredentials) toDBConf() config.DBConf { var dbFlags = []cli.Flag{ &cli.StringFlag{ - Name: "user", - Aliases: []string{"u", "root-user", "db-user"}, + Name: "user", + Aliases: []string{ + "u", + "root-user", + "db-user", + }, Usage: "The username for the (root) user used for setting up the db", EnvVars: []string{"DB_USER"}, Value: "root", @@ -49,10 +52,18 @@ var dbFlags = []cli.Flag{ Placeholder: "ROOT", }, &cli.StringFlag{ - Name: "password", - Aliases: []string{"p", "pw", "db-password", "db-pw"}, - Usage: "The password for the (root) user used for setting up the db", - EnvVars: []string{"DB_PW", "DB_PASSWORD"}, + Name: "password", + Aliases: []string{ + "p", + "pw", + "db-password", + "db-pw", + }, + Usage: "The password for the (root) user used for setting up the db", + EnvVars: []string{ + "DB_PW", + "DB_PASSWORD", + }, Destination: &rootDBCredentials.Password, Placeholder: "PASSWORD", }, @@ -75,7 +86,7 @@ var sigKeyFile string var app = &cli.App{ Name: "mytoken-setup", Usage: "Command line client for easily setting up a mytoken server", - Version: version.VERSION(), + Version: version.VERSION, Compiled: time.Time{}, Authors: []*cli.Author{ { @@ -162,7 +173,7 @@ func installGEOIPDB(_ *cli.Context) error { return err } log.Debug("Downloaded zip file") - err = ioutil.WriteFile(config.Get().GeoIPDBFile, archive["IP2LOCATION-LITE-DB1.IPV6.BIN"], 0644) + err = os.WriteFile(config.Get().GeoIPDBFile, archive["IP2LOCATION-LITE-DB1.IPV6.BIN"], 0600) if err == nil { log.WithField("file", config.Get().GeoIPDBFile).Debug("Installed geo ip database") fmt.Printf("Installed geo ip database file to '%s'.\n", config.Get().GeoIPDBFile) @@ -185,7 +196,7 @@ func createSigningKey(_ *cli.Context) error { os.Exit(1) } } - if err = ioutil.WriteFile(sigKeyFile, []byte(str), 0600); err != nil { + if err = os.WriteFile(sigKeyFile, []byte(str), 0600); err != nil { return err } log.WithField("filepath", sigKeyFile).Debug("Wrote key to file") diff --git a/config/example-config.yaml b/config/example-config.yaml index 5957ec6a..6c48d07a 100644 --- a/config/example-config.yaml +++ b/config/example-config.yaml @@ -37,7 +37,8 @@ server: # The time window in which the maximum number of requests is allowed, i.e. the quota is reset after this time. # The time is given in seconds. window: 300 - # Use the list to exclude hosts from the request limit. You can specify single IP addresses as well as subnets. + # Use the list to exclude hosts from the request limit. You can specify single IP addresses, subnets and + # hostnames including wildcards. always_allow: - "127.0.0.1" @@ -123,7 +124,7 @@ features: # - exp # - scope # - audience - # - ip + # - hosts # - geoip_allow # - geoip_disallow # - usages_AT diff --git a/docker/example-docker-config.yaml b/docker/example-docker-config.yaml index 75b3e68c..9b35f334 100644 --- a/docker/example-docker-config.yaml +++ b/docker/example-docker-config.yaml @@ -26,6 +26,19 @@ server: key: # If behind a load balancer or reverse proxy, set this option. Mytoken will read the client's ip address from this header. proxy_header: "X-FORWARDED-FOR" + # Configure the request limits (these are per IP) + request_limits: + # Unless false request limits are enabled + enabled: true + # The number of requests that are allowed within the specified time window, e.g. 10/1s 100/5min 1000/1h + max_requests: 100 + # The time window in which the maximum number of requests is allowed, i.e. the quota is reset after this time. + # The time is given in seconds. + window: 300 + # Use the list to exclude hosts from the request limit. You can specify single IP addresses, subnets and + # hostnames including wildcards. +# always_allow: +# - "127.0.0.1" # The database file for ip geo location. Will be installed by setup to this location. geo_ip_db_file: "/mytoken/IP2LOCATION-LITE-DB1.IPV6.BIN" @@ -102,7 +115,7 @@ features: # - exp # - scope # - audience - # - ip + # - hosts # - geoip_allow # - geoip_disallow # - usages_AT diff --git a/go.mod b/go.mod index c13712a1..2b77b162 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/oidc-mytoken/server -go 1.16 +go 1.19 require ( github.com/Songmu/prompter v0.5.1 @@ -9,27 +9,56 @@ require ( github.com/gliderlabs/ssh v0.3.5 github.com/go-resty/resty/v2 v2.7.0 github.com/go-sql-driver/mysql v1.6.0 - github.com/gofiber/fiber/v2 v2.37.1 - github.com/gofiber/helmet/v2 v2.2.16 + github.com/gofiber/fiber/v2 v2.39.0 + github.com/gofiber/helmet/v2 v2.2.18 github.com/gofiber/template v1.7.1 github.com/golang-jwt/jwt v3.2.2+incompatible github.com/ip2location/ip2location-go v8.3.0+incompatible github.com/jinzhu/copier v0.3.5 github.com/jmoiron/sqlx v1.3.5 github.com/lestrrat-go/jwx v1.2.25 - github.com/oidc-mytoken/api v0.8.0 - github.com/oidc-mytoken/lib v0.5.0 + github.com/oidc-mytoken/api v0.9.1 + github.com/oidc-mytoken/lib v0.6.1 + github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pires/go-proxyproto v0.6.2 github.com/pkg/errors v0.9.1 github.com/satori/go.uuid v1.2.0 github.com/sirupsen/logrus v1.9.0 github.com/urfave/cli/v2 v2.3.1-0.20211205195634-e8d81738896c - github.com/valyala/fasthttp v1.40.0 - golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d - golang.org/x/mod v0.5.1 + github.com/valyala/fasthttp v1.41.0 + golang.org/x/crypto v0.2.0 + golang.org/x/mod v0.7.0 golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094 - golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 + golang.org/x/term v0.2.0 gopkg.in/yaml.v3 v3.0.1 ) +require ( + github.com/andybalholm/brotli v1.0.4 // indirect + github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect + github.com/cbroglie/mustache v1.4.0 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d // indirect + github.com/goccy/go-json v0.9.7 // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/klauspost/compress v1.15.11 // indirect + github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect + github.com/lestrrat-go/blackmagic v1.0.0 // indirect + github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/iter v1.0.1 // indirect + github.com/lestrrat-go/option v1.0.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/net v0.2.0 // indirect + golang.org/x/sys v0.2.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/protobuf v1.28.0 // indirect + gopkg.in/square/go-jose.v2 v2.6.0 // indirect +) + replace github.com/urfave/cli/v2 => github.com/zachmann/cli/v2 v2.3.1-0.20211220102037-d619fd40a704 diff --git a/go.sum b/go.sum index 73ea072a..47a0e349 100644 --- a/go.sum +++ b/go.sum @@ -160,11 +160,11 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/goccy/go-json v0.9.7 h1:IcB+Aqpx/iMHu5Yooh7jEzJk1JZ7Pjtmys2ukPr7EeM= github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= -github.com/gofiber/fiber/v2 v2.37.0/go.mod h1:xm3pDGlfE1xqVKb77iH8weLU0FFoTeWeK3nbiYM2Nh0= -github.com/gofiber/fiber/v2 v2.37.1 h1:QK2032gjv0ulegpv/qlTEBoXQD3eFFzCHXcNN12UZCs= github.com/gofiber/fiber/v2 v2.37.1/go.mod h1:j3UslgQeJQP3mNhBxHnLLE8TPqA1Fd/lrl4gD25rRUY= -github.com/gofiber/helmet/v2 v2.2.16 h1:ssLTF6z6GuIN2USq23psTCMYWgzrNhrBoJVwgCY4b80= -github.com/gofiber/helmet/v2 v2.2.16/go.mod h1:rJ/S3yuSzSQAQROSoHE4uqsB1oLUREDnRJScaoByHtM= +github.com/gofiber/fiber/v2 v2.39.0 h1:uhWpYQ6EHN8J7FOPYbI2hrdBD/KNZBC5CjbuOd4QUt4= +github.com/gofiber/fiber/v2 v2.39.0/go.mod h1:Cmuu+elPYGqlvQvdKyjtYsjGMi69PDp8a1AY2I5B2gM= +github.com/gofiber/helmet/v2 v2.2.18 h1:N6LcowwRpwhjLJZVEWTf3c/MjNKGdQSJffMUp02q1z0= +github.com/gofiber/helmet/v2 v2.2.18/go.mod h1:hGsMgmaBpCHX2GZlPXW7rghCFrGR0gXWfhsTljGQjhQ= github.com/gofiber/template v1.7.1 h1:QCRChZA6UrLROgMbzCMKm4a1yqM/5S8RTBKYWZ9GfL4= github.com/gofiber/template v1.7.1/go.mod h1:l3ZOSp8yrMvROzqyh0QTCw7MHet/yLBzaRX+wsiw+gM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -301,8 +301,10 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= 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.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U= github.com/klauspost/compress v1.15.0/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/klauspost/compress v1.15.9/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/compress v1.15.11 h1:Lcadnb3RKGin4FYM/orgq0qde+nc15E5Cbqg4B9Sx9c= +github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= github.com/konsorten/go-windows-terminal-sequences v1.0.1/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= @@ -333,13 +335,18 @@ github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-colorable v0.1.6/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.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4= +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.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 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y= 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-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-slim v0.0.0-20200618151855-bde33eecb5ee/go.mod h1:ma9TUJeni8LGZMJvOwbAv/FOwiwqIMQN570LnpqCBSM= github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= @@ -361,12 +368,15 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/oidc-mytoken/api v0.8.0 h1:V/8LyLcVtYX1xxj+r6KyShDYUhl1giHLPVB6dTZyQtk= -github.com/oidc-mytoken/api v0.8.0/go.mod h1:DBIlUbaIgGlf607VZx8zFC97VR3WNN0kaMVO1AqyTdE= -github.com/oidc-mytoken/lib v0.5.0 h1:/DHEjHCSVDFE5DXyXUp3dO7NWZfSFN2nYVaigYdmv5w= -github.com/oidc-mytoken/lib v0.5.0/go.mod h1:r6shfKy8/15vqGJvciCPphRkKffvIegSqj0uA6kzuns= +github.com/oidc-mytoken/api v0.9.0/go.mod h1:DBIlUbaIgGlf607VZx8zFC97VR3WNN0kaMVO1AqyTdE= +github.com/oidc-mytoken/api v0.9.1 h1:Hmv+KaGyxiodf92mXjELFeZOa9tBsQnUyEoBAFQNls8= +github.com/oidc-mytoken/api v0.9.1/go.mod h1:DBIlUbaIgGlf607VZx8zFC97VR3WNN0kaMVO1AqyTdE= +github.com/oidc-mytoken/lib v0.6.1 h1:ZtPj/1dc8rOf7VJlyCp3uBWEcEZJ7L2Ab50oI/ruoa4= +github.com/oidc-mytoken/lib v0.6.1/go.mod h1:AuKCljwZSdYfia6G6FvHl926pR/8ICyxrkbYKQgoGd4= 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/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pires/go-proxyproto v0.6.2 h1:KAZ7UteSOt6urjme6ZldyFm4wDe/z0ZUP0Yv0Dos0d8= github.com/pires/go-proxyproto v0.6.2/go.mod h1:Odh9VFOZJCf9G8cLW5o435Xf1J95Jw9Gw5rnCjcwzAY= @@ -391,6 +401,8 @@ github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8b github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -430,9 +442,9 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= -github.com/valyala/fasthttp v1.39.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= -github.com/valyala/fasthttp v1.40.0 h1:CRq/00MfruPGFLTQKY8b+8SfdK60TxNztjRMnH0t1Yc= github.com/valyala/fasthttp v1.40.0/go.mod h1:t/G+3rLek+CyY9bnIE+YlMRddxVAAGjhxndDB4i4C0I= +github.com/valyala/fasthttp v1.41.0 h1:zeR0Z1my1wDHTRiamBCXVglQdbUwgb9uWG3k1HQz6jY= +github.com/valyala/fasthttp v1.41.0/go.mod h1:f6VbjjoI3z1NDOZOv17o6RvtRSWxC77seBFc2uWtgiY= github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0= @@ -470,8 +482,9 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE= +golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= 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= @@ -508,8 +521,9 @@ 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.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= -golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38= golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= +golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= 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-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -562,8 +576,10 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b h1:ZmngSVLe/wycRns9MKikG9OWIEjGcGAkacif7oYQaUY= golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.0.0-20220906165146-f3363e06e74c/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= +golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= 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= @@ -678,13 +694,15 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/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-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64 h1:UiNENfZ8gDvpiWw7IpOMQ27spWmThO1RwwdQVbJahJM= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220825204002-c680a09ffe64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc= golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= +golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= 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= diff --git a/internal/config/config.go b/internal/config/config.go index 1362d728..9c518bfc 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -14,12 +14,12 @@ import ( model2 "github.com/oidc-mytoken/server/internal/model" "github.com/oidc-mytoken/server/internal/utils/errorfmt" + "github.com/oidc-mytoken/server/shared/utils/issuerutils" "github.com/oidc-mytoken/server/pkg/oauth2x" "github.com/oidc-mytoken/server/shared/context" "github.com/oidc-mytoken/server/shared/utils" "github.com/oidc-mytoken/server/shared/utils/fileutil" - "github.com/oidc-mytoken/server/shared/utils/issuerUtils" ) var defaultConfig = Config{ @@ -417,7 +417,7 @@ func validate() error { if len(p.Scopes) <= 0 { return errors.Errorf("invalid config: provider.scopes not set (Index %d)", i) } - iss0, iss1 := issuerUtils.GetIssuerWithAndWithoutSlash(p.Issuer) + iss0, iss1 := issuerutils.GetIssuerWithAndWithoutSlash(p.Issuer) conf.ProviderByIssuer[iss0] = p conf.ProviderByIssuer[iss1] = p if p.AudienceRequestParameter == "" { diff --git a/internal/db/cluster/cluster.go b/internal/db/cluster/cluster.go index ea9a67b5..dcee805c 100644 --- a/internal/db/cluster/cluster.go +++ b/internal/db/cluster/cluster.go @@ -20,7 +20,7 @@ import ( func NewFromConfig(conf config.DBConf) *Cluster { c := newCluster(len(conf.Hosts)) c.conf = &conf - c.startReconnector() + go c.runReconnector() c.AddNodes() log.Debug("Created db cluster") return c @@ -93,27 +93,25 @@ func (c *Cluster) addNode(n *node) error { return nil } -func (c *Cluster) startReconnector() { - go func() { - for { - select { - case <-c.stop: +func (c *Cluster) runReconnector() { + for { + select { + case <-c.stop: + log.Debug("Stopping re-connector") + return + default: + log.Debug("Run checkNodesDown") + if c.checkNodesDown() { log.Debug("Stopping re-connector") return - default: - log.Debug("Run checkNodesDown") - if c.checkNodesDown() { - log.Debug("Stopping re-connector") - return - } - conf := c.conf - if conf == nil { - conf = &config.Get().DB - } - time.Sleep(time.Duration(conf.ReconnectInterval) * time.Second) } + conf := c.conf + if conf == nil { + conf = &config.Get().DB + } + time.Sleep(time.Duration(conf.ReconnectInterval) * time.Second) } - }() + } } func (c *Cluster) checkNodesDown() bool { @@ -227,7 +225,6 @@ func (c *Cluster) next(rlog log.Ext1FieldLogger) *node { func (c *Cluster) RunWithinTransaction(rlog log.Ext1FieldLogger, tx *sqlx.Tx, fn func(*sqlx.Tx) error) error { if tx == nil { return c.Transact(rlog, fn) - } else { - return fn(tx) } + return fn(tx) } diff --git a/internal/db/db.go b/internal/db/db.go index 3f925649..7dc34d2d 100644 --- a/internal/db/db.go +++ b/internal/db/db.go @@ -100,9 +100,8 @@ type BitBool bool func (b BitBool) Value() (driver.Value, error) { if b { return []byte{1}, nil - } else { - return []byte{0}, nil } + return []byte{0}, nil } // Scan implements the sql.Scanner interface, diff --git a/internal/db/dbrepo/accesstokenrepo/accessToken.go b/internal/db/dbrepo/accesstokenrepo/accessToken.go index 997c4ac5..9efb5bb0 100644 --- a/internal/db/dbrepo/accesstokenrepo/accessToken.go +++ b/internal/db/dbrepo/accesstokenrepo/accessToken.go @@ -9,7 +9,7 @@ import ( "github.com/oidc-mytoken/server/internal/model" mytoken "github.com/oidc-mytoken/server/shared/mytoken/pkg" "github.com/oidc-mytoken/server/shared/mytoken/pkg/mtid" - "github.com/oidc-mytoken/server/shared/utils/cryptUtils" + "github.com/oidc-mytoken/server/shared/utils/cryptutils" ) // AccessToken holds database information about an access token @@ -35,7 +35,7 @@ func (t *AccessToken) toDBObject() (*accessToken, error) { if err != nil { return nil, err } - token, err := cryptUtils.AES256Encrypt(t.Token, stJWT) + token, err := cryptutils.AES256Encrypt(t.Token, stJWT) if err != nil { return nil, err } diff --git a/internal/db/dbrepo/authcodeinforepo/state/consentcode.go b/internal/db/dbrepo/authcodeinforepo/state/consentcode.go index 8b9894c7..9b0b0455 100644 --- a/internal/db/dbrepo/authcodeinforepo/state/consentcode.go +++ b/internal/db/dbrepo/authcodeinforepo/state/consentcode.go @@ -1,7 +1,7 @@ package state import ( - "github.com/oidc-mytoken/server/internal/utils/hashUtils" + "github.com/oidc-mytoken/server/internal/utils/hashutils" "github.com/oidc-mytoken/server/shared/utils" ) @@ -32,7 +32,7 @@ func ConsentCodeFromStr(code string) *ConsentCode { // GetState returns the state linked to a ConsentCode func (c *ConsentCode) GetState() string { if c.state == "" { - c.state = hashUtils.HMACBasedHash([]byte(c.code))[:stateLen] + c.state = hashutils.HMACBasedHash([]byte(c.code))[:stateLen] } return c.state } diff --git a/internal/db/dbrepo/authcodeinforepo/state/state.go b/internal/db/dbrepo/authcodeinforepo/state/state.go index d70d2892..45c5e211 100644 --- a/internal/db/dbrepo/authcodeinforepo/state/state.go +++ b/internal/db/dbrepo/authcodeinforepo/state/state.go @@ -9,7 +9,7 @@ import ( "github.com/oidc-mytoken/server/internal/config" "github.com/oidc-mytoken/server/internal/db" - "github.com/oidc-mytoken/server/internal/utils/hashUtils" + "github.com/oidc-mytoken/server/internal/utils/hashutils" ) const stateLen = 16 @@ -38,7 +38,7 @@ func NewState(state string) *State { // Hash returns the hash for this State func (s *State) Hash() string { if s.hash == "" { - s.hash = hashUtils.SHA3_512Str([]byte(s.state)) + s.hash = hashutils.SHA3_512Str([]byte(s.state)) } return s.hash } @@ -46,7 +46,7 @@ func (s *State) Hash() string { // PollingCode returns the polling code for this State func (s *State) PollingCode(rlog log.Ext1FieldLogger) string { if s.pollingCode == "" { - s.pollingCode = hashUtils.HMACBasedHash([]byte(s.state))[:config.Get().Features.Polling.Len] + s.pollingCode = hashutils.HMACBasedHash([]byte(s.state))[:config.Get().Features.Polling.Len] rlog.WithField("state", s.state).WithField( "polling_code", s.pollingCode, ).Debug("Created polling_code for state") diff --git a/internal/db/dbrepo/cryptstore/cryptstore.go b/internal/db/dbrepo/cryptstore/cryptstore.go index cf5ee524..6a3a6616 100644 --- a/internal/db/dbrepo/cryptstore/cryptstore.go +++ b/internal/db/dbrepo/cryptstore/cryptstore.go @@ -8,7 +8,7 @@ import ( "github.com/oidc-mytoken/server/internal/db" "github.com/oidc-mytoken/server/internal/db/dbrepo/encryptionkeyrepo" "github.com/oidc-mytoken/server/shared/mytoken/pkg/mtid" - "github.com/oidc-mytoken/server/shared/utils/cryptUtils" + "github.com/oidc-mytoken/server/shared/utils/cryptutils" ) // DeleteCrypted deletes an entry from the CryptStore @@ -29,7 +29,7 @@ func UpdateRefreshToken(rlog log.Ext1FieldLogger, tx *sqlx.Tx, tokenID mtid.MTID if err != nil { return err } - updatedRT, err := cryptUtils.AESEncrypt(newRT, key) + updatedRT, err := cryptutils.AESEncrypt(newRT, key) if err != nil { return err } diff --git a/internal/db/dbrepo/encryptionkeyrepo/encryptionkeyRepo.go b/internal/db/dbrepo/encryptionkeyrepo/encryptionkeyRepo.go index 77b76a07..f963c9cd 100644 --- a/internal/db/dbrepo/encryptionkeyrepo/encryptionkeyRepo.go +++ b/internal/db/dbrepo/encryptionkeyrepo/encryptionkeyRepo.go @@ -9,7 +9,7 @@ import ( "github.com/oidc-mytoken/server/internal/db" "github.com/oidc-mytoken/server/shared/mytoken/pkg/mtid" - "github.com/oidc-mytoken/server/shared/utils/cryptUtils" + "github.com/oidc-mytoken/server/shared/utils/cryptutils" ) // ReencryptEncryptionKey re-encrypts the encryption key for a mytoken. This is needed when the mytoken changes, e.g. on @@ -25,11 +25,11 @@ func ReencryptEncryptionKey(rlog log.Ext1FieldLogger, tx *sqlx.Tx, tokenID mtid. if err = errors.WithStack(tx.Get(&encryptedKey, `CALL EncryptionKeys_Get(?)`, keyID)); err != nil { return err } - key, err := cryptUtils.AES256Decrypt(encryptedKey, oldJWT) + key, err := cryptutils.AES256Decrypt(encryptedKey, oldJWT) if err != nil { return err } - updatedKey, err := cryptUtils.AES256Encrypt(key, newJWT) + updatedKey, err := cryptutils.AES256Encrypt(key, newJWT) if err != nil { return err } @@ -78,7 +78,7 @@ type EncryptionKey string // Decrypt returns the decrypted encryption key func (k EncryptionKey) Decrypt(jwt string) ([]byte, error) { - decryptedKey, err := cryptUtils.AES256Decrypt(string(k), jwt) + decryptedKey, err := cryptutils.AES256Decrypt(string(k), jwt) if err != nil { return nil, err } @@ -100,7 +100,7 @@ func (res RTCryptKeyDBRes) Decrypt(jwt string) (string, error) { if err != nil { return "", err } - return cryptUtils.AESDecrypt(res.RT, key) + return cryptutils.AESDecrypt(res.RT, key) } // getEncryptionKeyID returns the id of the encryption key used for encrypting the RT linked to this mytoken diff --git a/internal/db/dbrepo/mytokenrepo/mytoken.go b/internal/db/dbrepo/mytokenrepo/mytoken.go index 7a0f91f0..0ae7ca58 100644 --- a/internal/db/dbrepo/mytokenrepo/mytoken.go +++ b/internal/db/dbrepo/mytokenrepo/mytoken.go @@ -15,7 +15,7 @@ import ( event "github.com/oidc-mytoken/server/shared/mytoken/event/pkg" mytoken "github.com/oidc-mytoken/server/shared/mytoken/pkg" "github.com/oidc-mytoken/server/shared/mytoken/pkg/mtid" - "github.com/oidc-mytoken/server/shared/utils/cryptUtils" + "github.com/oidc-mytoken/server/shared/utils/cryptutils" "github.com/oidc-mytoken/server/shared/utils/unixtime" ) @@ -40,8 +40,8 @@ type MytokenEntry struct { // InitRefreshToken links a refresh token to this MytokenEntry func (mte *MytokenEntry) InitRefreshToken(rt string) error { mte.refreshToken = rt - mte.encryptionKey = cryptUtils.RandomBytes(32) - tmp, err := cryptUtils.AESEncrypt(mte.refreshToken, mte.encryptionKey) + mte.encryptionKey = cryptutils.RandomBytes(32) + tmp, err := cryptutils.AESEncrypt(mte.refreshToken, mte.encryptionKey) if err != nil { return err } @@ -50,7 +50,7 @@ func (mte *MytokenEntry) InitRefreshToken(rt string) error { if err != nil { return err } - tmp, err = cryptUtils.AES256Encrypt(base64.StdEncoding.EncodeToString(mte.encryptionKey), jwt) + tmp, err = cryptutils.AES256Encrypt(base64.StdEncoding.EncodeToString(mte.encryptionKey), jwt) if err != nil { return err } @@ -65,7 +65,7 @@ func (mte *MytokenEntry) SetRefreshToken(rtID uint64, key []byte) error { if err != nil { return err } - tmp, err := cryptUtils.AES256Encrypt(base64.StdEncoding.EncodeToString(key), jwt) + tmp, err := cryptutils.AES256Encrypt(base64.StdEncoding.EncodeToString(key), jwt) if err != nil { return err } diff --git a/internal/db/dbrepo/mytokenrepo/mytokenrepohelper/helpers.go b/internal/db/dbrepo/mytokenrepo/mytokenrepohelper/helpers.go index 14ecae60..fa16bee4 100644 --- a/internal/db/dbrepo/mytokenrepo/mytokenrepohelper/helpers.go +++ b/internal/db/dbrepo/mytokenrepo/mytokenrepohelper/helpers.go @@ -10,7 +10,7 @@ import ( "github.com/oidc-mytoken/server/internal/db" "github.com/oidc-mytoken/server/internal/db/dbrepo/encryptionkeyrepo" - "github.com/oidc-mytoken/server/internal/utils/hashUtils" + "github.com/oidc-mytoken/server/internal/utils/hashutils" "github.com/oidc-mytoken/server/shared/mytoken/pkg/mtid" ) @@ -129,9 +129,8 @@ func revokeMT(rlog log.Ext1FieldLogger, tx *sqlx.Tx, id interface{}) error { func RevokeMT(rlog log.Ext1FieldLogger, tx *sqlx.Tx, id interface{}, recursive bool) error { if recursive { return recursiveRevokeMT(rlog, tx, id) - } else { - return revokeMT(rlog, tx, id) } + return revokeMT(rlog, tx, id) } // RevocationIDHasParent checks if the token for a revocation id is a child of the (potential) parent mytoken @@ -197,7 +196,7 @@ func IncreaseTokenUsageAT(rlog log.Ext1FieldLogger, tx *sqlx.Tx, myID mtid.MTID, rlog, tx, func(tx *sqlx.Tx) error { _, err := tx.Exec( `CALL TokenUsages_IncrAT(?,?,?)`, - myID, jsonRestriction, hashUtils.SHA512Str(jsonRestriction), + myID, jsonRestriction, hashutils.SHA512Str(jsonRestriction), ) return errors.WithStack(err) }, @@ -210,7 +209,7 @@ func IncreaseTokenUsageOther(rlog log.Ext1FieldLogger, tx *sqlx.Tx, myID mtid.MT rlog, tx, func(tx *sqlx.Tx) error { _, err := tx.Exec( `CALL TokenUsages_IncrOther(?,?,?)`, - myID, jsonRestriction, hashUtils.SHA512Str(jsonRestriction), + myID, jsonRestriction, hashutils.SHA512Str(jsonRestriction), ) return errors.WithStack(err) }, diff --git a/internal/db/dbrepo/mytokenrepo/transfercoderepo/proxytoken.go b/internal/db/dbrepo/mytokenrepo/transfercoderepo/proxytoken.go index 2dac7918..b0a6f936 100644 --- a/internal/db/dbrepo/mytokenrepo/transfercoderepo/proxytoken.go +++ b/internal/db/dbrepo/mytokenrepo/transfercoderepo/proxytoken.go @@ -8,10 +8,10 @@ import ( log "github.com/sirupsen/logrus" "github.com/oidc-mytoken/server/internal/db" - "github.com/oidc-mytoken/server/internal/utils/hashUtils" + "github.com/oidc-mytoken/server/internal/utils/hashutils" "github.com/oidc-mytoken/server/shared/mytoken/pkg/mtid" "github.com/oidc-mytoken/server/shared/utils" - "github.com/oidc-mytoken/server/shared/utils/cryptUtils" + "github.com/oidc-mytoken/server/shared/utils/cryptutils" ) // proxyToken holds information for proxy tokens, i.e. tokens that proxy another token, e.g. a short token @@ -31,7 +31,7 @@ func newProxyToken(size int) *proxyToken { } func createProxyToken(token string) *proxyToken { - id := hashUtils.SHA512Str([]byte(token)) + id := hashutils.SHA512Str([]byte(token)) return &proxyToken{ id: id, token: token, @@ -42,7 +42,7 @@ func createProxyToken(token string) *proxyToken { func parseProxyToken(token string) *proxyToken { var id string if token != "" { - id = hashUtils.SHA512Str([]byte(token)) + id = hashutils.SHA512Str([]byte(token)) } return &proxyToken{ id: id, @@ -62,7 +62,7 @@ func (pt proxyToken) Token() string { // ID returns the id of this token func (pt *proxyToken) ID() string { if pt.id == "" { - pt.id = hashUtils.SHA512Str([]byte(pt.token)) + pt.id = hashutils.SHA512Str([]byte(pt.token)) } return pt.id } @@ -71,7 +71,7 @@ func (pt *proxyToken) ID() string { func (pt *proxyToken) SetJWT(jwt string, mID mtid.MTID) (err error) { pt.mtID = mID pt.decryptedJWT = jwt - pt.encryptedJWT, err = cryptUtils.AES256Encrypt(jwt, pt.token) + pt.encryptedJWT, err = cryptutils.AES256Encrypt(jwt, pt.token) return } @@ -108,7 +108,7 @@ func (pt *proxyToken) JWT(rlog log.Ext1FieldLogger, tx *sqlx.Tx) (jwt string, va if pt.encryptedJWT == "" { return } - jwt, err = cryptUtils.AES256Decrypt(pt.encryptedJWT, pt.token) + jwt, err = cryptutils.AES256Decrypt(pt.encryptedJWT, pt.token) pt.decryptedJWT = jwt return } diff --git a/internal/db/dbrepo/sshrepo/sshrepo.go b/internal/db/dbrepo/sshrepo/sshrepo.go index 7b7e0010..524994b2 100644 --- a/internal/db/dbrepo/sshrepo/sshrepo.go +++ b/internal/db/dbrepo/sshrepo/sshrepo.go @@ -13,7 +13,7 @@ import ( mytoken "github.com/oidc-mytoken/server/shared/mytoken/pkg" "github.com/oidc-mytoken/server/shared/mytoken/pkg/mtid" "github.com/oidc-mytoken/server/shared/utils" - "github.com/oidc-mytoken/server/shared/utils/cryptUtils" + "github.com/oidc-mytoken/server/shared/utils/cryptutils" ) // GetSSHInfo returns the SSHInfo stored in the database for the passed key and user hashes. @@ -65,7 +65,7 @@ type SSHInfo struct { // Decrypt decrypts the encrypted mytoken linked to this ssh key with the passed password func (i SSHInfo) Decrypt(password string) (*mytoken.Mytoken, error) { - decryptedMT, err := cryptUtils.AES256Decrypt(i.EncryptedMT, password) + decryptedMT, err := cryptutils.AES256Decrypt(i.EncryptedMT, password) if err != nil { return nil, err } diff --git a/internal/db/dbrepo/versionrepo/versionrepo.go b/internal/db/dbrepo/versionrepo/versionrepo.go index 3fdce40a..0c8ef569 100644 --- a/internal/db/dbrepo/versionrepo/versionrepo.go +++ b/internal/db/dbrepo/versionrepo/versionrepo.go @@ -126,7 +126,7 @@ func ConnectToVersion() { if hasAllVersions, missingVersions := state.dBHasAllVersions(); !hasAllVersions { log.WithFields( log.Fields{ - "server_version": version.VERSION(), + "server_version": version.VERSION, "missing_versions_in_db": missingVersions, }, ).Fatal("database schema not updated to this server version") diff --git a/internal/endpoints/configuration/configurationEndpoint.go b/internal/endpoints/configuration/configurationEndpoint.go index 2287d755..1553f569 100644 --- a/internal/endpoints/configuration/configurationEndpoint.go +++ b/internal/endpoints/configuration/configurationEndpoint.go @@ -62,7 +62,7 @@ func basicConfiguration() *pkg.MytokenConfiguration { ProvidersSupported: getProvidersFromConfig(), TokenSigningAlgValue: config.Get().Signing.Alg, ServiceDocumentation: config.Get().ServiceDocumentation, - Version: version.VERSION(), + Version: version.VERSION, }, AccessTokenEndpointGrantTypesSupported: []pkgModel.GrantType{pkgModel.GrantTypeMytoken}, MytokenEndpointGrantTypesSupported: []pkgModel.GrantType{ diff --git a/internal/endpoints/consent/consent.go b/internal/endpoints/consent/consent.go index fe6ad91c..92e328d8 100644 --- a/internal/endpoints/consent/consent.go +++ b/internal/endpoints/consent/consent.go @@ -15,7 +15,7 @@ import ( "github.com/oidc-mytoken/server/internal/db" pkg2 "github.com/oidc-mytoken/server/internal/endpoints/token/mytoken/pkg" - "github.com/oidc-mytoken/server/internal/server/httpStatus" + "github.com/oidc-mytoken/server/internal/server/httpstatus" "github.com/oidc-mytoken/server/internal/utils/auth" "github.com/oidc-mytoken/server/internal/utils/errorfmt" "github.com/oidc-mytoken/server/internal/utils/logger" @@ -58,7 +58,7 @@ func handleConsent(ctx *fiber.Ctx, info *pkg2.OIDCFlowRequest, includeConsentCal if iss[len(iss)-1] == '/' { iss = iss[:len(iss)-1] } - binding[templating.MustacheKeyInstanceUrl] = iss + binding[templating.MustacheKeyInstanceURL] = iss } return ctx.Render("sites/consent", binding, "layouts/main") } @@ -144,7 +144,7 @@ func handleConsentDecline(ctx *fiber.Ctx, authInfo *authcodeinforepo.AuthFlowInf } } return model.Response{ - Status: httpStatus.StatusOKForward, + Status: httpstatus.StatusOKForward, Response: map[string]string{ "url": url, }, @@ -188,7 +188,7 @@ func handleConsentAccept( return model.ErrorToInternalServerErrorResponse(err) } return &model.Response{ - Status: httpStatus.StatusOKForward, + Status: httpstatus.StatusOKForward, Response: map[string]string{ "authorization_uri": authURI, }, diff --git a/internal/endpoints/consent/pkg/restriction.go b/internal/endpoints/consent/pkg/restriction.go index d44e25d3..69b235b3 100644 --- a/internal/endpoints/consent/pkg/restriction.go +++ b/internal/endpoints/consent/pkg/restriction.go @@ -24,7 +24,7 @@ func (r WebRestrictions) Text() string { return string(data) } -func (r WebRestrictions) getTimeClass() int { +func (r *WebRestrictions) getTimeClass() int { if r.timeClass != nil { return *r.timeClass } @@ -42,7 +42,7 @@ func (r WebRestrictions) getTimeClass() int { return -1 } -func (r WebRestrictions) getScopeClass() bool { +func (r *WebRestrictions) getScopeClass() bool { if r.scopeClass != nil { return *r.scopeClass } @@ -55,13 +55,13 @@ func (r WebRestrictions) getScopeClass() bool { return s } -func (r WebRestrictions) getIPClass() bool { +func (r *WebRestrictions) getIPClass() bool { if r.ipClass != nil { return *r.ipClass } ip := false for _, rr := range r.Restrictions { - if len(rr.IPs) > 0 { + if len(rr.Hosts) > 0 { ip = true break } @@ -78,7 +78,7 @@ func (r WebRestrictions) getIPClass() bool { return ip } -func (r WebRestrictions) getAudClass() bool { +func (r *WebRestrictions) getAudClass() bool { if r.audClass != nil { return *r.audClass } @@ -91,7 +91,7 @@ func (r WebRestrictions) getAudClass() bool { return a } -func (r WebRestrictions) getUsageClass() bool { +func (r *WebRestrictions) getUsageClass() bool { if r.usagesClass != nil { return *r.usagesClass } diff --git a/internal/endpoints/redirect/redirectEndpoint.go b/internal/endpoints/redirect/redirectEndpoint.go index 47e8c64a..5fe8b4f4 100644 --- a/internal/endpoints/redirect/redirectEndpoint.go +++ b/internal/endpoints/redirect/redirectEndpoint.go @@ -13,8 +13,8 @@ import ( "github.com/oidc-mytoken/server/internal/db/dbrepo/authcodeinforepo/state" "github.com/oidc-mytoken/server/internal/db/dbrepo/mytokenrepo/transfercoderepo" "github.com/oidc-mytoken/server/internal/oidc/authcode" - "github.com/oidc-mytoken/server/internal/server/httpStatus" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" + "github.com/oidc-mytoken/server/internal/server/httpstatus" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/errorfmt" "github.com/oidc-mytoken/server/internal/utils/logger" pkgModel "github.com/oidc-mytoken/server/shared/model" @@ -40,7 +40,7 @@ func HandleOIDCRedirect(ctx *fiber.Ctx) error { } } oidcErrorDescription := ctx.Query("error_description") - return ctx.Status(httpStatus.StatusOIDPError).Render( + return ctx.Status(httpstatus.StatusOIDPError).Render( "sites/error", map[string]interface{}{ "empty-navbar": true, "error-heading": "OIDC error", @@ -49,7 +49,7 @@ func HandleOIDCRedirect(ctx *fiber.Ctx) error { ) } code := ctx.Query("code") - res := authcode.CodeExchange(rlog, oState, code, *ctxUtils.ClientMetaData(ctx)) + res := authcode.CodeExchange(rlog, oState, code, *ctxutils.ClientMetaData(ctx)) if fasthttp.StatusCodeIsRedirect(res.Status) { return res.Send(ctx) diff --git a/internal/endpoints/settings/grants/ssh/ssh.go b/internal/endpoints/settings/grants/ssh/ssh.go index 1db8620f..bd844cb2 100644 --- a/internal/endpoints/settings/grants/ssh/ssh.go +++ b/internal/endpoints/settings/grants/ssh/ssh.go @@ -21,16 +21,16 @@ import ( serverModel "github.com/oidc-mytoken/server/internal/model" "github.com/oidc-mytoken/server/internal/oidc/authcode" "github.com/oidc-mytoken/server/internal/server/ssh" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/errorfmt" - "github.com/oidc-mytoken/server/internal/utils/hashUtils" + "github.com/oidc-mytoken/server/internal/utils/hashutils" "github.com/oidc-mytoken/server/internal/utils/logger" "github.com/oidc-mytoken/server/shared/model" event "github.com/oidc-mytoken/server/shared/mytoken/event/pkg" mytoken "github.com/oidc-mytoken/server/shared/mytoken/pkg" "github.com/oidc-mytoken/server/shared/mytoken/universalmytoken" "github.com/oidc-mytoken/server/shared/utils" - "github.com/oidc-mytoken/server/shared/utils/cryptUtils" + "github.com/oidc-mytoken/server/shared/utils/cryptutils" ) // HandleGetSSHInfo handles requests to return information about a user's ssh keys @@ -102,7 +102,7 @@ func HandleDeleteSSHKey(ctx *fiber.Ctx) error { // HandlePost handles POST requests to the ssh grant endpoint, this includes the initial request to add an ssh public // key as well as the following polling requests. func HandlePost(ctx *fiber.Ctx) error { - grantType, err := ctxUtils.GetGrantType(ctx) + grantType, err := ctxutils.GetGrantType(ctx) if err != nil { return serverModel.ErrorToBadRequestErrorResponse(err).Send(ctx) } @@ -249,14 +249,14 @@ func handlePollingCode(ctx *fiber.Ctx) error { if err := json.Unmarshal(ctx.Body(), &req); err != nil { return serverModel.ErrorToBadRequestErrorResponse(err).Send(ctx) } - clientMetaData := ctxUtils.ClientMetaData(ctx) + clientMetaData := ctxutils.ClientMetaData(ctx) mt, token, status, errRes := polling.CheckPollingCodeReq(rlog, req, *clientMetaData, true) if errRes != nil { return errRes.Send(ctx) } user := utils.RandASCIIString(16) - userHash := hashUtils.SHA3_512Str([]byte(user)) - encryptedMT, err := cryptUtils.AES256Encrypt(token, user) + userHash := hashutils.SHA3_512Str([]byte(user)) + encryptedMT, err := cryptutils.AES256Encrypt(token, user) if err != nil { rlog.Errorf("%s", errorfmt.Full(err)) return serverModel.ErrorToInternalServerErrorResponse(err).Send(ctx) diff --git a/internal/endpoints/settings/settings.go b/internal/endpoints/settings/settings.go index d796b50b..e88f9875 100644 --- a/internal/endpoints/settings/settings.go +++ b/internal/endpoints/settings/settings.go @@ -14,7 +14,7 @@ import ( "github.com/oidc-mytoken/server/internal/server/routes" "github.com/oidc-mytoken/server/internal/utils/auth" "github.com/oidc-mytoken/server/internal/utils/cookies" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/errorfmt" "github.com/oidc-mytoken/server/internal/utils/logger" eventService "github.com/oidc-mytoken/server/shared/mytoken/event" @@ -37,6 +37,7 @@ var settingsMetadata = api.SettingsMetaData{ GrantTypeEndpoint: "grants", } +// HandleSettings handles Metadata requests to the settings endpoint func HandleSettings(ctx *fiber.Ctx) error { res := serverModel.Response{ Status: fiber.StatusOK, @@ -77,7 +78,7 @@ func HandleSettingsHelper( if tokenGoneAfterCallback { return } - clientMetaData := ctxUtils.ClientMetaData(ctx) + clientMetaData := ctxutils.ClientMetaData(ctx) if logEvent != nil { if err = eventService.LogEvent( rlog, tx, eventService.MTEvent{ diff --git a/internal/endpoints/token/access/accessTokenEndpoint.go b/internal/endpoints/token/access/accessTokenEndpoint.go index d9406aed..6bf84fb5 100644 --- a/internal/endpoints/token/access/accessTokenEndpoint.go +++ b/internal/endpoints/token/access/accessTokenEndpoint.go @@ -18,7 +18,7 @@ import ( "github.com/oidc-mytoken/server/internal/oidc/refresh" "github.com/oidc-mytoken/server/internal/utils/auth" "github.com/oidc-mytoken/server/internal/utils/cookies" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/errorfmt" "github.com/oidc-mytoken/server/internal/utils/logger" "github.com/oidc-mytoken/server/shared/model" @@ -65,7 +65,7 @@ func HandleAccessTokenEndpoint(ctx *fiber.Ctx) error { return errRes.Send(ctx) } - return HandleAccessTokenRefresh(rlog, mt, req, *ctxUtils.ClientMetaData(ctx), provider, usedRestriction).Send(ctx) + return HandleAccessTokenRefresh(rlog, mt, req, *ctxutils.ClientMetaData(ctx), provider, usedRestriction).Send(ctx) } func parseScopesAndAudienceToUse( @@ -110,7 +110,7 @@ func HandleAccessTokenRefresh( } scopes, auds := parseScopesAndAudienceToUse(req.Scope, req.Audience, usedRestriction, provider.Scopes) - oidcRes, oidcErrRes, err := refresh.RefreshFlowAndUpdateDB(rlog, provider, mt.ID, req.Mytoken.JWT, rt, scopes, auds) + oidcRes, oidcErrRes, err := refresh.DoFlowAndUpdateDB(rlog, provider, mt.ID, req.Mytoken.JWT, rt, scopes, auds) if err != nil { rlog.Errorf("%s", errorfmt.Full(err)) return serverModel.ErrorToInternalServerErrorResponse(err) diff --git a/internal/endpoints/token/mytoken/mytokenEndpoint.go b/internal/endpoints/token/mytoken/mytokenEndpoint.go index 2e6496a2..05b6a01c 100644 --- a/internal/endpoints/token/mytoken/mytokenEndpoint.go +++ b/internal/endpoints/token/mytoken/mytokenEndpoint.go @@ -11,7 +11,7 @@ import ( "github.com/oidc-mytoken/server/internal/endpoints/token/mytoken/polling" serverModel "github.com/oidc-mytoken/server/internal/model" "github.com/oidc-mytoken/server/internal/oidc/authcode" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/logger" "github.com/oidc-mytoken/server/shared/model" "github.com/oidc-mytoken/server/shared/mytoken" @@ -25,7 +25,7 @@ var defaultCapabilities = api.Capabilities{ // HandleMytokenEndpoint handles requests on the mytoken endpoint func HandleMytokenEndpoint(ctx *fiber.Ctx) error { rlog := logger.GetRequestLogger(ctx) - grantType, err := ctxUtils.GetGrantType(ctx) + grantType, err := ctxutils.GetGrantType(ctx) if err != nil { return serverModel.ErrorToBadRequestErrorResponse(err).Send(ctx) } diff --git a/internal/endpoints/token/mytoken/polling/pollingEndpoint.go b/internal/endpoints/token/mytoken/polling/pollingEndpoint.go index d51c07ff..8622d0d3 100644 --- a/internal/endpoints/token/mytoken/polling/pollingEndpoint.go +++ b/internal/endpoints/token/mytoken/polling/pollingEndpoint.go @@ -10,7 +10,7 @@ import ( "github.com/oidc-mytoken/server/internal/db/dbrepo/mytokenrepo/transfercoderepo" response "github.com/oidc-mytoken/server/internal/endpoints/token/mytoken/pkg" "github.com/oidc-mytoken/server/internal/model" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/errorfmt" "github.com/oidc-mytoken/server/internal/utils/logger" mytoken "github.com/oidc-mytoken/server/shared/mytoken/pkg" @@ -23,7 +23,7 @@ func HandlePollingCode(ctx *fiber.Ctx) error { if err := json.Unmarshal(ctx.Body(), &req); err != nil { return model.ErrorToBadRequestErrorResponse(err).Send(ctx) } - clientMetaData := ctxUtils.ClientMetaData(ctx) + clientMetaData := ctxutils.ClientMetaData(ctx) mt, token, pollingCodeStatus, errRes := CheckPollingCodeReq(rlog, req, *clientMetaData, false) if errRes != nil { return errRes.Send(ctx) diff --git a/internal/endpoints/token/mytoken/transferEndpoint.go b/internal/endpoints/token/mytoken/transferEndpoint.go index abd9cdef..5da6de2d 100644 --- a/internal/endpoints/token/mytoken/transferEndpoint.go +++ b/internal/endpoints/token/mytoken/transferEndpoint.go @@ -9,7 +9,7 @@ import ( "github.com/oidc-mytoken/server/internal/endpoints/token/mytoken/pkg" "github.com/oidc-mytoken/server/internal/model" "github.com/oidc-mytoken/server/internal/utils/auth" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/errorfmt" "github.com/oidc-mytoken/server/internal/utils/logger" pkgModel "github.com/oidc-mytoken/server/shared/model" @@ -32,7 +32,7 @@ func HandleCreateTransferCodeForExistingMytoken(ctx *fiber.Ctx) error { } transferCode, expiresIn, err := mytoken.CreateTransferCode( - rlog, mt.ID, req.Mytoken.JWT, false, req.Mytoken.OriginalTokenType, *ctxUtils.ClientMetaData(ctx), + rlog, mt.ID, req.Mytoken.JWT, false, req.Mytoken.OriginalTokenType, *ctxutils.ClientMetaData(ctx), ) if err != nil { rlog.Errorf("%s", errorfmt.Full(err)) diff --git a/internal/endpoints/tokeninfo/tokeninfo.go b/internal/endpoints/tokeninfo/tokeninfo.go index f313fc49..40343fee 100644 --- a/internal/endpoints/tokeninfo/tokeninfo.go +++ b/internal/endpoints/tokeninfo/tokeninfo.go @@ -11,7 +11,7 @@ import ( "github.com/oidc-mytoken/server/internal/model" "github.com/oidc-mytoken/server/internal/utils/auth" "github.com/oidc-mytoken/server/internal/utils/cookies" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/logger" model2 "github.com/oidc-mytoken/server/shared/model" ) @@ -27,7 +27,7 @@ func HandleTokenInfo(ctx *fiber.Ctx) error { if errRes != nil { return errRes.Send(ctx) } - clientMetadata := ctxUtils.ClientMetaData(ctx) + clientMetadata := ctxutils.ClientMetaData(ctx) switch req.Action { case model2.TokeninfoActionIntrospect: return HandleTokenInfoIntrospect(rlog, mt, req.Mytoken.OriginalTokenType, clientMetadata).Send(ctx) diff --git a/internal/model/restrictionKey.go b/internal/model/restrictionKey.go index d762ddf5..58358810 100644 --- a/internal/model/restrictionKey.go +++ b/internal/model/restrictionKey.go @@ -32,7 +32,7 @@ const ( // assert that these are in the same order as api.AllRestrictionKeys RestrictionClaimExpiresAt RestrictionClaimScope RestrictionClaimAudiences - RestrictionClaimIPs + RestrictionClaimHosts RestrictionClaimGeoIPAllow RestrictionClaimGeoIPDisallow RestrictionClaimUsagesAT @@ -106,7 +106,7 @@ func (rc RestrictionClaim) MarshalJSON() ([]byte, error) { return data, errors.WithStack(err) } -// Has checks if a a RestrictionClaim is in a RestrictionClaims +// Has checks if a RestrictionClaim is in a RestrictionClaims func (rks RestrictionClaims) Has(rk RestrictionClaim) bool { for _, k := range rks { if k == rk { diff --git a/internal/model/version/VERSION b/internal/model/version/VERSION new file mode 100644 index 00000000..ee6cdce3 --- /dev/null +++ b/internal/model/version/VERSION @@ -0,0 +1 @@ +0.6.1 diff --git a/internal/model/version/version.go b/internal/model/version/version.go index 41b944b6..cedb5911 100644 --- a/internal/model/version/version.go +++ b/internal/model/version/version.go @@ -1,24 +1,35 @@ package version import ( - "fmt" + _ "embed" // for go:embed + "strconv" + "strings" ) +// VERSION holds the server's version +// +//go:embed VERSION +var VERSION string + // Version segments -const ( - MAJOR = 0 - MINOR = 6 - FIX = 0 - DEV = false +var ( + MAJOR int + MINOR int + FIX int + PRE int ) -var version = fmt.Sprintf("%d.%d.%d", MAJOR, MINOR, FIX) -var devVersion = fmt.Sprintf("%s-dev", version) - -// VERSION returns the current mytoken version -func VERSION() string { - if DEV { - return devVersion +func init() { + if VERSION[len(VERSION)-1] == '\n' { + VERSION = VERSION[:len(VERSION)-1] + } + v := strings.Split(VERSION, ".") + MAJOR, _ = strconv.Atoi(v[0]) + MINOR, _ = strconv.Atoi(v[1]) + ps := strings.Split(v[2], "-") + FIX, _ = strconv.Atoi(ps[0]) + if len(ps) > 1 { + pre := strings.TrimPrefix(ps[1], "pr") + PRE, _ = strconv.Atoi(pre) } - return version } diff --git a/internal/oidc/authcode/authcode.go b/internal/oidc/authcode/authcode.go index 08ec19ef..300d3a77 100644 --- a/internal/oidc/authcode/authcode.go +++ b/internal/oidc/authcode/authcode.go @@ -24,7 +24,7 @@ import ( "github.com/oidc-mytoken/server/internal/model" "github.com/oidc-mytoken/server/internal/oidc/issuer" "github.com/oidc-mytoken/server/internal/oidc/pkce" - "github.com/oidc-mytoken/server/internal/server/httpStatus" + "github.com/oidc-mytoken/server/internal/server/httpstatus" "github.com/oidc-mytoken/server/internal/server/routes" "github.com/oidc-mytoken/server/internal/utils/cookies" "github.com/oidc-mytoken/server/internal/utils/errorfmt" @@ -34,7 +34,7 @@ import ( mytoken "github.com/oidc-mytoken/server/shared/mytoken/pkg" "github.com/oidc-mytoken/server/shared/mytoken/restrictions" "github.com/oidc-mytoken/server/shared/utils" - "github.com/oidc-mytoken/server/shared/utils/issuerUtils" + "github.com/oidc-mytoken/server/shared/utils/issuerutils" "github.com/oidc-mytoken/server/shared/utils/jwtutils" "github.com/oidc-mytoken/server/shared/utils/ternary" "github.com/oidc-mytoken/server/shared/utils/unixtime" @@ -81,7 +81,7 @@ func GetAuthorizationURL( oauth2.SetAuthURLParam("code_challenge", pkceChallenge), oauth2.SetAuthURLParam("code_challenge_method", pkce.TransformationS256.String()), } - if issuerUtils.CompareIssuerURLs(provider.Issuer, issuer.GOOGLE) { + if issuerutils.CompareIssuerURLs(provider.Issuer, issuer.GOOGLE) { additionalParams = append(additionalParams, oauth2.AccessTypeOffline) } else if !utils.StringInSlice(oidc.ScopeOfflineAccess, oauth2Config.Scopes) { oauth2Config.Scopes = append(oauth2Config.Scopes, oidc.ScopeOfflineAccess) @@ -101,9 +101,9 @@ func GetAuthorizationURL( return oauth2Config.AuthCodeURL(oState.State(), additionalParams...), nil } -func trustedRedirectURI(redirectUri string) bool { +func trustedRedirectURI(redirectURI string) bool { for _, r := range config.Get().Features.OIDCFlows.AuthCode.Web.TrustedRedirectsRegex { - if r.MatchString(redirectUri) { + if r.MatchString(redirectURI) { return true } } @@ -125,7 +125,7 @@ func StartAuthCodeFlow(ctx *fiber.Ctx, oidcReq *response.OIDCFlowRequest) *model }, } } - req.Restrictions.ReplaceThisIp(ctx.IP()) + req.Restrictions.ReplaceThisIP(ctx.IP()) req.Restrictions.ClearUnsupportedKeys() provider, ok := config.Get().ProviderByIssuer[req.Issuer] if !ok { @@ -176,7 +176,7 @@ func StartAuthCodeFlow(ctx *fiber.Ctx, oidcReq *response.OIDCFlowRequest) *model return model.ErrorToInternalServerErrorResponse(err) } return &model.Response{ - Status: httpStatus.StatusOKForward, + Status: httpstatus.StatusOKForward, Response: map[string]string{ "authorization_uri": authURI, }, diff --git a/internal/oidc/oidcReqRes/request.go b/internal/oidc/oidcreqres/request.go similarity index 99% rename from internal/oidc/oidcReqRes/request.go rename to internal/oidc/oidcreqres/request.go index 109d3bad..ecb09dc9 100644 --- a/internal/oidc/oidcReqRes/request.go +++ b/internal/oidc/oidcreqres/request.go @@ -1,4 +1,4 @@ -package oidcReqRes +package oidcreqres import ( "encoding/json" diff --git a/internal/oidc/oidcReqRes/response.go b/internal/oidc/oidcreqres/response.go similarity index 96% rename from internal/oidc/oidcReqRes/response.go rename to internal/oidc/oidcreqres/response.go index 0e547409..a433ca2a 100644 --- a/internal/oidc/oidcReqRes/response.go +++ b/internal/oidc/oidcreqres/response.go @@ -1,4 +1,4 @@ -package oidcReqRes +package oidcreqres // OIDCErrorResponse is the error response of an oidc provider type OIDCErrorResponse struct { diff --git a/internal/oidc/pkce/pkce.go b/internal/oidc/pkce/pkce.go index d2363eb5..19252517 100644 --- a/internal/oidc/pkce/pkce.go +++ b/internal/oidc/pkce/pkce.go @@ -11,31 +11,31 @@ import ( type PKCE struct { verifier string challenge string - method PKCEMethod + method Method } -// PKCEMethod is a type for the code challenge methods -type PKCEMethod string +// Method is a type for the code challenge methods +type Method string -// Defines for the possible PKCEMethod +// Defines for the possible Method const ( - TransformationPlain = PKCEMethod("plain") - TransformationS256 = PKCEMethod("S256") + TransformationPlain = Method("plain") + TransformationS256 = Method("S256") ) -func (m PKCEMethod) String() string { +func (m Method) String() string { return string(m) } -// NewPKCE creates a new PKCE for the passed verifier and PKCEMethod -func NewPKCE(verifier string, method PKCEMethod) *PKCE { +// NewPKCE creates a new PKCE for the passed verifier and Method +func NewPKCE(verifier string, method Method) *PKCE { return &PKCE{ verifier: verifier, method: method, } } -// NewS256PKCE creates a new PKCE for the passed verifier and the PKCEMethod TransformationS256 +// NewS256PKCE creates a new PKCE for the passed verifier and the Method TransformationS256 func NewS256PKCE(verifier string) *PKCE { return NewPKCE(verifier, TransformationS256) } @@ -45,7 +45,7 @@ func (pkce PKCE) Verifier() string { return pkce.verifier } -// Challenge returns the code_challenge according to the defined PKCEMethod +// Challenge returns the code_challenge according to the defined Method func (pkce *PKCE) Challenge() (string, error) { var err error if pkce.challenge == "" { diff --git a/internal/oidc/refresh/refresh.go b/internal/oidc/refresh/refresh.go index c2ba276a..dba6773b 100644 --- a/internal/oidc/refresh/refresh.go +++ b/internal/oidc/refresh/refresh.go @@ -6,44 +6,44 @@ import ( "github.com/oidc-mytoken/server/internal/config" "github.com/oidc-mytoken/server/internal/db/dbrepo/cryptstore" - "github.com/oidc-mytoken/server/internal/oidc/oidcReqRes" - "github.com/oidc-mytoken/server/shared/httpClient" + "github.com/oidc-mytoken/server/internal/oidc/oidcreqres" + "github.com/oidc-mytoken/server/shared/httpclient" "github.com/oidc-mytoken/server/shared/mytoken/pkg/mtid" ) // UpdateChangedRT is a function that should update a refresh token, it takes the old value as well as the new one type UpdateChangedRT func(rlog log.Ext1FieldLogger, tokenID mtid.MTID, newRT, mytoken string) error -// Refresh uses an refresh token to obtain a new access token; if the refresh token changes, this is ignored -func Refresh( +// DoFlowWithoutUpdate uses a refresh token to obtain a new access token; if the refresh token changes, this is ignored +func DoFlowWithoutUpdate( rlog log.Ext1FieldLogger, provider *config.ProviderConf, tokenID mtid.MTID, mytoken, rt, scopes, audiences string, -) (*oidcReqRes.OIDCTokenResponse, *oidcReqRes.OIDCErrorResponse, error) { - return RefreshFlowAndUpdate(rlog, provider, tokenID, mytoken, rt, scopes, audiences, nil) +) (*oidcreqres.OIDCTokenResponse, *oidcreqres.OIDCErrorResponse, error) { + return DoFlowAndUpdate(rlog, provider, tokenID, mytoken, rt, scopes, audiences, nil) } -// RefreshFlowAndUpdate uses an refresh token to obtain a new access token; if the refresh token changes, the +// DoFlowAndUpdate uses a refresh token to obtain a new access token; if the refresh token changes, the // UpdateChangedRT function is used to update the refresh token -func RefreshFlowAndUpdate( +func DoFlowAndUpdate( rlog log.Ext1FieldLogger, provider *config.ProviderConf, tokenID mtid.MTID, mytoken, rt, scopes, audiences string, updateFnc UpdateChangedRT, -) (*oidcReqRes.OIDCTokenResponse, *oidcReqRes.OIDCErrorResponse, error) { - req := oidcReqRes.NewRefreshRequest(rt, provider) +) (*oidcreqres.OIDCTokenResponse, *oidcreqres.OIDCErrorResponse, error) { + req := oidcreqres.NewRefreshRequest(rt, provider) req.Scopes = scopes req.Audiences = audiences - httpRes, err := httpClient.Do().R(). + httpRes, err := httpclient.Do().R(). SetBasicAuth(provider.ClientID, provider.ClientSecret). SetFormData(req.ToFormData()). - SetResult(&oidcReqRes.OIDCTokenResponse{}). - SetError(&oidcReqRes.OIDCErrorResponse{}). + SetResult(&oidcreqres.OIDCTokenResponse{}). + SetError(&oidcreqres.OIDCErrorResponse{}). Post(provider.Endpoints.Token) if err != nil { return nil, nil, errors.WithStack(err) } - if errRes, ok := httpRes.Error().(*oidcReqRes.OIDCErrorResponse); ok && errRes != nil && errRes.Error != "" { + if errRes, ok := httpRes.Error().(*oidcreqres.OIDCErrorResponse); ok && errRes != nil && errRes.Error != "" { errRes.Status = httpRes.RawResponse.StatusCode return nil, errRes, nil } - res, ok := httpRes.Result().(*oidcReqRes.OIDCTokenResponse) + res, ok := httpRes.Result().(*oidcreqres.OIDCTokenResponse) if !ok { return nil, nil, errors.New("could not unmarshal oidc response") } @@ -55,12 +55,12 @@ func RefreshFlowAndUpdate( return res, nil, nil } -// RefreshFlowAndUpdateDB uses an refresh token to obtain a new access token; if the refresh token changes, it is +// DoFlowAndUpdateDB uses a refresh token to obtain a new access token; if the refresh token changes, it is // updated in the database -func RefreshFlowAndUpdateDB( +func DoFlowAndUpdateDB( rlog log.Ext1FieldLogger, provider *config.ProviderConf, tokenID mtid.MTID, mytoken, rt, scopes, audiences string, -) (*oidcReqRes.OIDCTokenResponse, *oidcReqRes.OIDCErrorResponse, error) { - return RefreshFlowAndUpdate(rlog, provider, tokenID, mytoken, rt, scopes, audiences, updateChangedRTInDB) +) (*oidcreqres.OIDCTokenResponse, *oidcreqres.OIDCErrorResponse, error) { + return DoFlowAndUpdate(rlog, provider, tokenID, mytoken, rt, scopes, audiences, updateChangedRTInDB) } func updateChangedRTInDB(rlog log.Ext1FieldLogger, tokenID mtid.MTID, newRT, mytoken string) error { diff --git a/internal/oidc/revoke/revoke.go b/internal/oidc/revoke/revoke.go index 4855dc54..371d88e2 100644 --- a/internal/oidc/revoke/revoke.go +++ b/internal/oidc/revoke/revoke.go @@ -5,8 +5,8 @@ import ( "github.com/oidc-mytoken/server/internal/config" "github.com/oidc-mytoken/server/internal/model" - "github.com/oidc-mytoken/server/internal/oidc/oidcReqRes" - "github.com/oidc-mytoken/server/shared/httpClient" + "github.com/oidc-mytoken/server/internal/oidc/oidcreqres" + "github.com/oidc-mytoken/server/shared/httpclient" pkgModel "github.com/oidc-mytoken/server/shared/model" ) @@ -15,17 +15,17 @@ func RefreshToken(rlog log.Ext1FieldLogger, provider *config.ProviderConf, rt st if provider.Endpoints.Revocation == "" { return nil } - req := oidcReqRes.NewRTRevokeRequest(rt) - httpRes, err := httpClient.Do().R(). + req := oidcreqres.NewRTRevokeRequest(rt) + httpRes, err := httpclient.Do().R(). SetBasicAuth(provider.ClientID, provider.ClientSecret). SetFormData(req.ToFormData()). - SetError(&oidcReqRes.OIDCErrorResponse{}). + SetError(&oidcreqres.OIDCErrorResponse{}). Post(provider.Endpoints.Revocation) if err != nil { rlog.WithError(err).Error() return model.ErrorToInternalServerErrorResponse(err) } - if errRes, ok := httpRes.Error().(*oidcReqRes.OIDCErrorResponse); ok && errRes != nil && errRes.Error != "" { + if errRes, ok := httpRes.Error().(*oidcreqres.OIDCErrorResponse); ok && errRes != nil && errRes.Error != "" { return &model.Response{ Status: httpRes.RawResponse.StatusCode, Response: pkgModel.OIDCError(errRes.Error, errRes.ErrorDescription), diff --git a/internal/server/apiPath/apiPath.go b/internal/server/apipath/apiPath.go similarity index 88% rename from internal/server/apiPath/apiPath.go rename to internal/server/apipath/apiPath.go index abd6ad8a..0110e96f 100644 --- a/internal/server/apiPath/apiPath.go +++ b/internal/server/apipath/apiPath.go @@ -1,4 +1,4 @@ -package apiPath +package apipath // Prefix is the api prefix path component const Prefix = "/api" diff --git a/internal/server/httpStatus/httpStatus.go b/internal/server/httpstatus/httpStatus.go similarity index 83% rename from internal/server/httpStatus/httpStatus.go rename to internal/server/httpstatus/httpStatus.go index 114c4666..de83c157 100644 --- a/internal/server/httpStatus/httpStatus.go +++ b/internal/server/httpstatus/httpStatus.go @@ -1,4 +1,4 @@ -package httpStatus +package httpstatus // Proprietary defined status codes const ( diff --git a/internal/server/middlerwares.go b/internal/server/middlerwares.go index 2d5d3564..a0e3ce76 100644 --- a/internal/server/middlerwares.go +++ b/internal/server/middlerwares.go @@ -20,11 +20,11 @@ import ( log "github.com/sirupsen/logrus" "github.com/oidc-mytoken/server/internal/config" - "github.com/oidc-mytoken/server/internal/server/apiPath" + "github.com/oidc-mytoken/server/internal/server/apipath" "github.com/oidc-mytoken/server/internal/server/routes" "github.com/oidc-mytoken/server/internal/utils/fileio" + "github.com/oidc-mytoken/server/internal/utils/iputils" loggerUtils "github.com/oidc-mytoken/server/internal/utils/logger" - "github.com/oidc-mytoken/server/shared/utils" ) //go:embed web/static @@ -80,7 +80,7 @@ func addLimiterMiddleware(s fiber.Router) { limiter.New( limiter.Config{ Next: func(c *fiber.Ctx) bool { - return utils.IPIsIn(c.IP(), limiterConf.AlwaysAllow) + return iputils.IPIsIn(c.IP(), limiterConf.AlwaysAllow) }, Max: limiterConf.Max, Expiration: time.Duration(limiterConf.Window) * time.Second, @@ -142,7 +142,7 @@ func addCorsMiddleware(s fiber.Router) { routes.GetGeneralPaths().JWKSEndpoint, } allowedPrefixes := []string{ - apiPath.Prefix, + apipath.Prefix, "/static", } s.Use( diff --git a/internal/server/routes/routes.go b/internal/server/routes/routes.go index 3182c19d..6bf14199 100644 --- a/internal/server/routes/routes.go +++ b/internal/server/routes/routes.go @@ -2,13 +2,16 @@ package routes import ( "github.com/oidc-mytoken/server/internal/model/version" - "github.com/oidc-mytoken/server/internal/server/apiPath" + "github.com/oidc-mytoken/server/internal/server/apipath" "github.com/oidc-mytoken/server/shared/utils" ) var routes *paths +// WellknownMytokenConfiguration is the mytoken configuration path suffix const WellknownMytokenConfiguration = "/.well-known/mytoken-configuration" + +// WellknownOpenIDConfiguration is the openid configuration path suffix const WellknownOpenIDConfiguration = "/.well-known/openid-configuration" // init initializes the server route paths @@ -16,12 +19,12 @@ func init() { routes = &paths{ api: map[int]APIPaths{ 0: { - MytokenEndpoint: utils.CombineURLPath(apiPath.V0, "/token/my"), - AccessTokenEndpoint: utils.CombineURLPath(apiPath.V0, "/token/access"), - TokenInfoEndpoint: utils.CombineURLPath(apiPath.V0, "/tokeninfo"), - RevocationEndpoint: utils.CombineURLPath(apiPath.V0, "/token/revoke"), - TokenTransferEndpoint: utils.CombineURLPath(apiPath.V0, "/token/transfer"), - UserSettingEndpoint: utils.CombineURLPath(apiPath.V0, "/settings"), + MytokenEndpoint: utils.CombineURLPath(apipath.V0, "/token/my"), + AccessTokenEndpoint: utils.CombineURLPath(apipath.V0, "/token/access"), + TokenInfoEndpoint: utils.CombineURLPath(apipath.V0, "/tokeninfo"), + RevocationEndpoint: utils.CombineURLPath(apipath.V0, "/token/revoke"), + TokenTransferEndpoint: utils.CombineURLPath(apipath.V0, "/token/transfer"), + UserSettingEndpoint: utils.CombineURLPath(apipath.V0, "/settings"), }, }, other: GeneralPaths{ diff --git a/internal/server/server.go b/internal/server/server.go index 7b9cbee3..0b957c61 100644 --- a/internal/server/server.go +++ b/internal/server/server.go @@ -20,7 +20,7 @@ import ( "github.com/oidc-mytoken/server/internal/endpoints/consent" "github.com/oidc-mytoken/server/internal/endpoints/redirect" "github.com/oidc-mytoken/server/internal/model" - "github.com/oidc-mytoken/server/internal/server/apiPath" + "github.com/oidc-mytoken/server/internal/server/apipath" "github.com/oidc-mytoken/server/internal/server/routes" "github.com/oidc-mytoken/server/internal/server/ssh" "github.com/oidc-mytoken/server/internal/utils/fileio" @@ -80,7 +80,7 @@ func Init() { server.Use( func(ctx *fiber.Ctx) error { path := ctx.Path() - if !strings.HasPrefix(path, apiPath.Prefix) && ctx.Accepts( + if !strings.HasPrefix(path, apipath.Prefix) && ctx.Accepts( fiber.MIMETextHTML, fiber.MIMETextHTMLCharsetUTF8, ) != "" { ctx.Status(fiber.StatusNotFound) diff --git a/internal/server/ssh/sshServer.go b/internal/server/ssh/sshServer.go index 42a4480f..972da000 100644 --- a/internal/server/ssh/sshServer.go +++ b/internal/server/ssh/sshServer.go @@ -13,7 +13,7 @@ import ( "github.com/oidc-mytoken/server/internal/config" "github.com/oidc-mytoken/server/internal/db/dbrepo/sshrepo" "github.com/oidc-mytoken/server/internal/utils/errorfmt" - "github.com/oidc-mytoken/server/internal/utils/hashUtils" + "github.com/oidc-mytoken/server/internal/utils/hashutils" "github.com/oidc-mytoken/server/internal/utils/logger" ) @@ -21,7 +21,7 @@ func checkPubKey(ctx ssh.Context, key ssh.PublicKey) bool { sessionID := ctx.SessionID() rlog := logger.GetSSHRequestLogger(sessionID) sshUser := ctx.User() - sshUserHash := hashUtils.SHA3_512Str([]byte(sshUser)) + sshUserHash := hashutils.SHA3_512Str([]byte(sshUser)) sshKeyFP := gossh.FingerprintSHA256(key) ip := ctx.RemoteAddr().String() if addr, ok := ctx.RemoteAddr().(*net.TCPAddr); ok { diff --git a/internal/server/web/partials/restrictions-gui-editor.mustache b/internal/server/web/partials/restrictions-gui-editor.mustache index 0f09e2ce..ae9d88a5 100644 --- a/internal/server/web/partials/restrictions-gui-editor.mustache +++ b/internal/server/web/partials/restrictions-gui-editor.mustache @@ -82,20 +82,20 @@
-
- - +
+ +
- + - +
- If set, the mytoken can only be - used from these IP addresses or subnets. + If set, the mytoken can only be + used from these Hosts given by hostname, IP address or subnets.
diff --git a/internal/server/web/partials/restrictions.mustache b/internal/server/web/partials/restrictions.mustache index 86277045..36c5d741 100644 --- a/internal/server/web/partials/restrictions.mustache +++ b/internal/server/web/partials/restrictions.mustache @@ -18,7 +18,7 @@
- + @@ -64,5 +65,8 @@ crossorigin="anonymous" referrerpolicy="no-referrer" > + {{^home}} + + {{/home}} {{/restr-gui}} diff --git a/internal/server/web/partials/tokeninfo.mustache b/internal/server/web/partials/tokeninfo.mustache index 87a127ac..f505eaae 100644 --- a/internal/server/web/partials/tokeninfo.mustache +++ b/internal/server/web/partials/tokeninfo.mustache @@ -58,6 +58,13 @@
+ +
+ +

Do not lose access to your mytoken!

+

To keep access to your mytoken you must copy it to a safe location, as + you will not be able to retrieve it again from this website.

+
diff --git a/internal/server/web/static/img/mytoken-grey.png b/internal/server/web/static/img/mytoken-grey.png index 4c86eb0a..07e1767e 100644 Binary files a/internal/server/web/static/img/mytoken-grey.png and b/internal/server/web/static/img/mytoken-grey.png differ diff --git a/internal/server/web/static/img/mytoken.png b/internal/server/web/static/img/mytoken.png index 9f3b572b..5937f8b5 100644 Binary files a/internal/server/web/static/img/mytoken.png and b/internal/server/web/static/img/mytoken.png differ diff --git a/internal/server/web/static/js/create-at.js b/internal/server/web/static/js/create-at.js index 1ceed26c..8ea2466a 100644 --- a/internal/server/web/static/js/create-at.js +++ b/internal/server/web/static/js/create-at.js @@ -131,7 +131,8 @@ function initAT(...next) { } let $table = $('#at-scopeTableBody'); for (const scope of scopes) { - _addScopeValueToGUI(scope, $table, "at"); + _addScopeValueToGUI(scope, $table, "", "at"); } + initScopesGUI("at"); doNext(...next); } \ No newline at end of file diff --git a/internal/server/web/static/js/restr-gui.js b/internal/server/web/static/js/restr-gui.js index ed673a39..4e086665 100644 --- a/internal/server/web/static/js/restr-gui.js +++ b/internal/server/web/static/js/restr-gui.js @@ -94,29 +94,7 @@ function initRestrGUI(prefix = "") { } } - $('.scope-checkbox[instance-prefix="' + prefix + '"]').on("click", function () { - let allScopesInactive = $(this).parents('tbody').find('.scope-inactive'); - let allScopesActive = $(this).parents('tbody').find('.scope-active'); - let checkedScopeBoxes = $(this).parents('tbody').find('.scope-checkbox:checked'); - let activeIcon = $(this).parents('tr').find('.scope-active'); - let inactiveIcon = $(this).parents('tr').find('.scope-inactive'); - let activated = $(this).prop('checked'); - if (activated) { - if (checkedScopeBoxes.length === 1) { // There was no box checked before, but now one has been checked - allScopesActive.hideB(); - allScopesInactive.showB(); - } - inactiveIcon.hideB(); - activeIcon.showB(); - } else { - activeIcon.hideB(); - inactiveIcon.showB(); - } - if (checkedScopeBoxes.length === 0) { - allScopesInactive.hideB(); - allScopesActive.showB(); - } - }) + initScopesGUI(prefix); scopeTableBody(prefix).find('.scope-checkbox').on("click", function () { GUIToRestr_Scopes(prefix); }) @@ -227,19 +205,6 @@ function GUIToRestr_Scopes(prefix = "") { GUISetRestr('scope', scopes.join(' '), prefix); } -// -// function GUIToRestr_IPs(prefix="") { -// _guiToRestr_Table(prefixId('ipTableBody',prefix), "ip",prefix); -// } -// -// function GUIToRestr_GeoIPAllow(prefix="") { -// _guiToRestr_Table(prefixId('geoip-allowTableBody',prefix), "geoip_allow",prefix); -// } -// -// function GUIToRestr_GeoIPDisallow(prefix="") { -// _guiToRestr_Table(prefixId('geoip-disallowTableBody',prefix), "geoip_disallow",prefix); -// } - function GUIToRestr_UsagesAT(prefix = "") { let usages = usagesAT(prefix).val() if (usages === "") { @@ -324,11 +289,16 @@ function restrClauseToGUI(prefix = "") { _addListItem(a, $(prefixId('audienceTableBody', prefix)), prefix); } } - if (restr.ip) { + if (restr.hosts) { + for (const host of restr.hosts) { + _addListItem(host, $(prefixId('hostTableBody', prefix)), prefix); + } + } else if (restr.ip) { for (const ip of restr.ip) { - _addListItem(ip, $(prefixId('ipTableBody', prefix)), prefix); + _addListItem(ip, $(prefixId('hostTableBody', prefix)), prefix); } } + if (restr.geoip_allow) { for (const code of restr.geoip_allow) { let country = countriesByCode[code.toUpperCase()]; @@ -395,7 +365,7 @@ function delRestrClause(prefix = "") { } function selectIPTable(prefix = "") { - $(prefixId('restr-ip', prefix)).hideB(); + $(prefixId('restr-hosts', prefix)).hideB(); $(prefixId('restr-geoip_allow', prefix)).hideB(); $(prefixId('restr-geoip_disallow', prefix)).hideB(); $(prefixId('restr-' + $(this).val(), prefix)).showB(); diff --git a/internal/server/web/static/js/restrictions.js b/internal/server/web/static/js/restrictions.js index fa9cfa24..c573eef8 100644 --- a/internal/server/web/static/js/restrictions.js +++ b/internal/server/web/static/js/restrictions.js @@ -10,8 +10,8 @@ function restrIconTime(prefix = "") { return $('#' + prefix + 'r-icon-time'); } -function restrIconIP(prefix = "") { - return $('#' + prefix + 'r-icon-ip'); +function restrIconHost(prefix = "") { + return $('#' + prefix + 'r-icon-host'); } function restrIconScope(prefix = "") { @@ -49,10 +49,10 @@ function updateRestrIcons(prefix = "") { if (aud !== undefined && aud.length > 0) { howManyClausesRestrictAud++; } - let ip = r['ip']; + let hosts = r['hosts'] || r['ip']; let ipW = r['geoip_allow']; let ipB = r['geoip_disallow']; - if ((ip !== undefined && ip.length > 0) || + if ((hosts !== undefined && hosts.length > 0) || (ipW !== undefined && ipW.length > 0) || (ipB !== undefined && ipB.length > 0)) { howManyClausesRestrictIP++; @@ -72,15 +72,16 @@ function updateRestrIcons(prefix = "") { } let restr = getRestrictionsData(prefix); if (howManyClausesRestrictIP === restr.length && restr.length > 0) { - restrIconIP(prefix).addClass('text-success'); - restrIconIP(prefix).removeClass('text-warning'); - restrIconIP(prefix).removeClass('text-danger'); - restrIconIP(prefix).attr('data-original-title', "The IPs from which this token can be used are restricted."); + restrIconHost(prefix).addClass('text-success'); + restrIconHost(prefix).removeClass('text-warning'); + restrIconHost(prefix).removeClass('text-danger'); + restrIconHost(prefix).attr('data-original-title', "The hosts from which this token can be used are" + + " restricted."); } else { - restrIconIP(prefix).addClass('text-warning'); - restrIconIP(prefix).removeClass('text-success'); - restrIconIP(prefix).removeClass('text-danger'); - restrIconIP(prefix).attr('data-original-title', "This token can be used from any IP."); + restrIconHost(prefix).addClass('text-warning'); + restrIconHost(prefix).removeClass('text-success'); + restrIconHost(prefix).removeClass('text-danger'); + restrIconHost(prefix).attr('data-original-title', "This token can be used from any host."); } if (howManyClausesRestrictScope === restr.length && restr.length > 0) { restrIconScope(prefix).addClass('text-success'); diff --git a/internal/server/web/static/js/scope.js b/internal/server/web/static/js/scope.js new file mode 100644 index 00000000..44d7eb41 --- /dev/null +++ b/internal/server/web/static/js/scope.js @@ -0,0 +1,26 @@ +function initScopesGUI(prefix = "") { + $('.scope-checkbox[instance-prefix="' + prefix + '"]').on("click", function () { + let allScopesInactive = $(this).parents('tbody').find('.scope-inactive'); + let allScopesActive = $(this).parents('tbody').find('.scope-active'); + let checkedScopeBoxes = $(this).parents('tbody').find('.scope-checkbox:checked'); + let activeIcon = $(this).parents('tr').find('.scope-active'); + let inactiveIcon = $(this).parents('tr').find('.scope-inactive'); + let activated = $(this).prop('checked'); + if (activated) { + if (checkedScopeBoxes.length === 1) { // There was no box checked before, but now one has been checked + allScopesActive.hideB(); + allScopesInactive.showB(); + } + inactiveIcon.hideB(); + activeIcon.showB(); + } else { + activeIcon.hideB(); + inactiveIcon.showB(); + } + if (checkedScopeBoxes.length === 0) { + allScopesInactive.hideB(); + allScopesActive.showB(); + } + }) + +} diff --git a/internal/server/web/static/js/tokeninfo-status.js b/internal/server/web/static/js/tokeninfo-status.js index 6b6505fe..5e560a04 100644 --- a/internal/server/web/static/js/tokeninfo-status.js +++ b/internal/server/web/static/js/tokeninfo-status.js @@ -12,16 +12,23 @@ const $tokeninfoBadgeIat = $('#tokeninfo-token-iat'); const $tokeninfoBadgeExp = $('#tokeninfo-token-exp'); const $tokeninfoBadgeIatDate = $('#tokeninfo-token-iat-date'); const $tokeninfoBadgeExpDate = $('#tokeninfo-token-exp-date'); - const $tokeninfoTypeBadges = $('.tokeninfo-token-type'); +const $tokeninfoTokenGoneWarningMsg = $('#token-gone-warning'); +$('#tokeninfo-token-copy').on('click', function () { + if (!$tokeninfoTokenGoneWarningMsg.hasClass('d-none')) { + $tokeninfoTokenGoneWarningMsg.alert('close'); + } +}); async function update_tokeninfo() { let token = storagePop('tokeninfo_token', true); if (token === "") { token = $tokenInput.val(); + $tokeninfoTokenGoneWarningMsg.hideB(); } else { $tokenInput.val(token); + $tokeninfoTokenGoneWarningMsg.showB(); } let payload = {}; if (token === "") { diff --git a/internal/server/web/static/js/tokeninfo.js b/internal/server/web/static/js/tokeninfo.js index 9066efee..208a6ea0 100644 --- a/internal/server/web/static/js/tokeninfo.js +++ b/internal/server/web/static/js/tokeninfo.js @@ -83,6 +83,9 @@ function userAgentToHTMLIcons(userAgent) { if (userAgent.startsWith("oidc-agent")) { return ``; } + if (userAgent.startsWith("mytoken")) { + return ``; + } let icons = FaUserAgent.faUserAgent(userAgent); return `${icons.browser.html}${icons.os.html}${icons.platform.html}`; } diff --git a/internal/utils/auth/auther.go b/internal/utils/auth/auther.go index 34d3b10d..fa0d4504 100644 --- a/internal/utils/auth/auther.go +++ b/internal/utils/auth/auther.go @@ -9,7 +9,7 @@ import ( "github.com/oidc-mytoken/server/internal/config" dbhelper "github.com/oidc-mytoken/server/internal/db/dbrepo/mytokenrepo/mytokenrepohelper" "github.com/oidc-mytoken/server/internal/model" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/errorfmt" model2 "github.com/oidc-mytoken/server/shared/model" mytoken "github.com/oidc-mytoken/server/shared/mytoken/pkg" @@ -36,7 +36,7 @@ func RequireMytoken(rlog log.Ext1FieldLogger, reqToken *universalmytoken.Univers *mytoken.Mytoken, *model.Response, ) { if reqToken.JWT == "" { - t, found := ctxUtils.GetMytoken(ctx) + t, found := ctxutils.GetMytoken(ctx) if t == nil { errDesc := "no mytoken found in request" if found { diff --git a/internal/utils/cache/cache.go b/internal/utils/cache/cache.go new file mode 100644 index 00000000..8ec49016 --- /dev/null +++ b/internal/utils/cache/cache.go @@ -0,0 +1,62 @@ +package cache + +import ( + "fmt" + "net" + "time" + + "github.com/patrickmn/go-cache" +) + +var c *cache.Cache + +func init() { + c = cache.New(5*time.Minute, 10*time.Minute) +} + +// Type defines the type of cache +type Type int + +// Different cache types +const ( + IPHostCache Type = iota + IPAddrCache + IPNetCache +) + +func k(t Type, key string) string { + return fmt.Sprintf("%d:%s", t, key) +} + +// Set sets a value in a cache +func Set(t Type, key string, value interface{}, expiration ...time.Duration) { + exp := cache.DefaultExpiration + if len(expiration) > 0 { + exp = expiration[0] + } + c.Set(k(t, key), value, exp) +} + +// Get returns the cached value for a given key +func Get(t Type, key string) (interface{}, bool) { + return c.Get(k(t, key)) +} + +// SetIPParseResult caches the result of an ip parsing +func SetIPParseResult(ipStr string, ip net.IP, ipNet *net.IPNet) { + Set(IPAddrCache, ipStr, ip) + Set(IPNetCache, ipStr, ipNet) +} + +// GetIPParseResult returns the caches result of an ip parsing +func GetIPParseResult(ipStr string) (net.IP, *net.IPNet, bool) { + ip, ipFound := Get(IPAddrCache, ipStr) + if !ipFound { + return nil, nil, false + } + ipNet, netFound := Get(IPNetCache, ipStr) + if !netFound { + return nil, nil, false + } + return ip.(net.IP), ipNet.(*net.IPNet), true +} diff --git a/internal/utils/cookies/cookies.go b/internal/utils/cookies/cookies.go index f3ea113d..30f1bbaa 100644 --- a/internal/utils/cookies/cookies.go +++ b/internal/utils/cookies/cookies.go @@ -7,7 +7,7 @@ import ( log "github.com/sirupsen/logrus" "github.com/oidc-mytoken/server/internal/config" - "github.com/oidc-mytoken/server/internal/server/apiPath" + "github.com/oidc-mytoken/server/internal/server/apipath" ) const ( @@ -37,7 +37,7 @@ func MytokenCookie(mytoken string) *fiber.Cookie { return &fiber.Cookie{ Name: mytokenCookieName, Value: mytoken, - Path: apiPath.Prefix, + Path: apipath.Prefix, Domain: cookieDomain, MaxAge: CookieLifetime, Secure: cookieSecure, @@ -51,7 +51,7 @@ func TransferCodeCookie(transferCode string, expiresIn int) *fiber.Cookie { return &fiber.Cookie{ Name: transferCodeCookieName, Value: transferCode, - Path: apiPath.Prefix, + Path: apipath.Prefix, Domain: cookieDomain, MaxAge: expiresIn, Secure: cookieSecure, diff --git a/internal/utils/ctxUtils/authHeader.go b/internal/utils/ctxutils/authHeader.go similarity index 95% rename from internal/utils/ctxUtils/authHeader.go rename to internal/utils/ctxutils/authHeader.go index 42f2651d..09893447 100644 --- a/internal/utils/ctxUtils/authHeader.go +++ b/internal/utils/ctxutils/authHeader.go @@ -1,4 +1,4 @@ -package ctxUtils +package ctxutils import ( "strings" diff --git a/internal/utils/ctxUtils/grantType.go b/internal/utils/ctxutils/grantType.go similarity index 98% rename from internal/utils/ctxUtils/grantType.go rename to internal/utils/ctxutils/grantType.go index 3bf0cbff..c64a0997 100644 --- a/internal/utils/ctxUtils/grantType.go +++ b/internal/utils/ctxutils/grantType.go @@ -1,4 +1,4 @@ -package ctxUtils +package ctxutils import ( "encoding/json" diff --git a/internal/utils/ctxUtils/networkData.go b/internal/utils/ctxutils/networkData.go similarity index 94% rename from internal/utils/ctxUtils/networkData.go rename to internal/utils/ctxutils/networkData.go index d3ef82cc..b8ae0569 100644 --- a/internal/utils/ctxUtils/networkData.go +++ b/internal/utils/ctxutils/networkData.go @@ -1,4 +1,4 @@ -package ctxUtils +package ctxutils import ( "github.com/gofiber/fiber/v2" diff --git a/internal/utils/ctxUtils/oidcFlow.go b/internal/utils/ctxutils/oidcFlow.go similarity index 98% rename from internal/utils/ctxUtils/oidcFlow.go rename to internal/utils/ctxutils/oidcFlow.go index 5d320719..1aefdb3a 100644 --- a/internal/utils/ctxUtils/oidcFlow.go +++ b/internal/utils/ctxutils/oidcFlow.go @@ -1,4 +1,4 @@ -package ctxUtils +package ctxutils import ( "encoding/json" diff --git a/internal/utils/ctxUtils/token.go b/internal/utils/ctxutils/token.go similarity index 98% rename from internal/utils/ctxUtils/token.go rename to internal/utils/ctxutils/token.go index 3c8e3301..2836f659 100644 --- a/internal/utils/ctxUtils/token.go +++ b/internal/utils/ctxutils/token.go @@ -1,4 +1,4 @@ -package ctxUtils +package ctxutils import ( "encoding/json" diff --git a/internal/utils/fileio/filesystem.go b/internal/utils/fileio/filesystem.go index 29617cc3..aac42875 100644 --- a/internal/utils/fileio/filesystem.go +++ b/internal/utils/fileio/filesystem.go @@ -12,9 +12,9 @@ import ( // Filesystems for a file returning the first one found type SearcherFilesystem []http.FileSystem -type SearcherFile []http.File +type searcherFile []http.File -func (sf SearcherFile) collectErrors(callback func(file http.File) error) error { +func (sf searcherFile) collectErrors(callback func(file http.File) error) error { err := mulerrors.Errors{} for _, f := range sf { e := callback(f) @@ -29,7 +29,7 @@ func (sf SearcherFile) collectErrors(callback func(file http.File) error) error } // Close implements the http.File interface -func (sf SearcherFile) Close() error { +func (sf searcherFile) Close() error { return sf.collectErrors( func(file http.File) error { return file.Close() @@ -38,7 +38,7 @@ func (sf SearcherFile) Close() error { } // Read implements the http.File interface -func (sf SearcherFile) Read(p []byte) (n int, err error) { +func (sf searcherFile) Read(p []byte) (n int, err error) { for _, f := range sf { buffer := make([]byte, len(p)) n, err = f.Read(buffer) @@ -51,7 +51,7 @@ func (sf SearcherFile) Read(p []byte) (n int, err error) { } // Seek implements the http.File interface -func (sf SearcherFile) Seek(offset int64, whence int) (i int64, e error) { +func (sf searcherFile) Seek(offset int64, whence int) (i int64, e error) { for _, f := range sf { i, e = f.Seek(offset, whence) if e == nil { @@ -62,7 +62,7 @@ func (sf SearcherFile) Seek(offset int64, whence int) (i int64, e error) { } // Readdir implements the http.File interface -func (sf SearcherFile) Readdir(count int) (infos []fs.FileInfo, err error) { +func (sf searcherFile) Readdir(count int) (infos []fs.FileInfo, err error) { for _, f := range sf { if count > 0 && len(infos) >= count { break @@ -91,7 +91,7 @@ func (sf SearcherFile) Readdir(count int) (infos []fs.FileInfo, err error) { } // Stat implements the http.File interface -func (sf SearcherFile) Stat() (i fs.FileInfo, e error) { +func (sf searcherFile) Stat() (i fs.FileInfo, e error) { for _, f := range sf { i, e = f.Stat() if e == nil { @@ -103,7 +103,7 @@ func (sf SearcherFile) Stat() (i fs.FileInfo, e error) { // Open implements the http.FileSystem interface func (lfs SearcherFilesystem) Open(name string) (http.File, error) { - sf := SearcherFile{} + sf := searcherFile{} for _, ffs := range lfs { if ffs == nil { continue diff --git a/internal/utils/fileio/join.go b/internal/utils/fileio/join.go index fce97229..d82a39c8 100644 --- a/internal/utils/fileio/join.go +++ b/internal/utils/fileio/join.go @@ -4,6 +4,7 @@ import ( "path/filepath" ) +// JoinIfFirstNotEmpty only joins filepaths if the first element is not empty func JoinIfFirstNotEmpty(elem ...string) string { if len(elem) > 0 && elem[0] != "" { return filepath.Join(elem...) diff --git a/internal/utils/hashUtils/hashUtils.go b/internal/utils/hashutils/hashUtils.go similarity index 97% rename from internal/utils/hashUtils/hashUtils.go rename to internal/utils/hashutils/hashUtils.go index eaf64648..ab76a0a7 100644 --- a/internal/utils/hashUtils/hashUtils.go +++ b/internal/utils/hashutils/hashUtils.go @@ -1,4 +1,4 @@ -package hashUtils +package hashutils import ( "crypto/hmac" @@ -32,6 +32,7 @@ func HMACBasedHash(data []byte) string { } // SHA3_256Str hashes the passed data with SHA3 256 +// //goland:noinspection GoSnakeCaseUsage func SHA3_256Str(data []byte) string { hash := sha3.Sum256(data) @@ -39,6 +40,7 @@ func SHA3_256Str(data []byte) string { } // SHA3_512Str hashes the passed data with SHA3 512 +// //goland:noinspection GoSnakeCaseUsage func SHA3_512Str(data []byte) string { hash := sha3.Sum512(data) diff --git a/internal/utils/hashUtils/hashUtils_test.go b/internal/utils/hashutils/hashUtils_test.go similarity index 98% rename from internal/utils/hashUtils/hashUtils_test.go rename to internal/utils/hashutils/hashUtils_test.go index a7bf7376..0e7aacac 100644 --- a/internal/utils/hashUtils/hashUtils_test.go +++ b/internal/utils/hashutils/hashUtils_test.go @@ -1,4 +1,4 @@ -package hashUtils +package hashutils import ( "testing" diff --git a/internal/utils/iputils/iputils.go b/internal/utils/iputils/iputils.go new file mode 100644 index 00000000..739eafa1 --- /dev/null +++ b/internal/utils/iputils/iputils.go @@ -0,0 +1,166 @@ +package iputils + +import ( + "bytes" + "net" + "strings" + + "github.com/oidc-mytoken/server/internal/utils/cache" +) + +func getHosts(ip string) []string { + cacheHost, found := cache.Get(cache.IPHostCache, ip) + if found { + return cacheHost.([]string) + } + hosts, err := net.LookupAddr(ip) + if err != nil { + return nil + } + cache.Set(cache.IPHostCache, ip, hosts) + return hosts +} + +// IPsAreSubSet checks if all ips of ipsA are contained in ipsB, it will also check ip subnets +func IPsAreSubSet(ipsA, ipsB []string) bool { + for _, ipA := range ipsA { + if !IPIsIn(ipA, ipsB) { + return false + } + } + return true +} + +func parseIP(ip string) (net.IP, *net.IPNet) { + ipA, ipNet, found := cache.GetIPParseResult(ip) + if found { + return ipA, ipNet + } + var err error + ipA, ipNet, err = net.ParseCIDR(ip) + if err != nil { + ipA = net.ParseIP(ip) + } + if ipNet != nil && !ipA.Equal(ipNet.IP) { + ipNet = nil + } + cache.SetIPParseResult(ip, ipA, ipNet) + return ipA, ipNet +} + +// IPIsIn checks if an ip is in a slice of ip/hosts, it will also check ip subnets +func IPIsIn(ip string, ipOrHosts []string) bool { + for _, ipOrHost := range ipOrHosts { + if compareIPToIPOrHost(ip, ipOrHost) { + return true + } + } + return false +} + +func compareIPToIP(ip, ipp string) bool { + ipA, ipNetA := parseIP(ip) + ipB, ipNetB := parseIP(ipp) + if ipNetA == nil && ipNetB == nil { + if ipA.Equal(ipB) { + return true + } + } else if ipNetA == nil && ipNetB != nil { + if ipNetB.Contains(ipA) { + return true + } + } else if ipNetA != nil && ipNetB != nil { + if ipNetB.Contains(ipA) && bytes.Compare(ipNetA.Mask, ipNetB.Mask) >= 0 { + return true + } + } + // check for ipNetA != nil && ipNetB == nil not needed -> won't work + return false +} + +func compareIPToHost(ip, host string) bool { + ipHosts := getHosts(ip) + if len(ipHosts) == 0 { + return false + } + for _, ipHost := range ipHosts { + if ipHost[len(ipHost)-1] == '.' && host[len(host)-1] != '.' { + host += "." + } + if len(host) > 1 && host[0] == '*' { + if strings.HasSuffix(ipHost, host[1:]) { + return true + } + } else if strings.Compare(ipHost, host) == 0 { + return true + } + } + return false +} + +func ipValid(ip net.IP) bool { + return ip != nil && !ip.IsUnspecified() +} + +func compareIPToIPOrHost(ip, iphost string) bool { + ipA, _ := parseIP(ip) + ipHostA, _ := parseIP(iphost) + if ipValid(ipA) && !ipValid(ipHostA) { + return compareIPToHost(ip, iphost) + } + if ipValid(ipA) && ipValid(ipHostA) { + return compareIPToIP(ip, iphost) + } + if !ipValid(ipA) && !ipValid(ipHostA) { + return compareHostToHost(ip, iphost) + } + if !ipValid(ipA) && ipValid(ipHostA) { + return compareHostToIP(ip, iphost) + } + return false +} + +func compareHostToIP(host, ip string) bool { + if len(host) > 1 && host[0] == '*' { + return false + } + if len(host) > 0 && host[len(host)-1] != '.' { + host += "." + } + ipHosts := getHosts(ip) + for _, ipHost := range ipHosts { + if len(ipHost) > 0 && ipHost[len(ipHost)-1] != '.' { + ipHost += "." + } + if host == ipHost { + return true + } + } + return false +} + +func compareHostToHost(a, b string) bool { + if len(a) > 0 && a[len(a)-1] != '.' { + a += "." + } + if len(b) > 0 && b[len(b)-1] != '.' { + b += "." + } + if a == b { + return true + } + if len(a) > 1 && a[0] == '*' { + if len(b) > 1 && b[0] != '*' { + return false + } + return strings.HasSuffix(a[1:], b[1:]) + } + if len(b) > 0 && b[0] != '*' { + // a!=b + // a[0]!='*' + // b[0]!='*' + // -> a really different from b + return false + } + return len(b) > 1 && strings.HasSuffix(a, b[1:]) +} diff --git a/internal/utils/logger/logger.go b/internal/utils/logger/logger.go index d02e4cab..c3759d38 100644 --- a/internal/utils/logger/logger.go +++ b/internal/utils/logger/logger.go @@ -2,7 +2,6 @@ package logger import ( "io" - "io/ioutil" "os" "path/filepath" @@ -108,7 +107,7 @@ func SetOutput() { LogLevels: minLogLevelToLevels(logLevel), }, ) - log.SetOutput(ioutil.Discard) + log.SetOutput(io.Discard) } func minLogLevelToLevels(minLevel log.Level) (levels []log.Level) { diff --git a/internal/utils/logger/smartlogger.go b/internal/utils/logger/smartlogger.go index 3403406a..fdca6125 100644 --- a/internal/utils/logger/smartlogger.go +++ b/internal/utils/logger/smartlogger.go @@ -12,7 +12,7 @@ import ( "github.com/oidc-mytoken/server/internal/config" ) -type SmartLogger struct { +type smartLogger struct { *log.Entry rootHook *rootHook ctx smartLoggerContext @@ -127,7 +127,7 @@ func getIDlogger(id string) log.Ext1FieldLogger { if !config.Get().Logging.Internal.Smart.Enabled { return getLogEntry(id, log.StandardLogger()) } - smartLog := &SmartLogger{ + smartLog := &smartLogger{ ctx: smartLoggerContext{ buffer: new(bytes.Buffer), id: id, @@ -149,6 +149,6 @@ func GetRequestLogger(ctx *fiber.Ctx) log.Ext1FieldLogger { } // GetSSHRequestLogger returns a logrus.Ext1FieldLogger that always includes an ssh request's id -func GetSSHRequestLogger(sessionId string) log.Ext1FieldLogger { - return getIDlogger(sessionId) +func GetSSHRequestLogger(sessionID string) log.Ext1FieldLogger { + return getIDlogger(sessionID) } diff --git a/internal/utils/templating/keys.go b/internal/utils/templating/keys.go index ac894f9a..7abb9d8c 100644 --- a/internal/utils/templating/keys.go +++ b/internal/utils/templating/keys.go @@ -30,7 +30,7 @@ const ( MustacheKeyTokenName = "token-name" MustacheKeyIss = "iss" MustacheKeySupportedScopes = "supported_scopes" - MustacheKeyInstanceUrl = "instance-url" + MustacheKeyInstanceURL = "instance-url" ) // Keys for sub configs diff --git a/internal/utils/utils.go b/internal/utils/utils.go index 22c971c7..bdc2e1c0 100644 --- a/internal/utils/utils.go +++ b/internal/utils/utils.go @@ -1,12 +1,12 @@ package utils import ( - "github.com/oidc-mytoken/server/internal/utils/hashUtils" - "github.com/oidc-mytoken/server/shared/utils/issuerUtils" + "github.com/oidc-mytoken/server/internal/utils/hashutils" + "github.com/oidc-mytoken/server/shared/utils/issuerutils" ) // CreateMytokenSubject creates the subject of a Mytoken from the oidc subject and oidc issuer func CreateMytokenSubject(oidcSub, oidcIss string) string { - comb := issuerUtils.CombineSubIss(oidcSub, oidcIss) - return hashUtils.SHA3_256Str([]byte(comb)) + comb := issuerutils.CombineSubIss(oidcSub, oidcIss) + return hashutils.SHA3_256Str([]byte(comb)) } diff --git a/internal/utils/zipdownload/zipdownload.go b/internal/utils/zipdownload/zipdownload.go index dee16902..57725841 100644 --- a/internal/utils/zipdownload/zipdownload.go +++ b/internal/utils/zipdownload/zipdownload.go @@ -3,16 +3,16 @@ package zipdownload import ( "archive/zip" "bytes" - "io/ioutil" + "io" "github.com/pkg/errors" - "github.com/oidc-mytoken/server/shared/httpClient" + "github.com/oidc-mytoken/server/shared/httpclient" ) // DownloadZipped downloads a zip archive and returns all contained files func DownloadZipped(url string) (map[string][]byte, error) { - resp, err := httpClient.Do().R().Get(url) + resp, err := httpclient.Do().R().Get(url) if err != nil { return nil, errors.WithStack(err) } @@ -41,6 +41,6 @@ func readZipFile(zf *zip.File) ([]byte, error) { return nil, errors.WithStack(err) } defer f.Close() - data, err := ioutil.ReadAll(f) + data, err := io.ReadAll(f) return data, errors.WithStack(err) } diff --git a/mytoken.png b/mytoken.png index 9f3b572b..5937f8b5 100644 Binary files a/mytoken.png and b/mytoken.png differ diff --git a/pkg/oauth2x/config.go b/pkg/oauth2x/config.go index c7889c19..e4ed7352 100644 --- a/pkg/oauth2x/config.go +++ b/pkg/oauth2x/config.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" "strings" @@ -68,7 +68,7 @@ func (c *Config) discovery() error { } defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("unable to read response body: %v", err) } diff --git a/pkg/oauth2x/revoke.go b/pkg/oauth2x/revoke.go index 3939a2fe..74d098ac 100644 --- a/pkg/oauth2x/revoke.go +++ b/pkg/oauth2x/revoke.go @@ -2,7 +2,7 @@ package oauth2x import ( "fmt" - "io/ioutil" + "io" "net/http" "strings" @@ -24,7 +24,7 @@ func (c *Config) RevokeToken(oauth2Config *oauth2.Config, token string) error { defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return fmt.Errorf("unable to read response body: %v", err) } diff --git a/shared/httpClient/httpClient.go b/shared/httpclient/httpClient.go similarity index 97% rename from shared/httpClient/httpClient.go rename to shared/httpclient/httpClient.go index baf1d92c..79a9783b 100644 --- a/shared/httpClient/httpClient.go +++ b/shared/httpclient/httpClient.go @@ -1,4 +1,4 @@ -package httpClient +package httpclient import ( "time" diff --git a/shared/mytoken/mytokenHandler.go b/shared/mytoken/mytokenHandler.go index a01a9900..f4d73aa1 100644 --- a/shared/mytoken/mytokenHandler.go +++ b/shared/mytoken/mytokenHandler.go @@ -12,8 +12,10 @@ import ( "github.com/oidc-mytoken/server/internal/db/dbrepo/cryptstore" "github.com/oidc-mytoken/server/internal/db/dbrepo/encryptionkeyrepo" + "github.com/oidc-mytoken/server/internal/server/httpstatus" "github.com/oidc-mytoken/server/internal/utils/auth" "github.com/oidc-mytoken/server/internal/utils/cookies" + "github.com/oidc-mytoken/server/internal/utils/ctxutils" "github.com/oidc-mytoken/server/internal/utils/errorfmt" "github.com/oidc-mytoken/server/internal/utils/logger" "github.com/oidc-mytoken/server/shared/mytoken/rotation" @@ -29,8 +31,6 @@ import ( response "github.com/oidc-mytoken/server/internal/endpoints/token/mytoken/pkg" "github.com/oidc-mytoken/server/internal/model" "github.com/oidc-mytoken/server/internal/oidc/revoke" - "github.com/oidc-mytoken/server/internal/server/httpStatus" - "github.com/oidc-mytoken/server/internal/utils/ctxUtils" pkgModel "github.com/oidc-mytoken/server/shared/model" eventService "github.com/oidc-mytoken/server/shared/mytoken/event" event "github.com/oidc-mytoken/server/shared/mytoken/event/pkg" @@ -74,7 +74,7 @@ func HandleMytokenFromTransferCode(ctx *fiber.Ctx) *model.Response { return errors.New(errResPlaceholder) } tokenStr, err = transfercoderepo.PopTokenForTransferCode( - rlog, tx, req.TransferCode, *ctxUtils.ClientMetaData(ctx), + rlog, tx, req.TransferCode, *ctxutils.ClientMetaData(ctx), ) return err }, @@ -116,7 +116,7 @@ func HandleMytokenFromMytokenReqChecks( rlog log.Ext1FieldLogger, req *response.MytokenFromMytokenRequest, ip string, ctx *fiber.Ctx, ) (*restrictions.Restriction, *mytoken.Mytoken, *model.Response) { - req.Restrictions.ReplaceThisIp(ip) + req.Restrictions.ReplaceThisIP(ip) req.Restrictions.ClearUnsupportedKeys() rlog.Trace("Parsed mytoken request") @@ -150,7 +150,7 @@ func HandleMytokenFromMytoken(ctx *fiber.Ctx) *model.Response { if errRes != nil { return errRes } - return HandleMytokenFromMytokenReq(rlog, mt, req, ctxUtils.ClientMetaData(ctx), usedRestriction) + return HandleMytokenFromMytokenReq(rlog, mt, req, ctxutils.ClientMetaData(ctx), usedRestriction) } // HandleMytokenFromMytokenReq handles a mytoken request (from an existing mytoken) @@ -315,7 +315,7 @@ func RevokeMytoken( } if strings.HasPrefix(errorfmt.Error(err), "oidc_error") { return &model.Response{ - Status: httpStatus.StatusOIDPError, + Status: httpstatus.StatusOIDPError, Response: pkgModel.OIDCError(errorfmt.Error(err), ""), } } diff --git a/shared/mytoken/pkg/mtid/mtid.go b/shared/mytoken/pkg/mtid/mtid.go index a5a4e544..c79f3149 100644 --- a/shared/mytoken/pkg/mtid/mtid.go +++ b/shared/mytoken/pkg/mtid/mtid.go @@ -8,7 +8,7 @@ import ( uuid "github.com/satori/go.uuid" "github.com/oidc-mytoken/server/internal/db" - "github.com/oidc-mytoken/server/internal/utils/hashUtils" + "github.com/oidc-mytoken/server/internal/utils/hashutils" ) // MTID is a type for the mytoken id @@ -43,7 +43,7 @@ func (i *MTID) HashValid() bool { // Hash returns the MTID's hash func (i *MTID) Hash() string { if i.hash == "" && i.Valid() { - i.hash = hashUtils.SHA512Str(i.Bytes()) + i.hash = hashutils.SHA512Str(i.Bytes()) } return i.hash } diff --git a/shared/mytoken/restrictions/restriction.go b/shared/mytoken/restrictions/restriction.go index 4d208cd0..2fe8be8b 100644 --- a/shared/mytoken/restrictions/restriction.go +++ b/shared/mytoken/restrictions/restriction.go @@ -8,18 +8,17 @@ import ( "github.com/jinzhu/copier" "github.com/jmoiron/sqlx" + "github.com/oidc-mytoken/api/v0" "github.com/pkg/errors" log "github.com/sirupsen/logrus" "github.com/oidc-mytoken/server/internal/config" + "github.com/oidc-mytoken/server/internal/db/dbrepo/mytokenrepo/mytokenrepohelper" "github.com/oidc-mytoken/server/internal/model" "github.com/oidc-mytoken/server/internal/utils/errorfmt" - - "github.com/oidc-mytoken/api/v0" - - "github.com/oidc-mytoken/server/internal/db/dbrepo/mytokenrepo/mytokenrepohelper" "github.com/oidc-mytoken/server/internal/utils/geoip" - "github.com/oidc-mytoken/server/internal/utils/hashUtils" + "github.com/oidc-mytoken/server/internal/utils/hashutils" + "github.com/oidc-mytoken/server/internal/utils/iputils" "github.com/oidc-mytoken/server/shared/mytoken/pkg/mtid" "github.com/oidc-mytoken/server/shared/utils" "github.com/oidc-mytoken/server/shared/utils/unixtime" @@ -59,8 +58,8 @@ func (r *Restrictions) ClearUnsupportedKeys() { if disabledRestrictionKeys().Has(model.RestrictionClaimAudiences) { rr.Audiences = nil } - if disabledRestrictionKeys().Has(model.RestrictionClaimIPs) { - rr.IPs = nil + if disabledRestrictionKeys().Has(model.RestrictionClaimHosts) { + rr.Hosts = nil } if disabledRestrictionKeys().Has(model.RestrictionClaimGeoIPAllow) { rr.GeoIPAllow = nil @@ -78,13 +77,44 @@ func (r *Restrictions) ClearUnsupportedKeys() { } } +// legacyHash returns the legacy hash of this restriction (using "ip" instead of "hosts" key +func (r *Restriction) legacyHash() ([]byte, error) { + type legacy struct { + NotBefore unixtime.UnixTime `json:"nbf,omitempty"` + ExpiresAt unixtime.UnixTime `json:"exp,omitempty"` + Scope string `json:"scope,omitempty"` + Audiences []string `json:"audience,omitempty"` + Hosts []string `json:"ip,omitempty"` + GeoIPAllow []string `json:"geoip_allow,omitempty"` + GeoIPDisallow []string `json:"geoip_disallow,omitempty"` + UsagesAT *int64 `json:"usages_AT,omitempty"` + UsagesOther *int64 `json:"usages_other,omitempty"` + } + l := legacy{ + NotBefore: r.NotBefore, + ExpiresAt: r.ExpiresAt, + Scope: r.Scope, + Audiences: r.Audiences, + Hosts: r.Hosts, + GeoIPAllow: r.GeoIPAllow, + GeoIPDisallow: r.GeoIPDisallow, + UsagesAT: r.UsagesAT, + UsagesOther: r.UsagesOther, + } + j, err := json.Marshal(l) + if err != nil { + return nil, errors.WithStack(err) + } + return hashutils.SHA512(j), nil +} + // hash returns the hash of this restriction func (r *Restriction) hash() ([]byte, error) { j, err := json.Marshal(r) if err != nil { return nil, errors.WithStack(err) } - return hashUtils.SHA512(j), nil + return hashutils.SHA512(j), nil } func (r *Restriction) verifyNbf(now unixtime.UnixTime) bool { @@ -105,16 +135,16 @@ func (r *Restriction) verifyTimeBased(rlog log.Ext1FieldLogger) bool { now := unixtime.Now() return r.verifyNbf(now) && r.verifyExp(now) } -func (r *Restriction) verifyIPBased(rlog log.Ext1FieldLogger, ip string) bool { - return r.verifyIPs(rlog, ip) && r.verifyGeoIP(rlog, ip) +func (r *Restriction) verifyLocationBased(rlog log.Ext1FieldLogger, ip string) bool { + return r.verifyHosts(rlog, ip) && r.verifyGeoIP(rlog, ip) } -func (r *Restriction) verifyIPs(rlog log.Ext1FieldLogger, ip string) bool { - if disabledRestrictionKeys().Has(model.RestrictionClaimIPs) { +func (r *Restriction) verifyHosts(rlog log.Ext1FieldLogger, ip string) bool { + if disabledRestrictionKeys().Has(model.RestrictionClaimHosts) { return true } - rlog.Trace("Verifying ips") - return len(r.IPs) == 0 || - utils.IPIsIn(ip, r.IPs) + rlog.Trace("Verifying hosts") + return len(r.Hosts) == 0 || + iputils.IPIsIn(ip, r.Hosts) } func (r *Restriction) verifyGeoIP(rlog log.Ext1FieldLogger, ip string) bool { rlog.Trace("Verifying ip geo location") @@ -147,6 +177,14 @@ func (r *Restriction) getATUsageCounts(rlog log.Ext1FieldLogger, tx *sqlx.Tx, my if err != nil { return nil, err } + usages, err := mytokenrepohelper.GetTokenUsagesAT(rlog, tx, myID, string(hash)) + if err != nil || usages != nil { + return usages, err + } + hash, err = r.legacyHash() + if err != nil { + return nil, err + } return mytokenrepohelper.GetTokenUsagesAT(rlog, tx, myID, string(hash)) } func (r *Restriction) verifyATUsageCounts(rlog log.Ext1FieldLogger, tx *sqlx.Tx, myID mtid.MTID) bool { @@ -220,7 +258,7 @@ func (r *Restriction) verifyOtherUsageCounts(rlog log.Ext1FieldLogger, tx *sqlx. } func (r *Restriction) verify(rlog log.Ext1FieldLogger, ip string) bool { return r.verifyTimeBased(rlog) && - r.verifyIPBased(rlog, ip) + r.verifyLocationBased(rlog, ip) } func (r *Restriction) verifyAT(rlog log.Ext1FieldLogger, tx *sqlx.Tx, ip string, id mtid.MTID) bool { return r.verify(rlog, ip) && r.verifyATUsageCounts(rlog, tx, id) @@ -477,10 +515,10 @@ func Tighten(rlog log.Ext1FieldLogger, old, wanted Restrictions) (res Restrictio return } -// ReplaceThisIp replaces the special value 'this' with the given ip. -func (r *Restrictions) ReplaceThisIp(ip string) { +// ReplaceThisIP replaces the special value 'this' with the given ip. +func (r *Restrictions) ReplaceThisIP(ip string) { for _, rr := range *r { - utils.ReplaceStringInSlice(&rr.IPs, "this", ip, false) + utils.ReplaceStringInSlice(&rr.Hosts, "this", ip, false) } } @@ -512,7 +550,7 @@ func (r *Restriction) isTighterThan(b *Restriction) bool { ) && len(b.Audiences) != 0 { return false } - if len(r.IPs) == 0 && len(b.IPs) > 0 || !utils.IPsAreSubSet(r.IPs, b.IPs) && len(b.IPs) != 0 { + if len(r.Hosts) == 0 && len(b.Hosts) > 0 || !iputils.IPsAreSubSet(r.Hosts, b.Hosts) && len(b.Hosts) != 0 { return false } if len(r.GeoIPAllow) == 0 && len(b.GeoIPAllow) > 0 || !utils.IsSubSet( diff --git a/shared/mytoken/restrictions/restriction_test.go b/shared/mytoken/restrictions/restriction_test.go index 2069b446..ccd30871 100644 --- a/shared/mytoken/restrictions/restriction_test.go +++ b/shared/mytoken/restrictions/restriction_test.go @@ -528,10 +528,10 @@ func TestRestriction_isTighterThan(t *testing.T) { }, { name: "IP", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.12"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.12"}}}, b: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.12", "192.168.0.14", }, @@ -543,21 +543,21 @@ func TestRestriction_isTighterThan(t *testing.T) { name: "IP Reversed", a: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.12", "192.168.0.14", }, }, }, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.12"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.12"}}}, expected: false, }, { name: "IP with explicit net", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.12/24"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.12/24"}}}, b: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.12", "192.168.0.14", }, @@ -569,33 +569,33 @@ func TestRestriction_isTighterThan(t *testing.T) { name: "IP with explicit net Reversed", a: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.12", "192.168.0.14", }, }, }, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.12/24"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.12/24"}}}, expected: false, }, { name: "IP Subnet", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.12"}}}, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/24"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.12"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/24"}}}, expected: true, }, { name: "IP Subnet Reversed", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/24"}}}, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.12"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/24"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.12"}}}, expected: false, }, { name: "IP Subnet + IP", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.12"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.12"}}}, b: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.0/24", "192.168.1.2", }, @@ -607,21 +607,21 @@ func TestRestriction_isTighterThan(t *testing.T) { name: "IP Subnet + IP Reversed", a: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.0/24", "192.168.1.2", }, }, }, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.12"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.12"}}}, expected: false, }, { name: "IP Subnets + IP", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/24"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/24"}}}, b: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.0/24", "192.168.1.2", }, @@ -633,49 +633,49 @@ func TestRestriction_isTighterThan(t *testing.T) { name: "IP Subnets + IP Reversed", a: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.0/24", "192.168.1.2", }, }, }, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/24"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/24"}}}, expected: false, }, { name: "IP Different sized Subnets", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/24"}}}, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/16"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/24"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/16"}}}, expected: true, }, { name: "IP Different sized Subnets Reversed", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/16"}}}, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/24"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/16"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/24"}}}, expected: false, }, { name: "IP Different sized Subnets 2", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.128.0/24"}}}, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/16"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.128.0/24"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/16"}}}, expected: true, }, { name: "IP Different sized Subnets 2 Reversed", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/16"}}}, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.128.0/24"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/16"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.128.0/24"}}}, expected: false, }, { name: "IP Different Subnets", - a: Restriction{Restriction: api.Restriction{IPs: []string{"193.168.0.0/24"}}}, - b: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/16"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"193.168.0.0/24"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/16"}}}, expected: false, }, { name: "IP Different Subnets Reversed", - a: Restriction{Restriction: api.Restriction{IPs: []string{"192.168.0.0/16"}}}, - b: Restriction{Restriction: api.Restriction{IPs: []string{"193.168.0.0/24"}}}, + a: Restriction{Restriction: api.Restriction{Hosts: []string{"192.168.0.0/16"}}}, + b: Restriction{Restriction: api.Restriction{Hosts: []string{"193.168.0.0/24"}}}, expected: false, }, { @@ -683,7 +683,7 @@ func TestRestriction_isTighterThan(t *testing.T) { a: Restriction{}, b: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.12", "192.168.0.42", }, @@ -695,7 +695,7 @@ func TestRestriction_isTighterThan(t *testing.T) { name: "IP B empty", a: Restriction{ Restriction: api.Restriction{ - IPs: []string{ + Hosts: []string{ "192.168.0.12", "192.168.0.42", }, @@ -704,6 +704,276 @@ func TestRestriction_isTighterThan(t *testing.T) { b: Restriction{}, expected: true, }, + { + name: "Hosts equal", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "test.example.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "test.example.com", + }, + }, + }, + expected: true, + }, + { + name: "Hosts equal wildcard", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.example.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.example.com", + }, + }, + }, + expected: true, + }, + { + name: "Hosts one wildcard", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "test.example.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.example.com", + }, + }, + }, + expected: true, + }, + { + name: "Hosts one wildcard reversed", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.example.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "test.example.com", + }, + }, + }, + expected: false, + }, + { + name: "Hosts two wildcards", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.test.example.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.example.com", + }, + }, + }, + expected: true, + }, + { + name: "Hosts two wildcards reversed", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.example.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.test.example.com", + }, + }, + }, + expected: false, + }, + { + name: "Hosts wildcard different", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "test.other.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.example.com", + }, + }, + }, + expected: false, + }, + { + name: "Host with ip", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "stackoverflow.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "198.252.206.16", + }, + }, + }, + expected: true, + }, + { + name: "Host with ip reversed", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "198.252.206.16", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "stackoverflow.com", + }, + }, + }, + expected: true, + }, + { + name: "wildcard Host with ip", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "198.252.206.16", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*stackoverflow.com", + }, + }, + }, + expected: true, + }, + { + name: "wildcard Host with ip", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "198.252.206.16", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*stackoverflow.com", + }, + }, + }, + expected: true, + }, + { + name: "wildcard Host with ip reversed", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.stackoverflow.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "198.252.206.16", + }, + }, + }, + expected: false, + }, + { + name: "wildcard Host 2 with ip", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "198.252.206.16", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.stackoverflow.com", + }, + }, + }, + expected: false, + }, + { + name: "wildcard Host 2 with ip reversed", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "*.stackoverflow.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "198.252.206.16", + }, + }, + }, + expected: false, + }, + { + name: "invalid ip for host", + a: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "test.example.com", + }, + }, + }, + b: Restriction{ + Restriction: api.Restriction{ + Hosts: []string{ + "192.168.0.42", + }, + }, + }, + expected: false, + }, { name: "GeoIP Allow Subset", a: Restriction{ @@ -1058,7 +1328,7 @@ func TestRestriction_isTighterThan(t *testing.T) { "b", "c", }, - IPs: []string{ + Hosts: []string{ "a", "b", "c", @@ -1087,7 +1357,7 @@ func TestRestriction_isTighterThan(t *testing.T) { "b", "c", }, - IPs: []string{ + Hosts: []string{ "a", "b", "c", @@ -1120,7 +1390,7 @@ func TestRestriction_isTighterThan(t *testing.T) { "b", "c", }, - IPs: []string{ + Hosts: []string{ "a", "b", "c", @@ -1149,7 +1419,7 @@ func TestRestriction_isTighterThan(t *testing.T) { "b", "c", }, - IPs: []string{ + Hosts: []string{ "a", "b", "c", @@ -1182,7 +1452,7 @@ func TestRestriction_isTighterThan(t *testing.T) { "b", "c", }, - IPs: []string{ + Hosts: []string{ "a", "b", "c", @@ -1211,7 +1481,7 @@ func TestRestriction_isTighterThan(t *testing.T) { "b", "c", }, - IPs: []string{ + Hosts: []string{ "a", "b", "c", @@ -1360,18 +1630,70 @@ func TestRestriction_hash(t *testing.T) { NotBefore: 1599939600, ExpiresAt: 1599948600, Restriction: api.Restriction{ - IPs: []string{"192.168.0.31"}, + Hosts: []string{"192.168.0.31"}, UsagesAT: utils.NewInt64(11), }, } - hash, err := r.hash() - if err != nil { - t.Error(err) + cases := []struct { + name string + r Restriction + expHash string + }{ + { + name: "hash", + r: r, + expHash: "umVWTDmDgo2NLCgUWFtTn4G8PfjUZYTMxJ5QJGGo4ZNFOno76ggNdQcPhDsfWfYMy79n6oxnwiahbvHZUuI96w==", + }, } - expected := "BS3WfHbHNUiVU8sJ+F49H9+69HnFtfVDy2m22vBv588nZ0kGblVNxZEcrTN+5NUiRkM7W80N4VpPgwEZBZl+3g==" - if string(hash) != expected { - t.Errorf("hash '%s' does not match expected hash '%s'", hash, expected) + for _, c := range cases { + t.Run( + c.name, func(t *testing.T) { + hash, err := c.r.hash() + if err != nil { + t.Error(err) + } + if string(hash) != c.expHash { + t.Errorf("hash '%s' does not match expected hash '%s'", hash, c.expHash) + } + }, + ) + } +} + +func TestRestriction_legacyHash(t *testing.T) { + r := Restriction{ + NotBefore: 1599939600, + ExpiresAt: 1599948600, + Restriction: api.Restriction{ + Hosts: []string{"192.168.0.31"}, + UsagesAT: utils.NewInt64(11), + }, + } + + cases := []struct { + name string + r Restriction + expHash string + }{ + { + name: "legacy hash", + r: r, + expHash: "BS3WfHbHNUiVU8sJ+F49H9+69HnFtfVDy2m22vBv588nZ0kGblVNxZEcrTN+5NUiRkM7W80N4VpPgwEZBZl+3g==", + }, + } + for _, c := range cases { + t.Run( + c.name, func(t *testing.T) { + hash, err := c.r.legacyHash() + if err != nil { + t.Error(err) + } + if string(hash) != c.expHash { + t.Errorf("hash '%s' does not match expected hash '%s'", hash, c.expHash) + } + }, + ) } } diff --git a/shared/utils/cryptUtils/cryptUtils.go b/shared/utils/cryptutils/cryptUtils.go similarity index 99% rename from shared/utils/cryptUtils/cryptUtils.go rename to shared/utils/cryptutils/cryptUtils.go index 7cb1acce..b520d9f1 100644 --- a/shared/utils/cryptUtils/cryptUtils.go +++ b/shared/utils/cryptutils/cryptUtils.go @@ -1,4 +1,4 @@ -package cryptUtils +package cryptutils import ( "crypto/aes" diff --git a/shared/utils/fileutil/fileutil.go b/shared/utils/fileutil/fileutil.go index 40a5ac9d..6cff07f6 100644 --- a/shared/utils/fileutil/fileutil.go +++ b/shared/utils/fileutil/fileutil.go @@ -47,9 +47,11 @@ func Append(path, content string, doNotCreateIfDoesNotExist ...bool) error { if err != nil { return err } - defer f.Close() _, err = f.WriteString(content) - return err + if err != nil { + return err + } + return f.Close() } // ReadFile reads a given file and returns the content. diff --git a/shared/utils/issuerUtils/issuerUtils.go b/shared/utils/issuerutils/issuerUtils.go similarity index 91% rename from shared/utils/issuerUtils/issuerUtils.go rename to shared/utils/issuerutils/issuerUtils.go index 8639e70e..955603a1 100644 --- a/shared/utils/issuerUtils/issuerUtils.go +++ b/shared/utils/issuerutils/issuerUtils.go @@ -1,4 +1,4 @@ -package issuerUtils +package issuerutils import ( "fmt" @@ -13,10 +13,9 @@ func GetIssuerWithAndWithoutSlash(iss string) (string, string) { if strings.HasSuffix(iss0, "/") { iss1 = strings.TrimSuffix(iss0, "/") return iss1, iss0 - } else { - iss1 = fmt.Sprintf("%s%c", iss0, '/') - return iss0, iss1 } + iss1 = fmt.Sprintf("%s%c", iss0, '/') + return iss0, iss1 } // CompareIssuerURLs compares two issuer urls. Issuer urls are also accepted as diff --git a/shared/utils/issuerUtils/issuerUtils_test.go b/shared/utils/issuerutils/issuerUtils_test.go similarity index 99% rename from shared/utils/issuerUtils/issuerUtils_test.go rename to shared/utils/issuerutils/issuerUtils_test.go index e633aca0..df90ef86 100644 --- a/shared/utils/issuerUtils/issuerUtils_test.go +++ b/shared/utils/issuerutils/issuerUtils_test.go @@ -1,4 +1,4 @@ -package issuerUtils +package issuerutils import "testing" diff --git a/shared/utils/utils.go b/shared/utils/utils.go index 37d0a5a6..68034030 100644 --- a/shared/utils/utils.go +++ b/shared/utils/utils.go @@ -1,11 +1,9 @@ package utils import ( - "bytes" "encoding/base64" "fmt" "math/rand" - "net" "strings" "time" "unsafe" @@ -90,53 +88,6 @@ func IsSubSet(a, b []string) bool { return true } -// IPsAreSubSet checks if all ips of ipsA are contained in ipsB, it will also check ip subnets -func IPsAreSubSet(ipsA, ipsB []string) bool { - for _, ipA := range ipsA { - if !IPIsIn(ipA, ipsB) { - return false - } - } - return true -} - -func parseIP(ip string) (net.IP, *net.IPNet) { - ipA, ipNet, err := net.ParseCIDR(ip) - if err != nil { - ipA = net.ParseIP(ip) - } - if ipNet != nil && !ipA.Equal(ipNet.IP) { - ipNet = nil - } - return ipA, ipNet -} - -// IPIsIn checks if a ip is in a slice of ips, it will also check ip subnets -func IPIsIn(ip string, ips []string) bool { - if len(ips) == 0 { - return false - } - ipA, ipNetA := parseIP(ip) - for _, ipp := range ips { - ipB, ipNetB := parseIP(ipp) - if ipNetA == nil && ipNetB == nil { - if ipA.Equal(ipB) { - return true - } - } else if ipNetA == nil && ipNetB != nil { - if ipNetB.Contains(ipA) { - return true - } - } else if ipNetA != nil && ipNetB != nil { - if ipNetB.Contains(ipA) && bytes.Compare(ipNetA.Mask, ipNetB.Mask) >= 0 { - return true - } - } - // check for ipNetA != nil && ipNetB == nil not needed -> won't work - } - return false -} - // CombineURLPath combines multiple parts of a url func CombineURLPath(p string, ps ...string) (r string) { r = p