290 lines
8.8 KiB
Go
290 lines
8.8 KiB
Go
package racc_sysauth
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
|
|
"git.send.nrw/sendnrw/raccws/racc_session"
|
|
)
|
|
|
|
type Credential struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
// BearerToken repräsentiert ein gültiges Token
|
|
type BearerToken string
|
|
|
|
// MultiAuthMiddleware ist eine Middleware, die Basic Auth, Bearer Auth und Active Directory Auth unterstützt.
|
|
func MultiAuthMiddleware(basicCredFilePath, bearerTokenFilePath, adServer, adBaseDN, adUserDN, adPassword string) func(http.Handler) http.Handler {
|
|
basicCredentials, err := loadBasicCredentials(basicCredFilePath)
|
|
if err != nil {
|
|
fmt.Println("Error loading basic credentials:", err)
|
|
return nil
|
|
}
|
|
bearerTokens, err := loadBearerTokens(bearerTokenFilePath)
|
|
if err != nil {
|
|
fmt.Println("Error loading bearer tokens:", err)
|
|
return nil
|
|
}
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
authHeader := r.Header.Get("Authorization")
|
|
z0, _ := validateAuth(authHeader, basicCredentials, bearerTokens, adServer, adBaseDN, adUserDN, adPassword)
|
|
if !z0 {
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="Please provide credentials"`)
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|
|
|
|
// ADAuthMiddleware ist eine Middleware, die Active Directory-Authentifizierung durchführt.
|
|
/*func ADAuthMiddleware(adServer, adBaseDN, adUserDN, adPassword string) func(http.Handler) http.Handler {
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
authHeader := r.Header.Get("Authorization")
|
|
if authHeader == "" || !strings.HasPrefix(authHeader, "Basic ") {
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="Please provide credentials"`)
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
encodedCredentials := strings.TrimPrefix(authHeader, "Basic ")
|
|
decodedCredentials, err := base64.StdEncoding.DecodeString(encodedCredentials)
|
|
if err != nil {
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
parts := strings.SplitN(string(decodedCredentials), ":", 2)
|
|
if len(parts) != 2 {
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
username := parts[0]
|
|
password := parts[1]
|
|
if !validateADCredentials(adServer, adBaseDN, adUserDN, adPassword, username, password) {
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}*/
|
|
|
|
// BasicAuthMiddleware ist eine Middleware, die Basic-Authentifizierung erfordert.
|
|
func BasicAuthMiddleware(credFilePath string) func(http.Handler) http.Handler {
|
|
credentials, err := loadCredentials(credFilePath)
|
|
if err != nil {
|
|
fmt.Println("Error loading credentials:", err)
|
|
return nil
|
|
}
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
authHeader := r.Header.Get("Authorization")
|
|
z0, z1 := validateBasicAuth(authHeader, credentials)
|
|
if !z0 {
|
|
w.Header().Set("WWW-Authenticate", `Basic realm="Please provide credentials"`)
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
} else {
|
|
sessionID := r.Context().Value(racc_session.SessionKey).(string)
|
|
authMethod := racc_session.SessionItem{Key: "authmethod", Value: "Basic"}
|
|
racc_session.AddOrUpdateSessionItem(sessionID, authMethod)
|
|
authUser := racc_session.SessionItem{Key: "authuser", Value: z1}
|
|
racc_session.AddOrUpdateSessionItem(sessionID, authUser)
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|
|
|
|
// BearerAuthMiddleware ist eine Middleware, die Bearer-Authentifizierung erfordert.
|
|
func BearerAuthMiddleware(tokenFilePath string) func(http.Handler) http.Handler {
|
|
tokens, err := loadBearerTokens(tokenFilePath)
|
|
if err != nil {
|
|
fmt.Println("Error loading tokens:", err)
|
|
return nil
|
|
}
|
|
return func(next http.Handler) http.Handler {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
authHeader := r.Header.Get("Authorization")
|
|
if !validateBearerToken(authHeader, tokens) {
|
|
w.Header().Set("WWW-Authenticate", `Bearer realm="Please provide a valid token"`)
|
|
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
}
|
|
|
|
// loadBasicCredentials lädt die Anmeldeinformationen für Basic Auth aus einer JSON-Datei
|
|
func loadBasicCredentials(filePath string) ([]Credential, error) {
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
var credentials []Credential
|
|
decoder := json.NewDecoder(file)
|
|
if err := decoder.Decode(&credentials); err != nil {
|
|
return nil, err
|
|
}
|
|
return credentials, nil
|
|
}
|
|
|
|
// loadBearerTokens lädt die gültigen Bearer-Tokens aus einer JSON-Datei
|
|
func loadBearerTokens(filePath string) ([]BearerToken, error) {
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
var tokens []BearerToken
|
|
decoder := json.NewDecoder(file)
|
|
if err := decoder.Decode(&tokens); err != nil {
|
|
return nil, err
|
|
}
|
|
return tokens, nil
|
|
}
|
|
|
|
// validateAuth überprüft, ob der Authorization-Header entweder Basic Auth, Bearer Token oder Active Directory enthält
|
|
func validateAuth(authHeader string, basicCredentials []Credential, bearerTokens []BearerToken, adServer, adBaseDN, adUserDN, adPassword string) (bool, string) {
|
|
if authHeader == "" {
|
|
return false, ""
|
|
}
|
|
if strings.HasPrefix(authHeader, "Basic ") {
|
|
return validateBasicAuth(authHeader, basicCredentials)
|
|
} else if strings.HasPrefix(authHeader, "Bearer ") {
|
|
return validateBearerToken(authHeader, bearerTokens), ""
|
|
} else if strings.HasPrefix(authHeader, "AD ") {
|
|
/*return validateADAuth(authHeader, adServer, adBaseDN, adUserDN, adPassword), ""*/
|
|
}
|
|
return false, ""
|
|
}
|
|
|
|
// validateBasicAuth überprüft, ob der Authorization-Header gültige Basic-Authentifizierungsdaten enthält
|
|
func validateBasicAuth(authHeader string, credentials []Credential) (bool, string) {
|
|
encodedCredentials := strings.TrimPrefix(authHeader, "Basic ")
|
|
decodedCredentials, err := base64.StdEncoding.DecodeString(encodedCredentials)
|
|
if err != nil {
|
|
return false, ""
|
|
}
|
|
parts := strings.SplitN(string(decodedCredentials), ":", 2)
|
|
if len(parts) != 2 {
|
|
return false, ""
|
|
}
|
|
username := parts[0]
|
|
password := parts[1]
|
|
for _, cred := range credentials {
|
|
if username == cred.Username && password == cred.Password {
|
|
return true, cred.Username
|
|
}
|
|
}
|
|
return false, ""
|
|
}
|
|
|
|
// validateBearerToken überprüft, ob der Authorization-Header ein gültiges Bearer-Token enthält
|
|
func validateBearerToken(authHeader string, validTokens []BearerToken) bool {
|
|
token := strings.TrimPrefix(authHeader, "Bearer ")
|
|
for _, validToken := range validTokens {
|
|
if BearerToken(token) == validToken {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// validateADAuth überprüft die Benutzeranmeldeinformationen gegen Active Directory
|
|
/*func validateADAuth(authHeader, adServer, adBaseDN, adUserDN, adPassword string) bool {
|
|
if !strings.HasPrefix(authHeader, "AD ") {
|
|
return false
|
|
}
|
|
|
|
encodedCredentials := strings.TrimPrefix(authHeader, "AD ")
|
|
decodedCredentials, err := base64.StdEncoding.DecodeString(encodedCredentials)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
|
|
parts := strings.SplitN(string(decodedCredentials), ":", 2)
|
|
if len(parts) != 2 {
|
|
return false
|
|
}
|
|
|
|
username := parts[0]
|
|
password := parts[1]
|
|
|
|
return validateADCredentials(adServer, adBaseDN, adUserDN, adPassword, username, password)
|
|
}*/
|
|
|
|
// validateADCredentials überprüft die Benutzeranmeldeinformationen gegen Active Directory
|
|
/*func validateADCredentials(adServer, adBaseDN, adUserDN, adPassword, username, password string) bool {
|
|
l, err := ldap.DialURL(adServer)
|
|
if err != nil {
|
|
fmt.Println("Failed to connect to AD server:", err)
|
|
return false
|
|
}
|
|
defer l.Close()
|
|
|
|
err = l.Bind(adUserDN, adPassword)
|
|
if err != nil {
|
|
fmt.Println("Failed to bind to AD server:", err)
|
|
return false
|
|
}
|
|
|
|
searchRequest := ldap.NewSearchRequest(
|
|
adBaseDN,
|
|
ldap.ScopeWholeSubtree,
|
|
ldap.NeverDerefAliases,
|
|
0,
|
|
0,
|
|
false,
|
|
fmt.Sprintf("(sAMAccountName=%s)", username),
|
|
[]string{"dn"},
|
|
nil,
|
|
)
|
|
|
|
sr, err := l.Search(searchRequest)
|
|
if err != nil {
|
|
fmt.Println("Failed to search user in AD:", err)
|
|
return false
|
|
}
|
|
|
|
if len(sr.Entries) != 1 {
|
|
fmt.Println("User not found or multiple users found")
|
|
return false
|
|
}
|
|
|
|
userDN := sr.Entries[0].DN
|
|
err = l.Bind(userDN, password)
|
|
if err != nil {
|
|
fmt.Println("Failed to authenticate user:", err)
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}*/
|
|
|
|
func loadCredentials(filePath string) ([]Credential, error) {
|
|
file, err := os.Open(filePath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
var credentials []Credential
|
|
decoder := json.NewDecoder(file)
|
|
if err := decoder.Decode(&credentials); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return credentials, nil
|
|
}
|