feat: add Mattermost session auth for browser requests
- Add dual auth path in ServeHTTP: shared secret (daemon) OR Mattermost session (browser) - Read-only endpoints (GET /sessions, GET /health) accept either auth method - Write endpoints (POST, PUT, DELETE) still require shared secret - Browser requests authenticated via Mattermost-User-Id header (auto-injected by MM server) - Unauthenticated requests now properly rejected with 401 Fixes: Issue #5 Phase 1 - RHS Panel auth fix
This commit is contained in:
@@ -16,19 +16,40 @@ import (
|
||||
func (p *Plugin) ServeHTTP(c *plugin.Context, w http.ResponseWriter, r *http.Request) {
|
||||
path := r.URL.Path
|
||||
|
||||
// Auth middleware: validate shared secret for write operations.
|
||||
// Read-only endpoints (GET /sessions, GET /health) are accessible to any
|
||||
// authenticated Mattermost user — no shared secret required.
|
||||
// Auth middleware: two auth paths.
|
||||
// 1. Shared secret (Bearer token) — used by the daemon for write operations.
|
||||
// 2. Mattermost session (Mattermost-User-Id header) — used by browser requests.
|
||||
// The Mattermost server automatically injects this header for authenticated
|
||||
// requests routed through the plugin HTTP handler.
|
||||
//
|
||||
// Read-only endpoints (GET /sessions, GET /health) accept either auth method.
|
||||
// Write endpoints (POST, PUT, DELETE) require the shared secret.
|
||||
isReadOnly := r.Method == http.MethodGet && (path == "/api/v1/sessions" || path == "/api/v1/health")
|
||||
if !isReadOnly {
|
||||
config := p.getConfiguration()
|
||||
if config.SharedSecret != "" {
|
||||
auth := r.Header.Get("Authorization")
|
||||
expected := "Bearer " + config.SharedSecret
|
||||
if auth != expected {
|
||||
http.Error(w, `{"error": "unauthorized"}`, http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
config := p.getConfiguration()
|
||||
hasSharedSecret := false
|
||||
if config.SharedSecret != "" {
|
||||
auth := r.Header.Get("Authorization")
|
||||
expected := "Bearer " + config.SharedSecret
|
||||
hasSharedSecret = (auth == expected)
|
||||
}
|
||||
|
||||
// Check Mattermost session auth (browser requests).
|
||||
// The MM server injects Mattermost-User-Id for authenticated users.
|
||||
mmUserID := r.Header.Get("Mattermost-User-Id")
|
||||
hasMattermostSession := mmUserID != ""
|
||||
|
||||
if isReadOnly {
|
||||
// Read-only: accept either shared secret OR Mattermost session
|
||||
if !hasSharedSecret && !hasMattermostSession {
|
||||
http.Error(w, `{"error": "unauthorized: valid Mattermost session or shared secret required"}`, http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Write operations: require shared secret (daemon auth)
|
||||
if !hasSharedSecret {
|
||||
http.Error(w, `{"error": "unauthorized"}`, http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user