mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-06 23:56:37 +08:00
fix(cordis): fail-closed auth guards for user/message_gateway/admin (#1)
* autoresearch iter 23: fail-closed auth guarding for user/message_gateway Both plugins resolve contracts.AuthService in Apply to build their route middleware, but declared only DBService in Inject(). The kernel gates a plugin's Apply solely on declared deps, and cmd/app.go registers user before auth, so user mounted first, core.Inject failed, and loginMW silently degraded to a pass-through closure — leaving /api/v1/user change-password, profile and access-tokens unguarded. message_gateway was saved only by its later list position. Declare AuthService in Inject() for both, and pin the property with a reconcile-level test that mirrors production registration order and asserts the real auth middleware reaches the route table. * autoresearch iter 24: make auth middleware fallbacks fail closed user, message_gateway and admin each fell back to a c.Next() closure when contracts.AuthService could not be resolved, so a route would be served as if authenticated. For admin this is reachable at runtime: OnDispose calls service.ResetServices(), which nils the global the per-request guard reads, so requests still in flight during dispose bypass authorization entirely. Add ginutil.AuthUnavailable() and bind every fallback to it, with a test that drives each plugin's registered guard without an auth service present and asserts the request is aborted rather than passed through. * chore(autoresearch): log iter 23 (fail-open auth ordering, proven) * autoresearch iter 24 follow-up: let staticcheck infer the auth guard type * docs(autoresearch): log iters 24-25 and lessons 9-11 (declared-dep bug class, gate discipline)
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"Wavelet/core"
|
||||
"Wavelet/core/contracts"
|
||||
"Wavelet/core/extpoints"
|
||||
"Wavelet/pkg/ginutil"
|
||||
"context"
|
||||
"embed"
|
||||
"reflect"
|
||||
@@ -56,6 +57,10 @@ func (p *Plugin) Name() string {
|
||||
func (p *Plugin) Inject() []reflect.Type {
|
||||
return []reflect.Type{
|
||||
reflect.TypeFor[contracts.DBService](),
|
||||
// Apply resolves AuthService to build the route auth middleware. The
|
||||
// kernel only gates Apply on declared deps, so leaving this out lets
|
||||
// user mount before auth and fall back to a pass-through middleware.
|
||||
reflect.TypeFor[contracts.AuthService](),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,8 +90,9 @@ func (p *Plugin) Apply(ctx *core.Context) error {
|
||||
})
|
||||
|
||||
// 0.1 Resolve auth service for middleware (via IoC, not direct import)
|
||||
var loginMW gin.HandlerFunc = func(c *gin.Context) { c.Next() }
|
||||
var noTokenMW gin.HandlerFunc = func(c *gin.Context) { c.Next() }
|
||||
denyAuth := ginutil.AuthUnavailable()
|
||||
loginMW := denyAuth
|
||||
noTokenMW := denyAuth
|
||||
if authSvc, err := core.Inject[contracts.AuthService](ctx); err == nil && authSvc != nil {
|
||||
if mw, ok := authSvc.RequireAuthMiddleware().(gin.HandlerFunc); ok {
|
||||
loginMW = mw
|
||||
|
||||
Reference in New Issue
Block a user