1818package cmd
1919
2020import (
21+ "bytes"
2122 "context"
23+ "crypto/sha256"
24+ "encoding/hex"
25+ "encoding/json"
2226 "fmt"
27+ "io/ioutil"
28+ "net/http"
29+ "net/url"
2330 "os"
2431 "strings"
2532 "testing"
@@ -29,7 +36,9 @@ import (
2936 minio "github.com/minio/minio-go/v7"
3037 "github.com/minio/minio-go/v7/pkg/credentials"
3138 cr "github.com/minio/minio-go/v7/pkg/credentials"
39+ "github.com/minio/minio-go/v7/pkg/s3utils"
3240 "github.com/minio/minio-go/v7/pkg/set"
41+ "github.com/minio/minio-go/v7/pkg/signer"
3342 "github.com/minio/minio/internal/auth"
3443)
3544
@@ -177,6 +186,7 @@ func TestIAMInternalIDPServerSuite(t *testing.T) {
177186
178187 suite .SetUpSuite (c )
179188 suite .TestUserCreate (c )
189+ suite .TestUserPolicyEscalationBug (c )
180190 suite .TestPolicyCreate (c )
181191 suite .TestCannedPolicies (c )
182192 suite .TestGroupAddRemove (c )
@@ -222,6 +232,24 @@ func (s *TestSuiteIAM) TestUserCreate(c *check) {
222232 c .Fatalf ("user could not create bucket: %v" , err )
223233 }
224234
235+ // 3.10. Check that user's password can be updated.
236+ _ , newSecretKey := mustGenerateCredentials (c )
237+ err = s .adm .SetUser (ctx , accessKey , newSecretKey , madmin .AccountEnabled )
238+ if err != nil {
239+ c .Fatalf ("Unable to update user's secret key: %v" , err )
240+ }
241+ // 3.10.1 Check that old password no longer works.
242+ err = client .MakeBucket (ctx , getRandomBucketName (), minio.MakeBucketOptions {})
243+ if err == nil {
244+ c .Fatalf ("user was unexpectedly able to create bucket with bad password!" )
245+ }
246+ // 3.10.2 Check that new password works.
247+ client = s .getUserClient (c , accessKey , newSecretKey , "" )
248+ err = client .MakeBucket (ctx , getRandomBucketName (), minio.MakeBucketOptions {})
249+ if err != nil {
250+ c .Fatalf ("user could not create bucket: %v" , err )
251+ }
252+
225253 // 4. Check that user can be disabled and verify it.
226254 err = s .adm .SetUserStatus (ctx , accessKey , madmin .AccountDisabled )
227255 if err != nil {
@@ -260,6 +288,108 @@ func (s *TestSuiteIAM) TestUserCreate(c *check) {
260288 }
261289}
262290
291+ func (s * TestSuiteIAM ) TestUserPolicyEscalationBug (c * check ) {
292+ ctx , cancel := context .WithTimeout (context .Background (), testDefaultTimeout )
293+ defer cancel ()
294+
295+ bucket := getRandomBucketName ()
296+ err := s .client .MakeBucket (ctx , bucket , minio.MakeBucketOptions {})
297+ if err != nil {
298+ c .Fatalf ("bucket creat error: %v" , err )
299+ }
300+
301+ // 2. Create a user, associate policy and verify access
302+ accessKey , secretKey := mustGenerateCredentials (c )
303+ err = s .adm .SetUser (ctx , accessKey , secretKey , madmin .AccountEnabled )
304+ if err != nil {
305+ c .Fatalf ("Unable to set user: %v" , err )
306+ }
307+ // 2.1 check that user does not have any access to the bucket
308+ uClient := s .getUserClient (c , accessKey , secretKey , "" )
309+ c .mustNotListObjects (ctx , uClient , bucket )
310+
311+ // 2.2 create and associate policy to user
312+ policy := "mypolicy-test-user-update"
313+ policyBytes := []byte (fmt .Sprintf (`{
314+ "Version": "2012-10-17",
315+ "Statement": [
316+ {
317+ "Effect": "Allow",
318+ "Action": [
319+ "s3:PutObject",
320+ "s3:GetObject",
321+ "s3:ListBucket"
322+ ],
323+ "Resource": [
324+ "arn:aws:s3:::%s/*"
325+ ]
326+ }
327+ ]
328+ }` , bucket ))
329+ err = s .adm .AddCannedPolicy (ctx , policy , policyBytes )
330+ if err != nil {
331+ c .Fatalf ("policy add error: %v" , err )
332+ }
333+ err = s .adm .SetPolicy (ctx , policy , accessKey , false )
334+ if err != nil {
335+ c .Fatalf ("Unable to set policy: %v" , err )
336+ }
337+ // 2.3 check user has access to bucket
338+ c .mustListObjects (ctx , uClient , bucket )
339+ // 2.3 check that user cannot delete the bucket
340+ err = uClient .RemoveBucket (ctx , bucket )
341+ if err == nil || err .Error () != "Access Denied." {
342+ c .Fatalf ("bucket was deleted unexpectedly or got unexpected err: %v" , err )
343+ }
344+
345+ // 3. Craft a request to update the user's permissions
346+ ep := s .adm .GetEndpointURL ()
347+ urlValue := url.Values {}
348+ urlValue .Add ("accessKey" , accessKey )
349+ u , err := url .Parse (fmt .Sprintf ("%s://%s/minio/admin/v3/add-user?%s" , ep .Scheme , ep .Host , s3utils .QueryEncode (urlValue )))
350+ if err != nil {
351+ c .Fatalf ("unexpected url parse err: %v" , err )
352+ }
353+ req , err := http .NewRequestWithContext (ctx , http .MethodPut , u .String (), nil )
354+ if err != nil {
355+ c .Fatalf ("unexpected new request err: %v" , err )
356+ }
357+ reqBodyArg := madmin.UserInfo {
358+ SecretKey : secretKey ,
359+ PolicyName : "consoleAdmin" ,
360+ Status : madmin .AccountEnabled ,
361+ }
362+ buf , err := json .Marshal (reqBodyArg )
363+ if err != nil {
364+ c .Fatalf ("unexpected json encode err: %v" , err )
365+ }
366+ buf , err = madmin .EncryptData (secretKey , buf )
367+ if err != nil {
368+ c .Fatalf ("unexpected encryption err: %v" , err )
369+ }
370+
371+ req .ContentLength = int64 (len (buf ))
372+ sum := sha256 .Sum256 (buf )
373+ req .Header .Set ("X-Amz-Content-Sha256" , hex .EncodeToString (sum [:]))
374+ req .Body = ioutil .NopCloser (bytes .NewReader (buf ))
375+ req = signer .SignV4 (* req , accessKey , secretKey , "" , "" )
376+
377+ // 3.1 Execute the request.
378+ resp , err := s .TestSuiteCommon .client .Do (req )
379+ if err != nil {
380+ c .Fatalf ("unexpected request err: %v" , err )
381+ }
382+ if resp .StatusCode != 200 {
383+ c .Fatalf ("got unexpected response: %#v\n " , resp )
384+ }
385+
386+ // 3.2 check that user cannot delete the bucket
387+ err = uClient .RemoveBucket (ctx , bucket )
388+ if err == nil || err .Error () != "Access Denied." {
389+ c .Fatalf ("User was able to escalate privileges (Err=%v)!" , err )
390+ }
391+ }
392+
263393func (s * TestSuiteIAM ) TestAddServiceAccountPerms (c * check ) {
264394 ctx , cancel := context .WithTimeout (context .Background (), testDefaultTimeout )
265395 defer cancel ()
0 commit comments