You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

174 lines
4.6 KiB

package s3api
import (
"fmt"
"github.com/seaweedfs/seaweedfs/weed/iam/policy"
"github.com/seaweedfs/seaweedfs/weed/s3api/policy_engine"
)
// ConvertPolicyDocumentToPolicyEngine converts a policy.PolicyDocument to policy_engine.PolicyDocument
// This function provides efficient type conversion without JSON marshaling overhead.
// It handles the differences between the two types:
// - Converts []string fields to StringOrStringSlice
// - Maps Condition types
// - Handles optional fields (Id, NotPrincipal, NotAction, NotResource are ignored in policy_engine)
func ConvertPolicyDocumentToPolicyEngine(src *policy.PolicyDocument) *policy_engine.PolicyDocument {
if src == nil {
return nil
}
dest := &policy_engine.PolicyDocument{
Version: src.Version,
Statement: make([]policy_engine.PolicyStatement, len(src.Statement)),
}
for i, srcStmt := range src.Statement {
dest.Statement[i] = convertStatement(&srcStmt)
}
return dest
}
// convertStatement converts a policy.Statement to policy_engine.PolicyStatement
func convertStatement(src *policy.Statement) policy_engine.PolicyStatement {
stmt := policy_engine.PolicyStatement{
Sid: src.Sid,
Effect: policy_engine.PolicyEffect(src.Effect),
}
// Convert Action ([]string to StringOrStringSlice)
if len(src.Action) > 0 {
stmt.Action = policy_engine.NewStringOrStringSlice(src.Action...)
}
// Convert Resource ([]string to StringOrStringSlice)
if len(src.Resource) > 0 {
stmt.Resource = policy_engine.NewStringOrStringSlice(src.Resource...)
}
// Convert Principal (interface{} to *StringOrStringSlice)
if src.Principal != nil {
stmt.Principal = convertPrincipal(src.Principal)
}
// Convert Condition (map[string]map[string]interface{} to PolicyConditions)
if len(src.Condition) > 0 {
stmt.Condition = convertCondition(src.Condition)
}
return stmt
}
// convertPrincipal converts a Principal field to *StringOrStringSlice
func convertPrincipal(principal interface{}) *policy_engine.StringOrStringSlice {
if principal == nil {
return nil
}
switch p := principal.(type) {
case string:
result := policy_engine.NewStringOrStringSlice(p)
return &result
case []string:
result := policy_engine.NewStringOrStringSlice(p...)
return &result
case []interface{}:
// Convert []interface{} to []string
strs := make([]string, 0, len(p))
for _, v := range p {
if str, ok := v.(string); ok {
strs = append(strs, str)
}
}
if len(strs) > 0 {
result := policy_engine.NewStringOrStringSlice(strs...)
return &result
}
case map[string]interface{}:
// Handle AWS-style principal with service/user keys
// Example: {"AWS": "arn:aws:iam::123456789012:user/Alice"}
strs := make([]string, 0)
for _, v := range p {
switch val := v.(type) {
case string:
strs = append(strs, val)
case []string:
strs = append(strs, val...)
case []interface{}:
for _, item := range val {
if str, ok := item.(string); ok {
strs = append(strs, str)
}
}
}
}
if len(strs) > 0 {
result := policy_engine.NewStringOrStringSlice(strs...)
return &result
}
}
return nil
}
// convertCondition converts policy conditions to PolicyConditions
func convertCondition(src map[string]map[string]interface{}) policy_engine.PolicyConditions {
if len(src) == 0 {
return nil
}
dest := make(policy_engine.PolicyConditions)
for condType, condBlock := range src {
destBlock := make(map[string]policy_engine.StringOrStringSlice)
for key, value := range condBlock {
destBlock[key] = convertConditionValue(value)
}
dest[condType] = destBlock
}
return dest
}
// convertConditionValue converts a condition value to StringOrStringSlice
func convertConditionValue(value interface{}) policy_engine.StringOrStringSlice {
switch v := value.(type) {
case string:
return policy_engine.NewStringOrStringSlice(v)
case []string:
return policy_engine.NewStringOrStringSlice(v...)
case []interface{}:
strs := make([]string, 0, len(v))
for _, item := range v {
if str, ok := item.(string); ok {
strs = append(strs, str)
}
}
return policy_engine.NewStringOrStringSlice(strs...)
default:
// For non-string types, convert to string
// This handles numbers, booleans, etc.
return policy_engine.NewStringOrStringSlice(convertToString(v))
}
}
// convertToString converts any value to string representation
func convertToString(value interface{}) string {
switch v := value.(type) {
case string:
return v
case bool:
if v {
return "true"
}
return "false"
case int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64,
float32, float64:
// Use fmt.Sprint for numeric types
return fmt.Sprint(v)
default:
return ""
}
}