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)
}
 
 
 
 

acl.go的更多相关文章

  1. haproxy利用ACL规则封禁自定义IP地址拒绝访问

    现在有一个需求就是在发版的时候希望除公司IP外的外网访问服务的时候都是拒绝访问的 现在利用haproxy 的acl规则作出限制 errorfile       403 /etc/haproxy/err ...

  2. HAProxy的日志配置以及ACL规则实现负载均衡

    HAProxy配置日志策略 默认情况下,HAProxy是没有配置日志的在centos6.3下默认管理日志的是rsyslog,可以实现UDP日志的接收,将日志写入文件,写入数据库先检测rsyslog是否 ...

  3. CISCO VLAN ACL

    对于cisco VLAN ACL 首先得定义 standard ACL或 extented ACL用于抓取流量 注意这里的抓取流量不是最终的对流量的操作,而是决定什么样的流量用VLAN ACL 来处理 ...

  4. MAC OS X的ACL扩展权限设置

    在WEB开发时,网站是以_www的用户运行的,而我在本地是以liuwencan的用户编辑的.这就带来一个问题:如果所有文件属于liuwencan,那么网站运行需要写文件时就因无权限而失败:如果所有文件 ...

  5. linux ACL权限规划:getfacl,setfacl使用

    ACL即Access Control List 主要的目的是提供传统的owner,group,others的read,write,execute权限之外的具体权限设置,ACL可以针对单一用户.单一文件 ...

  6. ZooKeeper 笔记(5) ACL(Access Control List)访问控制列表

    zk做为分布式架构中的重要中间件,通常会在上面以节点的方式存储一些关键信息,默认情况下,所有应用都可以读写任何节点,在复杂的应用中,这不太安全,ZK通过ACL机制来解决访问权限问题,详见官网文档:ht ...

  7. Centos下ACL(访问控制列表)介绍(转)

    我们知道,在Linux操作系统中,传统的权限管理分是以三种身份(属主.属組以及其它人)搭配三种权限(可读.可写以及可执行),并且搭配三种特殊权限(SUID,SGID,SBIT),来实现对系统的安全保护 ...

  8. ACL权限设置命令setfacl和getfacl命令

    ACL权限设置命令setfacl和getfacl命令 setfacl命令是用来在命令行里设置ACL(访问控制列表).在命令行里,一系列的命令跟随以一系列的文件名. [TOC] 选项 |参数|说明|   ...

  9. ZooKeeper设置ACL权限控制

    ZK的节点有5种操作权限:CREATE.READ.WRITE.DELETE.ADMIN 也就是 增.删.改.查.管理权限,这5种权限简写为crwda(即:每个单词的首字符缩写)注:这5种权限中,del ...

  10. linux 账号管理与ACL权限设定

    此文涉及命令:useradd.usermod.userdel.passwd.chage.setfacl.getfacl.su.sudo.fingr.chfn.chsh.id.groupadd.grou ...

随机推荐

  1. ruby中如何直接编译运行C代码

    我们知道ruby通过C EXT可以很方便的运行C代码,其实只要是C接口的语言都可以,比如汇编语言也可以哦.但是一些简单的函数难道还得费劲用C扩展的方式吗?其实ruby gem里有RubyInline包 ...

  2. java 深入理解内部类以及之间的调用关系

    什么是内部类 内部类是指在一个外部类的内部再定义一个类.内部类作为外部类的一个成员,并且依附于外部类而存在的.内部类可为静态,可用protected和private修饰(而外部类只能使用public和 ...

  3. java web--DOM

    Dom总结dom:文档对象模型的简称.dom的解析:与XML一样遵循同样的规范 将标记型文档解析成一棵DOM树,并将树中的内容都封装成节点对象. 如果html文档过大,同样会造成解析过慢,怎么使用sa ...

  4. 前端CDN公共库整理

    转自: 灰狼博客, 地址: http://itlobo.com/articles/2016.html 现在web应用都在使用js类库,这些类库小的几十K,大的几百K,而国内网络访问速度大家都知道不是那 ...

  5. 分布式文件系统MFS、Ceph、GlusterFS、Lustre的比较

    原文:http://blog.csdn.net/metaxen/article/details/7108958 MooseFS(MFS) Ceph GlusterFS Lustre Metadata ...

  6. RESTful规范建议

    RESTful概述 RESTful是目前最流行的一种互联网软件架构.它结构清晰.符合标准.易于理解.扩展方便,所以正得到越来越多网站的采用. REST是Representational State T ...

  7. 大型三甲医院管理系统源码PACS超声科室源码DICOM影像工作站

    详情点击查看 开发环境 :VS2008 + C# + SQL2000 功能简介 1.患者登记工作站 集中登记患者基本信息和检查信息,包括就诊方式.患者来源.检查类型.检查部位.申请科室.申请医生等.可 ...

  8. 从有值的ID到汉字编码

    前些日子漫无目的地刷着朋友圈,突然一个ID从字丛中闯入我的眼睛--"某&字"(为保护当事人隐私,此处用'某''字'代替),浸淫于计算机而产生的直觉告诉我,这是一个有值的表达 ...

  9. 谈谈Javascript异步代码优化

    关于 微信公众号:前端呼啦圈(Love-FED) 我的博客:劳卜的博客 知乎专栏:前端呼啦圈 前言 在实际编码中,我们经常会遇到Javascript代码异步执行的场景,比如ajax的调用.定时器的使用 ...

  10. Python 基础【一】

    python运行流程 一.变量及注释 命名: 合法-变量名由字母.数字和下划线组成,并且不能以数字开头.以下保留字不可以当变量名: ['False', 'None', 'True', 'and', ' ...