Files
versitygw/iamapi/policy/document.go
T
niksis02 89b64910f3 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.
2026-07-10 03:17:23 +04:00

104 lines
2.8 KiB
Go

// Copyright 2026 Versity Software
// This file is licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package policy
import (
"bytes"
"encoding/json"
)
// Recognized values for a policy document's Version element.
const (
Version2008 = "2008-10-17"
Version2012 = "2012-10-17"
)
// Document is a parsed AWS IAM policy document.
type Document struct {
Version string
Statement []Statement
}
// Statement is a single element of a policy document's Statement list.
type Statement struct {
Sid string
Effect string
Action StringOrSlice
NotAction StringOrSlice
Resource StringOrSlice
NotResource StringOrSlice
Principal json.RawMessage
NotPrincipal json.RawMessage
}
// UnmarshalJSON accepts Statement as either a single JSON object or an
// array of objects, matching the AWS IAM policy grammar. A missing or
// JSON-null Statement leaves Document.Statement nil rather than erroring
// here — Validate reports that as a grammar error so all "empty document"
// shapes produce the same message.
func (d *Document) UnmarshalJSON(data []byte) error {
var raw struct {
Version string
Statement json.RawMessage
}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
d.Version = raw.Version
if len(raw.Statement) == 0 || string(bytes.TrimSpace(raw.Statement)) == "null" {
return nil
}
var stmts []Statement
if err := json.Unmarshal(raw.Statement, &stmts); err == nil {
d.Statement = stmts
return nil
}
var single Statement
if err := json.Unmarshal(raw.Statement, &single); err != nil {
return err
}
d.Statement = []Statement{single}
return nil
}
// StringOrSlice decodes a JSON value that may be either a single string or
// an array of strings, matching the AWS IAM policy grammar for Action,
// NotAction, Resource, and NotResource. A JSON-null value decodes to a nil
// StringOrSlice, identical to the key being absent.
type StringOrSlice []string
func (s *StringOrSlice) UnmarshalJSON(data []byte) error {
if string(bytes.TrimSpace(data)) == "null" {
*s = nil
return nil
}
var single string
if err := json.Unmarshal(data, &single); err == nil {
*s = StringOrSlice{single}
return nil
}
var multi []string
if err := json.Unmarshal(data, &multi); err != nil {
return err
}
*s = StringOrSlice(multi)
return nil
}