You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
sonic/handler/middleware/application_password.go

101 lines
2.2 KiB
Go

package middleware
import (
"encoding/base64"
"fmt"
"net/http"
"regexp"
"strings"
"github.com/gin-gonic/gin"
"github.com/go-sonic/sonic/consts"
"github.com/go-sonic/sonic/model/dto"
"github.com/go-sonic/sonic/service"
)
var (
basicAuthRegexp = regexp.MustCompile(`^Basic [a-z\\d/+]*={0,2}`)
)
type ApplicationPasswordMiddleware struct {
PasswordService service.ApplicationPasswordService
UserService service.UserService
}
func NewApplicationPasswordMiddleware(passwordService service.ApplicationPasswordService, userService service.UserService) *ApplicationPasswordMiddleware {
m := &ApplicationPasswordMiddleware{
PasswordService: passwordService,
UserService: userService,
}
return m
}
func (a *ApplicationPasswordMiddleware) Get() error {
return nil
}
func (a *ApplicationPasswordMiddleware) GetWrapHandler() gin.HandlerFunc {
return func(ctx *gin.Context) {
header := ctx.GetHeader("Authorization")
if len(header) == 0 {
abortUnauthorized(ctx)
return
}
match := verifyHeader(header)
if !match {
abortUnauthorized(ctx)
return
}
bytes, err := base64.StdEncoding.DecodeString(header[6:])
if err != nil {
abortUnauthorized(ctx)
return
}
userPass := string(bytes)
if !strings.Contains(userPass, ":") {
abortUnauthorized(ctx)
return
}
splits := strings.SplitN(userPass, ":", 2)
userEntity, err := a.UserService.GetByUsername(ctx, splits[0])
if err != nil {
abortUnauthorized(ctx)
return
}
pwdEntity, err := a.PasswordService.Verify(ctx, userEntity.ID, splits[1])
if err != nil || pwdEntity == nil {
abortUnauthorized(ctx)
return
}
err = a.PasswordService.Update(ctx, *pwdEntity.ID, ctx.ClientIP())
if err != nil {
ctx.AbortWithStatusJSON(http.StatusInternalServerError, &dto.BaseDTO{
Status: http.StatusInternalServerError,
Message: fmt.Sprintf("Update application password entity error, err=%s", err),
})
return
}
ctx.Set(consts.AuthorizedUser, userEntity)
}
}
func abortUnauthorized(ctx *gin.Context) {
ctx.AbortWithStatusJSON(http.StatusUnauthorized, &dto.BaseDTO{
Status: http.StatusUnauthorized,
Message: "Unauthorized",
})
}
func verifyHeader(header string) bool {
return basicAuthRegexp.MatchString(header)
}