mirror of
https://github.com/versity/versitygw.git
synced 2026-09-20 15:04:27 +00:00
feat: add IAM user inline policy CRUD
Add support for AWS-compatible inline identity-based policies on IAM users, implementing the `PutUserPolicy`, `GetUserPolicy`, `DeleteUserPolicy`, and `ListUserPolicies` actions on both the internal and Vault storage backends. - iamapi/policy is a new package that parses and validates policy documents against IAM's parameter-level constraints (max length, allowed charset) and policy grammar (Version, Effect, mutually exclusive Action/NotAction and Resource/NotResource, vendor-prefixed actions, ARN-shaped resources, no Principal/NotPrincipal, unique Sids). - `PutUserPolicy` creates or replaces a named inline policy on a user, enforcing a 2048-byte aggregate quota across all of a user's inline policies (MaxInlinePolicyBytesPerUser), matching the AWS IAM quota. - `GetUserPolicy` returns a policy's document RFC 3986 percent-encoded, matching how real IAM encodes the PolicyDocument response element. - `DeleteUserPolicy` removes a named inline policy from a user. - `ListUserPolicies` returns a paginated, sorted list of a user's inline policy names, honoring Marker/MaxItems like the other IAM list APIs. - `DeleteUser` is now rejected with a DeleteConflict error if the user still has inline policies attached, mirroring the existing access-key delete-conflict behavior.
This commit is contained in:
+31
-7
@@ -54,12 +54,12 @@ const (
|
||||
ErrInvalidClientTokenID
|
||||
ErrInvalidContentLength
|
||||
ErrThrottling
|
||||
ErrMissingUserNameValue
|
||||
ErrTooManyTags
|
||||
ErrInvalidPathPrefix
|
||||
ErrDuplicateTagKeys
|
||||
ErrInvalidAccessKeyIDChars
|
||||
ErrDeleteConflict
|
||||
ErrDeleteConflictPolicies
|
||||
)
|
||||
|
||||
type APIError interface {
|
||||
@@ -207,12 +207,6 @@ var errorCodeResponse = map[ErrorCode]Error{
|
||||
Message: "'Host' or ':authority' must be a 'SignedHeader' in the AWS Authorization.",
|
||||
HTTPStatusCode: http.StatusForbidden,
|
||||
},
|
||||
ErrMissingUserNameValue: {
|
||||
Type: TypeSender,
|
||||
Code: "ValidationError",
|
||||
Message: "1 validation error detected: Value at 'userName' failed to satisfy constraint: Member must not be null",
|
||||
HTTPStatusCode: http.StatusBadRequest,
|
||||
},
|
||||
ErrInvalidPathPrefix: {
|
||||
Type: TypeSender,
|
||||
Code: "ValidationError",
|
||||
@@ -243,6 +237,12 @@ var errorCodeResponse = map[ErrorCode]Error{
|
||||
Message: "Cannot delete entity, must delete access keys first.",
|
||||
HTTPStatusCode: http.StatusConflict,
|
||||
},
|
||||
ErrDeleteConflictPolicies: {
|
||||
Type: TypeSender,
|
||||
Code: "DeleteConflict",
|
||||
Message: "Cannot delete entity, must delete policies first.",
|
||||
HTTPStatusCode: http.StatusConflict,
|
||||
},
|
||||
}
|
||||
|
||||
func GetAPIError(code ErrorCode) Error {
|
||||
@@ -405,6 +405,30 @@ func InvalidTagValue(index int) Error {
|
||||
return ValidationError(fmt.Sprintf("1 validation error detected: Value at 'tags.%d.member.value' failed to satisfy constraint: Member must satisfy regular expression pattern: [\\p{L}\\p{Z}\\p{N}_.:/=+\\-@]*", index))
|
||||
}
|
||||
|
||||
func MissingValue(field string) Error {
|
||||
return ValidationError(fmt.Sprintf("1 validation error detected: Value at '%s' failed to satisfy constraint: Member must not be null", field))
|
||||
}
|
||||
|
||||
func ValueTooLong(field string, maxLength int) Error {
|
||||
return ValidationError(fmt.Sprintf("1 validation error detected: Value at '%s' failed to satisfy constraint: Member must have length less than or equal to %d", field, maxLength))
|
||||
}
|
||||
|
||||
func InvalidCharset(field string) Error {
|
||||
return ValidationError(fmt.Sprintf("The specified value for %s is invalid. It must contain only printable ASCII characters.", field))
|
||||
}
|
||||
|
||||
func MalformedPolicyDocument(message string) Error {
|
||||
return newSenderError("MalformedPolicyDocument", message, http.StatusBadRequest)
|
||||
}
|
||||
|
||||
func NoSuchEntityUserPolicy(userName, policyName string) Error {
|
||||
return newSenderError("NoSuchEntity", fmt.Sprintf("The user policy with name %s cannot be found.", policyName), http.StatusNotFound)
|
||||
}
|
||||
|
||||
func InlinePolicyQuotaExceeded(entityKind, entityName string, maxBytes int) Error {
|
||||
return newSenderError("LimitExceeded", fmt.Sprintf("Maximum policy size of %d bytes exceeded for %s %s", maxBytes, entityKind, entityName), http.StatusConflict)
|
||||
}
|
||||
|
||||
func newSenderError(code, message string, statusCode int) Error {
|
||||
return Error{
|
||||
Type: TypeSender,
|
||||
|
||||
Reference in New Issue
Block a user