feat: refuse instances Vantage HQ has locked under a dispute
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func TestRefuseLocked(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
prev := instanceLocked
|
||||
t.Cleanup(func() { instanceLocked = prev })
|
||||
instanceLocked = func(id string) bool { return id == "locked" }
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
if !refuseLocked(c, "locked") {
|
||||
t.Fatal("a locked instance must be refused")
|
||||
}
|
||||
if w.Code != http.StatusUnauthorized {
|
||||
t.Fatalf("status = %d, want 401", w.Code)
|
||||
}
|
||||
|
||||
w = httptest.NewRecorder()
|
||||
c, _ = gin.CreateTestContext(w)
|
||||
if refuseLocked(c, "open") {
|
||||
t.Fatal("an unlocked instance must pass")
|
||||
}
|
||||
if c.IsAborted() {
|
||||
t.Fatal("an unlocked instance must not abort")
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,20 @@ import (
|
||||
|
||||
const ctxSessionKey = "km_session"
|
||||
|
||||
// instanceLocked is a variable so tests can stub the Mongo-backed check.
|
||||
var instanceLocked = services.InstanceLocked
|
||||
|
||||
// refuseLocked answers 401 for a session or token on an instance Vantage HQ has
|
||||
// locked under a dispute. Same body as an expired session: a locked instance
|
||||
// is not announced as locked to whoever holds a credential for it.
|
||||
func refuseLocked(c *gin.Context, instanceID string) bool {
|
||||
if !instanceLocked(instanceID) {
|
||||
return false
|
||||
}
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "session expired"})
|
||||
return true
|
||||
}
|
||||
|
||||
func GetSessionFromContext(c *gin.Context) *Session {
|
||||
v, _ := c.Get(ctxSessionKey)
|
||||
sess, _ := v.(*Session)
|
||||
@@ -81,6 +95,13 @@ func Middleware() gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
// Explicit, because the host guard below cannot do this: the resolver
|
||||
// hides a locked instance, so its host resolves to nothing and that
|
||||
// guard is skipped rather than tripped.
|
||||
if refuseLocked(c, sess.InstanceID) {
|
||||
return
|
||||
}
|
||||
|
||||
c.Set(ctxSessionKey, sess)
|
||||
|
||||
// The host guard applies to both credential kinds. A token carries an
|
||||
|
||||
Reference in New Issue
Block a user