(rc requestContext)
| 195 | } |
| 196 | |
| 197 | func (s *Server) isAuthenticated(rc requestContext) bool { |
| 198 | authn := rc.srv.getAuthenticator() |
| 199 | if authn == nil { |
| 200 | return true |
| 201 | } |
| 202 | |
| 203 | username, password, ok := rc.req.BasicAuth() |
| 204 | if !ok { |
| 205 | rc.w.Header().Set("WWW-Authenticate", `Basic realm="Kopia"`) |
| 206 | http.Error(rc.w, "Missing credentials.\n", http.StatusUnauthorized) |
| 207 | |
| 208 | return false |
| 209 | } |
| 210 | |
| 211 | if c, err := rc.req.Cookie(kopiaAuthCookie); err == nil && c != nil { |
| 212 | if rc.srv.isAuthCookieValid(username, c.Value) { |
| 213 | // found a short-term JWT cookie that matches given username, trust it. |
| 214 | // this avoids potentially expensive password hashing inside the authenticator. |
| 215 | return true |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | if !authn.IsValid(rc.req.Context(), rc.rep, username, password) { |
| 220 | rc.w.Header().Set("WWW-Authenticate", `Basic realm="Kopia"`) |
| 221 | http.Error(rc.w, "Access denied.\n", http.StatusUnauthorized) |
| 222 | |
| 223 | // Log failed authentication attempt |
| 224 | userLog(rc.req.Context()).Warnf("failed login attempt by client %s for user %s", rc.req.RemoteAddr, username) |
| 225 | |
| 226 | return false |
| 227 | } |
| 228 | |
| 229 | now := clock.Now() |
| 230 | |
| 231 | ac, err := rc.srv.generateShortTermAuthCookie(username, now) |
| 232 | if err != nil { |
| 233 | userLog(rc.req.Context()).Errorf("unable to generate short-term auth cookie: %v", err) |
| 234 | } else { |
| 235 | http.SetCookie(rc.w, &http.Cookie{ |
| 236 | Name: kopiaAuthCookie, |
| 237 | Value: ac, |
| 238 | Expires: now.Add(kopiaAuthCookieTTL), |
| 239 | Path: "/", |
| 240 | }) |
| 241 | |
| 242 | if s.options.LogRequests { |
| 243 | // Log successful authentication |
| 244 | userLog(rc.req.Context()).Infof("successful login by client %s for user %s", rc.req.RemoteAddr, username) |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | return true |
| 249 | } |
| 250 | |
| 251 | func (s *Server) isAuthCookieValid(username, cookieValue string) bool { |
| 252 | tok, err := jwt.ParseWithClaims(cookieValue, &jwt.RegisteredClaims{}, func(_ *jwt.Token) (any, error) { |
no test coverage detected