Skip to content
Snippets Groups Projects
Commit 70835184 authored by ale's avatar ale
Browse files

Implement PEER ACLs

Introduce a new 'PEER' ACL operation, so that peeres can be
authenticated using the same mechanism as other clients.

Fixes issue #1.
parent a008e1cf
No related branches found
No related tags found
No related merge requests found
...@@ -2,6 +2,7 @@ package acl ...@@ -2,6 +2,7 @@ package acl
import ( import (
"bufio" "bufio"
"errors"
"fmt" "fmt"
"os" "os"
"strings" "strings"
...@@ -14,6 +15,7 @@ type ACLOp int ...@@ -14,6 +15,7 @@ type ACLOp int
const ( const (
OpRead = iota OpRead = iota
OpWrite OpWrite
OpPeer
) )
func (op ACLOp) String() string { func (op ACLOp) String() string {
...@@ -22,6 +24,8 @@ func (op ACLOp) String() string { ...@@ -22,6 +24,8 @@ func (op ACLOp) String() string {
return "READ" return "READ"
case OpWrite: case OpWrite:
return "WRITE" return "WRITE"
case OpPeer:
return "PEER"
} }
return "<ERROR>" return "<ERROR>"
} }
...@@ -61,6 +65,18 @@ func (m *Manager) Check(identity string, op ACLOp, path string) bool { ...@@ -61,6 +65,18 @@ func (m *Manager) Check(identity string, op ACLOp, path string) bool {
return false return false
} }
// Load ACL rules from a text file. The file should contain one rule
// per line, either:
//
// <identity> <path> <op(READ|WRITE)>
//
// or:
//
// <identity> <op(PEER)>
//
// (PEER ACLs have no path). Empty lines and lines starting with a #
// are ignored.
//
func Load(path string) (*Manager, error) { func Load(path string) (*Manager, error) {
f, err := os.Open(path) f, err := os.Open(path)
if err != nil { if err != nil {
...@@ -77,19 +93,11 @@ func Load(path string) (*Manager, error) { ...@@ -77,19 +93,11 @@ func Load(path string) (*Manager, error) {
if strings.HasPrefix(line, "#") || line == "" { if strings.HasPrefix(line, "#") || line == "" {
continue continue
} }
fields := strings.Fields(line) e, err := parseEntry(line)
if len(fields) != 3 {
return nil, fmt.Errorf("syntax error at %s:%d: not enough fields", path, lineno)
}
op, err := parseOp(fields[2])
if err != nil { if err != nil {
return nil, fmt.Errorf("syntax error at %s:%d: %w", path, lineno, err) return nil, fmt.Errorf("syntax error at %s:%d: %w", path, lineno, err)
} }
acls = append(acls, Entry{ acls = append(acls, e)
Identity: fields[0],
Path: fields[1],
Op: op,
})
} }
if err := scanner.Err(); err != nil { if err := scanner.Err(); err != nil {
...@@ -99,12 +107,48 @@ func Load(path string) (*Manager, error) { ...@@ -99,12 +107,48 @@ func Load(path string) (*Manager, error) {
return NewManager(acls), nil return NewManager(acls), nil
} }
func parseEntry(line string) (e Entry, err error) {
fields := strings.Fields(line)
switch len(fields) {
case 2:
e.Op, err = parseOp(fields[1])
if err != nil {
return
}
if e.Op != OpPeer {
err = errors.New("non-PEER acl without path")
return
}
case 3:
e.Path = fields[1]
e.Op, err = parseOp(fields[2])
if err != nil {
return
}
if e.Op != OpRead && e.Op != OpWrite {
err = errors.New("acl op is not 'read' or 'write'")
return
}
default:
err = errors.New("not enough fields")
return
}
e.Identity = fields[0]
return
}
func parseOp(s string) (op ACLOp, err error) { func parseOp(s string) (op ACLOp, err error) {
switch strings.ToLower(s) { switch strings.ToLower(s) {
case "read", "r": case "read", "r":
op = OpRead op = OpRead
case "write", "w": case "write", "w":
op = OpWrite op = OpWrite
case "peer":
op = OpPeer
default: default:
err = fmt.Errorf("unknown op '%s'", s) err = fmt.Errorf("unknown op '%s'", s)
} }
......
...@@ -101,6 +101,10 @@ func (s *Server) Store(ctx context.Context, req *pb.StoreRequest) (*empty.Empty, ...@@ -101,6 +101,10 @@ func (s *Server) Store(ctx context.Context, req *pb.StoreRequest) (*empty.Empty,
} }
func (s *Server) SyncNodes(ctx context.Context, req *pb.SyncNodesRequest) (*pb.SyncNodesResponse, error) { func (s *Server) SyncNodes(ctx context.Context, req *pb.SyncNodesRequest) (*pb.SyncNodesResponse, error) {
if !s.acl.Check(common.GetAuthIdentity(ctx), acl.OpPeer, "") {
return nil, status.Error(codes.PermissionDenied, "unauthorized")
}
s.mx.Lock() s.mx.Lock()
diff := s.nodes.TreeDiff(req.Summary, "/") diff := s.nodes.TreeDiff(req.Summary, "/")
s.mx.Unlock() s.mx.Unlock()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment