...

Source file src/github.com/cybertec-postgresql/pgwatch/v3/internal/webserver/jwt.go

Documentation: github.com/cybertec-postgresql/pgwatch/v3/internal/webserver

     1  package webserver
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/http"
     7  	"time"
     8  
     9  	jsoniter "github.com/json-iterator/go"
    10  
    11  	"github.com/golang-jwt/jwt/v5"
    12  )
    13  
    14  type loginReq struct {
    15  	Username string `json:"user"`
    16  	Password string `json:"password"`
    17  }
    18  
    19  func (Server *WebUIServer) IsCorrectPassword(lr loginReq) bool {
    20  	return (Server.WebUser+Server.WebPassword == "") ||
    21  		(Server.WebUser == lr.Username && Server.WebPassword == lr.Password)
    22  }
    23  
    24  func (Server *WebUIServer) handleLogin(w http.ResponseWriter, r *http.Request) {
    25  	var (
    26  		err   error
    27  		lr    loginReq
    28  		token string
    29  	)
    30  
    31  	defer func() {
    32  		if err != nil {
    33  			http.Error(w, err.Error(), http.StatusInternalServerError)
    34  		}
    35  	}()
    36  
    37  	switch r.Method {
    38  	case "POST":
    39  		if err = jsoniter.ConfigFastest.NewDecoder(r.Body).Decode(&lr); err != nil {
    40  			return
    41  		}
    42  		if !Server.IsCorrectPassword(lr) {
    43  			http.Error(w, "can not authenticate this user", http.StatusUnauthorized)
    44  			return
    45  		}
    46  		if token, err = generateJWT(lr.Username); err != nil {
    47  			return
    48  		}
    49  		_, err = w.Write([]byte(token))
    50  
    51  	case "GET":
    52  		fmt.Fprintf(w, "only POST methods is allowed.")
    53  		return
    54  	}
    55  }
    56  
    57  type EnsureAuth struct {
    58  	handler http.HandlerFunc
    59  }
    60  
    61  func (ea *EnsureAuth) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    62  	if err := validateToken(r); err != nil {
    63  		http.Error(w, err.Error(), http.StatusUnauthorized)
    64  		return
    65  	}
    66  	ea.handler(w, r)
    67  }
    68  
    69  func NewEnsureAuth(handlerToWrap http.HandlerFunc) *EnsureAuth {
    70  	return &EnsureAuth{handlerToWrap}
    71  }
    72  
    73  var sampleSecretKey = []byte("5m3R7K4754p4m")
    74  
    75  func generateJWT(username string) (string, error) {
    76  	token := jwt.New(jwt.SigningMethodHS256)
    77  	claims := token.Claims.(jwt.MapClaims)
    78  
    79  	claims["authorized"] = true
    80  	claims["username"] = username
    81  	claims["exp"] = time.Now().Add(time.Hour * 8).Unix()
    82  
    83  	return token.SignedString(sampleSecretKey)
    84  }
    85  
    86  func validateToken(r *http.Request) (err error) {
    87  	var t string
    88  	if r.Header["Token"] == nil {
    89  		t = r.URL.Query().Get("Token")
    90  	} else {
    91  		t = r.Header["Token"][0]
    92  	}
    93  	if t == "" {
    94  		return errors.New("can not find token in header")
    95  	}
    96  
    97  	_, err = jwt.Parse(t,
    98  		func(_ *jwt.Token) (any, error) {
    99  			return sampleSecretKey, nil
   100  		},
   101  		jwt.WithExpirationRequired(),
   102  		jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}))
   103  	return err
   104  }
   105