WebUI: add a token validation mode that allows checking the signature
Some checks failed
Code scanning - action / CodeQL-Build (push) Has been cancelled
CI / Test and deploy (1.22, macos-latest, true) (push) Has been cancelled
CI / Test and deploy (1.22, ubuntu-latest, true) (push) Has been cancelled
CI / Test and deploy (1.22, windows-latest, false) (push) Has been cancelled
CI / Test build flags (push) Has been cancelled
CI / Test with PgSQL/MySQL/Cockroach (push) Has been cancelled
CI / Build Linux packages (aarch64, ubuntu18.04, go1.22.7, arm64) (push) Has been cancelled
CI / Build Linux packages (amd64, ubuntu:18.04, go1.22.7, amd64) (push) Has been cancelled
CI / Build Linux packages (armv7, ubuntu18.04, go1.22.7, arm7) (push) Has been cancelled
CI / Build Linux packages (ppc64le, ubuntu18.04, go1.22.7, ppc64le) (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Docker / Build (alpine, false, ubuntu-latest) (push) Has been cancelled
Docker / Build (alpine, true, ubuntu-latest) (push) Has been cancelled
Docker / Build (debian, false, ubuntu-latest) (push) Has been cancelled
Docker / Build (debian, true, ubuntu-latest) (push) Has been cancelled
Docker / Build (debian-plugins, true, ubuntu-latest) (push) Has been cancelled
Docker / Build (distroless, false, ubuntu-latest) (push) Has been cancelled

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2024-09-21 14:06:25 +02:00
parent 5f67fcdce5
commit 433d45ed87
No known key found for this signature in database
GPG key ID: 935D2952DEC4EECF
15 changed files with 485 additions and 85 deletions

50
go.mod
View file

@ -5,19 +5,19 @@ go 1.22.2
require (
cloud.google.com/go/storage v1.43.0
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5
github.com/alexedwards/argon2id v1.0.0
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964
github.com/aws/aws-sdk-go-v2 v1.30.5
github.com/aws/aws-sdk-go-v2/config v1.27.33
github.com/aws/aws-sdk-go-v2/credentials v1.17.32
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.18
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.23.6
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.8
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7
github.com/aws/aws-sdk-go-v2 v1.31.0
github.com/aws/aws-sdk-go-v2/config v1.27.36
github.com/aws/aws-sdk-go-v2/credentials v1.17.34
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.22
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.24.0
github.com/aws/aws-sdk-go-v2/service/s3 v1.63.0
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.33.0
github.com/aws/aws-sdk-go-v2/service/sts v1.31.0
github.com/bmatcuk/doublestar/v4 v4.6.1
github.com/cockroachdb/cockroach-go/v2 v2.3.8
github.com/coreos/go-oidc/v3 v3.11.0
@ -47,7 +47,7 @@ require (
github.com/pires/go-proxyproto v0.7.0
github.com/pkg/sftp v1.13.7-0.20240410063531-637088883317
github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.20.3
github.com/prometheus/client_golang v1.20.4
github.com/robfig/cron/v3 v3.0.1
github.com/rs/cors v1.11.1
github.com/rs/xid v1.6.0
@ -73,7 +73,7 @@ require (
golang.org/x/sys v0.25.0
golang.org/x/term v0.24.0
golang.org/x/time v0.6.0
google.golang.org/api v0.197.0
google.golang.org/api v0.198.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
@ -86,24 +86,24 @@ require (
filippo.io/edwards25519 v1.1.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.19 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.17 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 // indirect
github.com/aws/smithy-go v1.20.4 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.18 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.20 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.23.0 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.0 // indirect
github.com/aws/smithy-go v1.21.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.2 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect
github.com/fatih/color v1.17.0 // indirect
@ -176,7 +176,7 @@ require (
google.golang.org/genproto v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect
google.golang.org/grpc v1.66.2 // indirect
google.golang.org/grpc v1.67.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

99
go.sum
View file

@ -26,8 +26,8 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xP
github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0 h1:PiSrjRPpkQNjrM8H0WwKMnZUdu1RGMtd/LdGKUrOo+c=
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.6.0/go.mod h1:oDrbWx4ewMylP7xHivfgixbfGBT6APAwsSoHRKotnIc=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0 h1:Be6KInmFEKV81c0pOAEbRYehLMwmmGI1exuFj248AMk=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.0/go.mod h1:WCPBHsOXfBVnivScjs2ypRfimjEW0qPVLGgJkZlrIOA=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1 h1:cf+OIKbkmMHBaC3u78AXomweqM0oxQSgBXRZf3WH4yM=
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.4.1/go.mod h1:ap1dmS6vQKJxSMNiGJcq4QuUQkOynyD93gLw6MDF7ek=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@ -39,48 +39,48 @@ github.com/alexedwards/argon2id v1.0.0 h1:wJzDx66hqWX7siL/SRUmgz3F8YMrd/nfX/xHHc
github.com/alexedwards/argon2id v1.0.0/go.mod h1:tYKkqIjzXvZdzPvADMWOEZ+l6+BD6CtBXMj5fnJppiw=
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964 h1:I9YN9WMo3SUh7p/4wKeNvD/IQla3U3SUa61U7ul+xM4=
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964/go.mod h1:eFiR01PwTcpbzXtdMces7zxg6utvFM5puiWHpWB8D/k=
github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g=
github.com/aws/aws-sdk-go-v2 v1.30.5/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4 h1:70PVAiL15/aBMh5LThwgXdSQorVr91L127ttckI9QQU=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.4/go.mod h1:/MQxMqci8tlqDH+pjmoLu1i0tbWCUP1hhyMRuFxpQCw=
github.com/aws/aws-sdk-go-v2/config v1.27.33 h1:Nof9o/MsmH4oa0s2q9a0k7tMz5x/Yj5k06lDODWz3BU=
github.com/aws/aws-sdk-go-v2/config v1.27.33/go.mod h1:kEqdYzRb8dd8Sy2pOdEbExTTF5v7ozEXX0McgPE7xks=
github.com/aws/aws-sdk-go-v2/credentials v1.17.32 h1:7Cxhp/BnT2RcGy4VisJ9miUPecY+lyE9I8JvcZofn9I=
github.com/aws/aws-sdk-go-v2/credentials v1.17.32/go.mod h1:P5/QMF3/DCHbXGEGkdbilXHsyTBX5D3HSwcrSc9p20I=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 h1:pfQ2sqNpMVK6xz2RbqLEL0GH87JOwSxPV2rzm8Zsb74=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13/go.mod h1:NG7RXPUlqfsCLLFfi0+IpKN4sCB9D9fw/qTaSB+xRoU=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.18 h1:9DIp7vhmOPmueCDwpXa45bEbLHHTt1kcxChdTJWWxvI=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.18/go.mod h1:aJv/Fwz8r56ozwYFRC4bzoeL1L17GYQYemfblOBux1M=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 h1:pI7Bzt0BJtYA0N/JEC6B8fJ4RBrEMi1LBrkMdFYNSnQ=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17/go.mod h1:Dh5zzJYMtxfIjYW+/evjQ8uj2OyR/ve2KROHGHlSFqE=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 h1:Mqr/V5gvrhA2gvgnF42Zh5iMiQNcOYthFYwCyrnuWlc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17/go.mod h1:aLJpZlCmjE+V+KtN1q1uyZkfnUWpQGpbsn89XPKyzfU=
github.com/aws/aws-sdk-go-v2 v1.31.0 h1:3V05LbxTSItI5kUqNwhJrrrY1BAXxXt0sN0l72QmG5U=
github.com/aws/aws-sdk-go-v2 v1.31.0/go.mod h1:ztolYtaEUtdpf9Wftr31CJfLVjOnD/CVRkKOOYgF8hA=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5 h1:xDAuZTn4IMm8o1LnBZvmrL8JA1io4o3YWNXgohbf20g=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.5/go.mod h1:wYSv6iDS621sEFLfKvpPE2ugjTuGlAG7iROg0hLOkfc=
github.com/aws/aws-sdk-go-v2/config v1.27.36 h1:4IlvHh6Olc7+61O1ktesh0jOcqmq/4WG6C2Aj5SKXy0=
github.com/aws/aws-sdk-go-v2/config v1.27.36/go.mod h1:IiBpC0HPAGq9Le0Xxb1wpAKzEfAQ3XlYgJLYKEVYcfw=
github.com/aws/aws-sdk-go-v2/credentials v1.17.34 h1:gmkk1l/cDGSowPRzkdxYi8edw+gN4HmVK151D/pqGNc=
github.com/aws/aws-sdk-go-v2/credentials v1.17.34/go.mod h1:4R9OEV3tgFMsok4ZeFpExn7zQaZRa9MRGFYnI/xC/vs=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 h1:C/d03NAmh8C4BZXhuRNboF/DqhBkBCeDiJDcaqIT5pA=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14/go.mod h1:7I0Ju7p9mCIdlrfS+JCgqcYD0VXz/N4yozsox+0o078=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.22 h1:MUD/42Etbj6sVZ0HpOe4G/4+wDF7ZJhqZXSqNKZokPM=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.22/go.mod h1:wp0iN4VH1riPNX68N8MU+mz/7ggSeWc+zBhsdALp+zM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 h1:kYQ3H1u0ANr9KEKlGs/jTLrBFPo8P8NaH/w7A01NeeM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18/go.mod h1:r506HmK5JDUh9+Mw4CfGJGSSoqIiLCndAuqXuhbv67Y=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 h1:Z7IdFUONvTcvS7YuhtVxN99v2cCoHRXOS4mTr0B/pUc=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18/go.mod h1:DkKMmksZVVyat+Y+r1dEOgJEfUeA7UngIHWeKsi0yNc=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ=
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17 h1:Roo69qTpfu8OlJ2Tb7pAYVuF0CpuUMB0IYWwYP/4DZM=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17/go.mod h1:NcWPxQzGM1USQggaTVwz6VpqMZPX1CvDJLDh6jnOCa4=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.19 h1:FLMkfEiRjhgeDTCjjLoc3URo/TBkgeQbocA78lfkzSI=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.19/go.mod h1:Vx+GucNSsdhaxs3aZIKfSUjKVGsxN25nX2SRcdhuw08=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 h1:rfprUlsdzgl7ZL2KlXiUAoJnI/VxfHCvDFr2QDFj6u4=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19/go.mod h1:SCWkEdRq8/7EK60NcvvQ6NXKuTcchAD4ROAsC37VEZE=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.17 h1:u+EfGmksnJc/x5tq3A+OD7LrMbSSR/5TrKLvkdy/fhY=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.17/go.mod h1:VaMx6302JHax2vHJWgRo+5n9zvbacs3bLU/23DNQrTY=
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.23.6 h1:4ZL1yFmgCUTksVdHa71xao4X8ii5k6KtD93Fr08p1NU=
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.23.6/go.mod h1:ck+HLSlQVYL8LIth8IrZ5qPQ4KTletB/O+WWqW8gtjQ=
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 h1:Kp6PWAlXwP1UvIflkIP6MFZYBNDCa4mFCGtxrpICVOg=
github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2/go.mod h1:5FmD/Dqq57gP+XwaUnd5WFPipAuzrf0HmupX27Gvjvc=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.8 h1:HNXhQReFG2fbucvPRxDabbIGQf/6dieOfTnzoGPEqXI=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.32.8/go.mod h1:BYr9P/rrcLNJ8A36nT15p8tpoVDZ5lroHuMn/njecBw=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 h1:pIaGg+08llrP7Q5aiz9ICWbY8cqhTkyy+0SHvfzQpTc=
github.com/aws/aws-sdk-go-v2/service/sso v1.22.7/go.mod h1:eEygMHnTKH/3kNp9Jr1n3PdejuSNcgwLe1dWgQtO0VQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 h1:/Cfdu0XV3mONYKaOt1Gr0k1KvQzkzPyiKUdlWJqy+J4=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7/go.mod h1:bCbAxKDqNvkHxRaIMnyVPXPo+OaPRwvmgzMxbz1VKSA=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 h1:NKTa1eqZYw8tiHSRGpP0VtTdub/8KNk8sDkNPFaOKDE=
github.com/aws/aws-sdk-go-v2/service/sts v1.30.7/go.mod h1:NXi1dIAGteSaRLqYgarlhP/Ij0cFT+qmCwiJqWh/U5o=
github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4=
github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.18 h1:OWYvKL53l1rbsUmW7bQyJVsYU/Ii3bbAAQIIFNbM0Tk=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.18/go.mod h1:CUx0G1v3wG6l01tUB+j7Y8kclA8NSqK4ef0YG79a4cg=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 h1:QFASJGfT8wMXtuP3D5CRmMjARHv9ZmzFUMJznHDOY3w=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5/go.mod h1:QdZ3OmoIjSX+8D1OPAzPxDfjXASbBMDsz9qvtyIhtik=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.20 h1:rTWjG6AvWekO2B1LHeM3ktU7MqyX9rzWQ7hgzneZW7E=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.3.20/go.mod h1:RGW2DDpVc8hu6Y6yG8G5CHVmVOAn1oV8rNKOHRJyswg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 h1:Xbwbmk44URTiHNx6PNo0ujDE6ERlsCKJD3u1zfnzAPg=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20/go.mod h1:oAfOFzUB14ltPZj1rWwRc3d/6OgD76R8KlvU3EqM9Fg=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18 h1:eb+tFOIl9ZsUe2259/BKPeniKuz4/02zZFH/i4Nf8Rg=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.18/go.mod h1:GVCC2IJNJTmdlyEsSmofEy7EfJncP7DNnXDzRjJ5Keg=
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.24.0 h1:l6NntGJyBZfgSMxj7Djlo2t9R0bYk2iMpqhDtuD/RSQ=
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.24.0/go.mod h1:zyg91TcJAFCMk+J1eiKjtAEUD9CvFqz+8PYytGk00GM=
github.com/aws/aws-sdk-go-v2/service/s3 v1.63.0 h1:F6KG9CT7PPqAjnRxjKmYJopVnXPwjlzPI2FEgXHajNY=
github.com/aws/aws-sdk-go-v2/service/s3 v1.63.0/go.mod h1:NLTqRLe3pUNu3nTEHI6XlHLKYmc8fbHUdMxAB6+s41Q=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.33.0 h1:r+37fBAonXAmRx2MX0naWDKZpAaP2AOQ22cf9Cg71GA=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.33.0/go.mod h1:WyLS5qwXHtjKAONYZq/4ewdd+hcVsa3LBu77Ow5uj3k=
github.com/aws/aws-sdk-go-v2/service/sso v1.23.0 h1:fHySkG0IGj2nepgGJPmmhZYL9ndnsq1Tvc6MeuVQCaQ=
github.com/aws/aws-sdk-go-v2/service/sso v1.23.0/go.mod h1:XRlMvmad0ZNL+75C5FYdMvbbLkd6qiqz6foR1nA1PXY=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.0 h1:cU/OeQPNReyMj1JEBgjE29aclYZYtXcsPMXbTkVGMFk=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.0/go.mod h1:FnvDM4sfa+isJ3kDXIzAB9GAwVSzFzSy97uZ3IsHo4E=
github.com/aws/aws-sdk-go-v2/service/sts v1.31.0 h1:GNVxIHBTi2EgwCxpNiozhNasMOK+ROUA2Z3X+cSBX58=
github.com/aws/aws-sdk-go-v2/service/sts v1.31.0/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI=
github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA=
github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
@ -103,8 +103,9 @@ github.com/coreos/go-oidc/v3 v3.11.0 h1:Ia3MxdwpSw702YW0xgfmP1GVCMA9aEFWu12XUZ3/
github.com/coreos/go-oidc/v3 v3.11.0/go.mod h1:gE3LgjOgFoHi9a4ce4/tJczr0Ai2/BoDhf0r5lltWI0=
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc=
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
@ -316,8 +317,8 @@ github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg=
github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
github.com/prometheus/client_golang v1.20.3 h1:oPksm4K8B+Vt35tUhw6GbSNSgVlVSBH0qELP/7u83l4=
github.com/prometheus/client_golang v1.20.3/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI=
github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
@ -517,8 +518,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhSt0ABwskkZKjD3bXGnZGpNY=
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
google.golang.org/api v0.197.0 h1:x6CwqQLsFiA5JKAiGyGBjc2bNtHtLddhJCE2IKuhhcQ=
google.golang.org/api v0.197.0/go.mod h1:AuOuo20GoQ331nq7DquGHlU6d+2wN2fZ8O0ta60nRNw=
google.golang.org/api v0.198.0 h1:OOH5fZatk57iN0A7tjJQzt6aPfYQ1JiWkt1yGseazks=
google.golang.org/api v0.198.0/go.mod h1:/Lblzl3/Xqqk9hw/yS97TImKTUwnf1bv89v7+OagJzc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
@ -535,8 +536,8 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc v1.66.2 h1:3QdXkuq3Bkh7w+ywLdLvM56cmGvQHUMZpiCzt6Rqaoo=
google.golang.org/grpc v1.66.2/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y=
google.golang.org/grpc v1.67.0 h1:IdH9y6PF5MPSdAntIcpjQ+tXO41pcQsfZV2RxtQgVcw=
google.golang.org/grpc v1.67.0/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=

View file

@ -27,6 +27,7 @@ import (
"path/filepath"
"slices"
"sort"
"strconv"
"time"
bolt "go.etcd.io/bbolt"
@ -182,6 +183,50 @@ func (p *BoltProvider) updateAPIKeyLastUse(keyID string) error {
})
}
func (p *BoltProvider) getAdminSignature(username string) (string, error) {
var updatedAt int64
err := p.dbHandle.View(func(tx *bolt.Tx) error {
bucket, err := p.getAdminsBucket(tx)
if err != nil {
return err
}
u := bucket.Get([]byte(username))
var admin Admin
err = json.Unmarshal(u, &admin)
if err != nil {
return err
}
updatedAt = admin.UpdatedAt
return nil
})
if err != nil {
return "", err
}
return strconv.FormatInt(updatedAt, 10), nil
}
func (p *BoltProvider) getUserSignature(username string) (string, error) {
var updatedAt int64
err := p.dbHandle.View(func(tx *bolt.Tx) error {
bucket, err := p.getUsersBucket(tx)
if err != nil {
return err
}
u := bucket.Get([]byte(username))
var user User
err = json.Unmarshal(u, &user)
if err != nil {
return err
}
updatedAt = user.UpdatedAt
return nil
})
if err != nil {
return "", err
}
return strconv.FormatInt(updatedAt, 10), nil
}
func (p *BoltProvider) setUpdatedAt(username string) {
p.dbHandle.Update(func(tx *bolt.Tx) error { //nolint:errcheck
bucket, err := p.getUsersBucket(tx)

View file

@ -783,6 +783,8 @@ type Provider interface {
updateLastLogin(username string) error
updateAdminLastLogin(username string) error
setUpdatedAt(username string)
getAdminSignature(username string) (string, error)
getUserSignature(username string) (string, error)
getFolders(limit, offset int, order string, minimal bool) ([]vfs.BaseVirtualFolder, error)
getFolderByName(name string) (vfs.BaseVirtualFolder, error)
addFolder(folder *vfs.BaseVirtualFolder) error
@ -2098,6 +2100,20 @@ func UserExists(username, role string) (User, error) {
return provider.userExists(username, role)
}
// GetAdminSignature returns the signature for the admin with the specified
// username.
func GetAdminSignature(username string) (string, error) {
username = config.convertName(username)
return provider.getAdminSignature(username)
}
// GetUserSignature returns the signature for the user with the specified
// username.
func GetUserSignature(username string) (string, error) {
username = config.convertName(username)
return provider.getUserSignature(username)
}
// GetUserWithGroupSettings tries to return the user with the specified username
// loading also the group settings
func GetUserWithGroupSettings(username, role string) (User, error) {

View file

@ -24,6 +24,7 @@ import (
"path/filepath"
"slices"
"sort"
"strconv"
"sync"
"time"
@ -207,6 +208,32 @@ func (p *MemoryProvider) updateAPIKeyLastUse(keyID string) error {
return nil
}
func (p *MemoryProvider) getAdminSignature(username string) (string, error) {
p.dbHandle.Lock()
defer p.dbHandle.Unlock()
if p.dbHandle.isClosed {
return "", errMemoryProviderClosed
}
admin, err := p.adminExistsInternal(username)
if err != nil {
return "", err
}
return strconv.FormatInt(admin.UpdatedAt, 10), nil
}
func (p *MemoryProvider) getUserSignature(username string) (string, error) {
p.dbHandle.Lock()
defer p.dbHandle.Unlock()
if p.dbHandle.isClosed {
return "", errMemoryProviderClosed
}
user, err := p.userExistsInternal(username)
if err != nil {
return "", err
}
return strconv.FormatInt(user.UpdatedAt, 10), nil
}
func (p *MemoryProvider) setUpdatedAt(username string) {
p.dbHandle.Lock()
defer p.dbHandle.Unlock()

View file

@ -325,6 +325,14 @@ func (p *MySQLProvider) getUsedQuota(username string) (int, int64, int64, int64,
return sqlCommonGetUsedQuota(username, p.dbHandle)
}
func (p *MySQLProvider) getAdminSignature(username string) (string, error) {
return sqlCommonGetAdminSignature(username, p.dbHandle)
}
func (p *MySQLProvider) getUserSignature(username string) (string, error) {
return sqlCommonGetUserSignature(username, p.dbHandle)
}
func (p *MySQLProvider) setUpdatedAt(username string) {
sqlCommonSetUpdatedAt(username, p.dbHandle)
}

View file

@ -343,6 +343,14 @@ func (p *PGSQLProvider) getUsedQuota(username string) (int, int64, int64, int64,
return sqlCommonGetUsedQuota(username, p.dbHandle)
}
func (p *PGSQLProvider) getAdminSignature(username string) (string, error) {
return sqlCommonGetAdminSignature(username, p.dbHandle)
}
func (p *PGSQLProvider) getUserSignature(username string) (string, error) {
return sqlCommonGetUserSignature(username, p.dbHandle)
}
func (p *PGSQLProvider) setUpdatedAt(username string) {
sqlCommonSetUpdatedAt(username, p.dbHandle)
}

View file

@ -23,6 +23,7 @@ import (
"fmt"
"net/netip"
"runtime/debug"
"strconv"
"strings"
"time"
@ -1248,6 +1249,32 @@ func sqlCommonUpdateQuota(username string, filesAdd int, sizeAdd int64, reset bo
return err
}
func sqlCommonGetAdminSignature(username string, dbHandle *sql.DB) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
defer cancel()
q := getAdminSignatureQuery()
var updatedAt int64
err := dbHandle.QueryRowContext(ctx, q, username).Scan(&updatedAt)
if err != nil {
return "", err
}
return strconv.FormatInt(updatedAt, 10), nil
}
func sqlCommonGetUserSignature(username string, dbHandle *sql.DB) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
defer cancel()
q := getUserSignatureQuery()
var updatedAt int64
err := dbHandle.QueryRowContext(ctx, q, username).Scan(&updatedAt)
if err != nil {
return "", err
}
return strconv.FormatInt(updatedAt, 10), nil
}
func sqlCommonGetUsedQuota(username string, dbHandle *sql.DB) (int, int64, int64, int64, error) {
ctx, cancel := context.WithTimeout(context.Background(), defaultSQLQueryTimeout)
defer cancel()

View file

@ -246,6 +246,14 @@ func (p *SQLiteProvider) getUsedQuota(username string) (int, int64, int64, int64
return sqlCommonGetUsedQuota(username, p.dbHandle)
}
func (p *SQLiteProvider) getAdminSignature(username string) (string, error) {
return sqlCommonGetAdminSignature(username, p.dbHandle)
}
func (p *SQLiteProvider) getUserSignature(username string) (string, error) {
return sqlCommonGetUserSignature(username, p.dbHandle)
}
func (p *SQLiteProvider) setUpdatedAt(username string) {
sqlCommonSetUpdatedAt(username, p.dbHandle)
}

View file

@ -650,6 +650,14 @@ func getUpdateQuotaQuery(reset bool) string {
WHERE username = %s`, sqlTableUsers, sqlPlaceholders[0], sqlPlaceholders[1], sqlPlaceholders[2], sqlPlaceholders[3])
}
func getAdminSignatureQuery() string {
return fmt.Sprintf(`SELECT updated_at FROM %s WHERE username = %s`, sqlTableAdmins, sqlPlaceholders[0])
}
func getUserSignatureQuery() string {
return fmt.Sprintf(`SELECT updated_at FROM %s WHERE username = %s`, sqlTableUsers, sqlPlaceholders[0])
}
func getSetUpdateAtQuery() string {
return fmt.Sprintf(`UPDATE %s SET updated_at = %s WHERE username = %s`, sqlTableUsers, sqlPlaceholders[0], sqlPlaceholders[1])
}

View file

@ -45,11 +45,10 @@ const (
tokenAudienceWebLogin tokenAudience = "WebLogin"
)
type tokenValidation = int
const (
tokenValidationFull = iota
tokenValidationNoIPMatch tokenValidation = iota
tokenValidationModeDefault = 0
tokenValidationModeNoIPMatch = 1
tokenValidationModeUserSignature = 2
)
const (
@ -74,7 +73,7 @@ var (
// with the login form
csrfTokenDuration = 4 * time.Hour
tokenRefreshThreshold = 10 * time.Minute
tokenValidationMode = tokenValidationFull
tokenValidationMode = tokenValidationModeDefault
)
type jwtTokenClaims struct {
@ -567,10 +566,51 @@ func verifyOAuth2Token(csrfTokenAuth *jwtauth.JWTAuth, tokenString, ip string) (
}
func validateIPForToken(token jwt.Token, ip string) error {
if tokenValidationMode != tokenValidationNoIPMatch {
if tokenValidationMode&tokenValidationModeNoIPMatch == 0 {
if !slices.Contains(token.Audience(), ip) {
return errInvalidToken
}
}
return nil
}
func checkTokenSignature(r *http.Request, token jwt.Token) error {
if _, ok := r.Context().Value(oidcTokenKey).(string); ok {
return nil
}
var err error
if tokenValidationMode&tokenValidationModeUserSignature != 0 {
for _, audience := range token.Audience() {
switch audience {
case tokenAudienceAPI, tokenAudienceWebAdmin:
err = validateSignatureForToken(token, dataprovider.GetAdminSignature)
case tokenAudienceAPIUser, tokenAudienceWebClient:
err = validateSignatureForToken(token, dataprovider.GetUserSignature)
}
}
}
if err != nil {
invalidateToken(r, false)
}
return err
}
func validateSignatureForToken(token jwt.Token, getter func(string) (string, error)) error {
username := ""
if u, ok := token.Get(claimUsernameKey); ok {
c := jwtTokenClaims{}
username = c.decodeString(u)
}
signature, err := getter(username)
if err != nil {
logger.Debug(logSender, "", "unable to get signature for username %q: %v", username, err)
return errInvalidToken
}
if signature != "" && signature == token.Subject() {
return nil
}
logger.Debug(logSender, "", "signature mismatch for username %q, signature %q, token signature %q",
username, signature, token.Subject())
return errInvalidToken
}

View file

@ -967,11 +967,7 @@ func (c *Conf) getKeyPairs(configDir string) []common.TLSKeyPair {
}
func (c *Conf) setTokenValidationMode() {
if c.TokenValidation == 1 {
tokenValidationMode = tokenValidationNoIPMatch
} else {
tokenValidationMode = tokenValidationFull
}
tokenValidationMode = c.TokenValidation
}
func (c *Conf) loadFromProvider() error {

View file

@ -48,6 +48,7 @@ import (
"github.com/sftpgo/sdk/plugin/notifier"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/net/html"
"github.com/drakkan/sftpgo/v2/internal/acme"
"github.com/drakkan/sftpgo/v2/internal/common"
@ -285,6 +286,7 @@ RKjnkiEZeG4+G91Xu7+HmcBLwV86k5I+tXK9O1Okomr6Zry8oqVcxU5TB6VRS+rA
ubwF00Drdvk2+kDZfxIM137nBiy7wgCJi2Ksm5ihN3dUF6Q0oNPl
-----END RSA PRIVATE KEY-----`
defaultAdminUsername = "admin"
defaultAdminPass = "password"
defeaultUsername = "test_user"
)
@ -945,6 +947,172 @@ func TestInvalidToken(t *testing.T) {
assert.Contains(t, rr.Body.String(), util.I18nErrorInvalidToken)
}
func TestTokenSignatureValidation(t *testing.T) {
tokenValidationMode = 0
server := httpdServer{
binding: Binding{
Address: "",
Port: 8080,
EnableWebAdmin: true,
EnableWebClient: true,
EnableRESTAPI: true,
},
enableWebAdmin: true,
enableWebClient: true,
enableRESTAPI: true,
}
server.initializeRouter()
testServer := httptest.NewServer(server.router)
defer testServer.Close()
rr := httptest.NewRecorder()
req, err := http.NewRequest(http.MethodGet, tokenPath, nil)
require.NoError(t, err)
req.SetBasicAuth(defaultAdminUsername, defaultAdminPass)
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
var resp map[string]any
err = json.Unmarshal(rr.Body.Bytes(), &resp)
assert.NoError(t, err)
accessToken := resp["access_token"]
require.NotEmpty(t, accessToken)
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, versionPath, nil)
require.NoError(t, err)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
// change the token validation mode
tokenValidationMode = 2
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, versionPath, nil)
require.NoError(t, err)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
// Now update the admin
admin, err := dataprovider.AdminExists(defaultAdminUsername)
assert.NoError(t, err)
err = dataprovider.UpdateAdmin(&admin, "", "", "")
assert.NoError(t, err)
// token validation mode is 0, the old token is still valid
tokenValidationMode = 0
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, versionPath, nil)
require.NoError(t, err)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
// change the token validation mode
tokenValidationMode = 2
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, versionPath, nil)
require.NoError(t, err)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusUnauthorized, rr.Code)
// the token is invalidated, changing the validation mode has no effect
tokenValidationMode = 0
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, versionPath, nil)
require.NoError(t, err)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", accessToken))
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusUnauthorized, rr.Code)
userPwd := "pwd"
user := dataprovider.User{
BaseUser: sdk.BaseUser{
Username: defeaultUsername,
Password: userPwd,
HomeDir: filepath.Join(os.TempDir(), defeaultUsername),
Status: 1,
},
}
user.Permissions = make(map[string][]string)
user.Permissions["/"] = []string{dataprovider.PermAny}
err = dataprovider.AddUser(&user, "", "", "")
assert.NoError(t, err)
defer func() {
dataprovider.DeleteUser(defeaultUsername, "", "", "") //nolint:errcheck
}()
tokenValidationMode = 2
req, err = http.NewRequest(http.MethodGet, webClientLoginPath, nil)
require.NoError(t, err)
rr = httptest.NewRecorder()
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
loginCookie := strings.Split(rr.Header().Get("Set-Cookie"), ";")[0]
assert.NotEmpty(t, loginCookie)
csrfToken, err := getCSRFTokenFromBody(rr.Body)
assert.NoError(t, err)
assert.NotEmpty(t, csrfToken)
// Now login
form := make(url.Values)
form.Set(csrfFormToken, csrfToken)
form.Set("username", defeaultUsername)
form.Set("password", userPwd)
req, err = http.NewRequest(http.MethodPost, webClientLoginPath, bytes.NewBuffer([]byte(form.Encode())))
assert.NoError(t, err)
req.Header.Set("Cookie", loginCookie)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
rr = httptest.NewRecorder()
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusFound, rr.Code)
userCookie := strings.Split(rr.Header().Get("Set-Cookie"), ";")[0]
assert.NotEmpty(t, userCookie)
// Test a WebClient page and a JSON API
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, webClientFilesPath, nil)
require.NoError(t, err)
req.Header.Set("Cookie", userCookie)
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, webClientProfilePath, nil)
require.NoError(t, err)
req.Header.Set("Cookie", userCookie)
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code)
csrfToken, err = getCSRFTokenFromBody(rr.Body)
assert.NoError(t, err)
assert.NotEmpty(t, csrfToken)
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, webClientFilePath+"?path=missing.txt", nil)
require.NoError(t, err)
req.Header.Set("Cookie", userCookie)
req.Header.Set(csrfHeaderToken, csrfToken)
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusNotFound, rr.Code)
tokenValidationMode = 0
err = dataprovider.DeleteUser(defeaultUsername, "", "", "")
assert.NoError(t, err)
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, webClientFilePath+"?path=missing.txt", nil)
require.NoError(t, err)
req.Header.Set("Cookie", userCookie)
req.Header.Set(csrfHeaderToken, csrfToken)
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusNotFound, rr.Code)
tokenValidationMode = 2
rr = httptest.NewRecorder()
req, err = http.NewRequest(http.MethodGet, webClientFilePath+"?path=missing.txt", nil)
require.NoError(t, err)
req.Header.Set("Cookie", userCookie)
req.Header.Set(csrfHeaderToken, csrfToken)
testServer.Config.Handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusFound, rr.Code)
tokenValidationMode = 0
}
func TestUpdateWebAdminInvalidClaims(t *testing.T) {
server := httpdServer{}
server.initializeRouter()
@ -3848,6 +4016,46 @@ func TestI18NErrors(t *testing.T) {
assert.Equal(t, `{"a":"b"}`, errI18n.Args())
}
func getCSRFTokenFromBody(body io.Reader) (string, error) {
doc, err := html.Parse(body)
if err != nil {
return "", err
}
var csrfToken string
var f func(*html.Node)
f = func(n *html.Node) {
if n.Type == html.ElementNode && n.Data == "input" {
var name, value string
for _, attr := range n.Attr {
if attr.Key == "value" {
value = attr.Val
}
if attr.Key == "name" {
name = attr.Val
}
}
if name == csrfFormToken {
csrfToken = value
return
}
}
for c := n.FirstChild; c != nil; c = c.NextSibling {
f(c)
}
}
f(doc)
if csrfToken == "" {
return "", errors.New("CSRF token not found")
}
return csrfToken, nil
}
func isSharedProviderSupported() bool {
// SQLite shares the implementation with other SQL-based provider but it makes no sense
// to use it outside test cases

View file

@ -95,6 +95,10 @@ func validateJWTToken(w http.ResponseWriter, r *http.Request, audience tokenAudi
doRedirect("Your token is not valid", nil)
return err
}
if err := checkTokenSignature(r, token); err != nil {
doRedirect("Your token is no longer valid", nil)
return err
}
return nil
}

View file

@ -135,6 +135,8 @@ func TestOIDCInitialization(t *testing.T) {
}
func TestOIDCLoginLogout(t *testing.T) {
tokenValidationMode = 2
oidcMgr, ok := oidcMgr.(*memoryOIDCManager)
require.True(t, ok)
server := getTestOIDCServer()
@ -552,6 +554,8 @@ func TestOIDCLoginLogout(t *testing.T) {
assert.NoError(t, err)
err = dataprovider.DeleteUser(username, "", "", "")
assert.NoError(t, err)
tokenValidationMode = 0
}
func TestOIDCRefreshToken(t *testing.T) {