github.com/cozy/cozy-stack@v0.0.0-20240603063001-31110fa4cae1/web/middlewares/basic_auth.go (about) 1 package middlewares 2 3 import ( 4 "bytes" 5 "io" 6 "net/http" 7 "os" 8 "time" 9 10 "github.com/cozy/cozy-stack/pkg/config/config" 11 "github.com/cozy/cozy-stack/pkg/crypto" 12 "github.com/cozy/cozy-stack/pkg/logger" 13 "github.com/labstack/echo/v4" 14 ) 15 16 // BasicAuth use HTTP basic authentication to authenticate a user. The secret 17 // of the user should be stored in a file with the specified name, stored in 18 // one of the the config.Paths directories. 19 // 20 // The format of the secret is the same as our hashed passwords in database: a 21 // scrypt hash with a salt contained in the value. 22 func BasicAuth(secretFileName string) echo.MiddlewareFunc { 23 check := func(next echo.HandlerFunc, c echo.Context) error { 24 if c.QueryParam("Trace") == "true" { 25 t := time.Now() 26 defer func() { 27 elapsed := time.Since(t) 28 logger. 29 WithDomain("admin"). 30 WithNamespace("trace"). 31 Infof("Check basic auth: %v", elapsed) 32 }() 33 } 34 35 _, passphrase, ok := c.Request().BasicAuth() 36 if !ok { 37 return echo.NewHTTPError(http.StatusUnauthorized, "missing basic auth") 38 } 39 40 shadowFile, err := config.FindConfigFile(secretFileName) 41 if err != nil { 42 return echo.NewHTTPError(http.StatusInternalServerError, err) 43 } 44 45 f, err := os.Open(shadowFile) 46 if err != nil { 47 return echo.NewHTTPError(http.StatusInternalServerError, err) 48 } 49 defer f.Close() 50 51 b, err := io.ReadAll(f) 52 if err != nil { 53 return echo.NewHTTPError(http.StatusInternalServerError, err) 54 } 55 b = bytes.TrimSpace(b) 56 57 needUpdate, err := crypto.CompareHashAndPassphrase(b, []byte(passphrase)) 58 if err != nil { 59 return echo.NewHTTPError(http.StatusForbidden, "bad passphrase") 60 } 61 if needUpdate { 62 logger. 63 WithDomain("admin"). 64 Warnf("Passphrase hash from %q needs update and should be regenerated", secretFileName) 65 } 66 67 return nil 68 } 69 70 return func(next echo.HandlerFunc) echo.HandlerFunc { 71 return func(c echo.Context) error { 72 if err := check(next, c); err != nil { 73 return err 74 } 75 76 return next(c) 77 } 78 } 79 }