...

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