Files
zeekayandHanzo Dev 78ab4f2f83 Declare operations on the group that serves them, and build on Go 1.27
zip's registration is a verb method on the group, so a route that is not a typed
operation says which method it answers with. The security package's own
two-method router goes with it: it existed so both the app and a sub-router could
satisfy one name, and restating a routing surface is what let the two disagree —
the methods it named no longer exist. The app spells itself as a group, which
registers at exactly the paths it did.

The toolchain and the pin move together, because below zip v1.36.50 the JSON
encoder was selected on a build tag: a repo whose go directive rises first writes
a wire that is neither the old release's nor the new one's until the pin catches
up.

metrics_test.go still does not compile, before and after: it compares a metric
registry against a gatherer from a different metrics library, so the two Gather
signatures disagree. That is its own change.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-17 09:58:39 -07:00

138 lines
4.3 KiB
Go

package security
import (
"net/http"
"net/http/httptest"
"testing"
"github.com/zap-proto/zip"
"golang.org/x/oauth2"
)
func TestConfig_ValidateAndSetDefaults(t *testing.T) {
c := &Config{
Basic: nil,
OIDC: nil,
}
if c.ValidateAndSetDefaults() {
t.Error("expected empty config to be valid")
}
}
func TestConfig_ApplySecurityMiddleware(t *testing.T) {
///////////
// BASIC //
///////////
t.Run("basic", func(t *testing.T) {
// Bcrypt
c := &Config{Basic: &BasicConfig{
Username: "john.doe",
PasswordBcryptHashBase64Encoded: "JDJhJDA4JDFoRnpPY1hnaFl1OC9ISlFsa21VS09wOGlPU1ZOTDlHZG1qeTFvb3dIckRBUnlHUmNIRWlT",
}}
app := zip.New(zip.Config{})
if err := c.ApplySecurityMiddleware(app.Group("").Group("").Group("")); err != nil {
t.Error("expected no error, got", err)
}
app.Raw(http.MethodGet, "/test", func(c *zip.Ctx) error {
return c.NoContent(200)
})
// Try to access the route without basic auth
request := httptest.NewRequest("GET", "/test", http.NoBody)
response, err := app.Fiber().Test(request)
if err != nil {
t.Fatal("expected no error, got", err)
}
if response.StatusCode != 401 {
t.Error("expected code to be 401, but was", response.StatusCode)
}
// Try again, but with basic auth
request = httptest.NewRequest("GET", "/test", http.NoBody)
request.SetBasicAuth("john.doe", "hunter2")
response, err = app.Fiber().Test(request)
if err != nil {
t.Fatal("expected no error, got", err)
}
if response.StatusCode != 200 {
t.Error("expected code to be 200, but was", response.StatusCode)
}
})
//////////
// OIDC //
//////////
t.Run("oidc", func(t *testing.T) {
c := &Config{OIDC: &OIDCConfig{
IssuerURL: "https://sso.gatus.io/",
RedirectURL: "http://localhost:80/authorization-code/callback",
Scopes: []string{"openid"},
AllowedSubjects: []string{"[email protected]"},
SessionTTL: DefaultOIDCSessionTTL,
oauth2Config: oauth2.Config{},
verifier: nil,
}}
app := zip.New(zip.Config{})
if err := c.ApplySecurityMiddleware(app.Group("").Group("").Group("")); err != nil {
t.Error("expected no error, got", err)
}
app.Raw(http.MethodGet, "/test", func(c *zip.Ctx) error {
return c.NoContent(200)
})
// Try without any session cookie
request := httptest.NewRequest("GET", "/test", http.NoBody)
response, err := app.Fiber().Test(request)
if err != nil {
t.Fatal("expected no error, got", err)
}
if response.StatusCode != 401 {
t.Error("expected code to be 401, but was", response.StatusCode)
}
// Try with a session cookie
request = httptest.NewRequest("GET", "/test", http.NoBody)
request.AddCookie(&http.Cookie{Name: "session", Value: "123"})
response, err = app.Fiber().Test(request)
if err != nil {
t.Fatal("expected no error, got", err)
}
if response.StatusCode != 401 {
t.Error("expected code to be 401, but was", response.StatusCode)
}
})
}
func TestConfig_RegisterHandlers(t *testing.T) {
c := &Config{}
app := zip.New(zip.Config{})
c.RegisterHandlers(app.Group("").Group(""))
// Try to access the OIDC handler. This should fail, because the security config doesn't have OIDC
request := httptest.NewRequest("GET", "/oidc/login", http.NoBody)
response, err := app.Fiber().Test(request)
if err != nil {
t.Fatal("expected no error, got", err)
}
if response.StatusCode != 404 {
t.Error("expected code to be 404, but was", response.StatusCode)
}
// Set an empty OIDC config. This should fail, because the IssuerURL is required.
c.OIDC = &OIDCConfig{}
if err := c.RegisterHandlers(app.Group("").Group("")); err == nil {
t.Fatal("expected an error, but got none")
}
// Set the OIDC config and try again
c.OIDC = &OIDCConfig{
IssuerURL: "https://sso.gatus.io/",
RedirectURL: "http://localhost:80/authorization-code/callback",
Scopes: []string{"openid"},
AllowedSubjects: []string{"[email protected]"},
}
if err := c.RegisterHandlers(app.Group("").Group("")); err != nil {
t.Fatal("expected no error, but got", err)
}
request = httptest.NewRequest("GET", "/oidc/login", http.NoBody)
response, err = app.Fiber().Test(request)
if err != nil {
t.Fatal("expected no error, got", err)
}
if response.StatusCode != 302 {
t.Error("expected code to be 302, but was", response.StatusCode)
}
}