diff --git a/central_auth_acl_handling.go b/central_auth_acl_handling.go index 43bbe8f..055705c 100644 --- a/central_auth_acl_handling.go +++ b/central_auth_acl_handling.go @@ -4,8 +4,10 @@ import ( "crypto/sha256" "encoding/json" "fmt" + "io" "log" "os" + "path/filepath" "sort" "strings" "sync" @@ -42,13 +44,17 @@ type accessLists struct { func newAccessLists(errorKernel *errorKernel, configuration *Configuration) *accessLists { a := accessLists{ - schemaMain: newSchemaMain(), + schemaMain: newSchemaMain(configuration), schemaGenerated: newSchemaGenerated(), validator: validator.New(), errorKernel: errorKernel, configuration: configuration, } + // The main acl map gets loaded from disk in the newSchemaMain function, but since that + // function do not have access to the generated map we have to generate it here. + a.generateACLsForAllNodes() + return &a } @@ -60,17 +66,52 @@ 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{} + ACLMapFilePath string NodeGroupMap map[nodeGroup]map[Node]struct{} CommandGroupMap map[commandGroup]map[command]struct{} mu sync.Mutex } -func newSchemaMain() *schemaMain { +func newSchemaMain(configuration *Configuration) *schemaMain { s := schemaMain{ ACLMap: make(map[Node]map[Node]map[command]struct{}), + ACLMapFilePath: filepath.Join(configuration.DatabaseFolder, "central_aclmap.txt"), NodeGroupMap: make(map[nodeGroup]map[Node]struct{}), CommandGroupMap: make(map[commandGroup]map[command]struct{}), } + + // Load ACLMap from disk if present. + func() { + if _, err := os.Stat(s.ACLMapFilePath); os.IsNotExist(err) { + er := fmt.Errorf("error: newSchemaMain: no file for ACLMap found %v: %v", s.ACLMapFilePath, err) + log.Printf("%v\n", er) + + // If no aclmap is present on disk we just return from this + // function without loading any values. + return + } + + fh, err := os.Open(s.ACLMapFilePath) + if err != nil { + er := fmt.Errorf("error: newSchemaMain: failed to open file for reading %v: %v", s.ACLMapFilePath, err) + log.Printf("%v\n", er) + } + + b, err := io.ReadAll(fh) + if err != nil { + er := fmt.Errorf("error: newSchemaMain: failed to ReadAll file %v: %v", s.ACLMapFilePath, err) + log.Printf("%v\n", er) + } + + // Unmarshal the data read from disk. + err = json.Unmarshal(b, &s.ACLMap) + if err != nil { + er := fmt.Errorf("error: newSchemaMain: failed to unmarshal content from file %v: %v", s.ACLMapFilePath, err) + log.Printf("%v\n", er) + } + + // Generate the aclGenerated map happens in the function where this function is called. + }() return &s } @@ -242,6 +283,27 @@ func (a *accessLists) aclDeleteSource(host Node, source Node) error { // nodes. // The result will be written to the schemaGenerated.ACLsToConvert map. func (a *accessLists) generateACLsForAllNodes() error { + // We first one to save the current main ACLMap. + func() { + fh, err := os.OpenFile(a.schemaMain.ACLMapFilePath, os.O_CREATE|os.O_TRUNC|os.O_RDWR, 0600) + if err != nil { + er := fmt.Errorf("error: generateACLsForAllNodes: opening file for writing: %v, err: %v", a.schemaMain.ACLMapFilePath, err) + log.Printf("%v\n", er) + return + } + defer fh.Close() + + // a.schemaMain.mu.Lock() + // defer a.schemaMain.mu.Unlock() + enc := json.NewEncoder(fh) + enc.Encode(a.schemaMain.ACLMap) + if err != nil { + er := fmt.Errorf("error: generateACLsForAllNodes: encoding json to file failed: %v, err: %v", a.schemaMain.ACLMapFilePath, err) + log.Printf("%v\n", er) + return + } + }() + a.schemaGenerated.mu.Lock() defer a.schemaGenerated.mu.Unlock() diff --git a/processes.go b/processes.go index 5c93bf3..698db7b 100644 --- a/processes.go +++ b/processes.go @@ -178,6 +178,7 @@ func (p *processes) Start(proc process) { // TODO: Putting the acl publisher here. // Maybe we should also change the name of the configuration flag to something auth related ? proc.startup.pubREQAclRequestUpdate(proc) + proc.startup.subREQAclDeliverUpdate(proc) } if proc.configuration.IsCentralAuth { @@ -342,7 +343,7 @@ func (s startup) pubREQKeysRequestUpdate(p process) { // and update with new keys back. proc.nodeAuth.publicKeys.mu.Lock() - fmt.Printf("\n ----> REQKeysRequestUpdate: sending our current hash: %v\n\n", []byte(proc.nodeAuth.publicKeys.keysAndHash.Hash[:])) + fmt.Printf("\n ----> publisher REQKeysRequestUpdate: sending our current hash: %v\n\n", []byte(proc.nodeAuth.publicKeys.keysAndHash.Hash[:])) m := Message{ FileName: "publickeysget.log", @@ -397,7 +398,7 @@ func (s startup) pubREQAclRequestUpdate(p process) { // and update with new keys back. proc.nodeAuth.nodeAcl.mu.Lock() - fmt.Printf("\n ----> REQKeysRequestUpdate: sending our current hash: %v\n\n", []byte(proc.nodeAuth.nodeAcl.aclAndHash.Hash[:])) + fmt.Printf("\n ----> publisher REQAclRequestUpdate: sending our current hash: %v\n\n", []byte(proc.nodeAuth.nodeAcl.aclAndHash.Hash[:])) m := Message{ FileName: "aclRequestUpdate.log", @@ -461,6 +462,13 @@ func (s startup) subREQAclRequestUpdate(p process) { go proc.spawnWorker() } +func (s startup) subREQAclDeliverUpdate(p process) { + log.Printf("Starting Acl deliver update subscriber: %#v\n", p.node) + sub := newSubject(REQAclDeliverUpdate, string(p.node)) + proc := newProcess(p.ctx, s.server, sub, processKindSubscriber, nil) + go proc.spawnWorker() +} + // HERE! func (s startup) subREQAclAddCommand(p process) { diff --git a/requests_acl.go b/requests_acl.go index 07e869d..c6eca3b 100644 --- a/requests_acl.go +++ b/requests_acl.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "log" "github.com/fxamacker/cbor/v2" ) @@ -20,6 +21,11 @@ func (m methodREQAclRequestUpdate) getKind() Event { // Handler to get all acl's from a central server. func (m methodREQAclRequestUpdate) handler(proc process, message Message, node string) ([]byte, error) { + inf := fmt.Errorf("<--- subscriber methodREQAclRequestUpdate received from: %v, and the data which is the nodes current acl hash containing: %v", message.FromNode, message.MethodArgs) + proc.errorKernel.logConsoleOnlyIfDebug(inf, proc.configuration) + + fmt.Printf("\n --- subscriber methodREQAclRequestUpdate: the message brought to handler : %+v\n", message) + // Get a context with the timeout specified in message.MethodTimeout. ctx, _ := getContextForMethodTimeout(proc.ctx, message) @@ -47,27 +53,47 @@ func (m methodREQAclRequestUpdate) handler(proc process, message Message, node s proc.centralAuth.accessLists.schemaGenerated.mu.Lock() defer proc.centralAuth.accessLists.schemaGenerated.mu.Unlock() - fmt.Printf(" <---- methodREQAclRequestUpdate: received acl hash from NODE=%v, HASH=%v\n", message.FromNode, message.Data) + // DEBUGGING: + { + proc.centralAuth.accessLists.schemaMain.mu.Lock() + fmt.Printf("\n --- DEBUGGING: subscriber methodREQAclRequestUpdate: schemaGenerated contains: %v\n\n", proc.centralAuth.accessLists.schemaGenerated) + fmt.Printf("\n --- DEBUGGING: subscriber methodREQAclRequestUpdate: schemaMain contains: %v\n\n", proc.centralAuth.accessLists.schemaMain) + proc.centralAuth.accessLists.schemaMain.mu.Unlock() + + // TODO: PROBLEM: The existing generated acl's are not loaded when starting, or not stored at all. + } + + fmt.Printf(" ---- subscriber methodREQAclRequestUpdate: got acl hash from NODE=%v, HASH=%v\n", message.FromNode, message.Data) // Check if the received hash is the same as the one currently active, // If it is the same we exit the handler immediately. hash32 := proc.centralAuth.accessLists.schemaGenerated.GeneratedACLsMap[message.FromNode].Hash hash := hash32[:] + fmt.Printf("\n ---- subscriber methodREQAclRequestUpdate: on central hash32=%v\n\n", hash32) if bytes.Equal(hash, message.Data) { - fmt.Printf("\n ------------ NODE AND CENTRAL HAVE EQUAL ACL HASH, NOTHING TO DO, EXITING HANDLER\n\n") + fmt.Printf("\n ---- subscriber methodREQAclRequestUpdate: NODE AND CENTRAL HAVE EQUAL ACL HASH, NOTHING TO DO, EXITING HANDLER\n\n") return } - fmt.Printf("\n ------------ NODE AND CENTRAL HAD NOT EQUAL ACL, PREPARING TO SEND NEW VERSION OF Acl\n\n") + fmt.Printf("\n ---- subscriber methodREQAclRequestUpdate: NODE AND CENTRAL HAD NOT EQUAL ACL, PREPARING TO SEND NEW VERSION OF Acl\n\n") - fmt.Printf("\n ----> methodREQAclRequestUpdate: SENDING ACL'S TO NODE=%v\n", message.FromNode) + // Generate JSON for Message.Data - js, err := json.Marshal(proc.centralAuth.accessLists.schemaGenerated.GeneratedACLsMap[message.FromNode]) + hdh := HostACLsSerializedWithHash{} + hdh.Data = proc.centralAuth.accessLists.schemaGenerated.GeneratedACLsMap[message.FromNode].Data + fmt.Printf("\n * DEBUGGING: before marshalling, hdh.Data=%v\n", hdh.Data) + hdh.Hash = proc.centralAuth.accessLists.schemaGenerated.GeneratedACLsMap[message.FromNode].Hash + fmt.Printf("\n * DEBUGGING: before marshalling, hdh.Hash=%v\n\n", hdh.Hash) + + js, err := json.Marshal(hdh) if err != nil { er := fmt.Errorf("error: REQAclRequestUpdate : json marshal failed: %v, message: %v", err, message) proc.errorKernel.errSend(proc, message, er) + log.Fatalf("%v\n", er) } + fmt.Printf("\n ----> subscriber methodREQAclRequestUpdate: SENDING ACL'S TO NODE=%v, serializedAndHash=%+v\n", message.FromNode, hdh) + newReplyMessage(proc, message, js) }() } @@ -89,6 +115,11 @@ func (m methodREQAclDeliverUpdate) getKind() Event { // Handler to receive the acls from a central server. func (m methodREQAclDeliverUpdate) handler(proc process, message Message, node string) ([]byte, error) { + inf := fmt.Errorf("<--- subscriber methodREQAclDeliverUpdate received from: %v, containing: %v", message.FromNode, message.Data) + proc.errorKernel.logConsoleOnlyIfDebug(inf, proc.configuration) + + fmt.Printf("\n --- subscriber methodREQAclRequestUpdate: the message received on handler : %+v\n\n", message) + // Get a context with the timeout specified in message.MethodTimeout. ctx, _ := getContextForMethodTimeout(proc.ctx, message) @@ -120,27 +151,30 @@ func (m methodREQAclDeliverUpdate) handler(proc process, message Message, node s err := json.Unmarshal(message.Data, &hdh) if err != nil { - er := fmt.Errorf("error: REQAclDeliverUpdate : json unmarshal failed: %v, message: %v", err, message) + er := fmt.Errorf("error: subscriber REQAclDeliverUpdate : json unmarshal failed: %v, message: %v", err, message) proc.errorKernel.errSend(proc, message, er) + log.Fatalf("\n * DEBUG: ER: %v\n", er) } mapOfFromNodeCommands := make(map[Node]map[command]struct{}) err = cbor.Unmarshal(hdh.Data, &mapOfFromNodeCommands) if err != nil { - er := fmt.Errorf("error: REQAclDeliverUpdate : json unmarshal failed: %v, message: %v", err, message) + er := fmt.Errorf("error: subscriber REQAclDeliverUpdate : json unmarshal failed: %v, message: %v", err, message) proc.errorKernel.errSend(proc, message, er) + log.Fatalf("\n * DEBUG: ER: %v\n", er) + } proc.nodeAuth.nodeAcl.aclAndHash.Hash = hdh.Hash proc.nodeAuth.nodeAcl.aclAndHash.Acl = mapOfFromNodeCommands - fmt.Printf("\n <---- REQAclDeliverUpdate: after unmarshal, nodeAuth aclAndhash contains: %+v\n\n", proc.nodeAuth.nodeAcl.aclAndHash) + fmt.Printf("\n <---- subscriber REQAclDeliverUpdate: after unmarshal, nodeAuth aclAndhash contains: %+v\n\n", proc.nodeAuth.nodeAcl.aclAndHash) proc.nodeAuth.nodeAcl.mu.Unlock() err = proc.nodeAuth.nodeAcl.saveToFile() if err != nil { - er := fmt.Errorf("error: REQAclDeliverUpdate : save to file failed: %v, message: %v", err, message) + er := fmt.Errorf("error: subscriber REQAclDeliverUpdate : save to file failed: %v, message: %v", err, message) proc.errorKernel.errSend(proc, message, er) } @@ -842,6 +876,9 @@ func (m methodREQAclExport) handler(proc process, message Message, node string) // --- +// TODO: IMPORTANT: We also need to add importing and exporting of the groups to the +// import and export methods. + type methodREQAclImport struct { event Event } diff --git a/requests_keys.go b/requests_keys.go index 9761a96..a8a902b 100644 --- a/requests_keys.go +++ b/requests_keys.go @@ -117,11 +117,11 @@ func (m methodREQKeysRequestUpdate) handler(proc process, message Message, node // Check if the received hash is the same as the one currently active, if bytes.Equal(proc.centralAuth.pki.nodesAcked.keysAndHash.Hash[:], message.Data) { - fmt.Printf("\n ------------ NODE AND CENTRAL HAVE EQUAL KEYS, NOTHING TO DO, EXITING HANDLER\n\n") + fmt.Printf("\n --- methodREQKeysRequestUpdate: NODE AND CENTRAL HAVE EQUAL KEYS, NOTHING TO DO, EXITING HANDLER\n\n") return } - fmt.Printf("\n ------------ NODE AND CENTRAL HAD NOT EQUAL KEYS, PREPARING TO SEND NEW VERSION OF KEYS\n\n") + fmt.Printf("\n ------------methodREQKeysRequestUpdate: NODE AND CENTRAL HAD NOT EQUAL KEYS, PREPARING TO SEND NEW VERSION OF KEYS\n\n") fmt.Printf(" * methodREQKeysRequestUpdate: marshalling new keys and hash to send: map=%v, hash=%v\n\n", proc.centralAuth.pki.nodesAcked.keysAndHash.Keys, proc.centralAuth.pki.nodesAcked.keysAndHash.Hash)