github.com/greenpau/go-authcrunch@v1.1.4/pkg/acl/acl.go (about)

     1  // Copyright 2022 Paul Greenberg greenpau@outlook.com
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package acl
    16  
    17  import (
    18  	"context"
    19  	"go.uber.org/zap"
    20  )
    21  
    22  // AccessList is a collection of access list rules.
    23  type AccessList struct {
    24  	config       []*RuleConfiguration
    25  	rules        []aclRule
    26  	logger       *zap.Logger
    27  	defaultAllow bool
    28  }
    29  
    30  // NewAccessList returns an instance of AccessList.
    31  func NewAccessList() *AccessList {
    32  	return &AccessList{
    33  		rules: []aclRule{},
    34  	}
    35  }
    36  
    37  // GetRules returns configured ACL rules.
    38  func (acl *AccessList) GetRules() []*RuleConfiguration {
    39  	return acl.config
    40  }
    41  
    42  // SetDefaultAllowAction sets default allow for the AccessList,
    43  // i.e. the AccessList fails open.
    44  func (acl *AccessList) SetDefaultAllowAction() {
    45  	acl.defaultAllow = true
    46  }
    47  
    48  // SetLogger adds a logger to AccessList.
    49  func (acl *AccessList) SetLogger(logger *zap.Logger) {
    50  	acl.logger = logger
    51  }
    52  
    53  // AddRules adds multiple rules to AccessList.
    54  func (acl *AccessList) AddRules(ctx context.Context, cfgs []*RuleConfiguration) error {
    55  	for _, cfg := range cfgs {
    56  		if err := acl.AddRule(ctx, cfg); err != nil {
    57  			return err
    58  		}
    59  	}
    60  	return nil
    61  }
    62  
    63  // AddRule adds a rule to AccessList.
    64  func (acl *AccessList) AddRule(ctx context.Context, cfg *RuleConfiguration) error {
    65  	rule, err := newACLRule(ctx, len(acl.rules), cfg, acl.logger)
    66  	if err != nil {
    67  		return err
    68  	}
    69  	acl.config = append(acl.config, cfg)
    70  	acl.rules = append(acl.rules, rule)
    71  	return nil
    72  }
    73  
    74  // AsMap returns acl configuration as map.
    75  func (acl *AccessList) AsMap() map[string]interface{} {
    76  	m := make(map[string]interface{})
    77  	rules := []map[string]interface{}{}
    78  	for _, rule := range acl.rules {
    79  		ruleConfig := rule.getConfig(context.Background())
    80  		rules = append(rules, ruleConfig.AsMap())
    81  	}
    82  	if len(rules) > 0 {
    83  		m["rules"] = rules
    84  	}
    85  	m["count"] = len(rules)
    86  	return m
    87  }
    88  
    89  // Allow takes in client identity and metadata and returns an error when
    90  // denied access.
    91  func (acl *AccessList) Allow(ctx context.Context, data map[string]interface{}) bool {
    92  	var grantAccess bool
    93  	for _, rule := range acl.rules {
    94  		v := rule.eval(ctx, data)
    95  		switch v {
    96  		case ruleVerdictAllowStop:
    97  			return true
    98  		case ruleVerdictAllow:
    99  			grantAccess = true
   100  		case ruleVerdictDenyStop:
   101  			return false
   102  		case ruleVerdictDeny:
   103  			return false
   104  		}
   105  	}
   106  	if grantAccess || acl.defaultAllow {
   107  		return true
   108  	}
   109  	return false
   110  }
   111  
   112  // GetFieldDataType return data type for a particular data field.
   113  func GetFieldDataType(s string) (string, string) {
   114  	k := s
   115  	dt := dataTypeUnknown
   116  	if v, exists := inputDataAliases[s]; exists {
   117  		if vdt, exists := inputDataTypes[v]; exists {
   118  			dt = vdt
   119  			k = v
   120  		}
   121  	} else {
   122  		if sdt, exists := inputDataTypes[s]; exists {
   123  			dt = sdt
   124  		}
   125  	}
   126  	switch dt {
   127  	case dataTypeListStr:
   128  		return k, "list_str"
   129  	case dataTypeStr:
   130  		return k, "str"
   131  	}
   132  	return k, ""
   133  }