mirror of
https://git.rwth-aachen.de/acs/public/villas/web-backend-go/
synced 2025-03-30 00:00:12 +01:00
add support for external authentication via OAuth2 proxy
This commit is contained in:
parent
ffa532bddc
commit
fe2d291bb3
4 changed files with 103 additions and 31 deletions
|
@ -62,6 +62,7 @@ func InitConfig() error {
|
|||
jwtSecret = flag.String("jwt-secret", "This should NOT be here!!@33$8&", "The JSON Web Token secret")
|
||||
jwtExpiresAfter = flag.String("jwt-expires-after", "168h" /* 1 week */, "The time after which the JSON Web Token expires")
|
||||
testDataPath = flag.String("test-data-path", "database/testdata.json", "The path to the test data json file (used in test mode)")
|
||||
authExternal = flag.Bool("auth.external", false, "Use external authentication via X-Forwarded-User header (e.g. OAuth2 Proxy)")
|
||||
)
|
||||
flag.Parse()
|
||||
|
||||
|
@ -101,6 +102,12 @@ func InitConfig() error {
|
|||
static["s3.pathstyle"] = "false"
|
||||
}
|
||||
|
||||
if *authExternal == true {
|
||||
static["auth.external"] = "true"
|
||||
} else {
|
||||
static["auth.external"] = "false"
|
||||
}
|
||||
|
||||
mappings := map[string]string{
|
||||
"DB_HOST": "db.host",
|
||||
"DB_NAME": "db.name",
|
||||
|
@ -125,6 +132,7 @@ func InitConfig() error {
|
|||
"JWT_SECRET": "jwt.secret",
|
||||
"JWT_EXPIRES_AFTER": "jwt.expires-after",
|
||||
"TEST_DATA_PATH": "test.datapath",
|
||||
"AUTH_EXTERNAL": "auth.external",
|
||||
}
|
||||
|
||||
defaults := config.NewStatic(static)
|
||||
|
|
|
@ -23,8 +23,9 @@ package helper
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-gonic/gin"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func GetIDOfElement(c *gin.Context, elementName string, source string, providedID int) (int, error) {
|
||||
|
@ -50,3 +51,14 @@ func GetIDOfElement(c *gin.Context, elementName string, source string, providedI
|
|||
return -1, fmt.Errorf("invalid source of element ID")
|
||||
}
|
||||
}
|
||||
|
||||
// Find takes a slice and looks for an element in it. If found it will
|
||||
// return it's key, otherwise it will return -1 and a bool of false.
|
||||
func Find(slice []string, val string) (int, bool) {
|
||||
for i, item := range slice {
|
||||
if item == val {
|
||||
return i, true
|
||||
}
|
||||
}
|
||||
return -1, false
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ package user
|
|||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/configuration"
|
||||
|
@ -53,39 +54,18 @@ func RegisterAuthenticate(r *gin.RouterGroup) {
|
|||
// @Failure 500 {object} api.ResponseError "Internal server error."
|
||||
// @Router /authenticate [post]
|
||||
func authenticate(c *gin.Context) {
|
||||
var user *User
|
||||
|
||||
// Bind the response (context) with the loginRequest struct
|
||||
var credentials loginRequest
|
||||
if err := c.ShouldBindJSON(&credentials); err != nil {
|
||||
helper.UnauthorizedError(c, "Wrong username or password")
|
||||
return
|
||||
}
|
||||
|
||||
// Validate the login request
|
||||
if errs := credentials.validate(); errs != nil {
|
||||
helper.UnauthorizedError(c, "Wrong username or password")
|
||||
return
|
||||
}
|
||||
|
||||
// Find the username in the database
|
||||
var user User
|
||||
err := user.ByUsername(credentials.Username)
|
||||
externalAuth, err := configuration.GlobalConfig.Bool("external-auth")
|
||||
if err != nil {
|
||||
helper.UnauthorizedError(c, "Wrong username or password")
|
||||
helper.UnauthorizedError(c, "Backend configuration error")
|
||||
return
|
||||
}
|
||||
|
||||
// Check if this is an active user
|
||||
if !user.Active {
|
||||
helper.UnauthorizedError(c, "Wrong username or password")
|
||||
return
|
||||
}
|
||||
|
||||
// Validate the password
|
||||
err = user.validatePassword(credentials.Password)
|
||||
if err != nil {
|
||||
helper.UnauthorizedError(c, "Wrong username or password")
|
||||
return
|
||||
if err != nil || !externalAuth {
|
||||
user = authenticateStandard(c)
|
||||
} else {
|
||||
user = authenticateExternal(c)
|
||||
}
|
||||
|
||||
expiresStr, err := configuration.GlobalConfig.String("jwt.expires-after")
|
||||
|
@ -132,3 +112,77 @@ func authenticate(c *gin.Context) {
|
|||
"user": user.User,
|
||||
})
|
||||
}
|
||||
|
||||
func authenticateStandard(c *gin.Context) *User {
|
||||
// Bind the response (context) with the loginRequest struct
|
||||
var credentials loginRequest
|
||||
if err := c.ShouldBindJSON(&credentials); err != nil {
|
||||
helper.UnauthorizedError(c, "Wrong username or password")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate the login request
|
||||
if errs := credentials.validate(); errs != nil {
|
||||
helper.UnauthorizedError(c, "Failed to validate request")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Find the username in the database
|
||||
var user User
|
||||
err := user.ByUsername(credentials.Username)
|
||||
if err != nil {
|
||||
helper.UnauthorizedError(c, "Unknown username")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check if this is an active user
|
||||
if !user.Active {
|
||||
helper.UnauthorizedError(c, "User is not active")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate the password
|
||||
err = user.validatePassword(credentials.Password)
|
||||
if err != nil {
|
||||
helper.UnauthorizedError(c, "Invalid password")
|
||||
return nil
|
||||
}
|
||||
|
||||
return &user
|
||||
}
|
||||
|
||||
func authenticateExternal(c *gin.Context) *User {
|
||||
username := c.Request.Header.Get("X-Forwarded-User")
|
||||
if username == "" {
|
||||
helper.UnauthorizedAbort(c, "Authentication failed (X-Forwarded-User headers)")
|
||||
return nil
|
||||
}
|
||||
|
||||
email := c.Request.Header.Get("X-Forwarded-Email")
|
||||
if email == "" {
|
||||
helper.UnauthorizedAbort(c, "Authentication failed (X-Forwarded-Email headers)")
|
||||
return nil
|
||||
}
|
||||
|
||||
groups := strings.Split(c.Request.Header.Get("X-Forwarded-Groups"), ",")
|
||||
// preferred_username := c.Request.Header.Get("X-Forwarded-Preferred-Username")
|
||||
|
||||
var user User
|
||||
if err := user.ByUsername(username); err == nil {
|
||||
// There is already a user by this name
|
||||
return &user
|
||||
} else {
|
||||
role := "User"
|
||||
if _, found := helper.Find(groups, "admin"); found {
|
||||
role = "Admin"
|
||||
}
|
||||
|
||||
newUser, err := NewUser(username, "", email, role, true)
|
||||
if err != nil {
|
||||
helper.UnauthorizedAbort(c, "Authentication failed (failed to create new user: "+err.Error()+")")
|
||||
return nil
|
||||
}
|
||||
|
||||
return newUser
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,6 @@ import (
|
|||
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
|
||||
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/helper"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"git.rwth-aachen.de/acs/public/villas/web-backend-go/database"
|
||||
|
|
Loading…
Add table
Reference in a new issue