mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2024-11-24 02:59:13 +08:00
Merge branch 'master' of https://github.com/seaweedfs/seaweedfs
This commit is contained in:
commit
3d07895518
5
Makefile
5
Makefile
@ -10,5 +10,8 @@ install:
|
||||
full_install:
|
||||
cd weed; go install -tags "elastic gocdk sqlite ydb tikv"
|
||||
|
||||
tests:
|
||||
server: install
|
||||
weed -v 4 server -s3 -filer -volume.max=0 -master.volumeSizeLimitMB=1024 -volume.preStopSeconds=1 -s3.port=8000 -s3.allowEmptyFolder=false -s3.allowDeleteBucketNotEmpty=false -s3.config=./docker/compose/s3.json
|
||||
|
||||
test:
|
||||
cd weed; go test -tags "elastic gocdk sqlite ydb tikv" -v ./...
|
||||
|
@ -40,7 +40,10 @@
|
||||
"List",
|
||||
"Tagging",
|
||||
"Write"
|
||||
]
|
||||
],
|
||||
"account": {
|
||||
"id": "testid"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "s3_tests_alt",
|
||||
@ -101,5 +104,12 @@
|
||||
"Write"
|
||||
]
|
||||
}
|
||||
]
|
||||
],
|
||||
"accounts": [
|
||||
{
|
||||
"id" : "testid",
|
||||
"displayName": "M. Tester",
|
||||
"emailAddress": "tester@ceph.com"
|
||||
}
|
||||
]
|
||||
}
|
@ -18,10 +18,10 @@ bucket prefix = yournamehere-{random}-
|
||||
|
||||
[s3 main]
|
||||
# main display_name set in vstart.sh
|
||||
display_name = s3_tests
|
||||
display_name = M. Tester
|
||||
|
||||
# main user_idname set in vstart.sh
|
||||
user_id = s3_tests
|
||||
user_id = testid
|
||||
|
||||
# main email set in vstart.sh
|
||||
email = tester@ceph.com
|
||||
|
19
go.mod
19
go.mod
@ -32,7 +32,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/go-errors/errors v1.1.1 // indirect
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/go-redsync/redsync/v4 v4.8.2
|
||||
github.com/go-redsync/redsync/v4 v4.9.4
|
||||
github.com/go-sql-driver/mysql v1.7.1
|
||||
github.com/go-zookeeper/zk v1.0.3 // indirect
|
||||
github.com/gocql/gocql v1.6.0
|
||||
@ -111,7 +111,7 @@ require (
|
||||
go.opencensus.io v0.24.0 // indirect
|
||||
gocloud.dev v0.34.0
|
||||
gocloud.dev/pubsub/natspubsub v0.33.0
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.33.0
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.34.0
|
||||
golang.org/x/crypto v0.13.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
|
||||
golang.org/x/image v0.11.0
|
||||
@ -124,7 +124,7 @@ require (
|
||||
google.golang.org/api v0.141.0
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20230803162519-f966b187b2e5 // indirect
|
||||
google.golang.org/grpc v1.58.0
|
||||
google.golang.org/grpc v1.58.2
|
||||
google.golang.org/protobuf v1.31.0
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
modernc.org/b v1.0.0 // indirect
|
||||
@ -144,8 +144,8 @@ require (
|
||||
github.com/arangodb/go-driver v1.6.0
|
||||
github.com/armon/go-metrics v0.4.1
|
||||
github.com/aws/aws-sdk-go-v2 v1.21.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.39
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.37
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.42
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.40
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.38.5
|
||||
github.com/fluent/fluent-logger-golang v1.9.0
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0
|
||||
@ -185,7 +185,7 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.36 // indirect
|
||||
@ -193,9 +193,9 @@ require (
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.15.4 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sns v1.21.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.24.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.14.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 // indirect
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.22.0 // indirect
|
||||
github.com/aws/smithy-go v1.14.2 // indirect
|
||||
github.com/benbjohnson/clock v1.3.0 // indirect
|
||||
github.com/boltdb/bolt v1.3.1 // indirect
|
||||
@ -268,7 +268,6 @@ require (
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
github.com/putdotio/go-putio/putio v0.0.0-20200123120452-16d982cac2b8 // indirect
|
||||
github.com/rclone/ftp v0.0.0-20230327202000-dadc1f64e87d // indirect
|
||||
github.com/rdleal/intervalst v0.0.0-20221028215511-a098aa0d2cb8 // indirect
|
||||
github.com/rfjakob/eme v1.1.2 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/shoenig/go-m1cpu v0.1.6 // indirect
|
||||
|
36
go.sum
36
go.sum
@ -118,10 +118,10 @@ github.com/aws/aws-sdk-go-v2 v1.21.0 h1:gMT0IW+03wtYJhRqTVYn0wLzwdnK9sRMcxmtfGzR
|
||||
github.com/aws/aws-sdk-go-v2 v1.21.0/go.mod h1:/RfNgGmRxI+iFOB1OeJUyxiU+9s88k3pfHvDagGEp0M=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13 h1:OPLEkmhXf6xFPiz0bLeDArZIDx1NNS4oJyG4nv3Gct0=
|
||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.13/go.mod h1:gpAbvyDGQFozTEmlTFO8XcQKHzubdq0LzRyJpG6MiXM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.39 h1:oPVyh6fuu/u4OiW4qcuQyEtk7U7uuNBmHmJSLg1AJsQ=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.39/go.mod h1:+NH/ZigdPckFpgB1TRcRuWCB/Kbbvkxc/iNAKTq5RhE=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.37 h1:BvEdm09+ZEh2XtN+PVHPcYwKY3wIeB6pw7vPRM4M9/U=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.37/go.mod h1:ACLrdkd4CLZyXOghZ8IYumQbcooAcp2jo/s2xsFH8IM=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.42 h1:28jHROB27xZwU0CB88giDSjz7M1Sba3olb5JBGwina8=
|
||||
github.com/aws/aws-sdk-go-v2/config v1.18.42/go.mod h1:4AZM3nMMxwlG+eZlxvBKqwVbkDLlnN2a4UGTL6HjaZI=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.40 h1:s8yOkDh+5b1jUDhMBtngF6zKWLDs84chUk2Vk0c38Og=
|
||||
github.com/aws/aws-sdk-go-v2/credentials v1.13.40/go.mod h1:VtEHVAAqDWASwdOqj/1huyT6uHbs5s8FUHfDQdky/Rs=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11 h1:uDZJF1hu0EVT/4bogChk8DyjSF6fof6uL/0Y26Ma7Fg=
|
||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.13.11/go.mod h1:TEPP4tENqBGO99KwVpV9MlOX4NSrSLP8u3KRy2CDwA8=
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.37/go.mod h1:Pdn4j43v49Kk6+82spO3Tu5gSeQXRsxo56ePPQAvFiA=
|
||||
@ -130,8 +130,8 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.41/go.mod h1:CrObHAuPne
|
||||
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/endpoints/v2 v2.4.35 h1:SijA0mgjV8E+8G45ltVHs0fvKpTj8xmZJ3VwhGKtUSI=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.35/go.mod h1:SJC1nEVVva1g3pHAIdCp7QsRIkMmLAgoDquQ9Rr8kYw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42 h1:GPUcE/Yq7Ur8YSUk6lVkoIMWnJNO0HT18GUzCWCgCI0=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.42/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43 h1:g+qlObJH4Kn4n21g69DjspU0hKTjWtq7naZ9OLCv0ew=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.43/go.mod h1:rzfdUlfA+jdgLDmPKjd3Chq9V7LVLYo1Nz++Wb91aRo=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4 h1:6lJvvkQ9HmbHZ4h/IEwclwv2mrTW8Uq1SOB/kXy0mfw=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.1.4/go.mod h1:1PrKYwxTM+zjpw9Y41KFtoJCQrJ34Z47Y4VgVbfndjo=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.14 h1:m0QTSI6pZYJTk5WSKx3fm5cNW/DCicVzULBgU/6IyD0=
|
||||
@ -148,12 +148,12 @@ github.com/aws/aws-sdk-go-v2/service/sns v1.21.1 h1:Q01Dph/7FaB41Z7EY+SoVPa/kMpL
|
||||
github.com/aws/aws-sdk-go-v2/service/sns v1.21.1/go.mod h1:laHbYFVzphXdCiT3gitfuCDA2Oukrt9p40jWK7OJLgc=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.24.1 h1:KbGaxApdPOT2ZWqJiQY5ApnpNhUGbGTjYiKAidlFwp8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.24.1/go.mod h1:+phkm4aFvcM4jbsDRGoZ+mD8MMvksHF459Xpy5Z90f0=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.13.6 h1:2PylFCfKCEDv6PeSN09pC/VUiRd10wi1VfHG5FrW0/g=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.13.6/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6 h1:pSB560BbVj9ZlJZF4WYj5zsytWHWKxg+NgyGV4B2L58=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.15.6/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.21.5 h1:CQBFElb0LS8RojMJlxRSo/HXipvTZW2S44Lt9Mk2aYQ=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.21.5/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.14.1 h1:YkNzx1RLS0F5qdf9v1Q8Cuv9NXCL2TkosOxhzlUPV64=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.14.1/go.mod h1:fIAwKQKBFu90pBxx07BFOMJLpRUGu8VOzLJakeY+0K4=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1 h1:8lKOidPkmSmfUtiTgtdXWgaKItCZ/g75/jEk6Ql6GsA=
|
||||
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.17.1/go.mod h1:yygr8ACQRY2PrEcy3xsUI357stq2AxnFM6DIsR9lij4=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.22.0 h1:s4bioTgjSFRwOoyEFzAVCmFmoowBgjTR8gkrF/sQ4wk=
|
||||
github.com/aws/aws-sdk-go-v2/service/sts v1.22.0/go.mod h1:VC7JDqsqiwXukYEDjoHh9U0fOJtNWh04FPQz4ct4GGU=
|
||||
github.com/aws/smithy-go v1.14.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||
github.com/aws/smithy-go v1.14.2 h1:MJU9hqBGbvWZdApzpvoF2WAIJDbtjK2NDJSiJP7HblQ=
|
||||
github.com/aws/smithy-go v1.14.2/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||
@ -303,8 +303,8 @@ github.com/go-redis/redis/v7 v7.4.0/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRf
|
||||
github.com/go-redis/redis/v8 v8.11.4/go.mod h1:2Z2wHZXdQpCDXEGzqMockDpNyYvi2l4Pxt6RJr792+w=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-redsync/redsync/v4 v4.8.2 h1:/b+jidlwOnSOl605hmNsd+ohfr/qB1EpLiKnCYkiw28=
|
||||
github.com/go-redsync/redsync/v4 v4.8.2/go.mod h1:83QPGYHk0Wt2LhFo3n9xCrUGPQrQvejVTVR08KX032g=
|
||||
github.com/go-redsync/redsync/v4 v4.9.4 h1:vRmYusI+qF95XSpApHAdeu+RjyDvxBXbMthbc/x148c=
|
||||
github.com/go-redsync/redsync/v4 v4.9.4/go.mod h1:RqBDXUw0q+u9FJTeD2gMzGtHeSVV93DiqGl10B9Hn/4=
|
||||
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
|
||||
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
@ -965,8 +965,8 @@ gocloud.dev v0.34.0 h1:LzlQY+4l2cMtuNfwT2ht4+fiXwWf/NmPTnXUlLmGif4=
|
||||
gocloud.dev v0.34.0/go.mod h1:psKOachbnvY3DAOPbsFVmLIErwsbWPUG2H5i65D38vE=
|
||||
gocloud.dev/pubsub/natspubsub v0.33.0 h1:SwHh+PuDmZ3/xv1h/7VBRVlgiBI9Hw6vS7NcvJzW3Us=
|
||||
gocloud.dev/pubsub/natspubsub v0.33.0/go.mod h1:2hKJ2+CbUyuSv4pFkaU/Ay3buK5ACJMxqlfnVSXFZGs=
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.33.0 h1:zidscDuR/INRVV/MKepaVbx/XIhgGKSCosiqfhORDZE=
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.33.0/go.mod h1:hauJ0yE5eKuEBMT13npOAgERcQeAIyQvnzPwml0WFW8=
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.34.0 h1:JvgO79IoX59RHonnRJjp92Oo5ecjRX6O4t1jy38cO3I=
|
||||
gocloud.dev/pubsub/rabbitpubsub v0.34.0/go.mod h1:IaipzdqxYtjd+SRK6yGXRzovNaokMAfqq7VJHozTZD8=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
@ -1404,8 +1404,8 @@ google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI=
|
||||
google.golang.org/grpc v1.58.0 h1:32JY8YpPMSR45K+c3o6b8VL73V+rR8k+DeMIr4vRH8o=
|
||||
google.golang.org/grpc v1.58.0/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||
google.golang.org/grpc v1.58.2 h1:SXUpjxeVF3FKrTYQI4f4KvbGD5u2xccdYdurwowix5I=
|
||||
google.golang.org/grpc v1.58.2/go.mod h1:tgX3ZQDlNJGU96V6yHh1T/JeoBQ2TXdr43YbYSsCJk0=
|
||||
google.golang.org/grpc/examples v0.0.0-20201112215255-90f1b3ee835b h1:NuxyvVZoDfHZwYW9LD4GJiF5/nhiSyP4/InTrvw9Ibk=
|
||||
google.golang.org/grpc/examples v0.0.0-20201112215255-90f1b3ee835b/go.mod h1:IBqQ7wSUJ2Ep09a8rMWFsg4fmI2r38zwsq8a0GgxXpM=
|
||||
google.golang.org/grpc/security/advancedtls v0.0.0-20220622233350-5cdb09fa29c1 h1:0emxaJWaG6CfrA9Nbe4aHWbFz5AXw2QPEJP0/f42LCE=
|
||||
|
@ -16,13 +16,14 @@ service SeaweedIdentityAccessManagement {
|
||||
|
||||
message S3ApiConfiguration {
|
||||
repeated Identity identities = 1;
|
||||
repeated Account accounts = 2;
|
||||
}
|
||||
|
||||
message Identity {
|
||||
string name = 1;
|
||||
repeated Credential credentials = 2;
|
||||
repeated string actions = 3;
|
||||
string accountId = 4;
|
||||
Account account = 4;
|
||||
}
|
||||
|
||||
message Credential {
|
||||
@ -32,6 +33,12 @@ message Credential {
|
||||
// bool is_disabled = 4;
|
||||
}
|
||||
|
||||
message Account {
|
||||
string id = 1;
|
||||
string display_name = 2;
|
||||
string email_address = 3;
|
||||
}
|
||||
|
||||
/*
|
||||
message Policy {
|
||||
repeated Statement statements = 1;
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v4.23.3
|
||||
// protoc v4.23.2
|
||||
// source: iam.proto
|
||||
|
||||
package iam_pb
|
||||
@ -26,6 +26,7 @@ type S3ApiConfiguration struct {
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Identities []*Identity `protobuf:"bytes,1,rep,name=identities,proto3" json:"identities,omitempty"`
|
||||
Accounts []*Account `protobuf:"bytes,2,rep,name=accounts,proto3" json:"accounts,omitempty"`
|
||||
}
|
||||
|
||||
func (x *S3ApiConfiguration) Reset() {
|
||||
@ -67,6 +68,13 @@ func (x *S3ApiConfiguration) GetIdentities() []*Identity {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *S3ApiConfiguration) GetAccounts() []*Account {
|
||||
if x != nil {
|
||||
return x.Accounts
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Identity struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
@ -75,7 +83,7 @@ type Identity struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Credentials []*Credential `protobuf:"bytes,2,rep,name=credentials,proto3" json:"credentials,omitempty"`
|
||||
Actions []string `protobuf:"bytes,3,rep,name=actions,proto3" json:"actions,omitempty"`
|
||||
AccountId string `protobuf:"bytes,4,opt,name=accountId,proto3" json:"accountId,omitempty"`
|
||||
Account *Account `protobuf:"bytes,4,opt,name=account,proto3" json:"account,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Identity) Reset() {
|
||||
@ -131,11 +139,11 @@ func (x *Identity) GetActions() []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Identity) GetAccountId() string {
|
||||
func (x *Identity) GetAccount() *Account {
|
||||
if x != nil {
|
||||
return x.AccountId
|
||||
return x.Account
|
||||
}
|
||||
return ""
|
||||
return nil
|
||||
}
|
||||
|
||||
type Credential struct {
|
||||
@ -193,36 +201,109 @@ func (x *Credential) GetSecretKey() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
DisplayName string `protobuf:"bytes,2,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"`
|
||||
EmailAddress string `protobuf:"bytes,3,opt,name=email_address,json=emailAddress,proto3" json:"email_address,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Account) Reset() {
|
||||
*x = Account{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_iam_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Account) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Account) ProtoMessage() {}
|
||||
|
||||
func (x *Account) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_iam_proto_msgTypes[3]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Account.ProtoReflect.Descriptor instead.
|
||||
func (*Account) Descriptor() ([]byte, []int) {
|
||||
return file_iam_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *Account) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Account) GetDisplayName() string {
|
||||
if x != nil {
|
||||
return x.DisplayName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Account) GetEmailAddress() string {
|
||||
if x != nil {
|
||||
return x.EmailAddress
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_iam_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_iam_proto_rawDesc = []byte{
|
||||
0x0a, 0x09, 0x69, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x69, 0x61, 0x6d,
|
||||
0x5f, 0x70, 0x62, 0x22, 0x46, 0x0a, 0x12, 0x53, 0x33, 0x41, 0x70, 0x69, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x5f, 0x70, 0x62, 0x22, 0x73, 0x0a, 0x12, 0x53, 0x33, 0x41, 0x70, 0x69, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x0a, 0x69, 0x64, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e,
|
||||
0x69, 0x61, 0x6d, 0x5f, 0x70, 0x62, 0x2e, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52,
|
||||
0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x22, 0x8c, 0x01, 0x0a, 0x08,
|
||||
0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x0b,
|
||||
0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28,
|
||||
0x0b, 0x32, 0x12, 0x2e, 0x69, 0x61, 0x6d, 0x5f, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x61, 0x6c, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61,
|
||||
0x6c, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20,
|
||||
0x03, 0x28, 0x09, 0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09,
|
||||
0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x09, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x49, 0x64, 0x22, 0x4a, 0x0a, 0x0a, 0x43, 0x72,
|
||||
0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65,
|
||||
0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63,
|
||||
0x63, 0x65, 0x73, 0x73, 0x4b, 0x65, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65,
|
||||
0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63,
|
||||
0x72, 0x65, 0x74, 0x4b, 0x65, 0x79, 0x32, 0x21, 0x0a, 0x1f, 0x53, 0x65, 0x61, 0x77, 0x65, 0x65,
|
||||
0x64, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d,
|
||||
0x61, 0x6e, 0x61, 0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x4b, 0x0a, 0x10, 0x73, 0x65, 0x61,
|
||||
0x77, 0x65, 0x65, 0x64, 0x66, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x49,
|
||||
0x61, 0x6d, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
|
||||
0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x65, 0x61, 0x77, 0x65, 0x65, 0x64, 0x66, 0x73, 0x2f, 0x73, 0x65,
|
||||
0x61, 0x77, 0x65, 0x65, 0x64, 0x66, 0x73, 0x2f, 0x77, 0x65, 0x65, 0x64, 0x2f, 0x70, 0x62, 0x2f,
|
||||
0x69, 0x61, 0x6d, 0x5f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x12, 0x2b, 0x0a, 0x08, 0x61,
|
||||
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e,
|
||||
0x69, 0x61, 0x6d, 0x5f, 0x70, 0x62, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x08,
|
||||
0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, 0x99, 0x01, 0x0a, 0x08, 0x49, 0x64, 0x65,
|
||||
0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x0b, 0x63, 0x72, 0x65,
|
||||
0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12,
|
||||
0x2e, 0x69, 0x61, 0x6d, 0x5f, 0x70, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x61, 0x6c, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6c, 0x73, 0x12,
|
||||
0x18, 0x0a, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09,
|
||||
0x52, 0x07, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x07, 0x61, 0x63, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x69, 0x61, 0x6d,
|
||||
0x5f, 0x70, 0x62, 0x2e, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x07, 0x61, 0x63, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x22, 0x4a, 0x0a, 0x0a, 0x43, 0x72, 0x65, 0x64, 0x65, 0x6e, 0x74, 0x69,
|
||||
0x61, 0x6c, 0x12, 0x1d, 0x0a, 0x0a, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x6b, 0x65, 0x79,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4b, 0x65,
|
||||
0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x5f, 0x6b, 0x65, 0x79, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x4b, 0x65, 0x79,
|
||||
0x22, 0x61, 0x0a, 0x07, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x64,
|
||||
0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x23,
|
||||
0x0a, 0x0d, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x41, 0x64, 0x64, 0x72,
|
||||
0x65, 0x73, 0x73, 0x32, 0x21, 0x0a, 0x1f, 0x53, 0x65, 0x61, 0x77, 0x65, 0x65, 0x64, 0x49, 0x64,
|
||||
0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x4d, 0x61, 0x6e, 0x61,
|
||||
0x67, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x4b, 0x0a, 0x10, 0x73, 0x65, 0x61, 0x77, 0x65, 0x65,
|
||||
0x64, 0x66, 0x73, 0x2e, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x42, 0x08, 0x49, 0x61, 0x6d, 0x50,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x73, 0x65, 0x61, 0x77, 0x65, 0x65, 0x64, 0x66, 0x73, 0x2f, 0x73, 0x65, 0x61, 0x77, 0x65,
|
||||
0x65, 0x64, 0x66, 0x73, 0x2f, 0x77, 0x65, 0x65, 0x64, 0x2f, 0x70, 0x62, 0x2f, 0x69, 0x61, 0x6d,
|
||||
0x5f, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -237,20 +318,23 @@ func file_iam_proto_rawDescGZIP() []byte {
|
||||
return file_iam_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_iam_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_iam_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_iam_proto_goTypes = []interface{}{
|
||||
(*S3ApiConfiguration)(nil), // 0: iam_pb.S3ApiConfiguration
|
||||
(*Identity)(nil), // 1: iam_pb.Identity
|
||||
(*Credential)(nil), // 2: iam_pb.Credential
|
||||
(*Account)(nil), // 3: iam_pb.Account
|
||||
}
|
||||
var file_iam_proto_depIdxs = []int32{
|
||||
1, // 0: iam_pb.S3ApiConfiguration.identities:type_name -> iam_pb.Identity
|
||||
2, // 1: iam_pb.Identity.credentials:type_name -> iam_pb.Credential
|
||||
2, // [2:2] is the sub-list for method output_type
|
||||
2, // [2:2] is the sub-list for method input_type
|
||||
2, // [2:2] is the sub-list for extension type_name
|
||||
2, // [2:2] is the sub-list for extension extendee
|
||||
0, // [0:2] is the sub-list for field type_name
|
||||
3, // 1: iam_pb.S3ApiConfiguration.accounts:type_name -> iam_pb.Account
|
||||
2, // 2: iam_pb.Identity.credentials:type_name -> iam_pb.Credential
|
||||
3, // 3: iam_pb.Identity.account:type_name -> iam_pb.Account
|
||||
4, // [4:4] is the sub-list for method output_type
|
||||
4, // [4:4] is the sub-list for method input_type
|
||||
4, // [4:4] is the sub-list for extension type_name
|
||||
4, // [4:4] is the sub-list for extension extendee
|
||||
0, // [0:4] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_iam_proto_init() }
|
||||
@ -295,6 +379,18 @@ func file_iam_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_iam_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Account); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@ -302,7 +398,7 @@ func file_iam_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_iam_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
@ -1,7 +1,7 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.2.0
|
||||
// - protoc v4.23.3
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc v4.23.2
|
||||
// source: iam.proto
|
||||
|
||||
package iam_pb
|
||||
@ -15,6 +15,8 @@ import (
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const ()
|
||||
|
||||
// SeaweedIdentityAccessManagementClient is the client API for SeaweedIdentityAccessManagement service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
|
@ -7,8 +7,6 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/filer"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb"
|
||||
@ -29,6 +27,8 @@ type IdentityAccessManagement struct {
|
||||
|
||||
identities []*Identity
|
||||
accessKeyIdent map[string]*Identity
|
||||
accounts map[string]*Account
|
||||
emailAccount map[string]*Account
|
||||
hashes map[string]*sync.Pool
|
||||
hashCounters map[string]*int32
|
||||
identityAnonymous *Identity
|
||||
@ -39,20 +39,50 @@ type IdentityAccessManagement struct {
|
||||
|
||||
type Identity struct {
|
||||
Name string
|
||||
AccountId string
|
||||
Account *Account
|
||||
Credentials []*Credential
|
||||
Actions []Action
|
||||
}
|
||||
|
||||
func (i *Identity) isAnonymous() bool {
|
||||
return i.Name == s3account.AccountAnonymous.Name
|
||||
// Account represents a system user, a system user can
|
||||
// configure multiple IAM-Users, IAM-Users can configure
|
||||
// permissions respectively, and each IAM-User can
|
||||
// configure multiple security credentials
|
||||
type Account struct {
|
||||
//Name is also used to display the "DisplayName" as the owner of the bucket or object
|
||||
DisplayName string
|
||||
EmailAddress string
|
||||
|
||||
//Id is used to identify an Account when granting cross-account access(ACLs) to buckets and objects
|
||||
Id string
|
||||
}
|
||||
|
||||
// Predefined Accounts
|
||||
var (
|
||||
// AccountAdmin is used as the default account for IAM-Credentials access without Account configured
|
||||
AccountAdmin = Account{
|
||||
DisplayName: "admin",
|
||||
EmailAddress: "admin@example.com",
|
||||
Id: s3_constants.AccountAdminId,
|
||||
}
|
||||
|
||||
// AccountAnonymous is used to represent the account for anonymous access
|
||||
AccountAnonymous = Account{
|
||||
DisplayName: "anonymous",
|
||||
EmailAddress: "anonymous@example.com",
|
||||
Id: s3_constants.AccountAnonymousId,
|
||||
}
|
||||
)
|
||||
|
||||
type Credential struct {
|
||||
AccessKey string
|
||||
SecretKey string
|
||||
}
|
||||
|
||||
func (i *Identity) isAnonymous() bool {
|
||||
return i.Account.Id == s3_constants.AccountAnonymousId
|
||||
}
|
||||
|
||||
func (action Action) isAdmin() bool {
|
||||
return strings.HasPrefix(string(action), s3_constants.ACTION_ADMIN)
|
||||
}
|
||||
@ -65,14 +95,19 @@ func (action Action) overBucket(bucket string) bool {
|
||||
return strings.HasSuffix(string(action), ":"+bucket) || strings.HasSuffix(string(action), ":*")
|
||||
}
|
||||
|
||||
// "Permission": "FULL_CONTROL"|"WRITE"|"WRITE_ACP"|"READ"|"READ_ACP"
|
||||
func (action Action) getPermission() Permission {
|
||||
switch act := strings.Split(string(action), ":")[0]; act {
|
||||
case s3_constants.ACTION_ADMIN:
|
||||
return Permission("FULL_CONTROL")
|
||||
case s3_constants.ACTION_WRITE:
|
||||
return Permission("WRITE")
|
||||
case s3_constants.ACTION_WRITE_ACP:
|
||||
return Permission("WRITE_ACP")
|
||||
case s3_constants.ACTION_READ:
|
||||
return Permission("READ")
|
||||
case s3_constants.ACTION_READ_ACP:
|
||||
return Permission("READ_ACP")
|
||||
default:
|
||||
return Permission("")
|
||||
}
|
||||
@ -138,26 +173,69 @@ func (iam *IdentityAccessManagement) loadS3ApiConfiguration(config *iam_pb.S3Api
|
||||
var identities []*Identity
|
||||
var identityAnonymous *Identity
|
||||
accessKeyIdent := make(map[string]*Identity)
|
||||
accounts := make(map[string]*Account)
|
||||
emailAccount := make(map[string]*Account)
|
||||
foundAccountAdmin := false
|
||||
foundAccountAnonymous := false
|
||||
|
||||
for _, account := range config.Accounts {
|
||||
switch account.Id {
|
||||
case AccountAdmin.Id:
|
||||
AccountAdmin = Account{
|
||||
Id: account.Id,
|
||||
DisplayName: account.DisplayName,
|
||||
EmailAddress: account.EmailAddress,
|
||||
}
|
||||
accounts[account.Id] = &AccountAdmin
|
||||
foundAccountAdmin = true
|
||||
case AccountAnonymous.Id:
|
||||
AccountAnonymous = Account{
|
||||
Id: account.Id,
|
||||
DisplayName: account.DisplayName,
|
||||
EmailAddress: account.EmailAddress,
|
||||
}
|
||||
accounts[account.Id] = &AccountAnonymous
|
||||
foundAccountAnonymous = true
|
||||
default:
|
||||
t := Account{
|
||||
Id: account.Id,
|
||||
DisplayName: account.DisplayName,
|
||||
EmailAddress: account.EmailAddress,
|
||||
}
|
||||
accounts[account.Id] = &t
|
||||
}
|
||||
if account.EmailAddress != "" {
|
||||
emailAccount[account.EmailAddress] = accounts[account.Id]
|
||||
}
|
||||
}
|
||||
if !foundAccountAdmin {
|
||||
accounts[AccountAdmin.Id] = &AccountAdmin
|
||||
emailAccount[AccountAdmin.EmailAddress] = &AccountAdmin
|
||||
}
|
||||
if !foundAccountAnonymous {
|
||||
accounts[AccountAnonymous.Id] = &AccountAnonymous
|
||||
emailAccount[AccountAnonymous.EmailAddress] = &AccountAnonymous
|
||||
}
|
||||
for _, ident := range config.Identities {
|
||||
t := &Identity{
|
||||
Name: ident.Name,
|
||||
AccountId: s3account.AccountAdmin.Id,
|
||||
Credentials: nil,
|
||||
Actions: nil,
|
||||
}
|
||||
|
||||
if ident.Name == s3account.AccountAnonymous.Name {
|
||||
if ident.AccountId != "" && ident.AccountId != s3account.AccountAnonymous.Id {
|
||||
glog.Warningf("anonymous identity is associated with a non-anonymous account ID, the association is invalid")
|
||||
}
|
||||
t.AccountId = s3account.AccountAnonymous.Id
|
||||
switch {
|
||||
case ident.Name == AccountAnonymous.Id:
|
||||
t.Account = &AccountAnonymous
|
||||
identityAnonymous = t
|
||||
} else {
|
||||
if len(ident.AccountId) > 0 {
|
||||
t.AccountId = ident.AccountId
|
||||
case ident.Account == nil:
|
||||
t.Account = &AccountAdmin
|
||||
default:
|
||||
if account, ok := accounts[ident.Account.Id]; ok {
|
||||
t.Account = account
|
||||
} else {
|
||||
t.Account = &AccountAdmin
|
||||
glog.Warningf("identity %s is associated with a non exist account ID, the association is invalid", ident.Name)
|
||||
}
|
||||
}
|
||||
|
||||
for _, action := range ident.Actions {
|
||||
t.Actions = append(t.Actions, Action(action))
|
||||
}
|
||||
@ -170,15 +248,19 @@ func (iam *IdentityAccessManagement) loadS3ApiConfiguration(config *iam_pb.S3Api
|
||||
}
|
||||
identities = append(identities, t)
|
||||
}
|
||||
|
||||
iam.m.Lock()
|
||||
// atomically switch
|
||||
iam.identities = identities
|
||||
iam.identityAnonymous = identityAnonymous
|
||||
iam.accounts = accounts
|
||||
iam.emailAccount = emailAccount
|
||||
iam.accessKeyIdent = accessKeyIdent
|
||||
if !iam.isAuthEnabled { // one-directional, no toggling
|
||||
iam.isAuthEnabled = len(identities) > 0
|
||||
}
|
||||
iam.m.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -209,6 +291,24 @@ func (iam *IdentityAccessManagement) lookupAnonymous() (identity *Identity, foun
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (iam *IdentityAccessManagement) GetAccountNameById(canonicalId string) string {
|
||||
iam.m.RLock()
|
||||
defer iam.m.RUnlock()
|
||||
if account, ok := iam.accounts[canonicalId]; ok {
|
||||
return account.DisplayName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (iam *IdentityAccessManagement) GetAccountIdByEmail(email string) string {
|
||||
iam.m.RLock()
|
||||
defer iam.m.RUnlock()
|
||||
if account, ok := iam.emailAccount[email]; ok {
|
||||
return account.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (iam *IdentityAccessManagement) Auth(f http.HandlerFunc, action Action) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
if !iam.isEnabled() {
|
||||
@ -287,9 +387,8 @@ func (iam *IdentityAccessManagement) authRequest(r *http.Request, action Action)
|
||||
return identity, s3err.ErrAccessDenied
|
||||
}
|
||||
|
||||
if !identity.isAnonymous() {
|
||||
r.Header.Set(s3_constants.AmzAccountId, identity.AccountId)
|
||||
}
|
||||
r.Header.Set(s3_constants.AmzAccountId, identity.Account.Id)
|
||||
|
||||
return identity, s3err.ErrNone
|
||||
|
||||
}
|
||||
|
@ -2,14 +2,12 @@ package s3api
|
||||
|
||||
import (
|
||||
. "github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
jsonpb "google.golang.org/protobuf/encoding/protojson"
|
||||
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
||||
jsonpb "google.golang.org/protobuf/encoding/protojson"
|
||||
)
|
||||
|
||||
func TestIdentityListFileFormat(t *testing.T) {
|
||||
@ -146,11 +144,22 @@ func TestCanDo(t *testing.T) {
|
||||
}
|
||||
|
||||
type LoadS3ApiConfigurationTestCase struct {
|
||||
pbAccount *iam_pb.Account
|
||||
pbIdent *iam_pb.Identity
|
||||
expectIdent *Identity
|
||||
}
|
||||
|
||||
func TestLoadS3ApiConfiguration(t *testing.T) {
|
||||
specifiedAccount := Account{
|
||||
Id: "specifiedAccountID",
|
||||
DisplayName: "specifiedAccountName",
|
||||
EmailAddress: "specifiedAccounEmail@example.com",
|
||||
}
|
||||
pbSpecifiedAccount := iam_pb.Account{
|
||||
Id: "specifiedAccountID",
|
||||
DisplayName: "specifiedAccountName",
|
||||
EmailAddress: "specifiedAccounEmail@example.com",
|
||||
}
|
||||
testCases := map[string]*LoadS3ApiConfigurationTestCase{
|
||||
"notSpecifyAccountId": {
|
||||
pbIdent: &iam_pb.Identity{
|
||||
@ -167,8 +176,8 @@ func TestLoadS3ApiConfiguration(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expectIdent: &Identity{
|
||||
Name: "notSpecifyAccountId",
|
||||
AccountId: s3account.AccountAdmin.Id,
|
||||
Name: "notSpecifyAccountId",
|
||||
Account: &AccountAdmin,
|
||||
Actions: []Action{
|
||||
"Read",
|
||||
"Write",
|
||||
@ -182,17 +191,18 @@ func TestLoadS3ApiConfiguration(t *testing.T) {
|
||||
},
|
||||
},
|
||||
"specifiedAccountID": {
|
||||
pbAccount: &pbSpecifiedAccount,
|
||||
pbIdent: &iam_pb.Identity{
|
||||
Name: "specifiedAccountID",
|
||||
AccountId: "specifiedAccountID",
|
||||
Name: "specifiedAccountID",
|
||||
Account: &pbSpecifiedAccount,
|
||||
Actions: []string{
|
||||
"Read",
|
||||
"Write",
|
||||
},
|
||||
},
|
||||
expectIdent: &Identity{
|
||||
Name: "specifiedAccountID",
|
||||
AccountId: "specifiedAccountID",
|
||||
Name: "specifiedAccountID",
|
||||
Account: &specifiedAccount,
|
||||
Actions: []Action{
|
||||
"Read",
|
||||
"Write",
|
||||
@ -208,8 +218,8 @@ func TestLoadS3ApiConfiguration(t *testing.T) {
|
||||
},
|
||||
},
|
||||
expectIdent: &Identity{
|
||||
Name: "anonymous",
|
||||
AccountId: "anonymous",
|
||||
Name: "anonymous",
|
||||
Account: &AccountAnonymous,
|
||||
Actions: []Action{
|
||||
"Read",
|
||||
"Write",
|
||||
@ -223,6 +233,9 @@ func TestLoadS3ApiConfiguration(t *testing.T) {
|
||||
}
|
||||
for _, v := range testCases {
|
||||
config.Identities = append(config.Identities, v.pbIdent)
|
||||
if v.pbAccount != nil {
|
||||
config.Accounts = append(config.Accounts, v.pbAccount)
|
||||
}
|
||||
}
|
||||
|
||||
iam := IdentityAccessManagement{}
|
||||
@ -234,7 +247,7 @@ func TestLoadS3ApiConfiguration(t *testing.T) {
|
||||
for _, ident := range iam.identities {
|
||||
tc := testCases[ident.Name]
|
||||
if !reflect.DeepEqual(ident, tc.expectIdent) {
|
||||
t.Error("not expect")
|
||||
t.Errorf("not expect for ident name %s", ident.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util"
|
||||
"math"
|
||||
@ -19,7 +18,7 @@ var loadBucketMetadataFromFiler = func(r *BucketRegistry, bucketName string) (*B
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return buildBucketMetadata(r.s3a.accountManager, entry), nil
|
||||
return buildBucketMetadata(r.s3a.iam, entry), nil
|
||||
}
|
||||
|
||||
type BucketMetaData struct {
|
||||
@ -73,13 +72,13 @@ func (r *BucketRegistry) init() error {
|
||||
}
|
||||
|
||||
func (r *BucketRegistry) LoadBucketMetadata(entry *filer_pb.Entry) {
|
||||
bucketMetadata := buildBucketMetadata(r.s3a.accountManager, entry)
|
||||
bucketMetadata := buildBucketMetadata(r.s3a.iam, entry)
|
||||
r.metadataCacheLock.Lock()
|
||||
defer r.metadataCacheLock.Unlock()
|
||||
r.metadataCache[entry.Name] = bucketMetadata
|
||||
}
|
||||
|
||||
func buildBucketMetadata(accountManager *s3account.AccountManager, entry *filer_pb.Entry) *BucketMetaData {
|
||||
func buildBucketMetadata(accountManager AccountManager, entry *filer_pb.Entry) *BucketMetaData {
|
||||
entryJson, _ := json.Marshal(entry)
|
||||
glog.V(3).Infof("build bucket metadata,entry=%s", entryJson)
|
||||
bucketMetadata := &BucketMetaData{
|
||||
@ -90,8 +89,8 @@ func buildBucketMetadata(accountManager *s3account.AccountManager, entry *filer_
|
||||
|
||||
// Default owner: `AccountAdmin`
|
||||
Owner: &s3.Owner{
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
DisplayName: &s3account.AccountAdmin.Name,
|
||||
ID: &AccountAdmin.Id,
|
||||
DisplayName: &AccountAdmin.DisplayName,
|
||||
},
|
||||
}
|
||||
if entry.Extended != nil {
|
||||
@ -112,8 +111,8 @@ func buildBucketMetadata(accountManager *s3account.AccountManager, entry *filer_
|
||||
acpOwnerBytes, ok := entry.Extended[s3_constants.ExtAmzOwnerKey]
|
||||
if ok && len(acpOwnerBytes) > 0 {
|
||||
ownerAccountId := string(acpOwnerBytes)
|
||||
ownerAccountName, exists := accountManager.IdNameMapping[ownerAccountId]
|
||||
if !exists {
|
||||
ownerAccountName := accountManager.GetAccountNameById(ownerAccountId)
|
||||
if ownerAccountName == "" {
|
||||
glog.Warningf("owner[id=%s] is invalid, bucket: %s", ownerAccountId, bucketMetadata.Name)
|
||||
} else {
|
||||
bucketMetadata.Owner = &s3.Owner{
|
||||
|
@ -5,8 +5,8 @@ import (
|
||||
"fmt"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
"reflect"
|
||||
"sync"
|
||||
@ -31,7 +31,7 @@ var (
|
||||
Name: "entryWithValidAcp",
|
||||
Extended: map[string][]byte{
|
||||
s3_constants.ExtOwnershipKey: []byte(s3_constants.OwnershipBucketOwnerEnforced),
|
||||
s3_constants.ExtAmzOwnerKey: []byte(s3account.AccountAdmin.Name),
|
||||
s3_constants.ExtAmzOwnerKey: []byte(AccountAdmin.DisplayName),
|
||||
s3_constants.ExtAmzAclKey: goodEntryAcl,
|
||||
},
|
||||
}
|
||||
@ -88,8 +88,8 @@ var tcs = []*BucketMetadataTestCase{
|
||||
Name: badEntry.Name,
|
||||
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
||||
Owner: &s3.Owner{
|
||||
DisplayName: &s3account.AccountAdmin.Name,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
DisplayName: &AccountAdmin.DisplayName,
|
||||
ID: &AccountAdmin.Id,
|
||||
},
|
||||
Acl: nil,
|
||||
},
|
||||
@ -99,8 +99,8 @@ var tcs = []*BucketMetadataTestCase{
|
||||
Name: goodEntry.Name,
|
||||
ObjectOwnership: s3_constants.OwnershipBucketOwnerEnforced,
|
||||
Owner: &s3.Owner{
|
||||
DisplayName: &s3account.AccountAdmin.Name,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
DisplayName: &AccountAdmin.DisplayName,
|
||||
ID: &AccountAdmin.Id,
|
||||
},
|
||||
Acl: s3_constants.PublicRead,
|
||||
},
|
||||
@ -110,8 +110,8 @@ var tcs = []*BucketMetadataTestCase{
|
||||
Name: ownershipEmptyStr.Name,
|
||||
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
||||
Owner: &s3.Owner{
|
||||
DisplayName: &s3account.AccountAdmin.Name,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
DisplayName: &AccountAdmin.DisplayName,
|
||||
ID: &AccountAdmin.Id,
|
||||
},
|
||||
Acl: nil,
|
||||
},
|
||||
@ -121,8 +121,8 @@ var tcs = []*BucketMetadataTestCase{
|
||||
Name: ownershipValid.Name,
|
||||
ObjectOwnership: s3_constants.OwnershipBucketOwnerEnforced,
|
||||
Owner: &s3.Owner{
|
||||
DisplayName: &s3account.AccountAdmin.Name,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
DisplayName: &AccountAdmin.DisplayName,
|
||||
ID: &AccountAdmin.Id,
|
||||
},
|
||||
Acl: nil,
|
||||
},
|
||||
@ -132,8 +132,8 @@ var tcs = []*BucketMetadataTestCase{
|
||||
Name: acpEmptyStr.Name,
|
||||
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
||||
Owner: &s3.Owner{
|
||||
DisplayName: &s3account.AccountAdmin.Name,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
DisplayName: &AccountAdmin.DisplayName,
|
||||
ID: &AccountAdmin.Id,
|
||||
},
|
||||
Acl: nil,
|
||||
},
|
||||
@ -143,8 +143,8 @@ var tcs = []*BucketMetadataTestCase{
|
||||
Name: acpEmptyObject.Name,
|
||||
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
||||
Owner: &s3.Owner{
|
||||
DisplayName: &s3account.AccountAdmin.Name,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
DisplayName: &AccountAdmin.DisplayName,
|
||||
ID: &AccountAdmin.Id,
|
||||
},
|
||||
Acl: nil,
|
||||
},
|
||||
@ -154,8 +154,8 @@ var tcs = []*BucketMetadataTestCase{
|
||||
Name: acpOwnerNil.Name,
|
||||
ObjectOwnership: s3_constants.DefaultOwnershipForExists,
|
||||
Owner: &s3.Owner{
|
||||
DisplayName: &s3account.AccountAdmin.Name,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
DisplayName: &AccountAdmin.DisplayName,
|
||||
ID: &AccountAdmin.Id,
|
||||
},
|
||||
Acl: make([]*s3.Grant, 0),
|
||||
},
|
||||
@ -163,14 +163,10 @@ var tcs = []*BucketMetadataTestCase{
|
||||
}
|
||||
|
||||
func TestBuildBucketMetadata(t *testing.T) {
|
||||
accountManager := &s3account.AccountManager{
|
||||
IdNameMapping: map[string]string{
|
||||
s3account.AccountAdmin.Id: s3account.AccountAdmin.Name,
|
||||
s3account.AccountAnonymous.Id: s3account.AccountAnonymous.Name,
|
||||
},
|
||||
}
|
||||
iam := &IdentityAccessManagement{}
|
||||
_ = iam.loadS3ApiConfiguration(&iam_pb.S3ApiConfiguration{})
|
||||
for _, tc := range tcs {
|
||||
resultBucketMetadata := buildBucketMetadata(accountManager, tc.filerEntry)
|
||||
resultBucketMetadata := buildBucketMetadata(iam, tc.filerEntry)
|
||||
if !reflect.DeepEqual(resultBucketMetadata, tc.expectBucketMetadata) {
|
||||
t.Fatalf("result is unexpect: \nresult: %v, \nexpect: %v", resultBucketMetadata, tc.expectBucketMetadata)
|
||||
}
|
||||
|
6
weed/s3api/s3_constants/s3_acp.go
Normal file
6
weed/s3api/s3_constants/s3_acp.go
Normal file
@ -0,0 +1,6 @@
|
||||
package s3_constants
|
||||
|
||||
const (
|
||||
AccountAnonymousId = "anonymous"
|
||||
AccountAdminId = "admin"
|
||||
)
|
@ -1,70 +0,0 @@
|
||||
package s3account
|
||||
|
||||
import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"sync"
|
||||
)
|
||||
|
||||
//Predefined Accounts
|
||||
var (
|
||||
// AccountAdmin is used as the default account for IAM-Credentials access without Account configured
|
||||
AccountAdmin = Account{
|
||||
Name: "admin",
|
||||
EmailAddress: "admin@example.com",
|
||||
Id: "admin",
|
||||
}
|
||||
|
||||
// AccountAnonymous is used to represent the account for anonymous access
|
||||
AccountAnonymous = Account{
|
||||
Name: "anonymous",
|
||||
EmailAddress: "anonymous@example.com",
|
||||
Id: "anonymous",
|
||||
}
|
||||
)
|
||||
|
||||
//Account represents a system user, a system user can
|
||||
//configure multiple IAM-Users, IAM-Users can configure
|
||||
//permissions respectively, and each IAM-User can
|
||||
//configure multiple security credentials
|
||||
type Account struct {
|
||||
//Name is also used to display the "DisplayName" as the owner of the bucket or object
|
||||
Name string
|
||||
EmailAddress string
|
||||
|
||||
//Id is used to identify an Account when granting cross-account access(ACLs) to buckets and objects
|
||||
Id string
|
||||
}
|
||||
|
||||
type AccountManager struct {
|
||||
sync.Mutex
|
||||
filerClient filer_pb.FilerClient
|
||||
|
||||
IdNameMapping map[string]string
|
||||
EmailIdMapping map[string]string
|
||||
}
|
||||
|
||||
func NewAccountManager(filerClient filer_pb.FilerClient) *AccountManager {
|
||||
am := &AccountManager{
|
||||
filerClient: filerClient,
|
||||
IdNameMapping: make(map[string]string),
|
||||
EmailIdMapping: make(map[string]string),
|
||||
}
|
||||
am.initialize()
|
||||
return am
|
||||
}
|
||||
|
||||
func (am *AccountManager) GetAccountNameById(canonicalId string) string {
|
||||
return am.IdNameMapping[canonicalId]
|
||||
}
|
||||
|
||||
func (am *AccountManager) GetAccountIdByEmail(email string) string {
|
||||
return am.EmailIdMapping[email]
|
||||
}
|
||||
|
||||
func (am *AccountManager) initialize() {
|
||||
// load predefined Accounts
|
||||
for _, account := range []Account{AccountAdmin, AccountAnonymous} {
|
||||
am.IdNameMapping[account.Id] = account.Name
|
||||
am.EmailIdMapping[account.EmailAddress] = account.Id
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package s3acl
|
||||
package s3api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
@ -8,25 +8,29 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type AccountManager interface {
|
||||
GetAccountNameById(canonicalId string) string
|
||||
GetAccountIdByEmail(email string) string
|
||||
}
|
||||
|
||||
// GetAccountId get AccountId from request headers, AccountAnonymousId will be return if not presen
|
||||
func GetAccountId(r *http.Request) string {
|
||||
id := r.Header.Get(s3_constants.AmzAccountId)
|
||||
if len(id) == 0 {
|
||||
return s3account.AccountAnonymous.Id
|
||||
return s3_constants.AccountAnonymousId
|
||||
} else {
|
||||
return id
|
||||
}
|
||||
}
|
||||
|
||||
// ExtractAcl extracts the acl from the request body, or from the header if request body is empty
|
||||
func ExtractAcl(r *http.Request, accountManager *s3account.AccountManager, ownership, bucketOwnerId, ownerId, accountId string) (grants []*s3.Grant, errCode s3err.ErrorCode) {
|
||||
func ExtractAcl(r *http.Request, accountManager AccountManager, ownership, bucketOwnerId, ownerId, accountId string) (grants []*s3.Grant, errCode s3err.ErrorCode) {
|
||||
if r.Body != nil && r.Body != http.NoBody {
|
||||
defer util.CloseRequest(r)
|
||||
|
||||
@ -50,7 +54,7 @@ func ExtractAcl(r *http.Request, accountManager *s3account.AccountManager, owner
|
||||
}
|
||||
|
||||
// ParseAndValidateAclHeadersOrElseDefault will callParseAndValidateAclHeaders to get Grants, if empty, it will return Grant that grant `accountId` with `FullControl` permission
|
||||
func ParseAndValidateAclHeadersOrElseDefault(r *http.Request, accountManager *s3account.AccountManager, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
|
||||
func ParseAndValidateAclHeadersOrElseDefault(r *http.Request, accountManager AccountManager, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
|
||||
ownerId, grants, errCode = ParseAndValidateAclHeaders(r, accountManager, ownership, bucketOwnerId, accountId, putAcl)
|
||||
if errCode != s3err.ErrNone {
|
||||
return
|
||||
@ -69,7 +73,7 @@ func ParseAndValidateAclHeadersOrElseDefault(r *http.Request, accountManager *s3
|
||||
}
|
||||
|
||||
// ParseAndValidateAclHeaders parse and validate acl from header
|
||||
func ParseAndValidateAclHeaders(r *http.Request, accountManager *s3account.AccountManager, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
|
||||
func ParseAndValidateAclHeaders(r *http.Request, accountManager AccountManager, ownership, bucketOwnerId, accountId string, putAcl bool) (ownerId string, grants []*s3.Grant, errCode s3err.ErrorCode) {
|
||||
ownerId, grants, errCode = ParseAclHeaders(r, ownership, bucketOwnerId, accountId, putAcl)
|
||||
if errCode != s3err.ErrNone {
|
||||
return
|
||||
@ -257,7 +261,7 @@ func ParseCannedAclHeader(bucketOwnership, bucketOwnerId, accountId, cannedAcl s
|
||||
}
|
||||
|
||||
// ValidateAndTransferGrants validate grant & transfer Email-Grant to Id-Grant
|
||||
func ValidateAndTransferGrants(accountManager *s3account.AccountManager, grants []*s3.Grant) ([]*s3.Grant, s3err.ErrorCode) {
|
||||
func ValidateAndTransferGrants(accountManager AccountManager, grants []*s3.Grant) ([]*s3.Grant, s3err.ErrorCode) {
|
||||
var result []*s3.Grant
|
||||
for _, grant := range grants {
|
||||
grantee := grant.Grantee
|
||||
@ -283,8 +287,8 @@ func ValidateAndTransferGrants(accountManager *s3account.AccountManager, grants
|
||||
glog.Warning("invalid canonical grantee! account id is nil")
|
||||
return nil, s3err.ErrInvalidRequest
|
||||
}
|
||||
_, ok := accountManager.IdNameMapping[*grantee.ID]
|
||||
if !ok {
|
||||
name := accountManager.GetAccountNameById(*grantee.ID)
|
||||
if len(name) == 0 {
|
||||
glog.Warningf("invalid canonical grantee! account id[%s] is not exists", *grantee.ID)
|
||||
return nil, s3err.ErrInvalidRequest
|
||||
}
|
||||
@ -294,8 +298,8 @@ func ValidateAndTransferGrants(accountManager *s3account.AccountManager, grants
|
||||
glog.Warning("invalid email grantee! email address is nil")
|
||||
return nil, s3err.ErrInvalidRequest
|
||||
}
|
||||
accountId, ok := accountManager.EmailIdMapping[*grantee.EmailAddress]
|
||||
if !ok {
|
||||
accountId := accountManager.GetAccountIdByEmail(*grantee.EmailAddress)
|
||||
if len(accountId) == 0 {
|
||||
glog.Warningf("invalid email grantee! email address[%s] is not exists", *grantee.EmailAddress)
|
||||
return nil, s3err.ErrInvalidRequest
|
||||
}
|
||||
@ -348,7 +352,7 @@ func DetermineReqGrants(accountId, aclAction string) (grants []*s3.Grant) {
|
||||
})
|
||||
|
||||
// group grantee (AuthenticateUsers)
|
||||
if accountId != s3account.AccountAnonymous.Id {
|
||||
if accountId != s3_constants.AccountAnonymousId {
|
||||
grants = append(grants, &s3.Grant{
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeGroup,
|
@ -1,34 +1,38 @@
|
||||
package s3acl
|
||||
package s3api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/iam_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
accountManager = &s3account.AccountManager{
|
||||
IdNameMapping: map[string]string{
|
||||
s3account.AccountAdmin.Id: s3account.AccountAdmin.Name,
|
||||
s3account.AccountAnonymous.Id: s3account.AccountAnonymous.Name,
|
||||
"accountA": "accountA",
|
||||
"accountB": "accountB",
|
||||
var accountManager *IdentityAccessManagement
|
||||
|
||||
func init() {
|
||||
accountManager = &IdentityAccessManagement{}
|
||||
_ = accountManager.loadS3ApiConfiguration(&iam_pb.S3ApiConfiguration{
|
||||
Accounts: []*iam_pb.Account{
|
||||
{
|
||||
Id: "accountA",
|
||||
DisplayName: "accountAName",
|
||||
EmailAddress: "accountA@example.com",
|
||||
},
|
||||
{
|
||||
Id: "accountB",
|
||||
DisplayName: "accountBName",
|
||||
EmailAddress: "accountB@example.com",
|
||||
},
|
||||
},
|
||||
EmailIdMapping: map[string]string{
|
||||
s3account.AccountAdmin.EmailAddress: s3account.AccountAdmin.Id,
|
||||
s3account.AccountAnonymous.EmailAddress: s3account.AccountAnonymous.Id,
|
||||
"accountA@example.com": "accountA",
|
||||
"accountBexample.com": "accountB",
|
||||
},
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetAccountId(t *testing.T) {
|
||||
req := &http.Request{
|
||||
@ -36,22 +40,22 @@ func TestGetAccountId(t *testing.T) {
|
||||
}
|
||||
//case1
|
||||
//accountId: "admin"
|
||||
req.Header.Set(s3_constants.AmzAccountId, s3account.AccountAdmin.Id)
|
||||
if GetAccountId(req) != s3account.AccountAdmin.Id {
|
||||
req.Header.Set(s3_constants.AmzAccountId, s3_constants.AccountAdminId)
|
||||
if GetAccountId(req) != s3_constants.AccountAdminId {
|
||||
t.Fatal("expect accountId: admin")
|
||||
}
|
||||
|
||||
//case2
|
||||
//accountId: "anoymous"
|
||||
req.Header.Set(s3_constants.AmzAccountId, s3account.AccountAnonymous.Id)
|
||||
if GetAccountId(req) != s3account.AccountAnonymous.Id {
|
||||
req.Header.Set(s3_constants.AmzAccountId, s3_constants.AccountAnonymousId)
|
||||
if GetAccountId(req) != s3_constants.AccountAnonymousId {
|
||||
t.Fatal("expect accountId: anonymous")
|
||||
}
|
||||
|
||||
//case3
|
||||
//accountId is nil => "anonymous"
|
||||
req.Header.Del(s3_constants.AmzAccountId)
|
||||
if GetAccountId(req) != s3account.AccountAnonymous.Id {
|
||||
if GetAccountId(req) != s3_constants.AccountAnonymousId {
|
||||
t.Fatal("expect accountId: anonymous")
|
||||
}
|
||||
}
|
||||
@ -64,7 +68,6 @@ func TestExtractAcl(t *testing.T) {
|
||||
}
|
||||
testCases := make([]*Case, 0)
|
||||
accountAdminId := "admin"
|
||||
|
||||
{
|
||||
//case1 (good case)
|
||||
//parse acp from request body
|
||||
@ -249,14 +252,14 @@ func TestParseAndValidateAclHeaders(t *testing.T) {
|
||||
{
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeCanonicalUser,
|
||||
ID: &s3account.AccountAnonymous.Id,
|
||||
ID: aws.String(s3_constants.AccountAnonymousId),
|
||||
},
|
||||
Permission: &s3_constants.PermissionFullControl,
|
||||
},
|
||||
{
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeCanonicalUser,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
},
|
||||
Permission: &s3_constants.PermissionFullControl,
|
||||
},
|
||||
@ -391,7 +394,7 @@ func grantsEquals(a, b []*s3.Grant) bool {
|
||||
func TestDetermineReqGrants(t *testing.T) {
|
||||
{
|
||||
//case1: request account is anonymous
|
||||
accountId := s3account.AccountAnonymous.Id
|
||||
accountId := s3_constants.AccountAnonymousId
|
||||
reqPermission := s3_constants.PermissionRead
|
||||
|
||||
resultGrants := DetermineReqGrants(accountId, reqPermission)
|
||||
@ -496,7 +499,7 @@ func TestAssembleEntryWithAcp(t *testing.T) {
|
||||
Permission: &s3_constants.PermissionRead,
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeGroup,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
URI: &s3_constants.GranteeGroupAllUsers,
|
||||
},
|
||||
},
|
||||
@ -569,13 +572,13 @@ func TestGrantEquals(t *testing.T) {
|
||||
GrantEquals(&s3.Grant{
|
||||
Permission: &s3_constants.PermissionRead,
|
||||
Grantee: &s3.Grantee{
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
EmailAddress: &s3account.AccountAdmin.EmailAddress,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
//EmailAddress: &s3account.AccountAdmin.EmailAddress,
|
||||
},
|
||||
}, &s3.Grant{
|
||||
Permission: &s3_constants.PermissionRead,
|
||||
Grantee: &s3.Grantee{
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
},
|
||||
}): true,
|
||||
|
||||
@ -623,13 +626,13 @@ func TestGrantEquals(t *testing.T) {
|
||||
Permission: &s3_constants.PermissionRead,
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeGroup,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
},
|
||||
}, &s3.Grant{
|
||||
Permission: &s3_constants.PermissionRead,
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeGroup,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
},
|
||||
}): true,
|
||||
|
||||
@ -637,14 +640,14 @@ func TestGrantEquals(t *testing.T) {
|
||||
Permission: &s3_constants.PermissionRead,
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeGroup,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
URI: &s3_constants.GranteeGroupAllUsers,
|
||||
},
|
||||
}, &s3.Grant{
|
||||
Permission: &s3_constants.PermissionRead,
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeGroup,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
},
|
||||
}): false,
|
||||
|
||||
@ -652,7 +655,7 @@ func TestGrantEquals(t *testing.T) {
|
||||
Permission: &s3_constants.PermissionRead,
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeGroup,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
URI: &s3_constants.GranteeGroupAllUsers,
|
||||
},
|
||||
}, &s3.Grant{
|
||||
@ -692,7 +695,7 @@ func TestSetAcpGrantsHeader(t *testing.T) {
|
||||
Permission: &s3_constants.PermissionRead,
|
||||
Grantee: &s3.Grantee{
|
||||
Type: &s3_constants.GrantTypeGroup,
|
||||
ID: &s3account.AccountAdmin.Id,
|
||||
ID: aws.String(s3_constants.AccountAdminId),
|
||||
URI: &s3_constants.GranteeGroupAllUsers,
|
||||
},
|
||||
},
|
@ -2,7 +2,6 @@ package s3api
|
||||
|
||||
import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3_constants"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3err"
|
||||
"net/http"
|
||||
)
|
||||
@ -10,7 +9,7 @@ import (
|
||||
func getAccountId(r *http.Request) string {
|
||||
id := r.Header.Get(s3_constants.AmzAccountId)
|
||||
if len(id) == 0 {
|
||||
return s3account.AccountAnonymous.Id
|
||||
return AccountAnonymous.Id
|
||||
} else {
|
||||
return id
|
||||
}
|
||||
@ -22,7 +21,7 @@ func (s3a *S3ApiServer) checkAccessByOwnership(r *http.Request, bucket string) s
|
||||
return errCode
|
||||
}
|
||||
accountId := getAccountId(r)
|
||||
if accountId == s3account.AccountAdmin.Id || accountId == *metadata.Owner.ID {
|
||||
if accountId == AccountAdmin.Id || accountId == *metadata.Owner.ID {
|
||||
return s3err.ErrNone
|
||||
}
|
||||
return s3err.ErrAccessDenied
|
||||
|
@ -259,17 +259,18 @@ func (s3a *S3ApiServer) GetBucketAclHandler(w http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
identityId := r.Header.Get(s3_constants.AmzIdentityId)
|
||||
amzAccountId := r.Header.Get(s3_constants.AmzAccountId)
|
||||
amzDisplayName := s3a.iam.GetAccountNameById(amzAccountId)
|
||||
response := AccessControlPolicy{
|
||||
Owner: CanonicalUser{
|
||||
ID: identityId,
|
||||
DisplayName: identityId,
|
||||
ID: amzAccountId,
|
||||
DisplayName: amzDisplayName,
|
||||
},
|
||||
}
|
||||
response.AccessControlList.Grant = append(response.AccessControlList.Grant, Grant{
|
||||
Grantee: Grantee{
|
||||
ID: identityId,
|
||||
DisplayName: identityId,
|
||||
ID: amzAccountId,
|
||||
DisplayName: amzDisplayName,
|
||||
Type: "CanonicalUser",
|
||||
XMLXSI: "CanonicalUser",
|
||||
XMLNS: "http://www.w3.org/2001/XMLSchema-instance"},
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"fmt"
|
||||
"github.com/seaweedfs/seaweedfs/weed/filer"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/s3_pb"
|
||||
"github.com/seaweedfs/seaweedfs/weed/s3api/s3account"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
@ -42,7 +41,6 @@ type S3ApiServer struct {
|
||||
randomClientId int32
|
||||
filerGuard *security.Guard
|
||||
client *http.Client
|
||||
accountManager *s3account.AccountManager
|
||||
bucketRegistry *BucketRegistry
|
||||
}
|
||||
|
||||
@ -63,7 +61,6 @@ func NewS3ApiServer(router *mux.Router, option *S3ApiServerOption) (s3ApiServer
|
||||
filerGuard: security.NewGuard([]string{}, signingKey, expiresAfterSec, readSigningKey, readExpiresAfterSec),
|
||||
cb: NewCircuitBreaker(option),
|
||||
}
|
||||
s3ApiServer.accountManager = s3account.NewAccountManager(s3ApiServer)
|
||||
s3ApiServer.bucketRegistry = NewBucketRegistry(s3ApiServer)
|
||||
if option.LocalFilerSocket == "" {
|
||||
s3ApiServer.client = &http.Client{Transport: &http.Transport{
|
||||
|
Loading…
Reference in New Issue
Block a user