Prechádzať zdrojové kódy

Added api access to auth log

tobychui 4 rokov pred
rodič
commit
9dd2d38e6f

+ 1 - 0
.gitignore

@@ -16,6 +16,7 @@ system/db/*
 system/ao.db.lock
 *aofs.db.lock
 ./web/aofs.db
+system/auth/authlog.db
 
 #Setting related
 system/network/wifi/ap/*

+ 4 - 0
auth.go

@@ -70,4 +70,8 @@ func AuthSettingsInit() {
 	//Handle additional batch operations
 	adminRouter.HandleFunc("/system/auth/csvimport", authAgent.HandleCreateUserAccountsFromCSV)
 	adminRouter.HandleFunc("/system/auth/groupdel", authAgent.HandleUserDeleteByGroup)
+
+	//API for checking with the logger
+	adminRouter.HandleFunc("/system/auth/logger/index", authAgent.Logger.HandleIndexListing)
+	adminRouter.HandleFunc("/system/auth/logger/list", authAgent.Logger.HandleTableListing)
 }

+ 8 - 1
mod/auth/auth.go

@@ -80,7 +80,10 @@ func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database,
 	done := make(chan bool)
 
 	//Create a new logger for logging all login request
-	newLogger := authlogger.NewLogger()
+	newLogger, err := authlogger.NewLogger()
+	if err != nil {
+		panic(err)
+	}
 
 	//Create a new AuthAgent object
 	newAuthAgent := AuthAgent{
@@ -115,7 +118,11 @@ func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database,
 
 //Close the authAgent listener
 func (a *AuthAgent) Close() {
+	//Stop the token listening
 	a.terminateTokenListener <- true
+
+	//Close the auth logger database
+	a.Logger.Close()
 }
 
 //This function will handle an http request and redirect to the given login address if not logged in

+ 105 - 4
mod/auth/authlogger/authlogger.go

@@ -1,9 +1,15 @@
 package authlogger
 
 import (
+	"encoding/json"
+	"errors"
 	"log"
 	"net/http"
+	"strconv"
+	"strings"
 	"time"
+
+	"imuslab.com/arozos/mod/database"
 )
 
 /*
@@ -16,16 +22,111 @@ import (
 */
 
 type Logger struct {
+	database *database.Database
+}
+
+type LoginRecord struct {
+	Timestamp      int64
+	TargetUsername string
+	LoginSucceed   bool
+	IpAddr         string
+	Port           int
 }
 
 //New Logger create a new logger object
-func NewLogger() *Logger {
-	return &Logger{}
+func NewLogger() (*Logger, error) {
+	db, err := database.NewDatabase("./system/auth/authlog.db", false)
+	if err != nil {
+		return nil, errors.New("*ERROR* Failed to create database for login tracking")
+	}
+	return &Logger{
+		database: db,
+	}, nil
 }
 
 //Log the current authentication to record, Require the request object and login status
-func (l *Logger) LogAuth(r *http.Request, loginStatus bool) {
+func (l *Logger) LogAuth(r *http.Request, loginStatus bool) error {
 	username, _ := mv(r, "username", true)
 	timestamp := time.Now().Unix()
-	log.Println("Logger log (timestamp, username, login succeed)", timestamp, username, loginStatus)
+
+	//Get the current month as the table name, create table if not exists
+	current := time.Now().UTC()
+	tableName := current.Format("Jan-2006")
+
+	//Create table if not exists
+	l.database.NewTable(tableName)
+
+	//Split the remote address into ipaddr and port
+	remoteAddrInfo := strings.Split(r.RemoteAddr, ":")
+	port := -1
+	if len(remoteAddrInfo) > 1 {
+		port, _ = strconv.Atoi(remoteAddrInfo[1])
+	}
+
+	//Create the entry log struct
+	thisRecord := LoginRecord{
+		Timestamp:      timestamp,
+		TargetUsername: username,
+		LoginSucceed:   loginStatus,
+		IpAddr:         remoteAddrInfo[0],
+		Port:           port,
+	}
+	//Write the log to it
+	entryKey := strconv.Itoa(int(time.Now().UnixNano()))
+	err := l.database.Write(tableName, entryKey, thisRecord)
+	if err != nil {
+		log.Println("*ERROR* Failed to write authentication log. Is the storage fulled?")
+		log.Println(err.Error())
+		return err
+	}
+
+	return nil
+}
+
+//Close the database when system shutdown
+func (l *Logger) Close() {
+	l.database.Close()
+}
+
+//List the total number of months recorded in the database
+func (l *Logger) ListSummary() []string {
+	tableNames := []string{}
+	l.database.Tables.Range(func(tableName, _ interface{}) bool {
+		tableNames = append(tableNames, tableName.(string))
+		return true
+	})
+
+	return tableNames
+}
+
+func (l *Logger) ListRecords(key string) ([]LoginRecord, error) {
+	results := []LoginRecord{}
+	if l.database.TableExists(key) {
+		//Read all record from the database to login records
+		entries, err := l.database.ListTable(key)
+		if err != nil {
+			return results, err
+		}
+
+		for _, keypairs := range entries {
+			record := LoginRecord{}
+			json.Unmarshal(keypairs[1], &record)
+			results = append(results, record)
+		}
+
+		return results, nil
+	} else {
+		return results, errors.New("Table not exists")
+	}
+}
+
+//Extract the address information from the request object, the first one is the remote address from the last hop,
+//and the 2nd one is the source address filled in by the client (not accurate)
+func getIpAddressFromRequest(r *http.Request) (string, []string) {
+	lastHopAddress := r.RemoteAddr
+	possibleSourceAddress := []string{}
+	rawHeader := r.Header.Get("X-Forwarded-For")
+	possibleSourceAddress = strings.Split(rawHeader, ", ")
+
+	return lastHopAddress, possibleSourceAddress
 }

+ 37 - 0
mod/auth/authlogger/handlers.go

@@ -0,0 +1,37 @@
+package authlogger
+
+import (
+	"encoding/json"
+	"net/http"
+)
+
+//Handle of listing of the logger index (months)
+func (l *Logger) HandleIndexListing(w http.ResponseWriter, r *http.Request) {
+	indexes := l.ListSummary()
+	js, err := json.Marshal(indexes)
+	if err != nil {
+		sendErrorResponse(w, err.Error())
+		return
+	}
+
+	sendJSONResponse(w, string(js))
+}
+
+//Handle of the listing of a given index (month)
+func (l *Logger) HandleTableListing(w http.ResponseWriter, r *http.Request) {
+	//Get the record name request for listing
+	month, err := mv(r, "record", true)
+	if err != nil {
+		sendErrorResponse(w, err.Error())
+		return
+	}
+
+	records, err := l.ListRecords(month)
+	if err != nil {
+		sendErrorResponse(w, err.Error())
+		return
+	}
+
+	js, _ := json.Marshal(records)
+	sendJSONResponse(w, string(js))
+}

+ 4 - 1
mod/database/database.go

@@ -197,7 +197,10 @@ func (d *Database) Delete(tableName string, key string) error {
 	//List table example usage
 	//Assume the value is stored as a struct named "groupstruct"
 
-	entries := sysdb.ListTable("test")
+	entries, err := sysdb.ListTable("test")
+	if err != nil {
+		panic(err)
+	}
 	for _, keypairs := range entries{
 		log.Println(string(keypairs[0]))
 		group := new(groupstruct)

+ 0 - 0
system/auth/authlog.db.lock