| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  | import boto3 | 
					
						
							|  |  |  | import json | 
					
						
							|  |  |  | import requests | 
					
						
							|  |  |  | import pytest | 
					
						
							|  |  |  | import sure  # noqa # pylint: disable=unused-import | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 10:33:57 -01:00
										 |  |  | from botocore.exceptions import ClientError | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  | from moto.moto_server.threaded_moto_server import ThreadedMotoServer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class TestBucketPolicy: | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def setup_class(cls): | 
					
						
							|  |  |  |         cls.server = ThreadedMotoServer(port="6000", verbose=False) | 
					
						
							|  |  |  |         cls.server.start() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-27 17:37:11 -07:00
										 |  |  |     def setup_method(self) -> None: | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  |         self.client = boto3.client( | 
					
						
							| 
									
										
										
										
											2023-03-17 12:05:05 -01:00
										 |  |  |             "s3", | 
					
						
							|  |  |  |             region_name="us-east-1", | 
					
						
							|  |  |  |             endpoint_url="http://localhost:6000", | 
					
						
							|  |  |  |             aws_access_key_id="ak", | 
					
						
							|  |  |  |             aws_secret_access_key="sk", | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  |         ) | 
					
						
							|  |  |  |         self.client.create_bucket(Bucket="mybucket") | 
					
						
							|  |  |  |         self.client.put_object(Bucket="mybucket", Key="test_txt", Body=b"mybytes") | 
					
						
							|  |  |  |         self.key_name = "http://localhost:6000/mybucket/test_txt" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-27 17:37:11 -07:00
										 |  |  |     def teardown_method(self) -> None: | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  |         self.client.delete_object(Bucket="mybucket", Key="test_txt") | 
					
						
							|  |  |  |         self.client.delete_bucket(Bucket="mybucket") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @staticmethod | 
					
						
							|  |  |  |     def teardown_class(cls): | 
					
						
							|  |  |  |         cls.server.stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @pytest.mark.parametrize( | 
					
						
							|  |  |  |         "kwargs,status", | 
					
						
							|  |  |  |         [ | 
					
						
							|  |  |  |             ({}, 200), | 
					
						
							|  |  |  |             ({"resource": "arn:aws:s3:::mybucket/test_txt"}, 200), | 
					
						
							|  |  |  |             ({"resource": "arn:aws:s3:::notmybucket/*"}, 403), | 
					
						
							|  |  |  |             ({"resource": "arn:aws:s3:::mybucket/other*"}, 403), | 
					
						
							| 
									
										
										
										
											2023-02-07 19:54:59 +05:30
										 |  |  |             ({"resource": ["arn:aws:s3:::mybucket", "arn:aws:s3:::mybucket/*"]}, 200), | 
					
						
							|  |  |  |             ( | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "resource": [ | 
					
						
							|  |  |  |                         "arn:aws:s3:::notmybucket", | 
					
						
							|  |  |  |                         "arn:aws:s3:::notmybucket/*", | 
					
						
							|  |  |  |                     ] | 
					
						
							|  |  |  |                 }, | 
					
						
							|  |  |  |                 403, | 
					
						
							|  |  |  |             ), | 
					
						
							|  |  |  |             ( | 
					
						
							|  |  |  |                 {"resource": ["arn:aws:s3:::mybucket", "arn:aws:s3:::notmybucket/*"]}, | 
					
						
							|  |  |  |                 403, | 
					
						
							|  |  |  |             ), | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  |             ({"effect": "Deny"}, 403), | 
					
						
							|  |  |  |         ], | 
					
						
							|  |  |  |     ) | 
					
						
							| 
									
										
										
										
											2023-01-31 10:33:57 -01:00
										 |  |  |     def test_block_or_allow_get_object(self, kwargs, status): | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  |         self._put_policy(**kwargs) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 10:33:57 -01:00
										 |  |  |         if status == 200: | 
					
						
							|  |  |  |             self.client.get_object(Bucket="mybucket", Key="test_txt") | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             with pytest.raises(ClientError): | 
					
						
							|  |  |  |                 self.client.get_object(Bucket="mybucket", Key="test_txt") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  |         requests.get(self.key_name).status_code.should.equal(status) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-01-31 10:33:57 -01:00
										 |  |  |     def test_block_put_object(self): | 
					
						
							|  |  |  |         # Block Put-access | 
					
						
							|  |  |  |         self._put_policy(**{"effect": "Deny", "actions": ["s3:PutObject"]}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # GET still works | 
					
						
							|  |  |  |         self.client.get_object(Bucket="mybucket", Key="test_txt") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # But Put (via boto3 or requests) is not allowed | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             self.client.put_object(Bucket="mybucket", Key="test_txt", Body="new data") | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  |         err["Message"].should.equal("Forbidden") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         requests.put(self.key_name).status_code.should.equal(403) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_block_all_actions(self): | 
					
						
							|  |  |  |         # Block all access | 
					
						
							|  |  |  |         self._put_policy(**{"effect": "Deny", "actions": ["s3:*"]}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Nothing works | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             self.client.get_object(Bucket="mybucket", Key="test_txt") | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  |         err["Message"].should.equal("Forbidden") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # But Put (via boto3 or requests) is not allowed | 
					
						
							|  |  |  |         with pytest.raises(ClientError) as exc: | 
					
						
							|  |  |  |             self.client.put_object(Bucket="mybucket", Key="test_txt", Body="new data") | 
					
						
							|  |  |  |         err = exc.value.response["Error"] | 
					
						
							|  |  |  |         err["Message"].should.equal("Forbidden") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         requests.get(self.key_name).status_code.should.equal(403) | 
					
						
							|  |  |  |         requests.put(self.key_name).status_code.should.equal(403) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Allow access again, because we want to delete the object during teardown | 
					
						
							|  |  |  |         self._put_policy(**{"effect": "Allow", "actions": ["s3:*"]}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     def test_block_all_with_different_principal(self): | 
					
						
							|  |  |  |         # Block all access for principal y | 
					
						
							|  |  |  |         self._put_policy(**{"effect": "Deny", "actions": ["s3:*"], "principal": "y"}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Everything works - Moto only blocks access for principal * | 
					
						
							|  |  |  |         self.client.get_object(Bucket="mybucket", Key="test_txt") | 
					
						
							|  |  |  |         self.client.put_object(Bucket="mybucket", Key="test_txt", Body="new data") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  |     def _put_policy( | 
					
						
							| 
									
										
										
										
											2023-01-31 10:33:57 -01:00
										 |  |  |         self, | 
					
						
							|  |  |  |         resource="arn:aws:s3:::mybucket/*", | 
					
						
							|  |  |  |         effect="Allow", | 
					
						
							|  |  |  |         actions=None, | 
					
						
							|  |  |  |         principal=None, | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  |     ): | 
					
						
							|  |  |  |         policy = { | 
					
						
							|  |  |  |             "Version": "2012-10-17", | 
					
						
							|  |  |  |             "Statement": [ | 
					
						
							|  |  |  |                 { | 
					
						
							|  |  |  |                     "Effect": effect, | 
					
						
							| 
									
										
										
										
											2023-01-31 10:33:57 -01:00
										 |  |  |                     "Principal": principal or "*", | 
					
						
							| 
									
										
										
										
											2022-09-16 15:59:45 +00:00
										 |  |  |                     "Action": actions or ["s3:GetObject"], | 
					
						
							|  |  |  |                     "Resource": resource, | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             ], | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         self.client.put_bucket_policy(Bucket="mybucket", Policy=json.dumps(policy)) |