sftpd: refactor multi-step authentication

Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
Nicola Murino 2023-08-04 20:56:23 +02:00
parent c03bcb3a8a
commit af0d7b48ad
No known key found for this signature in database
GPG key ID: 935D2952DEC4EECF
9 changed files with 195 additions and 231 deletions

64
go.mod
View file

@ -9,15 +9,15 @@ require (
github.com/GehirnInc/crypt v0.0.0-20230320061759-8cc1b52080c5
github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736
github.com/amoghe/go-crypt v0.0.0-20220222110647-20eada5f5964
github.com/aws/aws-sdk-go-v2 v1.19.1
github.com/aws/aws-sdk-go-v2/config v1.18.30
github.com/aws/aws-sdk-go-v2/credentials v1.13.29
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.6
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.74
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.15
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.1
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.12
github.com/aws/aws-sdk-go-v2/service/sts v1.20.1
github.com/aws/aws-sdk-go-v2 v1.20.0
github.com/aws/aws-sdk-go-v2/config v1.18.32
github.com/aws/aws-sdk-go-v2/credentials v1.13.31
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.15.1
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.20.1
github.com/aws/aws-sdk-go-v2/service/sts v1.21.1
github.com/bmatcuk/doublestar/v4 v4.6.0
github.com/cockroachdb/cockroach-go/v2 v2.3.5
github.com/coreos/go-oidc/v3 v3.6.0
@ -54,7 +54,7 @@ require (
github.com/rs/xid v1.5.0
github.com/rs/zerolog v1.30.0
github.com/sftpgo/sdk v0.1.5
github.com/shirou/gopsutil/v3 v3.23.6
github.com/shirou/gopsutil/v3 v3.23.7
github.com/spf13/afero v1.9.5
github.com/spf13/cobra v1.7.0
github.com/spf13/viper v1.16.0
@ -67,36 +67,36 @@ require (
github.com/yl2chen/cidranger v1.0.3-0.20210928021809-d1cb2c52f37a
go.etcd.io/bbolt v1.3.7
go.uber.org/automaxprocs v1.5.3
gocloud.dev v0.32.0
gocloud.dev v0.33.0
golang.org/x/crypto v0.11.0
golang.org/x/net v0.12.0
golang.org/x/net v0.13.0
golang.org/x/oauth2 v0.10.0
golang.org/x/sys v0.10.0
golang.org/x/term v0.10.0
golang.org/x/sys v0.11.0
golang.org/x/term v0.11.0
golang.org/x/time v0.3.0
google.golang.org/api v0.134.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
require (
cloud.google.com/go v0.110.6 // indirect
cloud.google.com/go v0.110.7 // indirect
cloud.google.com/go/compute v1.23.0 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.3.0 // indirect
github.com/ajg/form v1.5.1 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.36 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.30 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.37 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.28 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.31 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.30 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.12.14 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.14 // indirect
github.com/aws/smithy-go v1.13.5 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.13.1 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1 // indirect
github.com/aws/smithy-go v1.14.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/boombuler/barcode v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
@ -158,13 +158,13 @@ require (
go.opencensus.io v0.24.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/text v0.11.0 // indirect
golang.org/x/text v0.12.0 // indirect
golang.org/x/tools v0.11.1 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e // indirect
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 // indirect
google.golang.org/grpc v1.57.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
@ -174,5 +174,5 @@ require (
replace (
github.com/jlaffaye/ftp => github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9
github.com/robfig/cron/v3 => github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20230614155948-29e7be6c0fab
golang.org/x/crypto => github.com/drakkan/crypto v0.0.0-20230804183749-f40d052136b8
)

131
go.sum
View file

@ -17,8 +17,8 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.110.6 h1:8uYAkj3YHTP/1iwReuHPxLSbdcyc+dSBbzFMrVwDR6Q=
cloud.google.com/go v0.110.6/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go v0.110.7 h1:rJyC7nWRg2jWGZ4wSJ5nY65GTdYJkg0cd/uXb+ACI6o=
cloud.google.com/go v0.110.7/go.mod h1:+EYjdK8e5RME/VY/qLCAtuyALQ9q67dvuum8i+H5xsI=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@ -33,7 +33,7 @@ cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/iam v1.1.1 h1:lW7fzj15aVIXYHREOqjRBV9PsH0Z6u8Y46a1YGvQP4Y=
cloud.google.com/go/iam v1.1.1/go.mod h1:A5avdyVL2tCppe4unb0951eI9jreack+RJ0/d+KUZOU=
cloud.google.com/go/kms v1.14.0 h1:B/F3X7OzZ2pFlKsJc0+5sbHV/k45+ITKIHH5l/HGUf4=
cloud.google.com/go/kms v1.15.0 h1:xYl5WEaSekKYN5gGRyhjvZKM22GVBBCzegGNVPy+aIs=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@ -68,48 +68,48 @@ github.com/alexedwards/argon2id v0.0.0-20230305115115-4b3c3280a736/go.mod h1:mTe
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/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/aws/aws-sdk-go-v2 v1.19.1 h1:STs0lbbpXu3byTPcnRLghs2DH0yk9qKDo27TyyJSKsM=
github.com/aws/aws-sdk-go-v2 v1.19.1/go.mod h1:uzbQtefpm44goOPmdKyAlXSNcwlRgF3ePWVW6EtJvvw=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10 h1:dK82zF6kkPeCo8J1e+tGx4JdvDIQzj7ygIoLg8WMuGs=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.10/go.mod h1:VeTZetY5KRJLuD/7fkQXMU6Mw7H5m/KP2J5Iy9osMno=
github.com/aws/aws-sdk-go-v2/config v1.18.30 h1:TTAXQIn31qYFUQjkW6siVrRTX1ux+sADZDOe3jsZcMg=
github.com/aws/aws-sdk-go-v2/config v1.18.30/go.mod h1:+YogjT7e/t9JVu/sOnZZgxTge1G+bPNk8zOaI0QIQvE=
github.com/aws/aws-sdk-go-v2/credentials v1.13.29 h1:KNgCpThGuZyCjq9EuuqoLDenKKMwO/x1Xx01ckDa7VI=
github.com/aws/aws-sdk-go-v2/credentials v1.13.29/go.mod h1:VMq1LcmSEa9qxBlOCYTjVuGJWEEzhGmgL552jQsmhss=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.6 h1:kortK122LvTU34CGX/F9oJpelXKkEA2j/MW48II+8+8=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.6/go.mod h1:k7IPHyHNIASI0m0RwOmCjWOTtgG+J0raqwuHH8WhWJE=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.74 h1:5iIuHdeN3/x3kFBENHgYQl1ZtD+ZhLBXy6IgXflUtSI=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.74/go.mod h1:kBEg7nSM1Dg9tsHX5eoFeJMmO+njnFOwxP0dPuQCEGc=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.36 h1:kbk81RlPoC6e4co7cQx2FAvH9TgbzxIqCqiosAFiB+w=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.36/go.mod h1:T8Jsn/uNL/AFOXrVYQ1YQaN1r9gN34JU1855/Lyjv+o=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.30 h1:lMl8S5SB8jNCB+Sty2Em4lnu3IJytceHQd7qbmfqKL0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.30/go.mod h1:v3GSCnFxbHzt9dlWBqvA1K1f9lmWuf4ztupZBCAIVs4=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.37 h1:BXiqvN7WuV/pMhz8CivhO8cG8icJcjnjHumif4ukQ0c=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.37/go.mod h1:d4GZ62cjnz/hjKFdAu11gAwK73bdhqaFv2O4J1gaqIs=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.28 h1:mGA+qm0tiLaZ04PfQtxthU3XTZ1sN44YlqVjd+1E+Pk=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.28/go.mod h1:KkWH+0gAmvloVXaVjdY6/LLwQV6TjYOZ1j5JdVm+XBc=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11 h1:y2+VQzC6Zh2ojtV2LoC0MNwHWc6qXv/j2vrQtlftkdA=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.11/go.mod h1:iV4q2hsqtNECrfmlXyord9u4zyuFEJX9eLgLpSPzWA8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.31 h1:TGjmYwqqE6dMDSUSyQNct4MyTAgz95bPnDAjBOEgwOI=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.31/go.mod h1:HvfQ61vGBanxBijrBIpyG32mS9w6fsPZa+BwtV1uQUY=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.30 h1:UcVZxLVNY4yayCmiG94Ge3l2qbc5WEB/oa4RmjoQEi0=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.30/go.mod h1:wPffyJiWWtHwvpFyn23WjAjVjMnlQOQrl02+vutBh3Y=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.5 h1:B90htdoSv7OMH6QzzZ9cuZUoXVwFml0fTCDOpcGakCw=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.14.5/go.mod h1:fdxqVm1S6xQa6obwHysh1GPowmyqO2pQuaRPWdyG2iQ=
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.15 h1:SdxyyE0gwqsVSHh0zeKA4udOGtJ1q9bDtIXYIiYMP3A=
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.14.15/go.mod h1:fdYccRnIDMa4bkwRKpWAY4jdOTKHlDUGtPLr8FjPnxs=
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.1 h1:OoFnDN7ZixctMX/Do4DgQXFvjtzQynz0p0ErQrOCeAs=
github.com/aws/aws-sdk-go-v2/service/s3 v1.37.1/go.mod h1:fBgi8xY80Fv2EveXOoTM008OhKdjrxxtVH0w0h0ozYU=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.12 h1:2C2a9VVs2Ob1I09GsmsKVvmlw5aebPj4yGfJX8EWMrk=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.19.12/go.mod h1:cglZ7TL22WrrkFCyDqD0X8GrByvmkOXXfkcRjj0ZkVA=
github.com/aws/aws-sdk-go-v2/service/sso v1.12.14 h1:gUjz7trfz9qBm0AlkKTvJHBXELi1wvw+2LA9GfD2AsM=
github.com/aws/aws-sdk-go-v2/service/sso v1.12.14/go.mod h1:9kfRdJgLCbnyeqZ/DpaSwcgj9ZDYLfRpe8Sze+NrYfQ=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.14 h1:8bEtxV5UT9ucdWGXfZ7CM3caQhSHGjWnTHt0OeF7m7s=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.14.14/go.mod h1:nd9BG2UnexN2sDx/mk2Jd6pf3d2E61AiA8m8Fdvdx8Y=
github.com/aws/aws-sdk-go-v2/service/sts v1.20.1 h1:U7h9CPoyMfVoN5jUglB0LglCMP10AK4vMBsbsCKM8Yw=
github.com/aws/aws-sdk-go-v2/service/sts v1.20.1/go.mod h1:BUHusg4cOA1TFGegj7x8/eoWrbdHzJfoMrXcbMQAG0k=
github.com/aws/smithy-go v1.13.5 h1:hgz0X/DX0dGqTYpGALqXJoRKRj5oQ7150i5FdTePzO8=
github.com/aws/smithy-go v1.13.5/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
github.com/aws/aws-sdk-go-v2 v1.20.0 h1:INUDpYLt4oiPOJl0XwZDK2OVAVf0Rzo+MGVTv9f+gy8=
github.com/aws/aws-sdk-go-v2 v1.20.0/go.mod h1:uWOr0m0jDsiWw8nnXiqZ+YG6LdvAlGYDLLf2NmHZoy4=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11 h1:/MS8AzqYNAhhRNalOmxUvYs8VEbNGifTnzhPFdcRQkQ=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.11/go.mod h1:va22++AdXht4ccO3kH2SHkHHYvZ2G9Utz+CXKmm2CaU=
github.com/aws/aws-sdk-go-v2/config v1.18.32 h1:tqEOvkbTxwEV7hToRcJ1xZRjcATqwDVsWbAscgRKyNI=
github.com/aws/aws-sdk-go-v2/config v1.18.32/go.mod h1:U3ZF0fQRRA4gnbn9GGvOWLoT2EzzZfAWeKwnVrm1rDc=
github.com/aws/aws-sdk-go-v2/credentials v1.13.31 h1:vJyON3lG7R8VOErpJJBclBADiWTwzcwdkQpTKx8D2sk=
github.com/aws/aws-sdk-go-v2/credentials v1.13.31/go.mod h1:T4sESjBtY2lNxLgkIASmeP57b5j7hTQqCbqG0tWnxC4=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7 h1:X3H6+SU21x+76LRglk21dFRgMTJMa5QcpW+SqUf5BBg=
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.7/go.mod h1:3we0V09SwcJBzNlnyovrR2wWJhWmVdqAsmVs4uronv8=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76 h1:DJ1kHj0GI9BbX+XhF0kHxlzOVjcncmDUXmCvXdbfdAE=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.76/go.mod h1:/AZCdswMSgwpB2yMSFfY5H4pVeBLnCuPehdmO/r3xSM=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37 h1:zr/gxAZkMcvP71ZhQOcvdm8ReLjFgIXnIn0fw5AM7mo=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37/go.mod h1:Pdn4j43v49Kk6+82spO3Tu5gSeQXRsxo56ePPQAvFiA=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31 h1:0HCMIkAkVY9KMgueD8tf4bRTUanzEYvhw7KkPXIMpO0=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.31/go.mod h1:fTJDMe8LOFYtqiFFFeHA+SVMAwqLhoq0kcInYoLa9Js=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38 h1:+i1DOFrW3YZ3apE45tCal9+aDKK6kNEbW6Ib7e1nFxE=
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.38/go.mod h1:1/jLp0OgOaWIetycOmycW+vYTYgTZFPttJQRgsI1PoU=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0 h1:U5yySdwt2HPo/pnQec04DImLzWORbeWML1fJiLkKruI=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.0/go.mod h1:EhC/83j8/hL/UB1WmExo3gkElaja/KlmZM/gl1rTfjM=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12 h1:uAiiHnWihGP2rVp64fHwzLDrswGjEjsPszwRYMiYQPU=
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.12/go.mod h1:fUTHpOXqRQpXvEpDPSa3zxCc2fnpW6YnBoba+eQr+Bg=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32 h1:kvN1jPHr9UffqqG3bSgZ8tx4+1zKVHz/Ktw/BwW6hX8=
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.32/go.mod h1:QmMEM7es84EUkbYWcpnkx8i5EW2uERPfrTFeOch128Y=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31 h1:auGDJ0aLZahF5SPvkJ6WcUuX7iQ7kyl2MamV7Tm8QBk=
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.31/go.mod h1:3+lloe3sZuBQw1aBc5MyndvodzQlyqCZ7x1QPDHaWP4=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0 h1:Wgjft9X4W5pMeuqgPCHIQtbZ87wsgom7S5F8obreg+c=
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.0/go.mod h1:FWNzS4+zcWAP05IF7TDYTY1ysZAzIvogxWaDT9p8fsA=
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.15.1 h1:9KxXG9wQ7MzFtCsXDpNx1JdtefTxKA0WnmaBsJXp84g=
github.com/aws/aws-sdk-go-v2/service/marketplacemetering v1.15.1/go.mod h1:2YAQv2BTTVhRlYOcHHyxAgPc6/N5I20QhKpqiu+3B2k=
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1 h1:mTgFVlfQT8gikc5+/HwD8UL9jnUro5MGv8n/VEYF12I=
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.1/go.mod h1:6SOWLiobcZZshbmECRTADIRYliPL0etqFSigauQEeT0=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.20.1 h1:AD8gRAXAXDU9+XTm0Q3D+NBsMCX4TlpN/qnNYbbQLO4=
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.20.1/go.mod h1:aFRHxQ3V4bs/uVQYpg8Wm6szKWuB2KnraKcIGp5JS/I=
github.com/aws/aws-sdk-go-v2/service/sso v1.13.1 h1:DSNpSbfEgFXRV+IfEcKE5kTbqxm+MeF5WgyeRlsLnHY=
github.com/aws/aws-sdk-go-v2/service/sso v1.13.1/go.mod h1:TC9BubuFMVScIU+TLKamO6VZiYTkYoEHqlSQwAe2omw=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1 h1:hd0SKLMdOL/Sl6Z0np1PX9LeH2gqNtBe0MhTedA8MGI=
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.1/go.mod h1:XO/VcyoQ8nKyKfFW/3DMsRQXsfh/052tHTWmg3xBXRg=
github.com/aws/aws-sdk-go-v2/service/sts v1.21.1 h1:pAOJj+80tC8sPVgSDHzMYD6KLWsaLQ1kZw31PTeORbs=
github.com/aws/aws-sdk-go-v2/service/sts v1.21.1/go.mod h1:G8SbvL0rFk4WOJroU8tKBczhsbhj2p/YY7qeJezJ3CI=
github.com/aws/smithy-go v1.14.0 h1:+X90sB94fizKjDmwb4vyl2cTTPXTE5E2G/1mjByb0io=
github.com/aws/smithy-go v1.14.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
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.0 h1:HTuxyug8GyFbRkrffIpzNCSK4luc0TY3wzXvzIZhEXc=
@ -151,8 +151,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0 h1:EW9gIJRmt9lzk66Fhh4S8VEtURA6QHZqGeSRE9Nb2/U=
github.com/drakkan/cron/v3 v3.0.0-20230222140221-217a1e4d96c0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/drakkan/crypto v0.0.0-20230614155948-29e7be6c0fab h1:6Oao/qdhMBSZdueKl/szzRKpGJ4qX7MeF6Q2z1ogJ18=
github.com/drakkan/crypto v0.0.0-20230614155948-29e7be6c0fab/go.mod h1:hoUAJL8P6kTML1aXtBlnY0EVZ7KH7o2rGfeDdbD62QI=
github.com/drakkan/crypto v0.0.0-20230804183749-f40d052136b8 h1:TUieQf6mz4xlWJavIb0peBYKQa9KhwvMkBpESA5o/TQ=
github.com/drakkan/crypto v0.0.0-20230804183749-f40d052136b8/go.mod h1:jjOR8ZXZPvxgpYUhVmAtGUCuD1OFc5Hq984QRL686so=
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9 h1:LPH1dEblAOO/LoG7yHPMtBLXhQmjaga91/DDjWk9jWA=
github.com/drakkan/ftp v0.0.0-20201114075148-9b9adce499a9/go.mod h1:2lmrmq866uF2tnje75wQHzmPXhmSWUt7Gyx2vgK1RCU=
github.com/drakkan/webdav v0.0.0-20230227175313-32996838bcd8 h1:tdkLkSKtYd3WSDsZXGJDKsakiNstLQJPN5HjnqCkf2c=
@ -423,8 +423,8 @@ github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/sftpgo/sdk v0.1.5 h1:3vpE5wohtJvJKyPKB7smAMZiLjLyoJzbtIkYNyNh5iw=
github.com/sftpgo/sdk v0.1.5/go.mod h1:TjeoMWS0JEXt9RukJveTnaiHj4+MVLtUiDC+mY++Odk=
github.com/shirou/gopsutil/v3 v3.23.6 h1:5y46WPI9QBKBbK7EEccUPNXpJpNrvPuTD0O2zHEHT08=
github.com/shirou/gopsutil/v3 v3.23.6/go.mod h1:j7QX50DrXYggrpN30W0Mo+I4/8U2UUIQrnrhqUeWrAU=
github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4=
github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
@ -494,8 +494,8 @@ go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8=
go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0=
gocloud.dev v0.32.0 h1:jHf8WSkByuAuXcvFt04OiiQH+N0zaRtxI6iEph8Bq8Y=
gocloud.dev v0.32.0/go.mod h1:m/x/N9cRjDF5MD0i5TLFbKbqkGffl/qayXA9FcMT5Oc=
gocloud.dev v0.33.0 h1:ET5z49jm1+eUhY5BkuGk2d7czfgGeXKd4vtg1Jcg9OQ=
gocloud.dev v0.33.0/go.mod h1:z6W8qorjrfM09H8t1MDk8KLPj3Xi26aFBzDKAHWIgLU=
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=
@ -567,9 +567,8 @@ golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50=
golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
golang.org/x/net v0.13.0 h1:Nvo8UFsZ8X3BhAC9699Z1j7XQ3rsZnUUm7jfBEk1ueY=
golang.org/x/net v0.13.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA=
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=
@ -649,15 +648,15 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.11.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.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/term v0.10.0 h1:3R7pNqamzBraeqj/Tj8qt1aQ2HpmlC+Cx/qL/7hn4/c=
golang.org/x/term v0.10.0/go.mod h1:lpqdcUyK/oCiQxvxVrppt5ggO2KCZ5QblwqPnfZ6d5o=
golang.org/x/term v0.11.0 h1:F9tnn/DA/Im8nCwm+fX+1/eBwi4qFjRT++MhtVC4ZX0=
golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU=
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=
@ -667,9 +666,9 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4=
golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -799,12 +798,12 @@ google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e h1:xIXmWJ303kJCuogpj0bHq+dcjcZHU+XFyc1I0Yl9cRg=
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e h1:z3vDksarJxsAKM5dmEGv0GHwE2hKJ096wZra71Vs4sw=
google.golang.org/genproto/googleapis/api v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:rsr7RhLuwsDKL7RmgDDCUc6yaGr1iqceVb5Wv6f6YvQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e h1:S83+ibolgyZ0bqz7KEsUOPErxcv4VzlszxY+31OfB/E=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 h1:L6iMMGrtzgHsWofoFcihmDEMYeDR9KN/ThbPWGrh++g=
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5/go.mod h1:oH/ZOT02u4kWEp7oYBGYFFkCdKS/uYR9Z7+0/xuuFp8=
google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5 h1:nIgk/EEq3/YlnmVVXVnm14rC2oxgs1o0ong4sD/rd44=
google.golang.org/genproto/googleapis/api v0.0.0-20230803162519-f966b187b2e5/go.mod h1:5DZzOUPCLYL3mNkQ0ms0F3EuUNZ7py1Bqeq6sxzI7/Q=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5 h1:eSaPbMR4T7WfH9FvABk36NBMacoTUKdWCvV0dx+KfOg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230803162519-f966b187b2e5/go.mod h1:zBEcrKX2ZOcEkHWxBPAIvYUWOKKMIhYcmNiUIu2ji3I=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=

View file

@ -1131,7 +1131,7 @@ func CheckCachedUserCredentials(user *CachedUser, password, ip, loginMethod, pro
return user, nil, err
}
if loginMethod == LoginMethodTLSCertificate {
if !user.User.IsLoginMethodAllowed(LoginMethodTLSCertificate, protocol, nil) {
if !user.User.IsLoginMethodAllowed(LoginMethodTLSCertificate, protocol) {
return user, nil, fmt.Errorf("certificate login method is not allowed for user %q", user.User.Username)
}
return user, nil, nil
@ -1174,7 +1174,7 @@ func CheckCompositeCredentials(username, password, ip, loginMethod, protocol str
if err != nil {
return user, loginMethod, err
}
if loginMethod == LoginMethodTLSCertificate && !user.IsLoginMethodAllowed(LoginMethodTLSCertificate, protocol, nil) {
if loginMethod == LoginMethodTLSCertificate && !user.IsLoginMethodAllowed(LoginMethodTLSCertificate, protocol) {
return user, loginMethod, fmt.Errorf("certificate login method is not allowed for user %q", user.Username)
}
if loginMethod == LoginMethodTLSCertificateAndPwd {

View file

@ -894,17 +894,10 @@ func (u *User) HasNoQuotaRestrictions(checkFiles bool) bool {
}
// IsLoginMethodAllowed returns true if the specified login method is allowed
func (u *User) IsLoginMethodAllowed(loginMethod, protocol string, partialSuccessMethods []string) bool {
func (u *User) IsLoginMethodAllowed(loginMethod, protocol string) bool {
if len(u.Filters.DeniedLoginMethods) == 0 {
return true
}
if len(partialSuccessMethods) == 1 {
for _, method := range u.GetNextAuthMethods(partialSuccessMethods, true) {
if method == loginMethod {
return true
}
}
}
if util.Contains(u.Filters.DeniedLoginMethods, loginMethod) {
return false
}
@ -916,18 +909,13 @@ func (u *User) IsLoginMethodAllowed(loginMethod, protocol string, partialSuccess
return true
}
// GetNextAuthMethods returns the list of authentications methods that
// can continue for multi-step authentication
func (u *User) GetNextAuthMethods(partialSuccessMethods []string, isPasswordAuthEnabled bool) []string {
// GetNextAuthMethods returns the list of authentications methods that can
// continue for multi-step authentication. We call this method after a
// successful public key authentication.
func (u *User) GetNextAuthMethods() []string {
var methods []string
if len(partialSuccessMethods) != 1 {
return methods
}
if partialSuccessMethods[0] != SSHLoginMethodPublicKey {
return methods
}
for _, method := range u.GetAllowedLoginMethods() {
if method == SSHLoginMethodKeyAndPassword && isPasswordAuthEnabled {
if method == SSHLoginMethodKeyAndPassword {
methods = append(methods, LoginMethodPassword)
}
if method == SSHLoginMethodKeyAndKeyboardInt {
@ -942,10 +930,7 @@ func (u *User) GetNextAuthMethods(partialSuccessMethods []string, isPasswordAuth
// We support publickey+password and publickey+keyboard-interactive, so
// only publickey can returns partial success.
// We can have partial success if only multi-step Auth methods are enabled
func (u *User) IsPartialAuth(loginMethod string) bool {
if loginMethod != SSHLoginMethodPublicKey {
return false
}
func (u *User) IsPartialAuth() bool {
for _, method := range u.GetAllowedLoginMethods() {
if method == LoginMethodTLSCertificate || method == LoginMethodTLSCertificateAndPwd ||
method == SSHLoginMethodPassword {

View file

@ -274,7 +274,7 @@ func (s *Server) VerifyConnection(cc ftpserver.ClientContext, user string, tlsCo
s.setTLSConnVerified(cc.ID(), true)
if dbUser.IsLoginMethodAllowed(dataprovider.LoginMethodTLSCertificate, common.ProtocolFTP, nil) {
if dbUser.IsLoginMethodAllowed(dataprovider.LoginMethodTLSCertificate, common.ProtocolFTP) {
connection, err := s.validateUser(dbUser, cc, dataprovider.LoginMethodTLSCertificate)
defer updateLoginMetrics(&dbUser, ipAddr, dataprovider.LoginMethodTLSCertificate, err)
@ -371,7 +371,7 @@ func (s *Server) validateUser(user dataprovider.User, cc ftpserver.ClientContext
logger.Info(logSender, connectionID, "cannot login user %q, protocol FTP is not allowed", user.Username)
return nil, fmt.Errorf("protocol FTP is not allowed for user %q", user.Username)
}
if !user.IsLoginMethodAllowed(loginMethod, common.ProtocolFTP, nil) {
if !user.IsLoginMethodAllowed(loginMethod, common.ProtocolFTP) {
logger.Info(logSender, connectionID, "cannot login user %q, %v login method is not allowed",
user.Username, loginMethod)
return nil, fmt.Errorf("login method %v is not allowed for user %q", loginMethod, user.Username)

View file

@ -630,7 +630,7 @@ func checkHTTPClientUser(user *dataprovider.User, r *http.Request, connectionID
logger.Info(logSender, connectionID, "cannot login user %q, protocol HTTP is not allowed", user.Username)
return fmt.Errorf("protocol HTTP is not allowed for user %q", user.Username)
}
if !isLoggedInWithOIDC(r) && !user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolHTTP, nil) {
if !isLoggedInWithOIDC(r) && !user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolHTTP) {
logger.Info(logSender, connectionID, "cannot login user %q, password login method is not allowed", user.Username)
return fmt.Errorf("login method password is not allowed for user %q", user.Username)
}
@ -764,7 +764,7 @@ func isUserAllowedToResetPassword(r *http.Request, user *dataprovider.User) bool
if util.Contains(user.Filters.DeniedProtocols, common.ProtocolHTTP) {
return false
}
if !user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolHTTP, nil) {
if !user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolHTTP) {
return false
}
if !user.IsLoginFromAddrAllowed(r.RemoteAddr) {

View file

@ -271,7 +271,7 @@ func (c *Configuration) getServerConfig() *ssh.ServerConfig {
MaxAuthTries: c.MaxAuthTries,
PublicKeyCallback: func(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
sp, err := c.validatePublicKeyCredentials(conn, pubKey)
if err == ssh.ErrPartialSuccess {
if errors.Is(err, &ssh.PartialSuccessError{}) {
return sp, err
}
if err != nil {
@ -281,26 +281,12 @@ func (c *Configuration) getServerConfig() *ssh.ServerConfig {
return sp, nil
},
NextAuthMethodsCallback: func(conn ssh.ConnMetadata) []string {
var nextMethods []string
user, err := dataprovider.GetUserWithGroupSettings(conn.User(), "")
if err == nil {
nextMethods = user.GetNextAuthMethods(conn.PartialSuccessMethods(), c.PasswordAuthentication)
}
return nextMethods
},
ServerVersion: fmt.Sprintf("SSH-2.0-%s", c.Banner),
}
if c.PasswordAuthentication {
serverConfig.PasswordCallback = func(conn ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
sp, err := c.validatePasswordCredentials(conn, pass)
if err != nil {
return nil, newAuthenticationError(fmt.Errorf("could not validate password credentials: %w", err),
dataprovider.SSHLoginMethodPassword)
}
return sp, nil
serverConfig.PasswordCallback = func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
return c.validatePasswordCredentials(conn, password, dataprovider.LoginMethodPassword)
}
serviceStatus.Authentications = append(serviceStatus.Authentications, dataprovider.LoginMethodPassword)
}
@ -544,6 +530,7 @@ func (c *Configuration) configureKeyboardInteractiveAuth(serverConfig *ssh.Serve
if c.KeyboardInteractiveHook != "" {
if !strings.HasPrefix(c.KeyboardInteractiveHook, "http") {
if !filepath.IsAbs(c.KeyboardInteractiveHook) {
c.KeyboardInteractiveAuthentication = false
logger.WarnToConsole("invalid keyboard interactive authentication program: %q must be an absolute path",
c.KeyboardInteractiveHook)
logger.Warn(logSender, "", "invalid keyboard interactive authentication program: %q must be an absolute path",
@ -552,6 +539,7 @@ func (c *Configuration) configureKeyboardInteractiveAuth(serverConfig *ssh.Serve
}
_, err := os.Stat(c.KeyboardInteractiveHook)
if err != nil {
c.KeyboardInteractiveAuthentication = false
logger.WarnToConsole("invalid keyboard interactive authentication program:: %v", err)
logger.Warn(logSender, "", "invalid keyboard interactive authentication program:: %v", err)
return
@ -559,13 +547,7 @@ func (c *Configuration) configureKeyboardInteractiveAuth(serverConfig *ssh.Serve
}
}
serverConfig.KeyboardInteractiveCallback = func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
sp, err := c.validateKeyboardInteractiveCredentials(conn, client)
if err != nil {
return nil, newAuthenticationError(fmt.Errorf("could not validate keyboard interactive credentials: %w", err),
dataprovider.SSHLoginMethodKeyboardInteractive)
}
return sp, nil
return c.validateKeyboardInteractiveCredentials(conn, client, dataprovider.SSHLoginMethodKeyboardInteractive)
}
serviceStatus.Authentications = append(serviceStatus.Authentications, dataprovider.SSHLoginMethodKeyboardInteractive)
@ -817,7 +799,7 @@ func loginUser(user *dataprovider.User, loginMethod, publicKey string, conn ssh.
return nil, fmt.Errorf("too many open sessions: %v", activeSessions)
}
}
if !user.IsLoginMethodAllowed(loginMethod, common.ProtocolSSH, conn.PartialSuccessMethods()) {
if !user.IsLoginMethodAllowed(loginMethod, common.ProtocolSSH) {
logger.Info(logSender, connectionID, "cannot login user %q, login method %q is not allowed",
user.Username, loginMethod)
return nil, fmt.Errorf("login method %q is not allowed for user %q", loginMethod, user.Username)
@ -1130,6 +1112,21 @@ func (c *Configuration) initializeCertChecker(configDir string) error {
return revokedCertManager.load()
}
func (c *Configuration) getPartialSuccessError(nextAuthMethods []string) error {
err := &ssh.PartialSuccessError{}
if c.PasswordAuthentication && util.Contains(nextAuthMethods, dataprovider.LoginMethodPassword) {
err.PasswordCallback = func(conn ssh.ConnMetadata, password []byte) (*ssh.Permissions, error) {
return c.validatePasswordCredentials(conn, password, dataprovider.SSHLoginMethodKeyAndPassword)
}
}
if c.KeyboardInteractiveAuthentication && util.Contains(nextAuthMethods, dataprovider.SSHLoginMethodKeyboardInteractive) {
err.KeyboardInteractiveCallback = func(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
return c.validateKeyboardInteractiveCredentials(conn, client, dataprovider.SSHLoginMethodKeyAndKeyboardInt)
}
}
return err
}
func (c *Configuration) validatePublicKeyCredentials(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) {
var err error
var user dataprovider.User
@ -1180,9 +1177,9 @@ func (c *Configuration) validatePublicKeyCredentials(conn ssh.ConnMetadata, pubK
keyID = fmt.Sprintf("%s: ID: %s, serial: %v, CA %s %s", certFingerprint,
cert.KeyId, cert.Serial, cert.Type(), ssh.FingerprintSHA256(cert.SignatureKey))
}
if user.IsPartialAuth(method) {
if user.IsPartialAuth() {
logger.Debug(logSender, connectionID, "user %q authenticated with partial success", conn.User())
return certPerm, ssh.ErrPartialSuccess
return certPerm, c.getPartialSuccessError(user.GetNextAuthMethods())
}
sshPerm, err = loginUser(&user, method, keyID, conn)
if err == nil && certPerm != nil {
@ -1201,33 +1198,30 @@ func (c *Configuration) validatePublicKeyCredentials(conn ssh.ConnMetadata, pubK
return sshPerm, err
}
func (c *Configuration) validatePasswordCredentials(conn ssh.ConnMetadata, pass []byte) (*ssh.Permissions, error) {
func (c *Configuration) validatePasswordCredentials(conn ssh.ConnMetadata, pass []byte, method string) (*ssh.Permissions, error) {
var err error
var user dataprovider.User
var sshPerm *ssh.Permissions
method := dataprovider.LoginMethodPassword
if len(conn.PartialSuccessMethods()) == 1 {
method = dataprovider.SSHLoginMethodKeyAndPassword
}
ipAddr := util.GetIPFromRemoteAddress(conn.RemoteAddr().String())
if user, err = dataprovider.CheckUserAndPass(conn.User(), string(pass), ipAddr, common.ProtocolSSH); err == nil {
sshPerm, err = loginUser(&user, method, "", conn)
}
user.Username = conn.User()
updateLoginMetrics(&user, ipAddr, method, err)
return sshPerm, err
if err != nil {
return nil, newAuthenticationError(fmt.Errorf("could not validate password credentials: %w", err), method)
}
return sshPerm, nil
}
func (c *Configuration) validateKeyboardInteractiveCredentials(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge) (*ssh.Permissions, error) {
func (c *Configuration) validateKeyboardInteractiveCredentials(conn ssh.ConnMetadata, client ssh.KeyboardInteractiveChallenge,
method string,
) (*ssh.Permissions, error) {
var err error
var user dataprovider.User
var sshPerm *ssh.Permissions
method := dataprovider.SSHLoginMethodKeyboardInteractive
if len(conn.PartialSuccessMethods()) == 1 {
method = dataprovider.SSHLoginMethodKeyAndKeyboardInt
}
ipAddr := util.GetIPFromRemoteAddress(conn.RemoteAddr().String())
if user, err = dataprovider.CheckKeyboardInteractiveAuth(conn.User(), c.KeyboardInteractiveHook, client,
ipAddr, common.ProtocolSSH); err == nil {
@ -1235,7 +1229,10 @@ func (c *Configuration) validateKeyboardInteractiveCredentials(conn ssh.ConnMeta
}
user.Username = conn.User()
updateLoginMetrics(&user, ipAddr, method, err)
return sshPerm, err
if err != nil {
return nil, newAuthenticationError(fmt.Errorf("could not validate keyboard interactive credentials: %w", err), method)
}
return sshPerm, nil
}
func updateLoginMetrics(user *dataprovider.User, ip, method string, err error) {

View file

@ -55,6 +55,7 @@ import (
"github.com/sftpgo/sdk"
sdkkms "github.com/sftpgo/sdk/kms"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/crypto/ssh"
"github.com/drakkan/sftpgo/v2/internal/common"
@ -276,13 +277,13 @@ func TestMain(m *testing.M) {
sftpdConf.TrustedUserCAKeys = append(sftpdConf.TrustedUserCAKeys, trustedCAUserKey)
sftpdConf.RevokedUserCertsFile = revokeUserCerts
go func() {
go func(cfg sftpd.Configuration) {
logger.Debug(logSender, "", "initializing SFTP server with config %+v", sftpdConf)
if err := sftpdConf.Initialize(configDir); err != nil {
if err := cfg.Initialize(configDir); err != nil {
logger.ErrorToConsole("could not start SFTP server: %v", err)
os.Exit(1)
}
}()
}(sftpdConf)
go func() {
if err := httpdConf.Initialize(configDir, 0); err != nil {
@ -302,36 +303,35 @@ func TestMain(m *testing.M) {
}
sftpdConf.PasswordAuthentication = false
common.Config.ProxyProtocol = 1
go func() {
go func(cfg sftpd.Configuration) {
logger.Debug(logSender, "", "initializing SFTP server with config %+v and proxy protocol %v",
sftpdConf, common.Config.ProxyProtocol)
if err := sftpdConf.Initialize(configDir); err != nil {
if err := cfg.Initialize(configDir); err != nil {
logger.ErrorToConsole("could not start SFTP server with proxy protocol 1: %v", err)
os.Exit(1)
}
}()
}(sftpdConf)
waitTCPListening(sftpdConf.Bindings[0].GetAddress())
prefixedConf := sftpdConf
prefixedConf.Bindings = []sftpd.Binding{
sftpdConf.Bindings = []sftpd.Binding{
{
Port: 2226,
ApplyProxyConfig: false,
},
}
prefixedConf.PasswordAuthentication = true
prefixedConf.FolderPrefix = "/prefix/files"
go func() {
sftpdConf.PasswordAuthentication = true
sftpdConf.FolderPrefix = "/prefix/files"
go func(cfg sftpd.Configuration) {
logger.Debug(logSender, "", "initializing SFTP server with config %+v and proxy protocol %v",
prefixedConf, common.Config.ProxyProtocol)
if err := prefixedConf.Initialize(configDir); err != nil {
cfg, common.Config.ProxyProtocol)
if err := cfg.Initialize(configDir); err != nil {
logger.ErrorToConsole("could not start SFTP server with proxy protocol 2: %v", err)
os.Exit(1)
}
}()
}(sftpdConf)
waitTCPListening(prefixedConf.Bindings[0].GetAddress())
waitTCPListening(sftpdConf.Bindings[0].GetAddress())
sftpdConf.Bindings = []sftpd.Binding{
{
@ -8596,27 +8596,25 @@ func TestUserPartialAuth(t *testing.T) {
dataprovider.SSHLoginMethodPublicKey,
dataprovider.SSHLoginMethodKeyboardInteractive,
}
assert.False(t, user.IsPartialAuth(dataprovider.LoginMethodPassword))
assert.False(t, user.IsPartialAuth(dataprovider.SSHLoginMethodKeyboardInteractive))
assert.True(t, user.IsPartialAuth(dataprovider.SSHLoginMethodPublicKey))
assert.True(t, user.IsPartialAuth())
user.Filters.DeniedLoginMethods = []string{
dataprovider.LoginMethodPassword,
dataprovider.SSHLoginMethodKeyboardInteractive,
}
assert.False(t, user.IsPartialAuth(dataprovider.SSHLoginMethodPublicKey))
assert.False(t, user.IsPartialAuth())
user.Filters.DeniedLoginMethods = []string{
dataprovider.LoginMethodPassword,
dataprovider.SSHLoginMethodPublicKey,
}
assert.False(t, user.IsPartialAuth(dataprovider.SSHLoginMethodPublicKey))
assert.False(t, user.IsPartialAuth())
user.Filters.DeniedLoginMethods = []string{
dataprovider.SSHLoginMethodPassword,
dataprovider.SSHLoginMethodPublicKey,
dataprovider.SSHLoginMethodKeyboardInteractive,
}
assert.True(t, user.IsPartialAuth(dataprovider.SSHLoginMethodPublicKey))
assert.True(t, user.IsPartialAuth())
}
func TestUserGetNextAuthMethods(t *testing.T) {
@ -8626,28 +8624,10 @@ func TestUserGetNextAuthMethods(t *testing.T) {
dataprovider.SSHLoginMethodPublicKey,
dataprovider.SSHLoginMethodKeyboardInteractive,
}
methods := user.GetNextAuthMethods(nil, true)
assert.Equal(t, 0, len(methods))
methods = user.GetNextAuthMethods([]string{dataprovider.LoginMethodPassword}, true)
assert.Equal(t, 0, len(methods))
methods = user.GetNextAuthMethods([]string{dataprovider.SSHLoginMethodKeyboardInteractive}, true)
assert.Equal(t, 0, len(methods))
methods = user.GetNextAuthMethods([]string{
dataprovider.SSHLoginMethodPublicKey,
dataprovider.SSHLoginMethodKeyboardInteractive,
}, true)
assert.Equal(t, 0, len(methods))
methods = user.GetNextAuthMethods([]string{dataprovider.SSHLoginMethodPublicKey}, true)
assert.Equal(t, 2, len(methods))
assert.True(t, util.Contains(methods, dataprovider.LoginMethodPassword))
assert.True(t, util.Contains(methods, dataprovider.SSHLoginMethodKeyboardInteractive))
methods = user.GetNextAuthMethods([]string{dataprovider.SSHLoginMethodPublicKey}, false)
assert.Equal(t, 1, len(methods))
assert.True(t, util.Contains(methods, dataprovider.SSHLoginMethodKeyboardInteractive))
methods := user.GetNextAuthMethods()
require.Len(t, methods, 2)
assert.Equal(t, dataprovider.LoginMethodPassword, methods[0])
assert.Equal(t, dataprovider.SSHLoginMethodKeyboardInteractive, methods[1])
user.Filters.DeniedLoginMethods = []string{
dataprovider.LoginMethodPassword,
@ -8655,9 +8635,9 @@ func TestUserGetNextAuthMethods(t *testing.T) {
dataprovider.SSHLoginMethodKeyboardInteractive,
dataprovider.SSHLoginMethodKeyAndKeyboardInt,
}
methods = user.GetNextAuthMethods([]string{dataprovider.SSHLoginMethodPublicKey}, true)
assert.Equal(t, 1, len(methods))
assert.True(t, util.Contains(methods, dataprovider.LoginMethodPassword))
methods = user.GetNextAuthMethods()
require.Len(t, methods, 1)
assert.Equal(t, dataprovider.LoginMethodPassword, methods[0])
user.Filters.DeniedLoginMethods = []string{
dataprovider.LoginMethodPassword,
@ -8665,9 +8645,18 @@ func TestUserGetNextAuthMethods(t *testing.T) {
dataprovider.SSHLoginMethodKeyboardInteractive,
dataprovider.SSHLoginMethodKeyAndPassword,
}
methods = user.GetNextAuthMethods([]string{dataprovider.SSHLoginMethodPublicKey}, true)
assert.Equal(t, 1, len(methods))
assert.True(t, util.Contains(methods, dataprovider.SSHLoginMethodKeyboardInteractive))
methods = user.GetNextAuthMethods()
require.Len(t, methods, 1)
assert.Equal(t, dataprovider.SSHLoginMethodKeyboardInteractive, methods[0])
user.Filters.DeniedLoginMethods = []string{
dataprovider.LoginMethodPassword,
dataprovider.SSHLoginMethodPublicKey,
dataprovider.SSHLoginMethodKeyAndPassword,
dataprovider.SSHLoginMethodKeyAndKeyboardInt,
}
methods = user.GetNextAuthMethods()
require.Len(t, methods, 0)
}
func TestUserIsLoginMethodAllowed(t *testing.T) {
@ -8677,31 +8666,25 @@ func TestUserIsLoginMethodAllowed(t *testing.T) {
dataprovider.SSHLoginMethodPublicKey,
dataprovider.SSHLoginMethodKeyboardInteractive,
}
assert.False(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolSSH, nil))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolFTP, nil))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolWebDAV, nil))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.SSHLoginMethodPublicKey, common.ProtocolSSH, nil))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.SSHLoginMethodKeyboardInteractive, common.ProtocolSSH, nil))
assert.True(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolSSH,
[]string{dataprovider.SSHLoginMethodPublicKey}))
assert.True(t, user.IsLoginMethodAllowed(dataprovider.SSHLoginMethodKeyboardInteractive, common.ProtocolSSH,
[]string{dataprovider.SSHLoginMethodPublicKey}))
assert.True(t, user.IsLoginMethodAllowed(dataprovider.SSHLoginMethodKeyAndPassword, common.ProtocolSSH,
[]string{dataprovider.SSHLoginMethodPublicKey}))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolSSH))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolFTP))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolWebDAV))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.SSHLoginMethodPublicKey, common.ProtocolSSH))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.SSHLoginMethodKeyboardInteractive, common.ProtocolSSH))
user.Filters.DeniedLoginMethods = []string{
dataprovider.SSHLoginMethodPublicKey,
dataprovider.SSHLoginMethodKeyboardInteractive,
}
assert.True(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolSSH, nil))
assert.True(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolSSH))
user.Filters.DeniedLoginMethods = []string{
dataprovider.SSHLoginMethodPassword,
}
assert.True(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolHTTP, nil))
assert.True(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolFTP, nil))
assert.True(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolWebDAV, nil))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolSSH, nil))
assert.True(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolHTTP))
assert.True(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolFTP))
assert.True(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolWebDAV))
assert.False(t, user.IsLoginMethodAllowed(dataprovider.LoginMethodPassword, common.ProtocolSSH))
}
func TestUserEmptySubDirPerms(t *testing.T) {

View file

@ -349,7 +349,7 @@ func (s *webDavServer) validateUser(user *dataprovider.User, r *http.Request, lo
logger.Info(logSender, connectionID, "cannot login user %q, protocol DAV is not allowed", user.Username)
return connID, fmt.Errorf("protocol DAV is not allowed for user %q", user.Username)
}
if !user.IsLoginMethodAllowed(loginMethod, common.ProtocolWebDAV, nil) {
if !user.IsLoginMethodAllowed(loginMethod, common.ProtocolWebDAV) {
logger.Info(logSender, connectionID, "cannot login user %q, %v login method is not allowed",
user.Username, loginMethod)
return connID, fmt.Errorf("login method %v is not allowed for user %q", loginMethod, user.Username)