Browse Source

converts a policy.PolicyDocument to policy_engine.PolicyDocument

pull/7472/head
chrislu 2 months ago
parent
commit
d81dc8885f
  1. 172
      weed/s3api/policy_conversion.go
  2. 17
      weed/s3api/s3api_bucket_policy_engine.go

172
weed/s3api/policy_conversion.go

@ -0,0 +1,172 @@
package s3api
import (
"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.Sprintf for numeric types
return ""
default:
return ""
}
}

17
weed/s3api/s3api_bucket_policy_engine.go

@ -49,11 +49,8 @@ func (bpe *BucketPolicyEngine) LoadBucketPolicy(bucket string, entry *filer_pb.E
// LoadBucketPolicyFromCache loads a bucket policy from a cached BucketConfig
//
// NOTE: This function uses JSON marshaling/unmarshaling to convert between
// policy.PolicyDocument and policy_engine.PolicyDocument. This is inefficient
// but necessary because the two types are defined in different packages and
// have subtle differences. A future improvement would be to unify these types
// or create a direct conversion function for better performance and type safety.
// This function uses a direct conversion function to efficiently convert between
// policy.PolicyDocument and policy_engine.PolicyDocument without JSON marshaling overhead.
func (bpe *BucketPolicyEngine) LoadBucketPolicyFromCache(bucket string, policyDoc *policy.PolicyDocument) error {
if policyDoc == nil {
// No policy for this bucket - remove it if it exists
@ -61,10 +58,12 @@ func (bpe *BucketPolicyEngine) LoadBucketPolicyFromCache(bucket string, policyDo
return nil
}
// Convert policy.PolicyDocument to policy_engine.PolicyDocument
// We use JSON marshaling as an intermediate format since both types
// follow the same AWS S3 policy structure
policyJSON, err := json.Marshal(policyDoc)
// Convert policy.PolicyDocument to policy_engine.PolicyDocument using direct conversion
// This is more efficient than JSON marshaling and provides better type safety
enginePolicyDoc := ConvertPolicyDocumentToPolicyEngine(policyDoc)
// Marshal the converted policy to JSON for storage in the engine
policyJSON, err := json.Marshal(enginePolicyDoc)
if err != nil {
glog.Errorf("Failed to marshal bucket policy for %s: %v", bucket, err)
return err

Loading…
Cancel
Save