m→manager, wg→waitGroup, w→recorder, da→digestAuth, nc→nonceCount, tt→testCase, tc→testCase, et→eventType, bt→bundleType, mu→mutex, c→testCase, h→hash, p→point, s→statEntry across all test files. Co-Authored-By: Charon <charon@lethean.io>
645 lines
18 KiB
Go
645 lines
18 KiB
Go
package mining
|
|
|
|
import (
|
|
"crypto/md5"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"fmt"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
)
|
|
|
|
func init() {
|
|
gin.SetMode(gin.TestMode)
|
|
}
|
|
|
|
// TestAuth_DefaultAuthConfig_Good — authConfig := DefaultAuthConfig()
|
|
func TestAuth_DefaultAuthConfig_Good(t *testing.T) {
|
|
authConfig := DefaultAuthConfig()
|
|
|
|
if authConfig.Enabled {
|
|
t.Error("expected Enabled to be false by default")
|
|
}
|
|
if authConfig.Username != "" {
|
|
t.Error("expected Username to be empty by default")
|
|
}
|
|
if authConfig.Password != "" {
|
|
t.Error("expected Password to be empty by default")
|
|
}
|
|
if authConfig.Realm != "Mining API" {
|
|
t.Errorf("expected Realm to be 'Mining API', got %s", authConfig.Realm)
|
|
}
|
|
if authConfig.NonceExpiry != 5*time.Minute {
|
|
t.Errorf("expected NonceExpiry to be 5 minutes, got %v", authConfig.NonceExpiry)
|
|
}
|
|
}
|
|
|
|
// TestAuth_AuthConfigFromEnv_Good — authConfig := AuthConfigFromEnv() with valid credentials
|
|
func TestAuth_AuthConfigFromEnv_Good(t *testing.T) {
|
|
// Save original env
|
|
origAuth := os.Getenv("MINING_API_AUTH")
|
|
origUser := os.Getenv("MINING_API_USER")
|
|
origPass := os.Getenv("MINING_API_PASS")
|
|
origRealm := os.Getenv("MINING_API_REALM")
|
|
defer func() {
|
|
os.Setenv("MINING_API_AUTH", origAuth)
|
|
os.Setenv("MINING_API_USER", origUser)
|
|
os.Setenv("MINING_API_PASS", origPass)
|
|
os.Setenv("MINING_API_REALM", origRealm)
|
|
}()
|
|
|
|
t.Run("auth enabled with valid credentials", func(t *testing.T) {
|
|
os.Setenv("MINING_API_AUTH", "true")
|
|
os.Setenv("MINING_API_USER", "testuser")
|
|
os.Setenv("MINING_API_PASS", "testpass")
|
|
|
|
authConfig := AuthConfigFromEnv()
|
|
if !authConfig.Enabled {
|
|
t.Error("expected Enabled to be true")
|
|
}
|
|
if authConfig.Username != "testuser" {
|
|
t.Errorf("expected Username 'testuser', got %s", authConfig.Username)
|
|
}
|
|
if authConfig.Password != "testpass" {
|
|
t.Errorf("expected Password 'testpass', got %s", authConfig.Password)
|
|
}
|
|
})
|
|
|
|
t.Run("custom realm", func(t *testing.T) {
|
|
os.Setenv("MINING_API_AUTH", "")
|
|
os.Setenv("MINING_API_REALM", "Custom Realm")
|
|
|
|
authConfig := AuthConfigFromEnv()
|
|
if authConfig.Realm != "Custom Realm" {
|
|
t.Errorf("expected Realm 'Custom Realm', got %s", authConfig.Realm)
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestAuth_AuthConfigFromEnv_Bad — AuthConfigFromEnv() with missing credentials disables auth
|
|
func TestAuth_AuthConfigFromEnv_Bad(t *testing.T) {
|
|
origAuth := os.Getenv("MINING_API_AUTH")
|
|
origUser := os.Getenv("MINING_API_USER")
|
|
origPass := os.Getenv("MINING_API_PASS")
|
|
origRealm := os.Getenv("MINING_API_REALM")
|
|
defer func() {
|
|
os.Setenv("MINING_API_AUTH", origAuth)
|
|
os.Setenv("MINING_API_USER", origUser)
|
|
os.Setenv("MINING_API_PASS", origPass)
|
|
os.Setenv("MINING_API_REALM", origRealm)
|
|
}()
|
|
|
|
t.Run("auth disabled by default", func(t *testing.T) {
|
|
os.Setenv("MINING_API_AUTH", "")
|
|
authConfig := AuthConfigFromEnv()
|
|
if authConfig.Enabled {
|
|
t.Error("expected Enabled to be false when env not set")
|
|
}
|
|
})
|
|
|
|
t.Run("auth disabled if credentials missing", func(t *testing.T) {
|
|
os.Setenv("MINING_API_AUTH", "true")
|
|
os.Setenv("MINING_API_USER", "")
|
|
os.Setenv("MINING_API_PASS", "")
|
|
|
|
authConfig := AuthConfigFromEnv()
|
|
if authConfig.Enabled {
|
|
t.Error("expected Enabled to be false when credentials missing")
|
|
}
|
|
})
|
|
}
|
|
|
|
// TestAuth_NewDigestAuth_Good — digestAuth := NewDigestAuth(authConfig); defer digestAuth.Stop()
|
|
func TestAuth_NewDigestAuth_Good(t *testing.T) {
|
|
authConfig := AuthConfig{
|
|
Enabled: true,
|
|
Username: "user",
|
|
Password: "pass",
|
|
Realm: "Test",
|
|
NonceExpiry: time.Second,
|
|
}
|
|
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
if digestAuth == nil {
|
|
t.Fatal("expected non-nil DigestAuth")
|
|
}
|
|
|
|
// Cleanup
|
|
digestAuth.Stop()
|
|
}
|
|
|
|
// TestAuth_DigestAuthStop_Ugly — digestAuth.Stop() is safe to call multiple times
|
|
func TestAuth_DigestAuthStop_Ugly(t *testing.T) {
|
|
authConfig := DefaultAuthConfig()
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
|
|
// Should not panic when called multiple times
|
|
digestAuth.Stop()
|
|
digestAuth.Stop()
|
|
digestAuth.Stop()
|
|
}
|
|
|
|
// TestAuth_Middleware_Good — router.Use(digestAuth.Middleware()) passes requests when auth disabled
|
|
func TestAuth_Middleware_Good(t *testing.T) {
|
|
authConfig := AuthConfig{Enabled: false}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
router := gin.New()
|
|
router.Use(digestAuth.Middleware())
|
|
router.GET("/test", func(c *gin.Context) {
|
|
c.String(http.StatusOK, "success")
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", "/test", nil)
|
|
recorder := httptest.NewRecorder()
|
|
router.ServeHTTP(recorder, req)
|
|
|
|
if recorder.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d", recorder.Code)
|
|
}
|
|
if recorder.Body.String() != "success" {
|
|
t.Errorf("expected body 'success', got %s", recorder.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestAuth_Middleware_Bad — unauthenticated requests receive 401 with Digest challenge
|
|
func TestAuth_Middleware_Bad(t *testing.T) {
|
|
authConfig := AuthConfig{
|
|
Enabled: true,
|
|
Username: "user",
|
|
Password: "pass",
|
|
Realm: "Test",
|
|
NonceExpiry: 5 * time.Minute,
|
|
}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
router := gin.New()
|
|
router.Use(digestAuth.Middleware())
|
|
router.GET("/test", func(c *gin.Context) {
|
|
c.String(http.StatusOK, "success")
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", "/test", nil)
|
|
recorder := httptest.NewRecorder()
|
|
router.ServeHTTP(recorder, req)
|
|
|
|
if recorder.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected status 401, got %d", recorder.Code)
|
|
}
|
|
|
|
wwwAuth := recorder.Header().Get("WWW-Authenticate")
|
|
if wwwAuth == "" {
|
|
t.Error("expected WWW-Authenticate header")
|
|
}
|
|
if !authTestContains(wwwAuth, "Digest") {
|
|
t.Error("expected Digest challenge in WWW-Authenticate")
|
|
}
|
|
if !authTestContains(wwwAuth, `realm="Test"`) {
|
|
t.Error("expected realm in WWW-Authenticate")
|
|
}
|
|
}
|
|
|
|
// TestAuth_BasicAuth_Good — req.SetBasicAuth("user", "pass") succeeds through middleware
|
|
func TestAuth_BasicAuth_Good(t *testing.T) {
|
|
authConfig := AuthConfig{
|
|
Enabled: true,
|
|
Username: "user",
|
|
Password: "pass",
|
|
Realm: "Test",
|
|
NonceExpiry: 5 * time.Minute,
|
|
}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
router := gin.New()
|
|
router.Use(digestAuth.Middleware())
|
|
router.GET("/test", func(c *gin.Context) {
|
|
c.String(http.StatusOK, "success")
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", "/test", nil)
|
|
req.SetBasicAuth("user", "pass")
|
|
recorder := httptest.NewRecorder()
|
|
router.ServeHTTP(recorder, req)
|
|
|
|
if recorder.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d", recorder.Code)
|
|
}
|
|
}
|
|
|
|
// TestAuth_BasicAuth_Bad — wrong credentials return 401
|
|
func TestAuth_BasicAuth_Bad(t *testing.T) {
|
|
authConfig := AuthConfig{
|
|
Enabled: true,
|
|
Username: "user",
|
|
Password: "pass",
|
|
Realm: "Test",
|
|
NonceExpiry: 5 * time.Minute,
|
|
}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
router := gin.New()
|
|
router.Use(digestAuth.Middleware())
|
|
router.GET("/test", func(c *gin.Context) {
|
|
c.String(http.StatusOK, "success")
|
|
})
|
|
|
|
testCases := []struct {
|
|
name string
|
|
user string
|
|
password string
|
|
}{
|
|
{"wrong user", "wronguser", "pass"},
|
|
{"wrong password", "user", "wrongpass"},
|
|
{"both wrong", "wronguser", "wrongpass"},
|
|
{"empty user", "", "pass"},
|
|
{"empty password", "user", ""},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
req := httptest.NewRequest("GET", "/test", nil)
|
|
req.SetBasicAuth(testCase.user, testCase.password)
|
|
recorder := httptest.NewRecorder()
|
|
router.ServeHTTP(recorder, req)
|
|
|
|
if recorder.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected status 401, got %d", recorder.Code)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAuth_DigestAuth_Good — full digest auth handshake succeeds
|
|
func TestAuth_DigestAuth_Good(t *testing.T) {
|
|
authConfig := AuthConfig{
|
|
Enabled: true,
|
|
Username: "testuser",
|
|
Password: "testpass",
|
|
Realm: "Test Realm",
|
|
NonceExpiry: 5 * time.Minute,
|
|
}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
router := gin.New()
|
|
router.Use(digestAuth.Middleware())
|
|
router.GET("/test", func(c *gin.Context) {
|
|
c.String(http.StatusOK, "success")
|
|
})
|
|
|
|
// First request to get nonce
|
|
req := httptest.NewRequest("GET", "/test", nil)
|
|
recorder := httptest.NewRecorder()
|
|
router.ServeHTTP(recorder, req)
|
|
|
|
if recorder.Code != http.StatusUnauthorized {
|
|
t.Fatalf("expected 401 to get nonce, got %d", recorder.Code)
|
|
}
|
|
|
|
wwwAuth := recorder.Header().Get("WWW-Authenticate")
|
|
params := parseDigestParams(wwwAuth[7:]) // Skip "Digest "
|
|
nonce := params["nonce"]
|
|
|
|
if nonce == "" {
|
|
t.Fatal("nonce not found in challenge")
|
|
}
|
|
|
|
// Build digest auth response
|
|
uri := "/test"
|
|
nonceCount := "00000001"
|
|
cnonce := "abc123"
|
|
qop := "auth"
|
|
|
|
ha1 := md5Hash(fmt.Sprintf("%s:%s:%s", authConfig.Username, authConfig.Realm, authConfig.Password))
|
|
ha2 := md5Hash(fmt.Sprintf("GET:%s", uri))
|
|
response := md5Hash(fmt.Sprintf("%s:%s:%s:%s:%s:%s", ha1, nonce, nonceCount, cnonce, qop, ha2))
|
|
|
|
authHeader := fmt.Sprintf(
|
|
`Digest username="%s", realm="%s", nonce="%s", uri="%s", qop=%s, nc=%s, cnonce="%s", response="%s"`,
|
|
authConfig.Username, authConfig.Realm, nonce, uri, qop, nonceCount, cnonce, response,
|
|
)
|
|
|
|
// Second request with digest auth
|
|
req2 := httptest.NewRequest("GET", "/test", nil)
|
|
req2.Header.Set("Authorization", authHeader)
|
|
authRecorder := httptest.NewRecorder()
|
|
router.ServeHTTP(authRecorder, req2)
|
|
|
|
if authRecorder.Code != http.StatusOK {
|
|
t.Errorf("expected status 200, got %d; body: %s", authRecorder.Code, authRecorder.Body.String())
|
|
}
|
|
}
|
|
|
|
// TestAuth_DigestAuth_Bad — invalid nonce returns 401
|
|
func TestAuth_DigestAuth_Bad(t *testing.T) {
|
|
authConfig := AuthConfig{
|
|
Enabled: true,
|
|
Username: "user",
|
|
Password: "pass",
|
|
Realm: "Test",
|
|
NonceExpiry: 5 * time.Minute,
|
|
}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
router := gin.New()
|
|
router.Use(digestAuth.Middleware())
|
|
router.GET("/test", func(c *gin.Context) {
|
|
c.String(http.StatusOK, "success")
|
|
})
|
|
|
|
// Try with a fake nonce that was never issued
|
|
authHeader := `Digest username="user", realm="Test", nonce="fakenonce123", uri="/test", qop=auth, nc=00000001, cnonce="abc", response="xxx"`
|
|
req := httptest.NewRequest("GET", "/test", nil)
|
|
req.Header.Set("Authorization", authHeader)
|
|
recorder := httptest.NewRecorder()
|
|
router.ServeHTTP(recorder, req)
|
|
|
|
if recorder.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected status 401 for invalid nonce, got %d", recorder.Code)
|
|
}
|
|
}
|
|
|
|
// TestAuth_DigestAuth_Ugly — expired nonce returns 401
|
|
func TestAuth_DigestAuth_Ugly(t *testing.T) {
|
|
authConfig := AuthConfig{
|
|
Enabled: true,
|
|
Username: "user",
|
|
Password: "pass",
|
|
Realm: "Test",
|
|
NonceExpiry: 50 * time.Millisecond, // Very short for testing
|
|
}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
router := gin.New()
|
|
router.Use(digestAuth.Middleware())
|
|
router.GET("/test", func(c *gin.Context) {
|
|
c.String(http.StatusOK, "success")
|
|
})
|
|
|
|
// Get a valid nonce
|
|
req := httptest.NewRequest("GET", "/test", nil)
|
|
recorder := httptest.NewRecorder()
|
|
router.ServeHTTP(recorder, req)
|
|
|
|
wwwAuth := recorder.Header().Get("WWW-Authenticate")
|
|
params := parseDigestParams(wwwAuth[7:])
|
|
nonce := params["nonce"]
|
|
|
|
// Wait for nonce to expire
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
// Try to use expired nonce
|
|
uri := "/test"
|
|
ha1 := md5Hash(fmt.Sprintf("%s:%s:%s", authConfig.Username, authConfig.Realm, authConfig.Password))
|
|
ha2 := md5Hash(fmt.Sprintf("GET:%s", uri))
|
|
response := md5Hash(fmt.Sprintf("%s:%s:%s", ha1, nonce, ha2))
|
|
|
|
authHeader := fmt.Sprintf(
|
|
`Digest username="%s", realm="%s", nonce="%s", uri="%s", response="%s"`,
|
|
authConfig.Username, authConfig.Realm, nonce, uri, response,
|
|
)
|
|
|
|
req2 := httptest.NewRequest("GET", "/test", nil)
|
|
req2.Header.Set("Authorization", authHeader)
|
|
w2 := httptest.NewRecorder()
|
|
router.ServeHTTP(w2, req2)
|
|
|
|
if w2.Code != http.StatusUnauthorized {
|
|
t.Errorf("expected status 401 for expired nonce, got %d", w2.Code)
|
|
}
|
|
}
|
|
|
|
// TestAuth_ParseDigestParams_Good — parseDigestParams(authHeader[7:]) returns expected map
|
|
func TestAuth_ParseDigestParams_Good(t *testing.T) {
|
|
testCases := []struct {
|
|
name string
|
|
input string
|
|
expected map[string]string
|
|
}{
|
|
{
|
|
name: "basic params",
|
|
input: `username="john", realm="test"`,
|
|
expected: map[string]string{
|
|
"username": "john",
|
|
"realm": "test",
|
|
},
|
|
},
|
|
{
|
|
name: "params with spaces",
|
|
input: ` username = "john" , realm = "test" `,
|
|
expected: map[string]string{
|
|
"username": "john",
|
|
"realm": "test",
|
|
},
|
|
},
|
|
{
|
|
name: "unquoted values",
|
|
input: `qop=auth, nc=00000001`,
|
|
expected: map[string]string{
|
|
"qop": "auth",
|
|
"nc": "00000001",
|
|
},
|
|
},
|
|
{
|
|
name: "full digest header",
|
|
input: `username="user", realm="Test", nonce="abc123", uri="/api", qop=auth, nc=00000001, cnonce="xyz", response="hash"`,
|
|
expected: map[string]string{
|
|
"username": "user",
|
|
"realm": "Test",
|
|
"nonce": "abc123",
|
|
"uri": "/api",
|
|
"qop": "auth",
|
|
"nc": "00000001",
|
|
"cnonce": "xyz",
|
|
"response": "hash",
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
result := parseDigestParams(testCase.input)
|
|
for key, expectedVal := range testCase.expected {
|
|
if result[key] != expectedVal {
|
|
t.Errorf("key %s: expected %s, got %s", key, expectedVal, result[key])
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAuth_ParseDigestParams_Ugly — parseDigestParams("") returns empty map
|
|
func TestAuth_ParseDigestParams_Ugly(t *testing.T) {
|
|
result := parseDigestParams("")
|
|
if len(result) != 0 {
|
|
t.Errorf("expected empty map for empty input, got %v", result)
|
|
}
|
|
}
|
|
|
|
// TestAuth_Md5Hash_Good — md5Hash("hello") == "5d41402abc4b2a76b9719d911017c592"
|
|
func TestAuth_Md5Hash_Good(t *testing.T) {
|
|
testCases := []struct {
|
|
input string
|
|
expected string
|
|
}{
|
|
{"hello", "5d41402abc4b2a76b9719d911017c592"},
|
|
{"user:realm:password", func() string {
|
|
hash := md5.Sum([]byte("user:realm:password"))
|
|
return hex.EncodeToString(hash[:])
|
|
}()},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
t.Run(testCase.input, func(t *testing.T) {
|
|
result := md5Hash(testCase.input)
|
|
if result != testCase.expected {
|
|
t.Errorf("expected %s, got %s", testCase.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestAuth_Md5Hash_Ugly — md5Hash("") returns known empty-string MD5
|
|
func TestAuth_Md5Hash_Ugly(t *testing.T) {
|
|
result := md5Hash("")
|
|
expected := "d41d8cd98f00b204e9800998ecf8427e"
|
|
if result != expected {
|
|
t.Errorf("expected %s, got %s", expected, result)
|
|
}
|
|
}
|
|
|
|
// TestAuth_NonceGeneration_Good — digestAuth.generateNonce() returns 32-char hex, no duplicates
|
|
func TestAuth_NonceGeneration_Good(t *testing.T) {
|
|
authConfig := DefaultAuthConfig()
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
nonces := make(map[string]bool)
|
|
for i := 0; i < 100; i++ {
|
|
nonce := digestAuth.generateNonce()
|
|
if len(nonce) != 32 { // 16 bytes = 32 hex chars
|
|
t.Errorf("expected nonce length 32, got %d", len(nonce))
|
|
}
|
|
if nonces[nonce] {
|
|
t.Error("duplicate nonce generated")
|
|
}
|
|
nonces[nonce] = true
|
|
}
|
|
}
|
|
|
|
// TestAuth_OpaqueGeneration_Good — digestAuth.generateOpaque() is stable per realm
|
|
func TestAuth_OpaqueGeneration_Good(t *testing.T) {
|
|
authConfig := AuthConfig{Realm: "TestRealm"}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
opaque1 := digestAuth.generateOpaque()
|
|
opaque2 := digestAuth.generateOpaque()
|
|
|
|
// Same realm should produce same opaque
|
|
if opaque1 != opaque2 {
|
|
t.Error("opaque should be consistent for same realm")
|
|
}
|
|
|
|
// Should be MD5 of realm
|
|
expected := md5Hash("TestRealm")
|
|
if opaque1 != expected {
|
|
t.Errorf("expected opaque %s, got %s", expected, opaque1)
|
|
}
|
|
}
|
|
|
|
// TestAuth_NonceCleanup_Ugly — expired nonces are removed by background goroutine
|
|
func TestAuth_NonceCleanup_Ugly(t *testing.T) {
|
|
authConfig := AuthConfig{
|
|
Enabled: true,
|
|
Username: "user",
|
|
Password: "pass",
|
|
Realm: "Test",
|
|
NonceExpiry: 50 * time.Millisecond,
|
|
}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
// Store a nonce
|
|
nonce := digestAuth.generateNonce()
|
|
digestAuth.nonces.Store(nonce, time.Now())
|
|
|
|
// Verify it exists
|
|
if _, ok := digestAuth.nonces.Load(nonce); !ok {
|
|
t.Error("nonce should exist immediately after storing")
|
|
}
|
|
|
|
// Wait for cleanup (2x expiry to be safe)
|
|
time.Sleep(150 * time.Millisecond)
|
|
|
|
// Verify it was cleaned up
|
|
if _, ok := digestAuth.nonces.Load(nonce); ok {
|
|
t.Error("expired nonce should have been cleaned up")
|
|
}
|
|
}
|
|
|
|
// Helper function
|
|
func authTestContains(s, substr string) bool {
|
|
for i := 0; i <= len(s)-len(substr); i++ {
|
|
if s[i:i+len(substr)] == substr {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Benchmark tests
|
|
func BenchmarkMd5Hash(b *testing.B) {
|
|
input := "user:realm:password"
|
|
for i := 0; i < b.N; i++ {
|
|
md5Hash(input)
|
|
}
|
|
}
|
|
|
|
func BenchmarkNonceGeneration(b *testing.B) {
|
|
authConfig := DefaultAuthConfig()
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
digestAuth.generateNonce()
|
|
}
|
|
}
|
|
|
|
func BenchmarkBasicAuthValidation(b *testing.B) {
|
|
authConfig := AuthConfig{
|
|
Enabled: true,
|
|
Username: "user",
|
|
Password: "pass",
|
|
Realm: "Test",
|
|
NonceExpiry: 5 * time.Minute,
|
|
}
|
|
digestAuth := NewDigestAuth(authConfig)
|
|
defer digestAuth.Stop()
|
|
|
|
router := gin.New()
|
|
router.Use(digestAuth.Middleware())
|
|
router.GET("/test", func(c *gin.Context) {
|
|
c.Status(http.StatusOK)
|
|
})
|
|
|
|
req := httptest.NewRequest("GET", "/test", nil)
|
|
req.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte("user:pass")))
|
|
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
recorder := httptest.NewRecorder()
|
|
router.ServeHTTP(recorder, req)
|
|
}
|
|
}
|