1
0
Fork 0
mirror of https://github.com/postmannen/ctrl.git synced 2024-12-14 12:37:31 +00:00

added initial REQ for adding acl

This commit is contained in:
postmannen 2022-05-18 11:26:06 +02:00
parent 57bedfe6c6
commit 0ba5f6ea5d
6 changed files with 154 additions and 54 deletions

View file

@ -48,23 +48,23 @@ func newAccessLists() *accessLists {
return &a
}
type node string
// type node string
type command string
type nodeGroup string
type commandGroup string
// schemaMain is the structure that holds the user editable parts for creating ACL's.
type schemaMain struct {
ACLMap map[node]map[node]map[command]struct{}
NodeGroupMap map[nodeGroup]map[node]struct{}
ACLMap map[Node]map[Node]map[command]struct{}
NodeGroupMap map[nodeGroup]map[Node]struct{}
CommandGroupMap map[commandGroup]map[command]struct{}
mu sync.Mutex
}
func newSchemaMain() *schemaMain {
s := schemaMain{
ACLMap: make(map[node]map[node]map[command]struct{}),
NodeGroupMap: make(map[nodeGroup]map[node]struct{}),
ACLMap: make(map[Node]map[Node]map[command]struct{}),
NodeGroupMap: make(map[nodeGroup]map[Node]struct{}),
CommandGroupMap: make(map[commandGroup]map[command]struct{}),
}
return &s
@ -74,15 +74,15 @@ func newSchemaMain() *schemaMain {
// to be sent to nodes.
// The ACL's here are generated from the schemaMain.ACLMap.
type schemaGenerated struct {
ACLsToConvert map[node]map[node]map[command]struct{}
GeneratedACLsMap map[node]HostACLsSerializedWithHash
ACLsToConvert map[Node]map[Node]map[command]struct{}
GeneratedACLsMap map[Node]HostACLsSerializedWithHash
mu sync.Mutex
}
func newSchemaGenerated() *schemaGenerated {
s := schemaGenerated{
ACLsToConvert: map[node]map[node]map[command]struct{}{},
GeneratedACLsMap: make(map[node]HostACLsSerializedWithHash),
ACLsToConvert: map[Node]map[Node]map[command]struct{}{},
GeneratedACLsMap: make(map[Node]HostACLsSerializedWithHash),
}
return &s
}
@ -104,8 +104,8 @@ type HostACLsSerializedWithHash struct {
// the slice.
// If the argument is not a group kind of value, then only a slice with that single
// value is returned.
func (a *accessLists) nodeAsSlice(n node) []node {
nodes := []node{}
func (a *accessLists) nodeAsSlice(n Node) []Node {
nodes := []Node{}
// Check if we are given a nodeGroup variable, and if we are, get all the
// nodes for that group.
@ -115,7 +115,7 @@ func (a *accessLists) nodeAsSlice(n node) []node {
}
} else {
// No group found meaning a single node was given as an argument.
nodes = []node{n}
nodes = []Node{n}
}
return nodes
@ -148,14 +148,14 @@ func (a *accessLists) commandAsSlice(c command) []command {
// If the node or the fromNode do not exist they will be created.
// The json encoded schema for a node and the hash of those data
// will also be generated.
func (a *accessLists) aclAdd(host node, source node, cmd command) {
func (a *accessLists) aclAdd(host Node, source Node, cmd command) {
a.schemaMain.mu.Lock()
defer a.schemaMain.mu.Unlock()
// Check if node exists in map.
if _, ok := a.schemaMain.ACLMap[host]; !ok {
// log.Printf("info: did not find node=%v in map, creating map[fromnode]map[command]struct{}\n", n)
a.schemaMain.ACLMap[host] = make(map[node]map[command]struct{})
a.schemaMain.ACLMap[host] = make(map[Node]map[command]struct{})
}
// Check if also source node exists in map
@ -177,7 +177,7 @@ func (a *accessLists) aclAdd(host node, source node, cmd command) {
}
// aclDeleteCommand will delete the specified command from the fromnode.
func (a *accessLists) aclDeleteCommand(host node, source node, cmd command) error {
func (a *accessLists) aclDeleteCommand(host Node, source Node, cmd command) error {
a.schemaMain.mu.Lock()
defer a.schemaMain.mu.Unlock()
@ -206,7 +206,7 @@ func (a *accessLists) aclDeleteCommand(host node, source node, cmd command) erro
}
// aclDeleteSource will delete specified source node and all commands specified for it.
func (a *accessLists) aclDeleteSource(host node, source node) error {
func (a *accessLists) aclDeleteSource(host Node, source Node) error {
a.schemaMain.mu.Lock()
defer a.schemaMain.mu.Unlock()
@ -241,7 +241,7 @@ func (a *accessLists) generateACLsForAllNodes() error {
a.schemaGenerated.mu.Lock()
defer a.schemaGenerated.mu.Unlock()
a.schemaGenerated.ACLsToConvert = make(map[node]map[node]map[command]struct{})
a.schemaGenerated.ACLsToConvert = make(map[Node]map[Node]map[command]struct{})
// Rangle all ACL's. Both for single hosts, and group of hosts.
// ACL's that are for a group of hosts will be generated split
@ -304,7 +304,7 @@ func (a *accessLists) generateACLsForAllNodes() error {
// and we then use the slice representation of the ACL to create the hash for
// a specific host node.
type sourceNode struct {
HostNode node
HostNode Node
SourceCommands []sourceNodeCommands
}
@ -312,7 +312,7 @@ type sourceNode struct {
// and we then use the slice representation of the ACL to create the hash for
// a specific host node.
type sourceNodeCommands struct {
Source node
Source Node
Commands []command
}
@ -321,7 +321,7 @@ type sourceNodeCommands struct {
// defined for each sourceNode are sorted.
// This function is used when creating the hash of the nodeMap since we can not
// guarantee the order of a hash map, but we can with a slice.
func (a *accessLists) nodeMapToSlice(host node) sourceNode {
func (a *accessLists) nodeMapToSlice(host Node) sourceNode {
srcNodes := sourceNode{
HostNode: host,
}
@ -355,7 +355,7 @@ func (a *accessLists) nodeMapToSlice(host node) sourceNode {
// groupNodesAddNode adds a node to a group. If the group does
// not exist it will be created.
func (a *accessLists) groupNodesAddNode(ng nodeGroup, n node) {
func (a *accessLists) groupNodesAddNode(ng nodeGroup, n Node) {
err := a.validator.Var(ng, "startswith=grp_nodes_")
if err != nil {
log.Printf("error: group name do not start with grp_nodes_: %v\n", err)
@ -365,7 +365,7 @@ func (a *accessLists) groupNodesAddNode(ng nodeGroup, n node) {
a.schemaMain.mu.Lock()
defer a.schemaMain.mu.Unlock()
if _, ok := a.schemaMain.NodeGroupMap[ng]; !ok {
a.schemaMain.NodeGroupMap[ng] = make(map[node]struct{})
a.schemaMain.NodeGroupMap[ng] = make(map[Node]struct{})
}
a.schemaMain.NodeGroupMap[ng][n] = struct{}{}
@ -381,7 +381,7 @@ func (a *accessLists) groupNodesAddNode(ng nodeGroup, n node) {
}
// groupNodesDeleteNode deletes a node from a group in the map.
func (a *accessLists) groupNodesDeleteNode(ng nodeGroup, n node) {
func (a *accessLists) groupNodesDeleteNode(ng nodeGroup, n Node) {
a.schemaMain.mu.Lock()
defer a.schemaMain.mu.Unlock()
if _, ok := a.schemaMain.NodeGroupMap[ng][n]; !ok {
@ -515,7 +515,7 @@ func (a *accessLists) importACLs(js []byte) error {
a.schemaMain.mu.Lock()
defer a.schemaMain.mu.Unlock()
m := make(map[node]map[node]map[command]struct{})
m := make(map[Node]map[Node]map[command]struct{})
err := json.Unmarshal(js, &m)
if err != nil {

View file

@ -5,16 +5,16 @@ import (
)
type authParser struct {
currentHost node
authSchema *accessLists
currentHost Node
accessLists *accessLists
//ACLsToConvert map[node]map[node]map[command]struct{}
}
// newAuthParser returns a new authParser, with the current host node set.
func newAuthParser(n node, accessLists *accessLists) *authParser {
func newAuthParser(n Node, accessLists *accessLists) *authParser {
a := authParser{
currentHost: n,
authSchema: accessLists,
accessLists: accessLists,
//ACLsToConvert: make(map[node]map[node]map[command]struct{}),
}
return &a
@ -50,27 +50,27 @@ func (a *authParser) hostGroupOrSingle() parseFn {
func (a *authParser) hostIsGroup() parseFn {
// fmt.Printf("%v is a grp type\n", a.currentHost)
hosts := a.authSchema.nodeAsSlice(a.currentHost)
hosts := a.accessLists.nodeAsSlice(a.currentHost)
for source, cmdMap := range a.authSchema.schemaMain.ACLMap[a.currentHost] {
for source, cmdMap := range a.accessLists.schemaMain.ACLMap[a.currentHost] {
for cmd, emptyStruct := range cmdMap {
cmdSlice := a.authSchema.commandAsSlice(cmd)
cmdSlice := a.accessLists.commandAsSlice(cmd)
// Expand eventual groups, so we use real fromNode nodenames in ACL for nodes.
sourceNodes := a.authSchema.nodeAsSlice(source)
sourceNodes := a.accessLists.nodeAsSlice(source)
for _, sourceNode := range sourceNodes {
for _, host := range hosts {
for _, cm := range cmdSlice {
if a.authSchema.schemaGenerated.ACLsToConvert[host] == nil {
a.authSchema.schemaGenerated.ACLsToConvert[host] = make(map[node]map[command]struct{})
if a.accessLists.schemaGenerated.ACLsToConvert[host] == nil {
a.accessLists.schemaGenerated.ACLsToConvert[host] = make(map[Node]map[command]struct{})
}
if a.authSchema.schemaGenerated.ACLsToConvert[host][sourceNode] == nil {
a.authSchema.schemaGenerated.ACLsToConvert[host][sourceNode] = make(map[command]struct{})
if a.accessLists.schemaGenerated.ACLsToConvert[host][sourceNode] == nil {
a.accessLists.schemaGenerated.ACLsToConvert[host][sourceNode] = make(map[command]struct{})
}
a.authSchema.schemaGenerated.ACLsToConvert[host][sourceNode][cm] = emptyStruct
a.accessLists.schemaGenerated.ACLsToConvert[host][sourceNode][cm] = emptyStruct
}
}
}
@ -88,24 +88,24 @@ func (a *authParser) hostIsNotGroup() parseFn {
host := a.currentHost
for source, cmdMap := range a.authSchema.schemaMain.ACLMap[a.currentHost] {
for source, cmdMap := range a.accessLists.schemaMain.ACLMap[a.currentHost] {
for cmd, emptyStruct := range cmdMap {
cmdSlice := a.authSchema.commandAsSlice(cmd)
cmdSlice := a.accessLists.commandAsSlice(cmd)
// Expand eventual groups, so we use real fromNode nodenames in ACL for nodes.
sourceNodes := a.authSchema.nodeAsSlice(source)
sourceNodes := a.accessLists.nodeAsSlice(source)
for _, sourceNode := range sourceNodes {
for _, cm := range cmdSlice {
if a.authSchema.schemaGenerated.ACLsToConvert[host] == nil {
a.authSchema.schemaGenerated.ACLsToConvert[host] = make(map[node]map[command]struct{})
if a.accessLists.schemaGenerated.ACLsToConvert[host] == nil {
a.accessLists.schemaGenerated.ACLsToConvert[host] = make(map[Node]map[command]struct{})
}
if a.authSchema.schemaGenerated.ACLsToConvert[host][sourceNode] == nil {
a.authSchema.schemaGenerated.ACLsToConvert[host][sourceNode] = make(map[command]struct{})
if a.accessLists.schemaGenerated.ACLsToConvert[host][sourceNode] == nil {
a.accessLists.schemaGenerated.ACLsToConvert[host][sourceNode] = make(map[command]struct{})
}
a.authSchema.schemaGenerated.ACLsToConvert[host][sourceNode][cm] = emptyStruct
a.accessLists.schemaGenerated.ACLsToConvert[host][sourceNode][cm] = emptyStruct
}
}
}

View file

@ -22,7 +22,7 @@ func TestACLSingleNode(t *testing.T) {
// --- TESTS ---
mapOfFromNodeCommands := make(map[node]map[command]struct{})
mapOfFromNodeCommands := make(map[Node]map[command]struct{})
err := cbor.Unmarshal(a.schemaGenerated.GeneratedACLsMap["ship101"].Data, &mapOfFromNodeCommands)
if err != nil {
t.Fatal(err)
@ -64,7 +64,7 @@ func TestACLWithGroups(t *testing.T) {
a.aclAdd(grp_nodes_ships, grp_nodes_operators, grp_commands_commandset1)
mapOfFromNodeCommands := make(map[node]map[command]struct{})
mapOfFromNodeCommands := make(map[Node]map[command]struct{})
err := cbor.Unmarshal(a.schemaGenerated.GeneratedACLsMap["ship101"].Data, &mapOfFromNodeCommands)
if err != nil {
t.Fatal(err)
@ -127,7 +127,7 @@ func TestACLNodesGroupDeleteNode(t *testing.T) {
// Check that we still got the data for ship100.
{
mapOfFromNodeCommands := make(map[node]map[command]struct{})
mapOfFromNodeCommands := make(map[Node]map[command]struct{})
err := cbor.Unmarshal(a.schemaGenerated.GeneratedACLsMap["ship100"].Data, &mapOfFromNodeCommands)
if err != nil {
t.Fatal(err)
@ -140,7 +140,7 @@ func TestACLNodesGroupDeleteNode(t *testing.T) {
// Check that we don't have any data for ship101.
{
mapOfFromNodeCommands := make(map[node]map[command]struct{})
mapOfFromNodeCommands := make(map[Node]map[command]struct{})
err := cbor.Unmarshal(a.schemaGenerated.GeneratedACLsMap["ship101"].Data, &mapOfFromNodeCommands)
if err != nil {
t.Fatal(err)
@ -184,7 +184,7 @@ func TestGroupNodesDeleteGroup(t *testing.T) {
// Check that we still got the data for other ACL's.
{
mapOfFromNodeCommands := make(map[node]map[command]struct{})
mapOfFromNodeCommands := make(map[Node]map[command]struct{})
err := cbor.Unmarshal(a.schemaGenerated.GeneratedACLsMap["ship101"].Data, &mapOfFromNodeCommands)
if err != nil {
t.Fatal(err)
@ -197,7 +197,7 @@ func TestGroupNodesDeleteGroup(t *testing.T) {
// Check that we don't have any data for grp_nodes_operators
{
mapOfFromNodeCommands := make(map[node]map[command]struct{})
mapOfFromNodeCommands := make(map[Node]map[command]struct{})
err := cbor.Unmarshal(a.schemaGenerated.GeneratedACLsMap["ship101"].Data, &mapOfFromNodeCommands)
if err != nil {
t.Fatal(err)
@ -241,7 +241,7 @@ func TestGroupCommandDeleteGroup(t *testing.T) {
// Check that we still got the data for other ACL's.
{
mapOfFromNodeCommands := make(map[node]map[command]struct{})
mapOfFromNodeCommands := make(map[Node]map[command]struct{})
err := cbor.Unmarshal(a.schemaGenerated.GeneratedACLsMap["ship101"].Data, &mapOfFromNodeCommands)
if err != nil {
t.Fatal(err)
@ -254,7 +254,7 @@ func TestGroupCommandDeleteGroup(t *testing.T) {
// Check that we don't have any data for grp_nodes_operators
{
mapOfFromNodeCommands := make(map[node]map[command]struct{})
mapOfFromNodeCommands := make(map[Node]map[command]struct{})
err := cbor.Unmarshal(a.schemaGenerated.GeneratedACLsMap["ship101"].Data, &mapOfFromNodeCommands)
if err != nil {
t.Fatal(err)
@ -287,7 +287,7 @@ func TestACLGenerated(t *testing.T) {
// --- TESTS ---
mapOfFromNodeCommands := make(map[node]map[command]struct{})
mapOfFromNodeCommands := make(map[Node]map[command]struct{})
err := cbor.Unmarshal(a.schemaGenerated.GeneratedACLsMap["ship101"].Data, &mapOfFromNodeCommands)
if err != nil {
t.Fatal(err)

View file

@ -173,6 +173,7 @@ func (p *processes) Start(proc process) {
if proc.configuration.IsCentralAuth {
proc.startup.subREQPublicKeysGet(proc)
proc.startup.subREQPublicKeysAllow(proc)
proc.startup.subREQAclAddAccessList(proc)
}
if proc.configuration.StartSubREQPublicKeysToNode {
@ -375,6 +376,13 @@ func (s startup) subREQPublicKeysToNode(p process) {
go proc.spawnWorker()
}
func (s startup) subREQAclAddAccessList(p process) {
log.Printf("Starting Add Access List subscriber: %#v\n", p.node)
sub := newSubject(REQAclAddAccessList, string(p.node))
proc := newProcess(p.ctx, s.server, sub, processKindSubscriber, nil)
go proc.spawnWorker()
}
func (s startup) subREQToConsole(p process) {
log.Printf("Starting Text To Console subscriber: %#v\n", p.node)
sub := newSubject(REQToConsole, string(p.node))

87
requests-acl.go Normal file
View file

@ -0,0 +1,87 @@
package steward
import (
"fmt"
)
// ---
type methodREQAclAddAccessList struct {
event Event
}
func (m methodREQAclAddAccessList) getKind() Event {
return m.event
}
func (m methodREQAclAddAccessList) handler(proc process, message Message, node string) ([]byte, error) {
inf := fmt.Errorf("<--- methodREQAclAddAccessList received from: %v, containing: %v", message.FromNode, message.MethodArgs)
proc.errorKernel.logConsoleOnlyIfDebug(inf, proc.configuration)
proc.processes.wg.Add(1)
go func() {
defer proc.processes.wg.Done()
switch {
case len(message.MethodArgs) < 3:
er := fmt.Errorf("error: methodREQAclAddAccessList: got <3 number methodArgs, want 3")
proc.errorKernel.errSend(proc, message, er)
return
}
// Get a context with the timeout specified in message.MethodTimeout.
ctx, cancel := getContextForMethodTimeout(proc.ctx, message)
outCh := make(chan []byte)
proc.processes.wg.Add(1)
go func() {
defer proc.processes.wg.Done()
host := message.MethodArgs[0]
source := message.MethodArgs[1]
cmd := message.MethodArgs[2]
proc.centralAuth.accessLists.aclAdd(Node(host), Node(source), command(cmd))
// Just print out for testing.
proc.centralAuth.accessLists.schemaMain.mu.Lock()
fmt.Printf("\n ---------- content of main acl map: %v-----------\n", proc.centralAuth.accessLists.schemaMain.ACLMap)
proc.centralAuth.accessLists.schemaMain.mu.Unlock()
proc.centralAuth.accessLists.schemaGenerated.mu.Lock()
fmt.Printf("\n ---------- content of generated acl map: %s-----------\n", proc.centralAuth.accessLists.schemaGenerated.GeneratedACLsMap)
proc.centralAuth.accessLists.schemaGenerated.mu.Unlock()
outString := fmt.Sprintf("acl added: host=%v, source=%v, command=%v\n", host, source, cmd)
out := []byte(outString)
select {
case outCh <- out:
case <-ctx.Done():
return
}
}()
select {
case <-ctx.Done():
cancel()
er := fmt.Errorf("error: methodREQAclAddAccessList: method timed out: %v", message.MethodArgs)
proc.errorKernel.errSend(proc, message, er)
case out := <-outCh:
// Prepare and queue for sending a new message with the output
// of the action executed.
newReplyMessage(proc, message, out)
}
}()
ackMsg := []byte("confirmed from: " + node + ": " + fmt.Sprint(message.ID))
return ackMsg, nil
}
// ---

View file

@ -144,6 +144,8 @@ const (
REQPublicKeysToNode Method = "REQPublicKeysToNode"
// REQAuthPublicKeysAllow
REQPublicKeysAllow Method = "REQPublicKeysAllow"
// REQAclAddAcl
REQAclAddAccessList = "REQAclAddAccessList"
)
// The mapping of all the method constants specified, what type
@ -234,6 +236,9 @@ func (m Method) GetMethodsAvailable() MethodsAvailable {
REQPublicKeysAllow: methodREQPublicKeysAllow{
event: EventACK,
},
REQAclAddAccessList: methodREQAclAddAccessList{
event: EventACK,
},
},
}