mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-03-15 03:02:08 +00:00
* wip * fix: add extauthz to friendly error messages * refactor: better module handling per proxy * fix: get envoy host from the gin request * tests: rework tests for proxy controller * fix: review comments
303 lines
8.2 KiB
Go
303 lines
8.2 KiB
Go
package controller_test
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/steveiliop56/tinyauth/internal/bootstrap"
|
|
"github.com/steveiliop56/tinyauth/internal/config"
|
|
"github.com/steveiliop56/tinyauth/internal/controller"
|
|
"github.com/steveiliop56/tinyauth/internal/repository"
|
|
"github.com/steveiliop56/tinyauth/internal/service"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
var loggedInCtx = config.UserContext{
|
|
Username: "test",
|
|
Name: "Test",
|
|
Email: "test@example.com",
|
|
IsLoggedIn: true,
|
|
Provider: "local",
|
|
}
|
|
|
|
func setupProxyController(t *testing.T, middlewares []gin.HandlerFunc) (*gin.Engine, *httptest.ResponseRecorder) {
|
|
// Setup
|
|
gin.SetMode(gin.TestMode)
|
|
router := gin.Default()
|
|
|
|
if len(middlewares) > 0 {
|
|
for _, m := range middlewares {
|
|
router.Use(m)
|
|
}
|
|
}
|
|
|
|
group := router.Group("/api")
|
|
recorder := httptest.NewRecorder()
|
|
|
|
// Mock app
|
|
app := bootstrap.NewBootstrapApp(config.Config{})
|
|
|
|
// Database
|
|
db, err := app.SetupDatabase(":memory:")
|
|
|
|
assert.NilError(t, err)
|
|
|
|
// Queries
|
|
queries := repository.New(db)
|
|
|
|
// Docker
|
|
dockerService := service.NewDockerService()
|
|
|
|
assert.NilError(t, dockerService.Init())
|
|
|
|
// Access controls
|
|
accessControlsService := service.NewAccessControlsService(dockerService, map[string]config.App{
|
|
"whoami": {
|
|
Path: config.AppPath{
|
|
Allow: "/allow",
|
|
},
|
|
},
|
|
})
|
|
|
|
assert.NilError(t, accessControlsService.Init())
|
|
|
|
// Auth service
|
|
authService := service.NewAuthService(service.AuthServiceConfig{
|
|
Users: []config.User{
|
|
{
|
|
Username: "testuser",
|
|
Password: "$2a$10$ne6z693sTgzT3ePoQ05PgOecUHnBjM7sSNj6M.l5CLUP.f6NyCnt.", // test
|
|
},
|
|
{
|
|
Username: "totpuser",
|
|
Password: "$2a$10$ne6z693sTgzT3ePoQ05PgOecUHnBjM7sSNj6M.l5CLUP.f6NyCnt.",
|
|
TotpSecret: "foo",
|
|
},
|
|
},
|
|
OauthWhitelist: []string{},
|
|
SessionExpiry: 3600,
|
|
SessionMaxLifetime: 0,
|
|
SecureCookie: false,
|
|
CookieDomain: "localhost",
|
|
LoginTimeout: 300,
|
|
LoginMaxRetries: 3,
|
|
SessionCookieName: "tinyauth-session",
|
|
}, dockerService, nil, queries)
|
|
|
|
// Controller
|
|
ctrl := controller.NewProxyController(controller.ProxyControllerConfig{
|
|
AppURL: "http://tinyauth.example.com",
|
|
}, group, accessControlsService, authService)
|
|
ctrl.SetupRoutes()
|
|
|
|
return router, recorder
|
|
}
|
|
|
|
// TODO: Needs tests for context middleware
|
|
|
|
func TestProxyHandler(t *testing.T) {
|
|
// Test logged out user traefik/caddy (forward_auth)
|
|
router, recorder := setupProxyController(t, nil)
|
|
|
|
req, err := http.NewRequest("GET", "/api/auth/traefik", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Header.Set("x-forwarded-host", "whoami.example.com")
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
req.Header.Set("x-forwarded-uri", "/")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusUnauthorized)
|
|
|
|
// Test logged out user nginx (auth_request)
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/nginx", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Header.Set("x-original-url", "http://whoami.example.com/")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusUnauthorized)
|
|
|
|
// Test logged out user envoy (ext_authz)
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/envoy?path=/", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Host = "whoami.example.com"
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusUnauthorized)
|
|
|
|
// Test logged in user traefik/caddy (forward_auth)
|
|
router, recorder = setupProxyController(t, []gin.HandlerFunc{
|
|
func(c *gin.Context) {
|
|
c.Set("context", &loggedInCtx)
|
|
c.Next()
|
|
},
|
|
})
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/traefik", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Header.Set("x-forwarded-host", "whoami.example.com")
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
req.Header.Set("x-forwarded-uri", "/")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusOK)
|
|
|
|
// Test logged in user nginx (auth_request)
|
|
router, recorder = setupProxyController(t, []gin.HandlerFunc{
|
|
func(c *gin.Context) {
|
|
c.Set("context", &loggedInCtx)
|
|
c.Next()
|
|
},
|
|
})
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/nginx", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Header.Set("x-original-url", "http://whoami.example.com/")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusOK)
|
|
|
|
// Test logged in user envoy (ext_authz)
|
|
router, recorder = setupProxyController(t, []gin.HandlerFunc{
|
|
func(c *gin.Context) {
|
|
c.Set("context", &loggedInCtx)
|
|
c.Next()
|
|
},
|
|
})
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/envoy?path=/", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Host = "whoami.example.com"
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusOK)
|
|
|
|
// Test ACL allow caddy/traefik (forward_auth)
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/traefik", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Header.Set("x-forwarded-host", "whoami.example.com")
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
req.Header.Set("x-forwarded-uri", "/allow")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusOK)
|
|
|
|
// Test ACL allow nginx
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/nginx", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Header.Set("x-original-url", "http://whoami.example.com/allow")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusOK)
|
|
|
|
// Test ACL allow envoy
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/envoy?path=/allow", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Host = "whoami.example.com"
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusOK)
|
|
|
|
// Test traefik/caddy (forward_auth) without required headers
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/traefik", nil)
|
|
assert.NilError(t, err)
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusBadRequest)
|
|
|
|
// Test nginx (forward_auth) without required headers
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/nginx", nil)
|
|
assert.NilError(t, err)
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusBadRequest)
|
|
|
|
// Test envoy (forward_auth) without required headers
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/envoy", nil)
|
|
assert.NilError(t, err)
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusBadRequest)
|
|
|
|
// Test nginx (auth_request) with forward_auth fallback with ACLs
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/nginx", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Header.Set("x-forwarded-host", "whoami.example.com")
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
req.Header.Set("x-forwarded-uri", "/allow")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusOK)
|
|
|
|
// Test envoy (ext_authz) with forward_auth fallback with ACLs
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/envoy", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Header.Set("x-forwarded-host", "whoami.example.com")
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
req.Header.Set("x-forwarded-uri", "/allow")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusOK)
|
|
|
|
// Test envoy (ext_authz) with empty path
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/envoy", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Host = "whoami.example.com"
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusUnauthorized)
|
|
|
|
// Ensure forward_auth fallback works with path (should ignore)
|
|
router, recorder = setupProxyController(t, nil)
|
|
|
|
req, err = http.NewRequest("GET", "/api/auth/traefik?path=/allow", nil)
|
|
assert.NilError(t, err)
|
|
|
|
req.Header.Set("x-forwarded-proto", "http")
|
|
req.Header.Set("x-forwarded-host", "whoami.example.com")
|
|
req.Header.Set("x-forwarded-uri", "/allow")
|
|
|
|
router.ServeHTTP(recorder, req)
|
|
assert.Equal(t, recorder.Code, http.StatusOK)
|
|
}
|