WIP: RESTful API for WireGuard Portal, user endpoint (#11)

This commit is contained in:
Christoph Haas
2021-04-26 14:40:49 +02:00
parent b6d9814021
commit 35513ae994
7 changed files with 835 additions and 1 deletions

View File

@@ -2,9 +2,14 @@ package server
import (
"net/http"
"strings"
"github.com/gin-gonic/gin"
wgportal "github.com/h44z/wg-portal"
"github.com/h44z/wg-portal/internal/authentication"
_ "github.com/h44z/wg-portal/internal/server/docs" // docs is generated by Swag CLI, you have to import it.
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
)
func SetupRoutes(s *Server) {
@@ -60,6 +65,23 @@ func SetupRoutes(s *Server) {
user.GET("/status", s.GetPeerStatus)
}
func SetupApiRoutes(s *Server) {
api := ApiServer{s: s}
// Auth routes
apiV1 := s.server.Group("/api/v1")
apiV1.Use(s.RequireApiAuthentication("admin"))
apiV1.GET("/users", api.GetUsers)
apiV1.POST("/users", api.PostUser)
apiV1.GET("/user/:email", api.GetUser)
apiV1.PUT("/user/:email", api.PutUser)
apiV1.PATCH("/user/:email", api.PatchUser)
apiV1.DELETE("/user/:email", api.DeleteUser)
// Swagger doc/ui
s.server.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}
func (s *Server) RequireAuthentication(scope string) gin.HandlerFunc {
return func(c *gin.Context) {
session := GetSessionData(c)
@@ -78,7 +100,7 @@ func (s *Server) RequireAuthentication(scope string) gin.HandlerFunc {
return
}
// default case if some randome scope was set...
// default case if some random scope was set...
if scope != "" && !session.IsAdmin {
// Abort the request with the appropriate error code
c.Abort()
@@ -90,3 +112,67 @@ func (s *Server) RequireAuthentication(scope string) gin.HandlerFunc {
c.Next()
}
}
func (s *Server) RequireApiAuthentication(scope string) gin.HandlerFunc {
return func(c *gin.Context) {
username, password, hasAuth := c.Request.BasicAuth()
if !hasAuth {
c.Abort()
c.JSON(http.StatusUnauthorized, ApiError{Message: "unauthorized"})
return
}
// Validate form input
if strings.Trim(username, " ") == "" || strings.Trim(password, " ") == "" {
c.Abort()
c.JSON(http.StatusUnauthorized, ApiError{Message: "unauthorized"})
return
}
// Check user database for an matching entry
var loginProvider authentication.AuthProvider
user := s.users.GetUser(username) // retrieve active candidate user from db
if user == nil || user.Email == "" {
c.Abort()
c.JSON(http.StatusUnauthorized, ApiError{Message: "unauthorized"})
return
}
loginProvider = s.auth.GetProvider(string(user.Source))
if loginProvider == nil {
c.Abort()
c.JSON(http.StatusUnauthorized, ApiError{Message: "unauthorized"})
return
}
authEmail, err := loginProvider.Login(&authentication.AuthContext{
Username: username,
Password: password,
})
// Test if authentication succeeded
if err != nil || authEmail == "" {
c.Abort()
c.JSON(http.StatusUnauthorized, ApiError{Message: "unauthorized"})
return
}
// Check admin scope
if scope == "admin" && !user.IsAdmin {
// Abort the request with the appropriate error code
c.Abort()
c.JSON(http.StatusForbidden, ApiError{Message: "unauthorized"})
return
}
// default case if some random scope was set...
if scope != "" && !user.IsAdmin {
// Abort the request with the appropriate error code
c.Abort()
c.JSON(http.StatusForbidden, ApiError{Message: "unauthorized"})
return
}
// Continue down the chain to handler etc
c.Next()
}
}