security: Try to set cookies secure, with force override option
This commit is contained in:
parent
4744169aa0
commit
03da2ff2e7
|
|
@ -158,7 +158,12 @@ func (api *oliveTinAPI) PasswordHash(ctx ctx.Context, req *connect.Request[apiv1
|
||||||
return connect.NewResponse(ret), nil
|
return connect.NewResponse(ret), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *oliveTinAPI) applyLocalLoginResult(req *apiv1.LocalUserLoginRequest, response *connect.Response[apiv1.LocalUserLoginResponse], match bool) {
|
func (api *oliveTinAPI) cookieSecure(header http.Header) bool {
|
||||||
|
useTLS := header.Get("X-Forwarded-Proto") == "https"
|
||||||
|
return useTLS || api.cfg.Security.ForceSecureCookies
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *oliveTinAPI) applyLocalLoginResult(req *apiv1.LocalUserLoginRequest, response *connect.Response[apiv1.LocalUserLoginResponse], match bool, secure bool) {
|
||||||
if match {
|
if match {
|
||||||
user := api.cfg.FindUserByUsername(req.Username)
|
user := api.cfg.FindUserByUsername(req.Username)
|
||||||
if user != nil {
|
if user != nil {
|
||||||
|
|
@ -171,6 +176,8 @@ func (api *oliveTinAPI) applyLocalLoginResult(req *apiv1.LocalUserLoginRequest,
|
||||||
MaxAge: 31556952,
|
MaxAge: 31556952,
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
|
Secure: secure,
|
||||||
|
SameSite: http.SameSiteLaxMode,
|
||||||
}
|
}
|
||||||
response.Header().Set("Set-Cookie", cookie.String())
|
response.Header().Set("Set-Cookie", cookie.String())
|
||||||
}
|
}
|
||||||
|
|
@ -192,7 +199,7 @@ func (api *oliveTinAPI) LocalUserLogin(ctx ctx.Context, req *connect.Request[api
|
||||||
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("checking password: %w", err))
|
return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("checking password: %w", err))
|
||||||
}
|
}
|
||||||
response := connect.NewResponse(&apiv1.LocalUserLoginResponse{Success: match})
|
response := connect.NewResponse(&apiv1.LocalUserLoginResponse{Success: match})
|
||||||
api.applyLocalLoginResult(req.Msg, response, match)
|
api.applyLocalLoginResult(req.Msg, response, match, api.cookieSecure(req.Header()))
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,6 +396,7 @@ func (api *oliveTinAPI) Logout(ctx ctx.Context, req *connect.Request[apiv1.Logou
|
||||||
}).Info("Logout: User logged out")
|
}).Info("Logout: User logged out")
|
||||||
|
|
||||||
response := connect.NewResponse(&apiv1.LogoutResponse{})
|
response := connect.NewResponse(&apiv1.LogoutResponse{})
|
||||||
|
secure := api.cookieSecure(req.Header())
|
||||||
|
|
||||||
// Clear the local authentication cookie by setting it to expire
|
// Clear the local authentication cookie by setting it to expire
|
||||||
localCookie := &http.Cookie{
|
localCookie := &http.Cookie{
|
||||||
|
|
@ -397,6 +405,8 @@ func (api *oliveTinAPI) Logout(ctx ctx.Context, req *connect.Request[apiv1.Logou
|
||||||
MaxAge: -1, // This tells the browser to delete the cookie
|
MaxAge: -1, // This tells the browser to delete the cookie
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
|
Secure: secure,
|
||||||
|
SameSite: http.SameSiteLaxMode,
|
||||||
}
|
}
|
||||||
response.Header().Set("Set-Cookie", localCookie.String())
|
response.Header().Set("Set-Cookie", localCookie.String())
|
||||||
|
|
||||||
|
|
@ -407,6 +417,8 @@ func (api *oliveTinAPI) Logout(ctx ctx.Context, req *connect.Request[apiv1.Logou
|
||||||
MaxAge: -1, // This tells the browser to delete the cookie
|
MaxAge: -1, // This tells the browser to delete the cookie
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
|
Secure: secure,
|
||||||
|
SameSite: http.SameSiteLaxMode,
|
||||||
}
|
}
|
||||||
response.Header().Add("Set-Cookie", oauth2Cookie.String())
|
response.Header().Add("Set-Cookie", oauth2Cookie.String())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,14 +108,20 @@ func randString(nByte int) (string, error) {
|
||||||
return base64.URLEncoding.EncodeToString(b), nil
|
return base64.URLEncoding.EncodeToString(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *OAuth2Handler) cookieSecure(r *http.Request) bool {
|
||||||
|
useTLS := r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https"
|
||||||
|
return useTLS || h.cfg.Security.ForceSecureCookies
|
||||||
|
}
|
||||||
|
|
||||||
func (h *OAuth2Handler) setOAuthCallbackCookie(w http.ResponseWriter, r *http.Request, name, value string) {
|
func (h *OAuth2Handler) setOAuthCallbackCookie(w http.ResponseWriter, r *http.Request, name, value string) {
|
||||||
cookie := &http.Cookie{
|
cookie := &http.Cookie{
|
||||||
Name: name,
|
Name: name,
|
||||||
Value: value,
|
Value: value,
|
||||||
MaxAge: 900, // 15 minutes
|
MaxAge: 900, // 15 minutes
|
||||||
Secure: r.TLS != nil,
|
Secure: h.cookieSecure(r),
|
||||||
HttpOnly: true,
|
HttpOnly: true,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
|
SameSite: http.SameSiteLaxMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
http.SetCookie(w, cookie)
|
http.SetCookie(w, cookie)
|
||||||
|
|
|
||||||
|
|
@ -107,13 +107,14 @@ type PrometheusConfig struct {
|
||||||
DefaultGoMetrics bool `koanf:"defaultGoMetrics"`
|
DefaultGoMetrics bool `koanf:"defaultGoMetrics"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecurityConfig allows users to fine tune the security related HTTP headers.
|
// SecurityConfig allows users to fine tune the security related HTTP headers and cookie options.
|
||||||
type SecurityConfig struct {
|
type SecurityConfig struct {
|
||||||
HeaderContentSecurityPolicy bool `koanf:"headerContentSecurityPolicy"`
|
HeaderContentSecurityPolicy bool `koanf:"headerContentSecurityPolicy"`
|
||||||
ContentSecurityPolicy string `koanf:"contentSecurityPolicy"`
|
ContentSecurityPolicy string `koanf:"contentSecurityPolicy"`
|
||||||
HeaderXContentTypeOptions bool `koanf:"headerXContentTypeOptions"`
|
HeaderXContentTypeOptions bool `koanf:"headerXContentTypeOptions"`
|
||||||
HeaderXFrameOptions bool `koanf:"headerXFrameOptions"`
|
HeaderXFrameOptions bool `koanf:"headerXFrameOptions"`
|
||||||
XFrameOptions string `koanf:"xFrameOptions"`
|
XFrameOptions string `koanf:"xFrameOptions"`
|
||||||
|
ForceSecureCookies bool `koanf:"forceSecureCookies"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config is the global config used through the whole app.
|
// Config is the global config used through the whole app.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue