external auth: add example HTTP server to use as authentication hook

The server authenticate against an LDAP server.
This commit is contained in:
Nicola Murino
2020-04-26 14:48:32 +02:00
parent 0a47412e8c
commit ebd6a11f3a
20 changed files with 1535 additions and 2 deletions

View File

@@ -0,0 +1,127 @@
package logger
import (
"fmt"
"os"
"path/filepath"
"runtime"
"sync"
"github.com/rs/zerolog"
lumberjack "gopkg.in/natefinch/lumberjack.v2"
)
const (
dateFormat = "2006-01-02T15:04:05.000" // YYYY-MM-DDTHH:MM:SS.ZZZ
)
var (
logger zerolog.Logger
consoleLogger zerolog.Logger
)
// GetLogger get the configured logger instance
func GetLogger() *zerolog.Logger {
return &logger
}
// InitLogger initialize loggers
func InitLogger(logFilePath string, logMaxSize, logMaxBackups, logMaxAge int, logCompress bool, level zerolog.Level) {
zerolog.TimeFieldFormat = dateFormat
if isLogFilePathValid(logFilePath) {
logger = zerolog.New(&lumberjack.Logger{
Filename: logFilePath,
MaxSize: logMaxSize,
MaxBackups: logMaxBackups,
MaxAge: logMaxAge,
Compress: logCompress,
})
EnableConsoleLogger(level)
} else {
logger = zerolog.New(logSyncWrapper{
output: os.Stdout,
lock: new(sync.Mutex)})
consoleLogger = zerolog.Nop()
}
logger.Level(level)
}
// DisableLogger disable the main logger.
// ConsoleLogger will not be affected
func DisableLogger() {
logger = zerolog.Nop()
}
// EnableConsoleLogger enables the console logger
func EnableConsoleLogger(level zerolog.Level) {
consoleOutput := zerolog.ConsoleWriter{
Out: os.Stdout,
TimeFormat: dateFormat,
NoColor: runtime.GOOS == "windows",
}
consoleLogger = zerolog.New(consoleOutput).With().Timestamp().Logger().Level(level)
}
// Debug logs at debug level for the specified sender
func Debug(prefix, requestID string, format string, v ...interface{}) {
logger.Debug().
Timestamp().
Str("sender", prefix).
Str("request_id", requestID).
Msg(fmt.Sprintf(format, v...))
}
// Info logs at info level for the specified sender
func Info(prefix, requestID string, format string, v ...interface{}) {
logger.Info().
Timestamp().
Str("sender", prefix).
Str("request_id", requestID).
Msg(fmt.Sprintf(format, v...))
}
// Warn logs at warn level for the specified sender
func Warn(prefix, requestID string, format string, v ...interface{}) {
logger.Warn().
Timestamp().
Str("sender", prefix).
Str("request_id", requestID).
Msg(fmt.Sprintf(format, v...))
}
// Error logs at error level for the specified sender
func Error(prefix, requestID string, format string, v ...interface{}) {
logger.Error().
Timestamp().
Str("sender", prefix).
Str("request_id", requestID).
Msg(fmt.Sprintf(format, v...))
}
// DebugToConsole logs at debug level to stdout
func DebugToConsole(format string, v ...interface{}) {
consoleLogger.Debug().Msg(fmt.Sprintf(format, v...))
}
// InfoToConsole logs at info level to stdout
func InfoToConsole(format string, v ...interface{}) {
consoleLogger.Info().Msg(fmt.Sprintf(format, v...))
}
// WarnToConsole logs at info level to stdout
func WarnToConsole(format string, v ...interface{}) {
consoleLogger.Warn().Msg(fmt.Sprintf(format, v...))
}
// ErrorToConsole logs at error level to stdout
func ErrorToConsole(format string, v ...interface{}) {
consoleLogger.Error().Msg(fmt.Sprintf(format, v...))
}
func isLogFilePathValid(logFilePath string) bool {
cleanInput := filepath.Clean(logFilePath)
if cleanInput == "." || cleanInput == ".." {
return false
}
return true
}

View File

@@ -0,0 +1,73 @@
package logger
import (
"fmt"
"net/http"
"time"
"github.com/go-chi/chi/middleware"
"github.com/rs/zerolog"
)
// StructuredLogger defines a simple wrapper around zerolog logger.
// It implements chi.middleware.LogFormatter interface
type StructuredLogger struct {
Logger *zerolog.Logger
}
// StructuredLoggerEntry ...
type StructuredLoggerEntry struct {
Logger *zerolog.Logger
fields map[string]interface{}
}
// NewStructuredLogger returns a chi.middleware.RequestLogger using our StructuredLogger.
// This structured logger is called by the chi.middleware.Logger handler to log each HTTP request
func NewStructuredLogger(logger *zerolog.Logger) func(next http.Handler) http.Handler {
return middleware.RequestLogger(&StructuredLogger{logger})
}
// NewLogEntry creates a new log entry for an HTTP request
func (l *StructuredLogger) NewLogEntry(r *http.Request) middleware.LogEntry {
scheme := "http"
if r.TLS != nil {
scheme = "https"
}
fields := map[string]interface{}{
"remote_addr": r.RemoteAddr,
"proto": r.Proto,
"method": r.Method,
"user_agent": r.UserAgent(),
"uri": fmt.Sprintf("%s://%s%s", scheme, r.Host, r.RequestURI)}
reqID := middleware.GetReqID(r.Context())
if reqID != "" {
fields["request_id"] = reqID
}
return &StructuredLoggerEntry{Logger: l.Logger, fields: fields}
}
// Write logs a new entry at the end of the HTTP request
func (l *StructuredLoggerEntry) Write(status, bytes int, header http.Header, elapsed time.Duration, extra interface{}) {
l.Logger.Info().
Timestamp().
Str("sender", "httpd").
Fields(l.fields).
Int("resp_status", status).
Int("resp_size", bytes).
Int64("elapsed_ms", elapsed.Nanoseconds()/1000000).
Msg("")
}
// Panic logs panics
func (l *StructuredLoggerEntry) Panic(v interface{}, stack []byte) {
l.Logger.Error().
Timestamp().
Str("sender", "httpd").
Fields(l.fields).
Str("stack", string(stack)).
Str("panic", fmt.Sprintf("%+v", v)).
Msg("")
}

View File

@@ -0,0 +1,17 @@
package logger
import (
"os"
"sync"
)
type logSyncWrapper struct {
lock *sync.Mutex
output *os.File
}
func (l logSyncWrapper) Write(b []byte) (n int, err error) {
l.lock.Lock()
defer l.lock.Unlock()
return l.output.Write(b)
}