aboutsummaryrefslogtreecommitdiff
path: root/lib/api/api_auth.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/api/api_auth.go')
-rw-r--r--lib/api/api_auth.go96
1 files changed, 18 insertions, 78 deletions
diff --git a/lib/api/api_auth.go b/lib/api/api_auth.go
index b24ad7950..3be4705f3 100644
--- a/lib/api/api_auth.go
+++ b/lib/api/api_auth.go
@@ -17,7 +17,6 @@ import (
ldap "github.com/go-ldap/ldap/v3"
"github.com/syncthing/syncthing/lib/config"
- "github.com/syncthing/syncthing/lib/db"
"github.com/syncthing/syncthing/lib/events"
"github.com/syncthing/syncthing/lib/rand"
)
@@ -80,24 +79,20 @@ func isNoAuthPath(path string) bool {
}
type basicAuthAndSessionMiddleware struct {
- cookieName string
- shortID string
- guiCfg config.GUIConfiguration
- ldapCfg config.LDAPConfiguration
- next http.Handler
- evLogger events.Logger
- tokens *tokenManager
+ tokenCookieManager *tokenCookieManager
+ guiCfg config.GUIConfiguration
+ ldapCfg config.LDAPConfiguration
+ next http.Handler
+ evLogger events.Logger
}
-func newBasicAuthAndSessionMiddleware(cookieName, shortID string, guiCfg config.GUIConfiguration, ldapCfg config.LDAPConfiguration, next http.Handler, evLogger events.Logger, miscDB *db.NamespacedKV) *basicAuthAndSessionMiddleware {
+func newBasicAuthAndSessionMiddleware(tokenCookieManager *tokenCookieManager, guiCfg config.GUIConfiguration, ldapCfg config.LDAPConfiguration, next http.Handler, evLogger events.Logger) *basicAuthAndSessionMiddleware {
return &basicAuthAndSessionMiddleware{
- cookieName: cookieName,
- shortID: shortID,
- guiCfg: guiCfg,
- ldapCfg: ldapCfg,
- next: next,
- evLogger: evLogger,
- tokens: newTokenManager("sessions", miscDB, maxSessionLifetime, maxActiveSessions),
+ tokenCookieManager: tokenCookieManager,
+ guiCfg: guiCfg,
+ ldapCfg: ldapCfg,
+ next: next,
+ evLogger: evLogger,
}
}
@@ -107,22 +102,14 @@ func (m *basicAuthAndSessionMiddleware) ServeHTTP(w http.ResponseWriter, r *http
return
}
- for _, cookie := range r.Cookies() {
- // We iterate here since there may, historically, be multiple
- // cookies with the same name but different path. Any "old" ones
- // won't match an existing session and will be ignored, then
- // later removed on logout or when timing out.
- if cookie.Name == m.cookieName {
- if m.tokens.Check(cookie.Value) {
- m.next.ServeHTTP(w, r)
- return
- }
- }
+ if m.tokenCookieManager.hasValidSession(r) {
+ m.next.ServeHTTP(w, r)
+ return
}
// Fall back to Basic auth if provided
if username, ok := attemptBasicAuth(r, m.guiCfg, m.ldapCfg, m.evLogger); ok {
- m.createSession(username, false, w, r)
+ m.tokenCookieManager.createSession(username, false, w, r)
m.next.ServeHTTP(w, r)
return
}
@@ -136,7 +123,7 @@ func (m *basicAuthAndSessionMiddleware) ServeHTTP(w http.ResponseWriter, r *http
// Some browsers don't send the Authorization request header unless prompted by a 401 response.
// This enables https://user:pass@localhost style URLs to keep working.
if m.guiCfg.SendBasicAuthPrompt {
- unauthorized(w, m.shortID)
+ unauthorized(w, m.tokenCookieManager.shortID)
return
}
@@ -156,7 +143,7 @@ func (m *basicAuthAndSessionMiddleware) passwordAuthHandler(w http.ResponseWrite
}
if auth(req.Username, req.Password, m.guiCfg, m.ldapCfg) {
- m.createSession(req.Username, req.StayLoggedIn, w, r)
+ m.tokenCookieManager.createSession(req.Username, req.StayLoggedIn, w, r)
w.WriteHeader(http.StatusNoContent)
return
}
@@ -189,55 +176,8 @@ func attemptBasicAuth(r *http.Request, guiCfg config.GUIConfiguration, ldapCfg c
return "", false
}
-func (m *basicAuthAndSessionMiddleware) createSession(username string, persistent bool, w http.ResponseWriter, r *http.Request) {
- sessionid := m.tokens.New()
-
- // Best effort detection of whether the connection is HTTPS --
- // either directly to us, or as used by the client towards a reverse
- // proxy who sends us headers.
- connectionIsHTTPS := r.TLS != nil ||
- strings.ToLower(r.Header.Get("x-forwarded-proto")) == "https" ||
- strings.Contains(strings.ToLower(r.Header.Get("forwarded")), "proto=https")
- // If the connection is HTTPS, or *should* be HTTPS, set the Secure
- // bit in cookies.
- useSecureCookie := connectionIsHTTPS || m.guiCfg.UseTLS()
-
- maxAge := 0
- if persistent {
- maxAge = int(maxSessionLifetime.Seconds())
- }
- http.SetCookie(w, &http.Cookie{
- Name: m.cookieName,
- Value: sessionid,
- // In HTTP spec Max-Age <= 0 means delete immediately,
- // but in http.Cookie MaxAge = 0 means unspecified (session) and MaxAge < 0 means delete immediately
- MaxAge: maxAge,
- Secure: useSecureCookie,
- Path: "/",
- })
-
- emitLoginAttempt(true, username, r.RemoteAddr, m.evLogger)
-}
-
func (m *basicAuthAndSessionMiddleware) handleLogout(w http.ResponseWriter, r *http.Request) {
- for _, cookie := range r.Cookies() {
- // We iterate here since there may, historically, be multiple
- // cookies with the same name but different path. We drop them
- // all.
- if cookie.Name == m.cookieName {
- m.tokens.Delete(cookie.Value)
-
- // Delete the cookie
- http.SetCookie(w, &http.Cookie{
- Name: m.cookieName,
- Value: "",
- MaxAge: -1,
- Secure: cookie.Secure,
- Path: cookie.Path,
- })
- }
- }
-
+ m.tokenCookieManager.destroySession(w, r)
w.WriteHeader(http.StatusNoContent)
}