diff options
Diffstat (limited to 'lib/api/api_auth.go')
-rw-r--r-- | lib/api/api_auth.go | 96 |
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) } |