initial commit
This commit is contained in:
192
policy-allow.go
Normal file
192
policy-allow.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package libpolicy
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net"
|
||||
"net/netip"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func contains(slice []string, val string) bool {
|
||||
for _, v := range slice {
|
||||
if v == val {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Effect uint8
|
||||
|
||||
const (
|
||||
Allow Effect = iota
|
||||
Deny
|
||||
NoMatch
|
||||
)
|
||||
|
||||
func IsIPInCIDR(ipStr, cidrStr string) bool {
|
||||
// Parse the IP address
|
||||
cidrStr = normalizeCIDR(cidrStr)
|
||||
log.Println("Parsing IP:", ipStr, " against CIDR:", cidrStr)
|
||||
ip := net.ParseIP(ipStr)
|
||||
if ip == nil {
|
||||
return false // Invalid IP
|
||||
}
|
||||
|
||||
// Parse the CIDR
|
||||
_, ipnet, err := net.ParseCIDR(cidrStr)
|
||||
if err != nil {
|
||||
return false // Invalid CIDR
|
||||
}
|
||||
|
||||
// net.IPNet.Contains() handles IPv4/IPv6 correctly, including IPv4-mapped IPv6
|
||||
return ipnet.Contains(ip)
|
||||
}
|
||||
|
||||
func normalizeCIDR(cidrStr string) string {
|
||||
cidrStr = strings.TrimSpace(cidrStr)
|
||||
if cidrStr == "" {
|
||||
return ""
|
||||
}
|
||||
|
||||
// Already has a mask suffix → use as-is
|
||||
if strings.Contains(cidrStr, "/") {
|
||||
return cidrStr
|
||||
}
|
||||
|
||||
// Try to parse as IP address to determine version
|
||||
addr, err := netip.ParseAddr(cidrStr)
|
||||
if err != nil {
|
||||
return "" // Invalid
|
||||
}
|
||||
|
||||
if addr.Is4() || addr.Is4In6() {
|
||||
return cidrStr + "/32"
|
||||
}
|
||||
return cidrStr + "/128"
|
||||
}
|
||||
|
||||
func verifyRequest(request *Request, policy *Policy) (Effect, string) {
|
||||
//conditionReview = []Condition{}
|
||||
var effect Effect
|
||||
effect = NoMatch
|
||||
statementid := "NoMatch"
|
||||
|
||||
for _, condition := range policy.Conditions {
|
||||
|
||||
log.Println("Checking Statement: ", condition.StatementID)
|
||||
|
||||
// Check the principal
|
||||
if !contains(condition.Principal, request.Principal) {
|
||||
log.Println("No match on principal")
|
||||
log.Println("Checked condition principal:", condition.Principal)
|
||||
log.Println("Against: request principal:", request.Principal)
|
||||
continue
|
||||
}
|
||||
|
||||
if !contains(condition.Actions, request.Action) {
|
||||
log.Println("No match on actions")
|
||||
log.Println("Checked condition actions:", condition.Actions)
|
||||
log.Println("Against: request action:", request.Action)
|
||||
continue
|
||||
}
|
||||
|
||||
// Source Check
|
||||
sourceMatch := false
|
||||
for _, source := range condition.Source {
|
||||
if IsIPInCIDR(request.SourceIPAddress, source) {
|
||||
sourceMatch = true
|
||||
}
|
||||
}
|
||||
|
||||
if sourceMatch == false {
|
||||
log.Println("No match on source")
|
||||
log.Println("Checked condition source:", condition.Source)
|
||||
log.Println("Against: request source:", request.SourceIPAddress)
|
||||
continue
|
||||
}
|
||||
|
||||
if condition.Effect == "allow" {
|
||||
effect = Allow
|
||||
log.Println("Allowed per ")
|
||||
log.Printf("Request is allowed by condition: %s\n", condition.StatementID)
|
||||
effect = Allow
|
||||
statementid = condition.StatementID
|
||||
} else if condition.Effect == "deny" {
|
||||
// Immediately deny upon explicit deny
|
||||
log.Printf("Request is denied by condition: %s\n", condition.StatementID)
|
||||
return Deny, condition.StatementID
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return effect, statementid
|
||||
}
|
||||
|
||||
/*
|
||||
func loadRequestFile(filename string) (*Request, error) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open '%s' %w", filename, err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var request Request
|
||||
if err := json.NewDecoder(file).Decode(&request); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse json from '%s': %w", filename, err)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully loaded request from %s\n", filename)
|
||||
return &request, nil
|
||||
}
|
||||
|
||||
func loadPolicyFile(filename string) (*Policy, error) {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open file '%s': %w", filename, err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var policy Policy
|
||||
if err := json.NewDecoder(file).Decode(&policy); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse JSON from '%s': %w", filename, err)
|
||||
}
|
||||
|
||||
fmt.Printf("Successfully loaded policy from %s\n", filename)
|
||||
return &policy, nil
|
||||
}
|
||||
*/
|
||||
/*
|
||||
func main() {
|
||||
policy, err := loadPolicyFile("policy.json")
|
||||
if err != nil {
|
||||
fmt.Println("Error: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Policy structure loaded successfully:")
|
||||
pretty, _ := json.MarshalIndent(policy, "", "\t")
|
||||
fmt.Println(string(pretty))
|
||||
|
||||
request, err := loadRequestFile("request.json")
|
||||
if err != nil {
|
||||
fmt.Println("Error: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Println("Loaded Request successfully\n")
|
||||
pretty, _ = json.MarshalIndent(request, "", "\t")
|
||||
fmt.Println(string(pretty))
|
||||
|
||||
effect, statementid := verifyRequest(request, policy)
|
||||
|
||||
fmt.Println("")
|
||||
if effect == NoMatch {
|
||||
fmt.Println("No matching conditions found. Defaulting to Deny.")
|
||||
} else if effect == Allow {
|
||||
fmt.Println("Request is allowed based on matching conditions.")
|
||||
} else {
|
||||
fmt.Println("Request is denied based on matching conditions.")
|
||||
}
|
||||
println("statementid:", statementid)
|
||||
|
||||
}
|
||||
*/
|
||||
Reference in New Issue
Block a user