1
0
mirror of https://github.com/muety/wakapi.git synced 2023-08-10 21:12:56 +03:00
wakapi/middlewares/authenticate.go

140 lines
3.2 KiB
Go
Raw Normal View History

2019-05-06 01:40:41 +03:00
package middlewares
import (
2021-10-11 10:58:29 +03:00
"fmt"
"github.com/muety/wakapi/helpers"
2021-10-11 10:10:30 +03:00
"net/http"
"strings"
2020-10-16 17:11:14 +03:00
conf "github.com/muety/wakapi/config"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/services"
"github.com/muety/wakapi/utils"
2019-05-06 01:40:41 +03:00
)
2021-10-11 11:00:48 +03:00
const (
// queryApiKey is the query parameter name for api key.
queryApiKey = "api_key"
)
2021-10-11 10:58:29 +03:00
var (
errEmptyKey = fmt.Errorf("the api_key is empty")
)
2019-05-06 01:40:41 +03:00
type AuthenticateMiddleware struct {
config *conf.Config
userSrvc services.IUserService
optionalForPaths []string
redirectTarget string // optional
}
func NewAuthenticateMiddleware(userService services.IUserService) *AuthenticateMiddleware {
return &AuthenticateMiddleware{
config: conf.Get(),
userSrvc: userService,
optionalForPaths: []string{},
}
2019-05-06 01:40:41 +03:00
}
func (m *AuthenticateMiddleware) WithOptionalFor(paths []string) *AuthenticateMiddleware {
m.optionalForPaths = paths
return m
}
func (m *AuthenticateMiddleware) WithRedirectTarget(path string) *AuthenticateMiddleware {
m.redirectTarget = path
return m
}
func (m *AuthenticateMiddleware) Handler(h http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
m.ServeHTTP(w, r, h.ServeHTTP)
})
}
func (m *AuthenticateMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
var user *models.User
user, err := m.tryGetUserByCookie(r)
if err != nil {
2021-10-11 10:58:29 +03:00
user, err = m.tryGetUserByApiKeyHeader(r)
}
2021-10-11 10:10:30 +03:00
if err != nil {
2021-10-11 10:58:29 +03:00
user, err = m.tryGetUserByApiKeyQuery(r)
2021-10-11 10:10:30 +03:00
}
if err != nil || user == nil {
if m.isOptional(r.URL.Path) {
next(w, r)
return
}
if m.redirectTarget == "" {
w.WriteHeader(http.StatusUnauthorized)
2021-02-13 13:23:58 +03:00
w.Write([]byte(conf.ErrUnauthorized))
} else {
http.SetCookie(w, m.config.GetClearCookie(models.AuthCookieKey))
http.Redirect(w, r, m.redirectTarget, http.StatusFound)
}
2019-05-06 01:40:41 +03:00
return
}
SetPrincipal(r, user)
next(w, r)
}
func (m *AuthenticateMiddleware) isOptional(requestPath string) bool {
for _, p := range m.optionalForPaths {
if strings.HasPrefix(requestPath, p) || requestPath == p {
return true
}
}
return false
}
2021-10-11 10:58:29 +03:00
func (m *AuthenticateMiddleware) tryGetUserByApiKeyHeader(r *http.Request) (*models.User, error) {
key, err := utils.ExtractBearerAuth(r)
2019-05-06 01:40:41 +03:00
if err != nil {
return nil, err
2019-05-06 01:40:41 +03:00
}
var user *models.User
userKey := strings.TrimSpace(key)
user, err = m.userSrvc.GetUserByKey(userKey)
if err != nil {
return nil, err
2019-05-06 01:40:41 +03:00
}
return user, nil
}
2019-05-06 01:40:41 +03:00
2021-10-11 10:58:29 +03:00
func (m *AuthenticateMiddleware) tryGetUserByApiKeyQuery(r *http.Request) (*models.User, error) {
2021-10-11 11:00:48 +03:00
key := r.URL.Query().Get(queryApiKey)
2021-10-11 10:10:30 +03:00
var user *models.User
userKey := strings.TrimSpace(key)
2021-10-11 10:58:29 +03:00
if userKey == "" {
return nil, errEmptyKey
}
2021-10-11 10:10:30 +03:00
user, err := m.userSrvc.GetUserByKey(userKey)
if err != nil {
return nil, err
}
return user, nil
}
func (m *AuthenticateMiddleware) tryGetUserByCookie(r *http.Request) (*models.User, error) {
2022-12-01 13:11:45 +03:00
username, err := helpers.ExtractCookieAuth(r, m.config)
if err != nil {
return nil, err
}
user, err := m.userSrvc.GetUserById(*username)
if err != nil {
return nil, err
}
// no need to check password here, as securecookie decoding will fail anyway,
// if cookie is not properly signed
return user, nil
2019-05-06 01:40:41 +03:00
}