为什么在使用AWS SDK时,双引号(“)在S3用户策略的条件策略语句中被解析为(\”)?

时间:2015-08-08 02:33:11

标签: amazon-s3 sdk subdirectory policy bucket

要求是通过AWS SDK限制IAM用户访问S3存储桶中的特定子文件夹。通过AWS控制台配置用户策略要容易得多,但是当使用AWS SDK将其转换为Java代码时我失败了。

例如,我希望IAM用户只能访问'mybucket'存储桶中的'subfolder1'文件夹。 以下是可与AWS控制台完美配合的用户策略: (解决方案本身请参考我在AWS控制台中成功验证的here

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Action": [
                "s3:ListAllMyBuckets",
                "s3:GetBucketLocation"
            ],
            "Resource": [
                "arn:aws:s3:::*"
            ]
        },
        {
            "Sid": "2",
            "Effect": "Allow",
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::mybucket"
            ],
            "Condition": {
                "StringEquals": {
                    "s3:prefix": [
                        "",
                        "subfolder1/"
                    ],
                    "s3:delimiter": [
                        "/"
                    ]
                }
            }
        },
        {
            "Sid": "3",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::mybucket/subfolder1/*"
            ]
        }
    ]
}

以下是生成上述政策的java代码段。

// Attach the required permission user policy to the new user
// 1. Permission to list all the buckets (view)
final Statement allowListStatement = new Statement(Effect.Allow)
    .withActions(
            S3Actions.ListBuckets,
            S3Actions.GetBucketLocation
        )
    .withResources(new Resource("arn:aws:s3:::*"));

// 2. Permission to list the objects within the bucket
final String dq = (char)(34) + "";
final String prefix = dq + dq + "," + dq + "subfolder1/" + dq;

final Statement allowBucketListStatement = new Statement(Effect.Allow)
.withActions(
        S3Actions.ListObjects
    )
.withResources(
        new S3BucketResource(bucketName)
    )
.withConditions(
        new StringCondition(
                StringComparisonType.StringEquals,
                S3ConditionFactory.PREFIX_CONDITION_KEY,
                prefix
            ),
        new StringCondition(
                StringComparisonType.StringEquals,
                S3ConditionFactory.DELIMITER_CONDITION_KEY,
                "/"
            )
    );

// 3. Permission to update the bucket content
final Statement allowBucketOperationsStatement = new Statement(Effect.Allow)
    .withActions(
            S3Actions.PutObject,
            S3Actions.GetObject,
            S3Actions.DeleteObject
        )
    .withResources(
            new S3ObjectResource(
                    bucketName,
                    usernameIAM + "/*"
                )
   );

final Policy policy = new Policy()
    .withStatements(
            allowListStatement,
            allowBucketListStatement,
            allowBucketOperationsStatement
        );

final PutUserPolicyRequest policyRequest = new PutUserPolicyRequest(
        usernameIAM,
        "policy_subfolder1",
        policy.toJson()

    );
client.putUserPolicy(policyRequest);

问题发生在'withConditions'行中(除此行外,所有其他策略行都正确生成)。

预期的行将是这样的(在AWS控制台中可以正常工作):

"Condition":{"StringEquals":{"s3:prefix":["","subfolder1/"], "s3:delimiter":["/"]}}

但实际生成的行是这样的:

"Condition":{"StringEquals":{"s3:prefix":["\"\",\"subfolder1/\""], "s3:delimiter":["/"]}}

令人奇怪的是,AWS SDK无法在语句中正确解析双引号(“):所有双引号(”)都被解析为(\“)。

'前缀'定义似乎很奇怪。在我的原始代码中,我使用了这个:

final String prefix = "\"\",\"" + usernameIAM + "/\"";

但这会产生与我目前的方法相同的问题(使用dq ascii代码)。

我不确定它是否是AWS SDK的错误。任何人都可以解决这个问题吗?或者任何其他方法或建议来实现我的要求(但必须使用SDK)?

1 个答案:

答案 0 :(得分:2)

感谢user2864740的建议。在此,我只是发布我对这个问题的回答。希望其他人可能更容易找到。 正如user2864740指出的那样,API期望值而不是“手动JSON文本”,双引号(“)将使用转义格式(\”)进行解析。

解决方案是将StringCondition拆分为不同的部分,而不是手动生成JSON字符串。这是最终可行的解决方案:

final String prefix1 = "";
final String prefix2 = "subfolder1/";
final Statement allowBucketListStatement = new Statement(Effect.Allow)
.withActions(
        S3Actions.ListObjects
    )
.withResources(
        new S3BucketResource(bucketName)
    )
.withConditions(
        new StringCondition(
                StringComparisonType.StringEquals,
                S3ConditionFactory.PREFIX_CONDITION_KEY,
                prefix1
            ),
        new StringCondition(
                StringComparisonType.StringEquals,
                S3ConditionFactory.PREFIX_CONDITION_KEY,
                prefix2
            ),
        new StringCondition(
                StringComparisonType.StringEquals,
                S3ConditionFactory.DELIMITER_CONDITION_KEY,
                "/"
            )
    );