2023-10-19 13:15:21 +00:00
|
|
|
package iam
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
"strings"
|
|
|
|
"time"
|
|
|
|
|
2023-11-07 17:20:54 +00:00
|
|
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
2023-10-19 13:15:21 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
RequestOwnerProperty = "Owner"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// String condition operators.
|
|
|
|
CondStringEquals string = "StringEquals"
|
|
|
|
CondStringNotEquals string = "StringNotEquals"
|
|
|
|
CondStringEqualsIgnoreCase string = "StringEqualsIgnoreCase"
|
|
|
|
CondStringNotEqualsIgnoreCase string = "StringNotEqualsIgnoreCase"
|
|
|
|
CondStringLike string = "StringLike"
|
|
|
|
CondStringNotLike string = "StringNotLike"
|
|
|
|
|
|
|
|
// Numeric condition operators.
|
|
|
|
CondNumericEquals string = "NumericEquals"
|
|
|
|
CondNumericNotEquals string = "NumericNotEquals"
|
|
|
|
CondNumericLessThan string = "NumericLessThan"
|
|
|
|
CondNumericLessThanEquals string = "NumericLessThanEquals"
|
|
|
|
CondNumericGreaterThan string = "NumericGreaterThan"
|
|
|
|
CondNumericGreaterThanEquals string = "NumericGreaterThanEquals"
|
|
|
|
|
|
|
|
// Date condition operators.
|
|
|
|
CondDateEquals string = "DateEquals"
|
|
|
|
CondDateNotEquals string = "DateNotEquals"
|
|
|
|
CondDateLessThan string = "DateLessThan"
|
|
|
|
CondDateLessThanEquals string = "DateLessThanEquals"
|
|
|
|
CondDateGreaterThan string = "DateGreaterThan"
|
|
|
|
CondDateGreaterThanEquals string = "DateGreaterThanEquals"
|
|
|
|
|
|
|
|
// Bolean condition operators.
|
|
|
|
CondBool string = "Bool"
|
|
|
|
|
|
|
|
// IP address condition operators.
|
|
|
|
CondIPAddress string = "IpAddress"
|
|
|
|
CondNotIPAddress string = "NotIpAddress"
|
|
|
|
|
|
|
|
// ARN condition operators.
|
|
|
|
CondArnEquals string = "ArnEquals"
|
|
|
|
CondArnLike string = "ArnLike"
|
|
|
|
CondArnNotEquals string = "ArnNotEquals"
|
|
|
|
CondArnNotLike string = "ArnNotLike"
|
|
|
|
)
|
|
|
|
|
2023-11-07 17:20:54 +00:00
|
|
|
func (p Policy) ToChain() (*chain.Chain, error) {
|
2023-10-30 13:34:53 +00:00
|
|
|
if err := p.Validate(GeneralPolicyType); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-11-07 17:20:54 +00:00
|
|
|
var ch chain.Chain
|
2023-10-19 13:15:21 +00:00
|
|
|
|
|
|
|
for _, statement := range p.Statement {
|
2023-11-07 17:20:54 +00:00
|
|
|
status := chain.AccessDenied
|
2023-10-19 13:15:21 +00:00
|
|
|
if statement.Effect == AllowEffect {
|
2023-11-07 17:20:54 +00:00
|
|
|
status = chain.Allow
|
2023-10-19 13:15:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var principals []string
|
2023-11-07 17:20:54 +00:00
|
|
|
var op chain.ConditionType
|
2023-10-30 13:34:53 +00:00
|
|
|
statementPrincipal, inverted := statement.principal()
|
|
|
|
if _, ok := statementPrincipal[Wildcard]; ok { // this can be true only if 'inverted' false
|
2023-10-19 13:15:21 +00:00
|
|
|
principals = []string{Wildcard}
|
2023-11-07 17:20:54 +00:00
|
|
|
op = chain.CondStringLike
|
2023-10-19 13:15:21 +00:00
|
|
|
} else {
|
2023-10-30 13:34:53 +00:00
|
|
|
for _, principal := range statementPrincipal {
|
|
|
|
principals = append(principals, principal...)
|
|
|
|
}
|
|
|
|
|
2023-11-07 17:20:54 +00:00
|
|
|
op = chain.CondStringEquals
|
2023-10-30 13:34:53 +00:00
|
|
|
if inverted {
|
2023-11-07 17:20:54 +00:00
|
|
|
op = chain.CondStringNotEquals
|
2023-10-30 13:34:53 +00:00
|
|
|
}
|
2023-10-19 13:15:21 +00:00
|
|
|
}
|
|
|
|
|
2023-11-07 17:20:54 +00:00
|
|
|
var conditions []chain.Condition
|
2023-10-19 13:15:21 +00:00
|
|
|
for _, principal := range principals {
|
2023-11-07 17:20:54 +00:00
|
|
|
conditions = append(conditions, chain.Condition{
|
2023-10-19 13:15:21 +00:00
|
|
|
Op: op,
|
2023-11-07 17:20:54 +00:00
|
|
|
Object: chain.ObjectRequest,
|
2023-10-19 13:15:21 +00:00
|
|
|
Key: RequestOwnerProperty,
|
|
|
|
Value: principal,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
conds, err := statement.Conditions.ToChainCondition()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
conditions = append(conditions, conds...)
|
|
|
|
|
2023-10-30 13:34:53 +00:00
|
|
|
action, actionInverted := statement.action()
|
2023-11-07 17:20:54 +00:00
|
|
|
ruleAction := chain.Actions{Inverted: actionInverted, Names: action}
|
2023-10-30 13:34:53 +00:00
|
|
|
|
|
|
|
resource, resourceInverted := statement.resource()
|
2023-11-07 17:20:54 +00:00
|
|
|
ruleResource := chain.Resources{Inverted: resourceInverted, Names: resource}
|
2023-10-30 13:34:53 +00:00
|
|
|
|
2023-11-07 17:20:54 +00:00
|
|
|
r := chain.Rule{
|
2023-10-19 13:15:21 +00:00
|
|
|
Status: status,
|
2023-10-30 13:34:53 +00:00
|
|
|
Actions: ruleAction,
|
|
|
|
Resources: ruleResource,
|
2023-10-19 13:15:21 +00:00
|
|
|
Any: true,
|
|
|
|
Condition: conditions,
|
|
|
|
}
|
2023-11-07 17:20:54 +00:00
|
|
|
ch.Rules = append(ch.Rules, r)
|
2023-10-19 13:15:21 +00:00
|
|
|
}
|
|
|
|
|
2023-11-07 17:20:54 +00:00
|
|
|
return &ch, nil
|
2023-10-19 13:15:21 +00:00
|
|
|
}
|
|
|
|
|
2023-11-01 08:02:16 +00:00
|
|
|
//nolint:funlen
|
2023-11-07 17:20:54 +00:00
|
|
|
func (c Conditions) ToChainCondition() ([]chain.Condition, error) {
|
|
|
|
var conditions []chain.Condition
|
2023-10-19 13:15:21 +00:00
|
|
|
|
|
|
|
var convertValue convertFunction
|
|
|
|
|
|
|
|
for op, KVs := range c {
|
2023-11-07 17:20:54 +00:00
|
|
|
var condType chain.ConditionType
|
2023-10-19 13:15:21 +00:00
|
|
|
|
|
|
|
switch {
|
|
|
|
case strings.HasPrefix(op, "String"):
|
|
|
|
convertValue = noConvertFunction
|
|
|
|
switch op {
|
|
|
|
case CondStringEquals:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringEquals
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondStringNotEquals:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringNotEquals
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondStringEqualsIgnoreCase:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringEqualsIgnoreCase
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondStringNotEqualsIgnoreCase:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringNotEqualsIgnoreCase
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondStringLike:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringLike
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondStringNotLike:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringNotLike
|
2023-10-19 13:15:21 +00:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unsupported condition operator: '%s'", op)
|
|
|
|
}
|
|
|
|
case strings.HasPrefix(op, "Arn"):
|
|
|
|
convertValue = noConvertFunction
|
|
|
|
switch op {
|
|
|
|
case CondArnEquals:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringEquals
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondArnNotEquals:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringNotEquals
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondArnLike:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringLike
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondArnNotLike:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringNotLike
|
2023-10-19 13:15:21 +00:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unsupported condition operator: '%s'", op)
|
|
|
|
}
|
|
|
|
case strings.HasPrefix(op, "Numeric"):
|
|
|
|
// TODO
|
|
|
|
case strings.HasPrefix(op, "Date"):
|
|
|
|
convertValue = dateConvertFunction
|
|
|
|
switch op {
|
|
|
|
case CondDateEquals:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringEquals
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondDateNotEquals:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringNotEquals
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondDateLessThan:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringLessThan
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondDateLessThanEquals:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringLessThanEquals
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondDateGreaterThan:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringGreaterThan
|
2023-10-19 13:15:21 +00:00
|
|
|
case CondDateGreaterThanEquals:
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringGreaterThanEquals
|
2023-10-19 13:15:21 +00:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unsupported condition operator: '%s'", op)
|
|
|
|
}
|
|
|
|
case op == CondBool:
|
|
|
|
convertValue = noConvertFunction
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringEqualsIgnoreCase
|
2023-10-19 13:15:21 +00:00
|
|
|
case op == CondIPAddress:
|
|
|
|
// todo consider using converters
|
|
|
|
// "203.0.113.0/24" -> "203.0.113.*",
|
|
|
|
// "2001:DB8:1234:5678::/64" -> "2001:DB8:1234:5678:*"
|
|
|
|
// or having specific condition type for IP
|
|
|
|
convertValue = noConvertFunction
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringLike
|
2023-10-19 13:15:21 +00:00
|
|
|
case op == CondNotIPAddress:
|
|
|
|
convertValue = noConvertFunction
|
2023-11-07 17:20:54 +00:00
|
|
|
condType = chain.CondStringNotLike
|
2023-10-19 13:15:21 +00:00
|
|
|
default:
|
|
|
|
return nil, fmt.Errorf("unsupported condition operator: '%s'", op)
|
|
|
|
}
|
|
|
|
|
|
|
|
for key, values := range KVs {
|
|
|
|
for _, val := range values {
|
|
|
|
converted, err := convertValue(val)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-11-07 17:20:54 +00:00
|
|
|
conditions = append(conditions, chain.Condition{
|
2023-10-19 13:15:21 +00:00
|
|
|
Op: condType,
|
2023-11-07 17:20:54 +00:00
|
|
|
Object: chain.ObjectRequest,
|
2023-10-19 13:15:21 +00:00
|
|
|
Key: key,
|
|
|
|
Value: converted,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return conditions, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type convertFunction func(string) (string, error)
|
|
|
|
|
|
|
|
func noConvertFunction(val string) (string, error) {
|
|
|
|
return val, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func dateConvertFunction(val string) (string, error) {
|
|
|
|
if _, err := strconv.ParseInt(val, 10, 64); err == nil {
|
|
|
|
return val, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
parsed, err := time.Parse(time.RFC3339, val)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return strconv.FormatInt(parsed.UTC().Unix(), 10), nil
|
|
|
|
}
|