2018-04-10 15:20:23 +02:00
|
|
|
package app
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"net/http"
|
2018-05-19 20:58:57 +02:00
|
|
|
"golang.org/x/crypto/bcrypt"
|
|
|
|
"fmt"
|
|
|
|
log "github.com/sirupsen/logrus"
|
2018-04-10 15:20:23 +02:00
|
|
|
)
|
|
|
|
|
2018-05-19 20:58:57 +02:00
|
|
|
type contextKey int
|
|
|
|
var authInfoKey contextKey = 0
|
2018-04-10 15:20:23 +02:00
|
|
|
|
2018-05-19 20:58:57 +02:00
|
|
|
type AuthInfo struct {
|
|
|
|
Username string
|
|
|
|
Authenticated bool
|
2018-04-10 15:20:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// AuthWebdavHandler provides a ServeHTTP function with context and an application reference.
|
2018-05-19 20:58:57 +02:00
|
|
|
type authWebdavHandler interface {
|
2018-04-10 15:20:23 +02:00
|
|
|
ServeHTTP(ctx context.Context, w http.ResponseWriter, r *http.Request, a *App)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AuthWebdavHandlerFunc is a type definition which holds a context and application reference to
|
|
|
|
// match the AuthWebdavHandler interface.
|
2018-05-19 20:58:57 +02:00
|
|
|
type authWebdavHandlerFunc func(c context.Context, w http.ResponseWriter, r *http.Request, a *App)
|
2018-04-10 15:20:23 +02:00
|
|
|
|
|
|
|
// ServeHTTP simply calls the AuthWebdavHandlerFunc with given parameters
|
2018-05-19 20:58:57 +02:00
|
|
|
func (f authWebdavHandlerFunc) ServeHTTP(c context.Context, w http.ResponseWriter, r *http.Request, a *App) {
|
2018-04-10 15:20:23 +02:00
|
|
|
f(c, w, r, a)
|
|
|
|
}
|
|
|
|
|
2018-05-19 20:58:57 +02:00
|
|
|
func authorize(config *Config, username, password string) *AuthInfo {
|
|
|
|
if username == "" || password == "" {
|
|
|
|
log.WithField("user", username).Warn("Username not found or password empty")
|
|
|
|
return &AuthInfo{Authenticated:false}
|
|
|
|
}
|
|
|
|
|
|
|
|
user := config.Users[username]
|
|
|
|
if user == nil {
|
|
|
|
log.WithField("user", username).Warn("User not found")
|
|
|
|
return &AuthInfo{Authenticated:false}
|
|
|
|
}
|
|
|
|
|
|
|
|
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
|
|
|
|
if err != nil {
|
|
|
|
log.WithField("user", username).Warn("Password doesn't match")
|
|
|
|
return &AuthInfo{Authenticated:false}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &AuthInfo{Username:username, Authenticated:true}
|
|
|
|
}
|
|
|
|
|
|
|
|
// AuthFromContext returns information about the authentication state of the
|
|
|
|
// current user.
|
|
|
|
func AuthFromContext(ctx context.Context) *AuthInfo {
|
|
|
|
info, ok := ctx.Value(authInfoKey).(*AuthInfo)
|
|
|
|
if !ok {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return info
|
|
|
|
}
|
|
|
|
|
|
|
|
func handle(ctx context.Context, w http.ResponseWriter, r *http.Request, a *App) {
|
|
|
|
username, password, ok := r.BasicAuth()
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
writeUnauthorized(w, a.Config.Realm)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
authInfo := authorize(a.Config, username, password)
|
|
|
|
if !authInfo.Authenticated {
|
|
|
|
writeUnauthorized(w, a.Config.Realm)
|
2018-04-10 15:20:23 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-05-19 20:58:57 +02:00
|
|
|
ctx = context.WithValue(ctx, authInfoKey, authInfo)
|
2018-04-10 22:02:48 +02:00
|
|
|
a.Handler.ServeHTTP(w, r.WithContext(ctx))
|
2018-04-10 15:20:23 +02:00
|
|
|
}
|
|
|
|
|
2018-05-19 20:58:57 +02:00
|
|
|
func writeUnauthorized(w http.ResponseWriter, realm string) {
|
|
|
|
w.Header().Set("WWW-Authenticate", "Basic realm=" + realm)
|
|
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
|
|
w.Write([]byte(fmt.Sprintf("%d %s", http.StatusUnauthorized, "Unauthorized")))
|
2018-04-10 15:20:23 +02:00
|
|
|
}
|
2018-04-10 22:02:48 +02:00
|
|
|
|
2018-05-19 20:58:57 +02:00
|
|
|
// NewBasicAuthWebdavHandler creates a new http handler with basic auth features.
|
|
|
|
// The handler will use the application config for user and password lookups.
|
2018-04-10 22:02:48 +02:00
|
|
|
func NewBasicAuthWebdavHandler(a *App) http.Handler {
|
2018-05-19 20:58:57 +02:00
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx := context.Background()
|
|
|
|
handlerFunc := authWebdavHandlerFunc(handle)
|
|
|
|
handlerFunc.ServeHTTP(ctx, w, r, a)
|
|
|
|
})
|
2018-04-10 22:02:48 +02:00
|
|
|
}
|