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