2022-05-16 06:15:09 +00:00
|
|
|
package middleware
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-05-18 04:29:40 +00:00
|
|
|
"fmt"
|
2023-01-30 23:41:37 +00:00
|
|
|
"hacklab.nilfm.cc/quartzgun/auth"
|
|
|
|
"hacklab.nilfm.cc/quartzgun/cookie"
|
|
|
|
"hacklab.nilfm.cc/quartzgun/renderer"
|
|
|
|
"hacklab.nilfm.cc/quartzgun/util"
|
2023-07-13 23:31:20 +00:00
|
|
|
"net/http"
|
2022-08-01 00:08:05 +00:00
|
|
|
"strings"
|
2022-05-16 06:15:09 +00:00
|
|
|
)
|
|
|
|
|
2022-08-01 00:08:05 +00:00
|
|
|
type TokenPayload struct {
|
2022-08-03 03:17:53 +00:00
|
|
|
AccessToken string `json:"access_token"`
|
|
|
|
TokenType string `json:"token_type"`
|
2023-01-27 03:54:48 +00:00
|
|
|
ExpiresIn int `json:"expires_in"`
|
2022-08-01 00:08:05 +00:00
|
|
|
}
|
|
|
|
|
2022-05-21 03:36:54 +00:00
|
|
|
func Protected(next http.Handler, method string, userStore auth.UserStore, login string) http.Handler {
|
2022-05-16 06:15:09 +00:00
|
|
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
user, err := cookie.GetToken("user", req)
|
|
|
|
if err == nil {
|
|
|
|
session, err := cookie.GetToken("session", req)
|
|
|
|
if err == nil {
|
|
|
|
login, err := userStore.ValidateUser(user, session)
|
|
|
|
if err == nil && login {
|
2022-08-01 00:08:05 +00:00
|
|
|
fmt.Printf("authorized user: %s\n", user)
|
2022-05-18 04:29:40 +00:00
|
|
|
req.Method = method
|
2022-05-16 06:15:09 +00:00
|
|
|
next.ServeHTTP(w, req)
|
|
|
|
return
|
2023-01-27 03:54:48 +00:00
|
|
|
} else if err != nil && err.Error() == "Cookie or token expired" {
|
|
|
|
auth.Logout(user, userStore, w)
|
2022-05-16 06:15:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-18 04:29:40 +00:00
|
|
|
fmt.Printf("unauthorized...\n")
|
2022-05-16 06:15:09 +00:00
|
|
|
req.Method = http.MethodGet
|
2022-05-21 03:36:54 +00:00
|
|
|
http.Redirect(w, req, login, http.StatusSeeOther)
|
2022-05-16 06:15:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return http.HandlerFunc(handlerFunc)
|
|
|
|
}
|
|
|
|
|
2022-05-21 03:36:54 +00:00
|
|
|
func Bunt(next string, userStore auth.UserStore, denied string) http.Handler {
|
|
|
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
user, err := cookie.GetToken("user", req)
|
|
|
|
if err == nil {
|
|
|
|
err := auth.Logout(
|
|
|
|
user,
|
|
|
|
userStore,
|
|
|
|
w)
|
|
|
|
if err == nil {
|
|
|
|
req.Method = http.MethodGet
|
|
|
|
http.Redirect(w, req, next, http.StatusSeeOther)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
req.Method = http.MethodGet
|
|
|
|
http.Redirect(w, req, denied, http.StatusUnauthorized)
|
|
|
|
}
|
|
|
|
|
|
|
|
return http.HandlerFunc(handlerFunc)
|
|
|
|
}
|
|
|
|
|
2022-08-03 02:46:34 +00:00
|
|
|
func Authorize(next string, userStore auth.UserStore, denied string, ttl int) http.Handler {
|
2022-05-16 06:15:09 +00:00
|
|
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
err := auth.Login(
|
|
|
|
req.FormValue("user"),
|
|
|
|
req.FormValue("password"),
|
|
|
|
userStore,
|
|
|
|
w,
|
2022-08-03 02:46:34 +00:00
|
|
|
ttl)
|
2022-05-16 06:15:09 +00:00
|
|
|
if err == nil {
|
|
|
|
req.Method = http.MethodGet
|
2022-05-18 04:29:40 +00:00
|
|
|
fmt.Printf("logged in as %s\n", req.FormValue("user"))
|
|
|
|
http.Redirect(w, req, next, http.StatusSeeOther)
|
2022-05-16 06:15:09 +00:00
|
|
|
} else {
|
2022-05-21 03:36:54 +00:00
|
|
|
fmt.Printf("login failed!\n")
|
|
|
|
req.Method = http.MethodGet
|
|
|
|
http.Redirect(w, req, denied, http.StatusSeeOther)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-01 00:08:05 +00:00
|
|
|
return http.HandlerFunc(handlerFunc)
|
|
|
|
}
|
|
|
|
|
2022-08-03 02:46:34 +00:00
|
|
|
func Provision(userStore auth.UserStore, ttl int) http.Handler {
|
2022-08-01 00:08:05 +00:00
|
|
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
user, password, ok := req.BasicAuth()
|
2022-08-03 02:46:34 +00:00
|
|
|
if ok {
|
|
|
|
token, err := userStore.GrantToken(user, password, ttl)
|
2022-08-01 00:08:05 +00:00
|
|
|
if err == nil {
|
|
|
|
token := TokenPayload{
|
2022-08-03 03:17:53 +00:00
|
|
|
AccessToken: token,
|
|
|
|
TokenType: "bearer",
|
|
|
|
ExpiresIn: ttl,
|
2022-08-01 00:08:05 +00:00
|
|
|
}
|
|
|
|
util.AddContextValue(req, "token", token)
|
|
|
|
renderer.JSON("token").ServeHTTP(w, req)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return http.HandlerFunc(handlerFunc)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Validate(next http.Handler, userStore auth.UserStore, scopes map[string]string) http.Handler {
|
|
|
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
2023-01-27 03:54:48 +00:00
|
|
|
errString := ""
|
2022-08-01 00:08:05 +00:00
|
|
|
authHeader := req.Header.Get("Authorization")
|
|
|
|
if strings.HasPrefix(authHeader, "Bearer ") {
|
|
|
|
authToken := strings.Split(authHeader, "Bearer ")[1]
|
|
|
|
validated, err := userStore.ValidateTokenWithScopes(authToken, scopes)
|
|
|
|
if validated && err == nil {
|
|
|
|
next.ServeHTTP(w, req)
|
|
|
|
return
|
2023-01-27 03:54:48 +00:00
|
|
|
} else {
|
|
|
|
errString = err.Error()
|
2022-08-01 00:08:05 +00:00
|
|
|
}
|
2023-01-27 03:54:48 +00:00
|
|
|
} else {
|
|
|
|
errString = "No authentication data"
|
2022-08-01 00:08:05 +00:00
|
|
|
}
|
2023-01-27 03:54:48 +00:00
|
|
|
w.Header().Add("Quartzgun-Error", errString)
|
2022-08-01 00:08:05 +00:00
|
|
|
w.WriteHeader(http.StatusUnauthorized)
|
|
|
|
}
|
|
|
|
|
2022-05-21 03:36:54 +00:00
|
|
|
return http.HandlerFunc(handlerFunc)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Fortify(next http.Handler) http.Handler {
|
|
|
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
token, err := cookie.GetToken("csrfToken", req)
|
|
|
|
if err == nil {
|
2022-05-16 06:15:09 +00:00
|
|
|
*req = *req.WithContext(
|
|
|
|
context.WithValue(
|
|
|
|
req.Context(),
|
2022-05-21 03:36:54 +00:00
|
|
|
"csrfToken",
|
|
|
|
token))
|
|
|
|
}
|
|
|
|
next.ServeHTTP(w, req)
|
|
|
|
}
|
|
|
|
|
|
|
|
return http.HandlerFunc(handlerFunc)
|
|
|
|
}
|
|
|
|
|
|
|
|
func Defend(next http.Handler, userStore auth.UserStore, denied string) http.Handler {
|
|
|
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
user, err := cookie.GetToken("user", req)
|
|
|
|
if err == nil {
|
|
|
|
masterToken, err := userStore.GetData(user, "csrfToken")
|
|
|
|
if err == nil {
|
|
|
|
cookieToken, err := cookie.GetToken("csrfToken", req)
|
|
|
|
if err == nil {
|
|
|
|
formToken := req.FormValue("csrfToken")
|
|
|
|
if formToken == cookieToken && formToken == masterToken.(string) {
|
|
|
|
next.ServeHTTP(w, req)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-05-16 06:15:09 +00:00
|
|
|
}
|
2022-05-21 03:36:54 +00:00
|
|
|
http.Redirect(w, req, denied, http.StatusUnauthorized)
|
2022-05-16 06:15:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return http.HandlerFunc(handlerFunc)
|
|
|
|
}
|
2024-11-28 16:54:35 +00:00
|
|
|
|
|
|
|
func Throttle(next http.Handler, bouncer func(*http.Request) bool) http.Handler {
|
|
|
|
handlerFunc := func(w http.ResponseWriter, req *http.Request) {
|
|
|
|
allowed := bouncer(req)
|
|
|
|
if allowed {
|
|
|
|
next.ServeHTTP(w, req)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
w.WriteHeader(http.StatusTooManyRequests)
|
|
|
|
}
|
|
|
|
return http.HandlerFunc(handlerFunc)
|
|
|
|
}
|