api.spaceplanner.app

Spaceplanner API
git clone git://jacobedwards.org/api.spaceplanner.app
Log | Files | Refs

auth.go (3048B)


      1 package main
      2 
      3 import (
      4 	"errors"
      5 	"log"
      6 	"net/http"
      7 	"time"
      8 
      9 	"github.com/gin-gonic/gin"
     10 	jwt "github.com/appleboy/gin-jwt/v2"
     11 
     12 	"jacobedwards.org/spaceplanner.app/internal/backend"
     13 )
     14 
     15 var (
     16 	identityKey = "id"
     17 )
     18 
     19 func AuthMiddleware(authMiddleware *jwt.GinJWTMiddleware) gin.HandlerFunc {
     20 	return func(context *gin.Context) {
     21 		errInit := authMiddleware.MiddlewareInit()
     22 		if errInit != nil {
     23 			log.Fatal("authMiddleware.MiddlewareInit() Error:" + errInit.Error())
     24 		}
     25 	}
     26 }
     27 
     28 func (e *Env) AuthParams(key []byte) (*jwt.GinJWTMiddleware, error) {
     29 	if key == nil || len(key) == 0 {
     30 		return nil, errors.New("Invalid key")
     31 	}
     32 	return &jwt.GinJWTMiddleware{
     33 		// TODO: Don't know what Realm is, but should probably be changed
     34 		Realm: "test zone",
     35 		Key: key,
     36 		Timeout: time.Hour * 24 * 7,
     37 		MaxRefresh: time.Hour * 24,
     38 		IdentityKey: identityKey,
     39 		PayloadFunc: payloadFunc(),
     40 
     41 		IdentityHandler: identityHandler(),
     42 		Authenticator: e.authenticator(),
     43 		Authorizator: authorizator(),
     44 		Unauthorized: unauthorized(),
     45 		TokenLookup: "header: Authorization, query: token, cookie: jwt",
     46 		// TokenLookup: "query:token",
     47 		// TokenLookup: "cookie:token",
     48 		TokenHeadName: "Bearer",
     49 		TimeFunc: time.Now,
     50 	}, nil
     51 }
     52 
     53 func payloadFunc() func(data interface{}) jwt.MapClaims {
     54 	return func(data interface{}) jwt.MapClaims {
     55 		if v, ok := data.(backend.User); ok {
     56 			return jwt.MapClaims{
     57 				identityKey: v.Name,
     58 			}
     59 		}
     60 		return jwt.MapClaims{}
     61 	}
     62 }
     63 
     64 func identityHandler() func(c *gin.Context) interface{} {
     65 	return func(c *gin.Context) interface{} {
     66 		claims := jwt.ExtractClaims(c)
     67 		return &backend.User{
     68 			Name: claims[identityKey].(string),
     69 		}
     70 	}
     71 }
     72 
     73 func (e *Env) authenticator() func(c *gin.Context) (interface{}, error) {
     74 	return func(c *gin.Context) (interface{}, error) {
     75 		var creds Credentials
     76 		if err := c.ShouldBind(&creds); err != nil {
     77 			return "", jwt.ErrMissingLoginValues
     78 		}
     79 
     80 		user, err := e.backend.LoginUser(creds.Username, creds.Password)
     81 		if err != nil {
     82 			return nil, err
     83 		}
     84 		return user, nil
     85 	}
     86 }
     87 
     88 func authorizator() func(data interface{}, c *gin.Context) bool {
     89 	// Is authenticated user allowed to do X?
     90 	return func(data interface{}, c *gin.Context) bool {
     91 		owner := c.Param("user")
     92 		v, ok := data.(*backend.User)
     93 		if !ok {
     94 			log.Panic("Expected *backend.User")
     95 		}
     96 
     97 		if v.Name == owner {
     98 			return true
     99 		}
    100 		log.Printf("User %q unauthorized to access resource owned by %q", v.Name, owner)
    101 		return false
    102 	}
    103 }
    104 
    105 func unauthorized() func(c *gin.Context, code int, message string) {
    106 	return func(c *gin.Context, code int, message string) {
    107 		RespondError(c, code, "Unauthorized: %s", message);
    108 	}
    109 }
    110 
    111 func handleNoRoute() func(c *gin.Context) {
    112 	return func(c *gin.Context) {
    113 		claims := jwt.ExtractClaims(c)
    114 		log.Printf("NoRoute claims: %#v\n", claims)
    115 		RespondError(c, http.StatusNotFound, "Endpoint not found")
    116 	}
    117 }
    118 
    119 func testHandler(c *gin.Context) {
    120 	claims := jwt.ExtractClaims(c)
    121 	user, _ := c.Get(identityKey)
    122 	c.JSON(200, gin.H{
    123 		"ID": claims[identityKey],
    124 		"Username": user,
    125 		"text": "Test.",
    126 	})
    127 }