From a7f15e79fe33a42eb26d8a400cdfd66766f50b76 Mon Sep 17 00:00:00 2001 From: smavros Date: Thu, 16 May 2019 15:39:48 +0200 Subject: [PATCH] First try for Authentication middleware --- routes/user/userEndpoints.go | 2 +- routes/user/userMiddleware.go | 85 +++++++++++++++++++++++++++++++++++ start.go | 12 ++--- 3 files changed, 93 insertions(+), 6 deletions(-) create mode 100644 routes/user/userMiddleware.go diff --git a/routes/user/userEndpoints.go b/routes/user/userEndpoints.go index ab0a7b6..b28235d 100644 --- a/routes/user/userEndpoints.go +++ b/routes/user/userEndpoints.go @@ -50,4 +50,4 @@ func userSelfEp(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "message": "NOT implemented", }) -} \ No newline at end of file +} diff --git a/routes/user/userMiddleware.go b/routes/user/userMiddleware.go new file mode 100644 index 0000000..d28f1d9 --- /dev/null +++ b/routes/user/userMiddleware.go @@ -0,0 +1,85 @@ +package user + +import ( + "fmt" + "git.rwth-aachen.de/acs/public/villas/villasweb-backend-go/common" + "github.com/dgrijalva/jwt-go" + "github.com/dgrijalva/jwt-go/request" + "github.com/gin-gonic/gin" + "net/http" + "strings" +) + +const signatureSecret = "_A_strong_password_as_enviromental_variable_" + +func UserToContext(ctx *gin.Context, user_id uint) { + var user common.User + if user_id != 0 { + db := common.GetDB() + db.First(&user, user_id) + } + ctx.Set("user_id", user_id) + ctx.Set("user", user) +} + +// func stripBearerPrefixFromTokenString() +// Originally is supposed to remove the 'BEARER' token from the Auth +// header "Authorization: Bearer ". Currently use curl's header +// like "$ curl -H 'Authorization: TOKEN ..." +func removeTokenPrefix(tok string) (string, error) { + // if the prefix exists remove it from token + if len(tok) > 5 && strings.ToUpper(tok[0:6]) == "TOKEN " { + return tok[6:], nil + } + // otherwise return token + return tok, nil +} + +// Extractor of Authorization Header +// var AuthorizationHeaderExtractor +var GetAuthorizationHeader = &request.PostExtractionFilter{ + request.HeaderExtractor{"Authorization"}, + removeTokenPrefix, +} + +// Extractor of OAuth2 tokens. Finds the 'access_token' +// var OAuth2Extractor +var GetAuth2 = &request.MultiExtractor{ + GetAuthorizationHeader, + request.ArgumentExtractor{"access_token"}, +} + +func Authentication(unauthorized bool) gin.HandlerFunc { + return func(ctx *gin.Context) { + // Initialize user_id and model in the context + UserToContext(ctx, 0) + + // Authentication's access token extraction + token, err := request.ParseFromRequest(ctx.Request, GetAuth2, + func(token *jwt.Token) (interface{}, error) { + // validate alg for signing the jwt + // XXX: whis is the default signing method? + if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { + return nil, fmt.Errorf("Unexpected signing alg: %v", + token.Header["alg"]) + } + // return secret in byte format + secret := ([]byte(signatureSecret)) + return secret, nil + }) + + // If the authentication extraction fails return HTTP CODE 401 + if err != nil { + if unauthorized { + ctx.AbortWithError(http.StatusUnauthorized, err) + } + return + } + + // If the token is ok, pass user_id to context + if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { + user_id := uint(claims["id"].(float64)) + UserToContext(ctx, user_id) + } + } +} diff --git a/start.go b/start.go index b1e14d8..da938f8 100644 --- a/start.go +++ b/start.go @@ -21,7 +21,11 @@ func main() { r := gin.Default() - api := r.Group("/api") + api := r.Group("/api/v1") + + // All endpoints require authentication TODO: except /authenticate + api.Use(user.Authentication(true)) + user.UsersRegister(api.Group("/users")) file.FilesRegister(api.Group("/files")) project.ProjectsRegister(api.Group("/projects")) @@ -30,8 +34,6 @@ func main() { simulator.SimulatorsRegister(api.Group("/simulators")) visualization.VisualizationsRegister(api.Group("/visualizations")) - - - - r.Run() + // server at port 4000 to match frontend's redirect path + r.Run(":4000") }