zoukankan      html  css  js  c++  java
  • acl.go

    package acl
     
    import (
    "github.com/armon/go-radix"
    )
     
    var (
    // allowAll is a singleton policy which allows all
    // non-management actions
    allowAll ACL
     
    // denyAll is a singleton policy which denies all actions
    denyAll ACL
     
    // manageAll is a singleton policy which allows all
    // actions, including management
    manageAll ACL
    )
     
    func init() {
    // Setup the singletons
    allowAll = &StaticACL{
    allowManage:  false,
    defaultAllow: true,
    }
    denyAll = &StaticACL{
    allowManage:  false,
    defaultAllow: false,
    }
    manageAll = &StaticACL{
    allowManage:  true,
    defaultAllow: true,
    }
    }
     
    // ACL is the interface for policy enforcement.
    type ACL interface {
    // ACLList checks for permission to list all the ACLs
    ACLList() bool
     
    // ACLModify checks for permission to manipulate ACLs
    ACLModify() bool
     
    // AgentRead checks for permission to read from agent endpoints for a
    // given node.
    AgentRead(string) bool
     
    // AgentWrite checks for permission to make changes via agent endpoints
    // for a given node.
    AgentWrite(string) bool
     
    // EventRead determines if a specific event can be queried.
    EventRead(string) bool
     
    // EventWrite determines if a specific event may be fired.
    EventWrite(string) bool
     
    // KeyRead checks for permission to read a given key
    KeyRead(string) bool
     
    // KeyWrite checks for permission to write a given key
    KeyWrite(string) bool
     
    // KeyWritePrefix checks for permission to write to an
    // entire key prefix. This means there must be no sub-policies
    // that deny a write.
    KeyWritePrefix(string) bool
     
    // KeyringRead determines if the encryption keyring used in
    // the gossip layer can be read.
    KeyringRead() bool
     
    // KeyringWrite determines if the keyring can be manipulated
    KeyringWrite() bool
     
    // NodeRead checks for permission to read (discover) a given node.
    NodeRead(string) bool
     
    // NodeWrite checks for permission to create or update (register) a
    // given node.
    NodeWrite(string) bool
     
    // OperatorRead determines if the read-only Consul operator functions
    // can be used.
    OperatorRead() bool
     
    // OperatorWrite determines if the state-changing Consul operator
    // functions can be used.
    OperatorWrite() bool
     
    // PrepardQueryRead determines if a specific prepared query can be read
    // to show its contents (this is not used for execution).
    PreparedQueryRead(string) bool
     
    // PreparedQueryWrite determines if a specific prepared query can be
    // created, modified, or deleted.
    PreparedQueryWrite(string) bool
     
    // ServiceRead checks for permission to read a given service
    ServiceRead(string) bool
     
    // ServiceWrite checks for permission to create or update a given
    // service
    ServiceWrite(string) bool
     
    // SessionRead checks for permission to read sessions for a given node.
    SessionRead(string) bool
     
    // SessionWrite checks for permission to create sessions for a given
    // node.
    SessionWrite(string) bool
     
    // Snapshot checks for permission to take and restore snapshots.
    Snapshot() bool
    }
     
    // StaticACL is used to implement a base ACL policy. It either
    // allows or denies all requests. This can be used as a parent
    // ACL to act in a blacklist or whitelist mode.
    type StaticACL struct {
    allowManage  bool
    defaultAllow bool
    }
     
    func (s *StaticACL) ACLList() bool {
    return s.allowManage
    }
     
    func (s *StaticACL) ACLModify() bool {
    return s.allowManage
    }
     
    func (s *StaticACL) AgentRead(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) AgentWrite(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) EventRead(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) EventWrite(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) KeyRead(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) KeyWrite(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) KeyWritePrefix(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) KeyringRead() bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) KeyringWrite() bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) NodeRead(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) NodeWrite(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) OperatorRead() bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) OperatorWrite() bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) PreparedQueryRead(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) PreparedQueryWrite(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) ServiceRead(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) ServiceWrite(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) SessionRead(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) SessionWrite(string) bool {
    return s.defaultAllow
    }
     
    func (s *StaticACL) Snapshot() bool {
    return s.allowManage
    }
     
    // AllowAll returns an ACL rule that allows all operations
    func AllowAll() ACL {
    return allowAll
    }
     
    // DenyAll returns an ACL rule that denies all operations
    func DenyAll() ACL {
    return denyAll
    }
     
    // ManageAll returns an ACL rule that can manage all resources
    func ManageAll() ACL {
    return manageAll
    }
     
    // RootACL returns a possible ACL if the ID matches a root policy
    func RootACL(id string) ACL {
    switch id {
    case "allow":
    return allowAll
    case "deny":
    return denyAll
    case "manage":
    return manageAll
    default:
    return nil
    }
    }
     
    // PolicyACL is used to wrap a set of ACL policies to provide
    // the ACL interface.
    type PolicyACL struct {
    // parent is used to resolve policy if we have
    // no matching rule.
    parent ACL
     
    // agentRules contains the agent policies
    agentRules *radix.Tree
     
    // keyRules contains the key policies
    keyRules *radix.Tree
     
    // nodeRules contains the node policies
    nodeRules *radix.Tree
     
    // serviceRules contains the service policies
    serviceRules *radix.Tree
     
    // sessionRules contains the session policies
    sessionRules *radix.Tree
     
    // eventRules contains the user event policies
    eventRules *radix.Tree
     
    // preparedQueryRules contains the prepared query policies
    preparedQueryRules *radix.Tree
     
    // keyringRule contains the keyring policies. The keyring has
    // a very simple yes/no without prefix matching, so here we
    // don't need to use a radix tree.
    keyringRule string
     
    // operatorRule contains the operator policies.
    operatorRule string
    }
     
    // New is used to construct a policy based ACL from a set of policies
    // and a parent policy to resolve missing cases.
    func New(parent ACL, policy *Policy) (*PolicyACL, error) {
    p := &PolicyACL{
    parent:             parent,
    agentRules:         radix.New(),
    keyRules:           radix.New(),
    nodeRules:          radix.New(),
    serviceRules:       radix.New(),
    sessionRules:       radix.New(),
    eventRules:         radix.New(),
    preparedQueryRules: radix.New(),
    }
     
    // Load the agent policy
    for _, ap := range policy.Agents {
    p.agentRules.Insert(ap.Node, ap.Policy)
    }
     
    // Load the key policy
    for _, kp := range policy.Keys {
    p.keyRules.Insert(kp.Prefix, kp.Policy)
    }
     
    // Load the node policy
    for _, np := range policy.Nodes {
    p.nodeRules.Insert(np.Name, np.Policy)
    }
     
    // Load the service policy
    for _, sp := range policy.Services {
    p.serviceRules.Insert(sp.Name, sp.Policy)
    }
     
    // Load the session policy
    for _, sp := range policy.Sessions {
    p.sessionRules.Insert(sp.Node, sp.Policy)
    }
     
    // Load the event policy
    for _, ep := range policy.Events {
    p.eventRules.Insert(ep.Event, ep.Policy)
    }
     
    // Load the prepared query policy
    for _, pq := range policy.PreparedQueries {
    p.preparedQueryRules.Insert(pq.Prefix, pq.Policy)
    }
     
    // Load the keyring policy
    p.keyringRule = policy.Keyring
     
    // Load the operator policy
    p.operatorRule = policy.Operator
     
    return p, nil
    }
     
    // ACLList checks if listing of ACLs is allowed
    func (p *PolicyACL) ACLList() bool {
    return p.parent.ACLList()
    }
     
    // ACLModify checks if modification of ACLs is allowed
    func (p *PolicyACL) ACLModify() bool {
    return p.parent.ACLModify()
    }
     
    // AgentRead checks for permission to read from agent endpoints for a given
    // node.
    func (p *PolicyACL) AgentRead(node string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.agentRules.LongestPrefix(node)
     
    if ok {
    switch rule {
    case PolicyRead, PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.AgentRead(node)
    }
     
    // AgentWrite checks for permission to make changes via agent endpoints for a
    // given node.
    func (p *PolicyACL) AgentWrite(node string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.agentRules.LongestPrefix(node)
     
    if ok {
    switch rule {
    case PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.AgentWrite(node)
    }
     
    // Snapshot checks if taking and restoring snapshots is allowed.
    func (p *PolicyACL) Snapshot() bool {
    return p.parent.Snapshot()
    }
     
    // EventRead is used to determine if the policy allows for a
    // specific user event to be read.
    func (p *PolicyACL) EventRead(name string) bool {
    // Longest-prefix match on event names
    if _, rule, ok := p.eventRules.LongestPrefix(name); ok {
    switch rule {
    case PolicyRead, PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // Nothing matched, use parent
    return p.parent.EventRead(name)
    }
     
    // EventWrite is used to determine if new events can be created
    // (fired) by the policy.
    func (p *PolicyACL) EventWrite(name string) bool {
    // Longest-prefix match event names
    if _, rule, ok := p.eventRules.LongestPrefix(name); ok {
    return rule == PolicyWrite
    }
     
    // No match, use parent
    return p.parent.EventWrite(name)
    }
     
    // KeyRead returns if a key is allowed to be read
    func (p *PolicyACL) KeyRead(key string) bool {
    // Look for a matching rule
    _, rule, ok := p.keyRules.LongestPrefix(key)
    if ok {
    switch rule.(string) {
    case PolicyRead, PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.KeyRead(key)
    }
     
    // KeyWrite returns if a key is allowed to be written
    func (p *PolicyACL) KeyWrite(key string) bool {
    // Look for a matching rule
    _, rule, ok := p.keyRules.LongestPrefix(key)
    if ok {
    switch rule.(string) {
    case PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.KeyWrite(key)
    }
     
    // KeyWritePrefix returns if a prefix is allowed to be written
    func (p *PolicyACL) KeyWritePrefix(prefix string) bool {
    // Look for a matching rule that denies
    _, rule, ok := p.keyRules.LongestPrefix(prefix)
    if ok && rule.(string) != PolicyWrite {
    return false
    }
     
    // Look if any of our children have a deny policy
    deny := false
    p.keyRules.WalkPrefix(prefix, func(path string, rule interface{}) bool {
    // We have a rule to prevent a write in a sub-directory!
    if rule.(string) != PolicyWrite {
    deny = true
    return true
    }
    return false
    })
     
    // Deny the write if any sub-rules may be violated
    if deny {
    return false
    }
     
    // If we had a matching rule, done
    if ok {
    return true
    }
     
    // No matching rule, use the parent.
    return p.parent.KeyWritePrefix(prefix)
    }
     
    // KeyringRead is used to determine if the keyring can be
    // read by the current ACL token.
    func (p *PolicyACL) KeyringRead() bool {
    switch p.keyringRule {
    case PolicyRead, PolicyWrite:
    return true
    case PolicyDeny:
    return false
    default:
    return p.parent.KeyringRead()
    }
    }
     
    // KeyringWrite determines if the keyring can be manipulated.
    func (p *PolicyACL) KeyringWrite() bool {
    if p.keyringRule == PolicyWrite {
    return true
    }
    return p.parent.KeyringWrite()
    }
     
    // OperatorRead determines if the read-only operator functions are allowed.
    func (p *PolicyACL) OperatorRead() bool {
    switch p.operatorRule {
    case PolicyRead, PolicyWrite:
    return true
    case PolicyDeny:
    return false
    default:
    return p.parent.OperatorRead()
    }
    }
     
    // NodeRead checks if reading (discovery) of a node is allowed
    func (p *PolicyACL) NodeRead(name string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.nodeRules.LongestPrefix(name)
     
    if ok {
    switch rule {
    case PolicyRead, PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.NodeRead(name)
    }
     
    // NodeWrite checks if writing (registering) a node is allowed
    func (p *PolicyACL) NodeWrite(name string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.nodeRules.LongestPrefix(name)
     
    if ok {
    switch rule {
    case PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.NodeWrite(name)
    }
     
    // OperatorWrite determines if the state-changing operator functions are
    // allowed.
    func (p *PolicyACL) OperatorWrite() bool {
    if p.operatorRule == PolicyWrite {
    return true
    }
    return p.parent.OperatorWrite()
    }
     
    // PreparedQueryRead checks if reading (listing) of a prepared query is
    // allowed - this isn't execution, just listing its contents.
    func (p *PolicyACL) PreparedQueryRead(prefix string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.preparedQueryRules.LongestPrefix(prefix)
     
    if ok {
    switch rule {
    case PolicyRead, PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.PreparedQueryRead(prefix)
    }
     
    // PreparedQueryWrite checks if writing (creating, updating, or deleting) of a
    // prepared query is allowed.
    func (p *PolicyACL) PreparedQueryWrite(prefix string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.preparedQueryRules.LongestPrefix(prefix)
     
    if ok {
    switch rule {
    case PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.PreparedQueryWrite(prefix)
    }
     
    // ServiceRead checks if reading (discovery) of a service is allowed
    func (p *PolicyACL) ServiceRead(name string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.serviceRules.LongestPrefix(name)
     
    if ok {
    switch rule {
    case PolicyRead, PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.ServiceRead(name)
    }
     
    // ServiceWrite checks if writing (registering) a service is allowed
    func (p *PolicyACL) ServiceWrite(name string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.serviceRules.LongestPrefix(name)
     
    if ok {
    switch rule {
    case PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.ServiceWrite(name)
    }
     
    // SessionRead checks for permission to read sessions for a given node.
    func (p *PolicyACL) SessionRead(node string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.sessionRules.LongestPrefix(node)
     
    if ok {
    switch rule {
    case PolicyRead, PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.SessionRead(node)
    }
     
    // SessionWrite checks for permission to create sessions for a given node.
    func (p *PolicyACL) SessionWrite(node string) bool {
    // Check for an exact rule or catch-all
    _, rule, ok := p.sessionRules.LongestPrefix(node)
     
    if ok {
    switch rule {
    case PolicyWrite:
    return true
    default:
    return false
    }
    }
     
    // No matching rule, use the parent.
    return p.parent.SessionWrite(node)
    }
  • 相关阅读:
    .net core读取appsettings.config中文乱码问题
    vs2017错误:当前页面的脚本发生错误
    VS Code中无法识别npm命令
    Visual Studio报错/plugin.vs.js,行:1074,错误:缺少标识符、字符串或数字
    记录一次在生成数据库服务器上出现The timeout period elapsed prior to completion of the operation or the server is not responding.和Exception has been thrown by the target of an invocation的解决办法
    Java集合框架
    java hash表
    Java Dictionary 类存储键值
    java数据结构 栈stack
    java封装
  • 原文地址:https://www.cnblogs.com/zhangboyu/p/7451893.html
Copyright © 2011-2022 走看看