浏览代码

Added wip logger for authentication

tobychui 4 年之前
父节点
当前提交
c9cb4b9288
共有 3 个文件被更改,包括 216 次插入0 次删除
  1. 14 0
      mod/auth/auth.go
  2. 31 0
      mod/auth/authlogger/authlogger.go
  3. 171 0
      mod/auth/authlogger/common.go

+ 14 - 0
mod/auth/auth.go

@@ -33,6 +33,7 @@ import (
 
 	"github.com/gorilla/sessions"
 
+	"imuslab.com/arozos/mod/auth/authlogger"
 	db "imuslab.com/arozos/mod/database"
 )
 
@@ -52,6 +53,9 @@ type AuthAgent struct {
 	//Autologin Related
 	AllowAutoLogin  bool
 	autoLoginTokens []AutoLoginToken
+
+	//Logger
+	Logger *authlogger.Logger
 }
 
 type AuthEndpoints struct {
@@ -75,6 +79,9 @@ func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database,
 	ticker := time.NewTicker(300 * time.Second)
 	done := make(chan bool)
 
+	//Create a new logger for logging all login request
+	newLogger := authlogger.NewLogger()
+
 	//Create a new AuthAgent object
 	newAuthAgent := AuthAgent{
 		SessionName:             sessionName,
@@ -87,6 +94,7 @@ func NewAuthenticationAgent(sessionName string, key []byte, sysdb *db.Database,
 		mutex:                   &sync.Mutex{},
 		AllowAutoLogin:          false,
 		autoLoginTokens:         []AutoLoginToken{},
+		Logger:                  newLogger,
 	}
 
 	//Create a timer to listen to its token storage
@@ -132,11 +140,14 @@ func (a *AuthAgent) RegisterPublicAPIs(ep AuthEndpoints) {
 
 //Handle login request, require POST username and password
 func (a *AuthAgent) HandleLogin(w http.ResponseWriter, r *http.Request) {
+
 	//Get username from request using POST mode
 	username, err := mv(r, "username", true)
 	if err != nil {
 		//Username not defined
 		log.Println("[System Auth] Someone trying to login with username: " + username)
+		//Write to log
+		a.Logger.LogAuth(r, false)
 		sendErrorResponse(w, "Username not defined or empty.")
 		return
 	}
@@ -145,6 +156,7 @@ func (a *AuthAgent) HandleLogin(w http.ResponseWriter, r *http.Request) {
 	password, err := mv(r, "password", true)
 	if err != nil {
 		//Password not defined
+		a.Logger.LogAuth(r, false)
 		sendErrorResponse(w, "Password not defined or empty.")
 		return
 	}
@@ -165,11 +177,13 @@ func (a *AuthAgent) HandleLogin(w http.ResponseWriter, r *http.Request) {
 		a.LoginUserByRequest(w, r, username, rememberme)
 		//Print the login message to console
 		log.Println(username + " logged in.")
+		a.Logger.LogAuth(r, true)
 		sendOK(w)
 	} else {
 		//Password incorrect
 		log.Println(username + " has entered an invalid username or password")
 		sendErrorResponse(w, "Invalid username or password")
+		a.Logger.LogAuth(r, false)
 		return
 	}
 }

+ 31 - 0
mod/auth/authlogger/authlogger.go

@@ -0,0 +1,31 @@
+package authlogger
+
+import (
+	"log"
+	"net/http"
+	"time"
+)
+
+/*
+	AuthLogger
+	Author: tobychui
+
+	This module help log the login request and help the user to trace who is trying
+	to break into their system.
+
+*/
+
+type Logger struct {
+}
+
+//New Logger create a new logger object
+func NewLogger() *Logger {
+	return &Logger{}
+}
+
+//Log the current authentication to record, Require the request object and login status
+func (l *Logger) LogAuth(r *http.Request, loginStatus bool) {
+	username, _ := mv(r, "username", true)
+	timestamp := time.Now().Unix()
+	log.Println("Logger log (timestamp, username, login succeed)", timestamp, username, loginStatus)
+}

+ 171 - 0
mod/auth/authlogger/common.go

@@ -0,0 +1,171 @@
+package authlogger
+
+import (
+	"bufio"
+	"encoding/base64"
+	"errors"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"os"
+	"time"
+)
+
+/*
+	SYSTEM COMMON FUNCTIONS
+
+	This is a system function that put those we usually use function but not belongs to
+	any module / system.
+
+	E.g. fileExists / IsDir etc
+
+*/
+
+/*
+	Basic Response Functions
+
+	Send response with ease
+*/
+//Send text response with given w and message as string
+func sendTextResponse(w http.ResponseWriter, msg string) {
+	w.Write([]byte(msg))
+}
+
+//Send JSON response, with an extra json header
+func sendJSONResponse(w http.ResponseWriter, json string) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte(json))
+}
+
+func sendErrorResponse(w http.ResponseWriter, errMsg string) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte("{\"error\":\"" + errMsg + "\"}"))
+}
+
+func sendOK(w http.ResponseWriter) {
+	w.Header().Set("Content-Type", "application/json")
+	w.Write([]byte("\"OK\""))
+}
+
+/*
+	The paramter move function (mv)
+
+	You can find similar things in the PHP version of ArOZ Online Beta. You need to pass in
+	r (HTTP Request Object)
+	getParamter (string, aka $_GET['This string])
+
+	Will return
+	Paramter string (if any)
+	Error (if error)
+
+*/
+func mv(r *http.Request, getParamter string, postMode bool) (string, error) {
+	if postMode == false {
+		//Access the paramter via GET
+		keys, ok := r.URL.Query()[getParamter]
+
+		if !ok || len(keys[0]) < 1 {
+			//log.Println("Url Param " + getParamter +" is missing")
+			return "", errors.New("GET paramter " + getParamter + " not found or it is empty")
+		}
+
+		// Query()["key"] will return an array of items,
+		// we only want the single item.
+		key := keys[0]
+		return string(key), nil
+	} else {
+		//Access the parameter via POST
+		r.ParseForm()
+		x := r.Form.Get(getParamter)
+		if len(x) == 0 || x == "" {
+			return "", errors.New("POST paramter " + getParamter + " not found or it is empty")
+		}
+		return string(x), nil
+	}
+
+}
+
+func stringInSlice(a string, list []string) bool {
+	for _, b := range list {
+		if b == a {
+			return true
+		}
+	}
+	return false
+}
+
+func fileExists(filename string) bool {
+	_, err := os.Stat(filename)
+	if os.IsNotExist(err) {
+		return false
+	}
+	return true
+}
+
+func isDir(path string) bool {
+	if fileExists(path) == false {
+		return false
+	}
+	fi, err := os.Stat(path)
+	if err != nil {
+		log.Fatal(err)
+		return false
+	}
+	switch mode := fi.Mode(); {
+	case mode.IsDir():
+		return true
+	case mode.IsRegular():
+		return false
+	}
+	return false
+}
+
+func inArray(arr []string, str string) bool {
+	for _, a := range arr {
+		if a == str {
+			return true
+		}
+	}
+	return false
+}
+
+func timeToString(targetTime time.Time) string {
+	return targetTime.Format("2006-01-02 15:04:05")
+}
+
+func loadImageAsBase64(filepath string) (string, error) {
+	if !fileExists(filepath) {
+		return "", errors.New("File not exists")
+	}
+	f, _ := os.Open(filepath)
+	reader := bufio.NewReader(f)
+	content, _ := ioutil.ReadAll(reader)
+	encoded := base64.StdEncoding.EncodeToString(content)
+	return string(encoded), nil
+}
+
+func pushToSliceIfNotExist(slice []string, newItem string) []string {
+	itemExists := false
+	for _, item := range slice {
+		if item == newItem {
+			itemExists = true
+		}
+	}
+
+	if !itemExists {
+		slice = append(slice, newItem)
+	}
+
+	return slice
+}
+
+func removeFromSliceIfExists(slice []string, target string) []string {
+	newSlice := []string{}
+	for _, item := range slice {
+		if item != target {
+			newSlice = append(newSlice, item)
+		}
+	}
+
+	return newSlice
+}