FS: Fix oauth login error not displaying
This commit is contained in:
@@ -187,6 +187,112 @@ func TestFrontendService_Middleware(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestFrontendService_LoginErrorCookie(t *testing.T) {
|
||||
publicDir := setupTestWebAssets(t)
|
||||
cfg := &setting.Cfg{
|
||||
HTTPPort: "3000",
|
||||
StaticRootPath: publicDir,
|
||||
BuildVersion: "10.3.0",
|
||||
OAuthLoginErrorMessage: "oauth.login.error",
|
||||
CookieSecure: false,
|
||||
CookieSameSiteDisabled: false,
|
||||
CookieSameSiteMode: http.SameSiteLaxMode,
|
||||
}
|
||||
|
||||
t.Run("should detect login_error cookie and set generic error message", func(t *testing.T) {
|
||||
service := createTestService(t, cfg)
|
||||
|
||||
mux := web.New()
|
||||
service.addMiddlewares(mux)
|
||||
service.registerRoutes(mux)
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
// Set the login_error cookie (with some encrypted-looking value)
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: "login_error",
|
||||
Value: "abc123encryptedvalue",
|
||||
})
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
mux.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
body := recorder.Body.String()
|
||||
|
||||
// Check that the generic error message is in the response
|
||||
assert.Contains(t, body, "loginError", "Should contain loginError when cookie is present")
|
||||
assert.Contains(t, body, "oauth.login.error", "Should contain the generic OAuth error message")
|
||||
|
||||
// Check that the cookie was deleted (MaxAge=-1)
|
||||
cookies := recorder.Result().Cookies()
|
||||
var foundDeletedCookie bool
|
||||
for _, cookie := range cookies {
|
||||
if cookie.Name == "login_error" {
|
||||
assert.Equal(t, -1, cookie.MaxAge, "Cookie should be deleted (MaxAge=-1)")
|
||||
assert.Equal(t, "", cookie.Value, "Cookie value should be empty")
|
||||
foundDeletedCookie = true
|
||||
break
|
||||
}
|
||||
}
|
||||
assert.True(t, foundDeletedCookie, "Should have set a cookie deletion header")
|
||||
})
|
||||
|
||||
t.Run("should not set error when login_error cookie is absent", func(t *testing.T) {
|
||||
service := createTestService(t, cfg)
|
||||
|
||||
mux := web.New()
|
||||
service.addMiddlewares(mux)
|
||||
service.registerRoutes(mux)
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
// No login_error cookie
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
mux.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
body := recorder.Body.String()
|
||||
|
||||
// The page should render but without the login error
|
||||
assert.Contains(t, body, "window.grafanaBootData")
|
||||
// Check that loginError is not set (or is empty/omitted in JSON)
|
||||
// Since it's omitempty, it shouldn't appear at all
|
||||
assert.NotContains(t, body, "loginError", "Should not contain loginError when cookie is absent")
|
||||
})
|
||||
|
||||
t.Run("should handle custom OAuth error message from config", func(t *testing.T) {
|
||||
customCfg := &setting.Cfg{
|
||||
HTTPPort: "3000",
|
||||
StaticRootPath: publicDir,
|
||||
BuildVersion: "10.3.0",
|
||||
OAuthLoginErrorMessage: "Oh no a boo-boo happened!",
|
||||
CookieSecure: false,
|
||||
CookieSameSiteDisabled: false,
|
||||
CookieSameSiteMode: http.SameSiteLaxMode,
|
||||
}
|
||||
service := createTestService(t, customCfg)
|
||||
|
||||
mux := web.New()
|
||||
service.addMiddlewares(mux)
|
||||
service.registerRoutes(mux)
|
||||
|
||||
req := httptest.NewRequest("GET", "/", nil)
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: "login_error",
|
||||
Value: "abc123encryptedvalue",
|
||||
})
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
mux.ServeHTTP(recorder, req)
|
||||
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
body := recorder.Body.String()
|
||||
|
||||
// Check that the custom error message is used
|
||||
assert.Contains(t, body, "Oh no a boo-boo happened!", "Should use custom OAuth error message from config")
|
||||
})
|
||||
}
|
||||
|
||||
func TestFrontendService_IndexHooks(t *testing.T) {
|
||||
publicDir := setupTestWebAssets(t)
|
||||
cfg := &setting.Cfg{
|
||||
|
||||
@@ -47,4 +47,6 @@ type FSFrontendSettings struct {
|
||||
CSPReportOnlyEnabled bool `json:"cspReportOnlyEnabled,omitempty"`
|
||||
Http2Enabled bool `json:"http2Enabled,omitempty"`
|
||||
ReportingStaticContext map[string]string `json:"reportingStaticContext,omitempty"`
|
||||
|
||||
LoginError string `json:"loginError,omitempty"`
|
||||
}
|
||||
|
||||
@@ -148,6 +148,30 @@ func (p *IndexProvider) HandleRequest(writer http.ResponseWriter, request *http.
|
||||
data.Nonce = nonce
|
||||
data.PublicDashboardAccessToken = reqCtx.PublicDashboardAccessToken
|
||||
|
||||
// TODO -- reevaluate with mt authnz
|
||||
// Check for login_error cookie and set a generic error message.
|
||||
// The backend sets an encrypted cookie on oauth login failures that we can't read
|
||||
// so we just show a generic error if the cookie is present.
|
||||
if cookie, err := request.Cookie("login_error"); err == nil && cookie.Value != "" {
|
||||
p.log.Info("request has login_error cookie")
|
||||
// Defaults to a translation key that the frontend will resolve to a localized message
|
||||
data.Settings.LoginError = p.data.Config.OAuthLoginErrorMessage
|
||||
|
||||
cookiePath := "/"
|
||||
if p.data.AppSubUrl != "" {
|
||||
cookiePath = p.data.AppSubUrl
|
||||
}
|
||||
http.SetCookie(writer, &http.Cookie{
|
||||
Name: "login_error",
|
||||
Value: "",
|
||||
Path: cookiePath,
|
||||
MaxAge: -1,
|
||||
HttpOnly: true,
|
||||
Secure: p.data.Config.CookieSecure,
|
||||
SameSite: p.data.Config.CookieSameSiteMode,
|
||||
})
|
||||
}
|
||||
|
||||
if data.CSPEnabled {
|
||||
data.CSPContent = middleware.ReplacePolicyVariables(p.data.CSPContent, p.data.AppSubUrl, data.Nonce)
|
||||
writer.Header().Set("Content-Security-Policy", data.CSPContent)
|
||||
|
||||
Reference in New Issue
Block a user