diff --git a/moto/s3/models.py b/moto/s3/models.py index 6796894f8..4a4601d3c 100644 --- a/moto/s3/models.py +++ b/moto/s3/models.py @@ -184,6 +184,7 @@ class FakeBucket(object): self.multiparts = {} self.versioning_status = None self.rules = [] + self.policy = None @property def location(self): @@ -269,6 +270,12 @@ class S3Backend(BaseBackend): return itertools.chain(*(l for _, l in bucket.keys.iterlists())) + def get_bucket_policy(self, bucket_name): + return self.get_bucket(bucket_name).policy + + def set_bucket_policy(self, bucket_name, policy): + self.get_bucket(bucket_name).policy = policy + def set_bucket_lifecycle(self, bucket_name, rules): bucket = self.get_bucket(bucket_name) bucket.set_lifecycle(rules) diff --git a/moto/s3/responses.py b/moto/s3/responses.py index adaefc230..551e22534 100644 --- a/moto/s3/responses.py +++ b/moto/s3/responses.py @@ -103,6 +103,12 @@ class ResponseObject(_TemplateEnvironmentMixin): versioning = self.backend.get_bucket_versioning(bucket_name) template = self.response_template(S3_BUCKET_GET_VERSIONING) return 200, headers, template.render(status=versioning) + elif 'policy' in querystring: + policy = self.backend.get_bucket_policy(bucket_name) + if not policy: + template = self.response_template(S3_NO_POLICY) + return 404, headers, template.render(bucket_name=bucket_name) + return 200, headers, policy elif 'versions' in querystring: delimiter = querystring.get('delimiter', [None])[0] encoding_type = querystring.get('encoding-type', [None])[0] @@ -167,6 +173,9 @@ class ResponseObject(_TemplateEnvironmentMixin): rules = [rules] self.backend.set_bucket_lifecycle(bucket_name, rules) return "" + elif 'policy' in querystring: + self.backend.set_bucket_policy(bucket_name, body) + return 'True' else: try: new_bucket = self.backend.create_bucket(bucket_name, region_name) @@ -706,3 +715,13 @@ S3_ALL_MULTIPARTS = """ {% endfor %} """ + +S3_NO_POLICY = """ + + NoSuchBucketPolicy + The bucket policy does not exist + {{ bucket_name }} + 0D68A23BB2E2215B + 9Gjjt1m+cjU4OPvX9O9/8RuvnG41MRb/18Oux2o5H5MY7ISNTlXN+Dz9IG62/ILVxhAGI0qyPfg= + +""" diff --git a/tests/test_s3/test_s3.py b/tests/test_s3/test_s3.py index 43f25c748..8e1c35f5c 100644 --- a/tests/test_s3/test_s3.py +++ b/tests/test_s3/test_s3.py @@ -6,6 +6,7 @@ from six.moves.urllib.error import HTTPError from functools import wraps from io import BytesIO +import json import boto from boto.exception import S3CreateError, S3ResponseError from boto.s3.connection import S3Connection @@ -823,3 +824,48 @@ def test_ranged_get(): key.get_contents_as_string(headers={'Range': 'bytes=-700'}).should.equal(rep * 10) key.size.should.equal(100) + + +@mock_s3 +def test_policy(): + conn = boto.connect_s3() + bucket_name = 'mybucket' + bucket = conn.create_bucket(bucket_name) + + policy = json.dumps({ + "Version": "2012-10-17", + "Id": "PutObjPolicy", + "Statement": [ + { + "Sid": "DenyUnEncryptedObjectUploads", + "Effect": "Deny", + "Principal": "*", + "Action": "s3:PutObject", + "Resource": "arn:aws:s3:::{bucket_name}/*".format(bucket_name=bucket_name), + "Condition": { + "StringNotEquals": { + "s3:x-amz-server-side-encryption": "aws:kms" + } + } + } + ] + }) + + with assert_raises(S3ResponseError) as err: + bucket.get_policy() + + ex = err.exception + ex.box_usage.should.be.none + ex.error_code.should.equal('NoSuchBucketPolicy') + ex.message.should.equal('The bucket policy does not exist') + ex.reason.should.equal('Not Found') + ex.resource.should.be.none + ex.status.should.equal(404) + ex.body.should.contain(bucket_name) + ex.request_id.should_not.be.none + + bucket.set_policy(policy).should.be.true + + bucket = conn.get_bucket(bucket_name) + + bucket.get_policy().decode('utf-8').should.equal(policy)