Skip to content

Commit

Permalink
Add postgres user verification
Browse files Browse the repository at this point in the history
  • Loading branch information
Superioz committed Nov 11, 2021
1 parent cc856a6 commit 2c91770
Show file tree
Hide file tree
Showing 10 changed files with 296 additions and 28 deletions.
6 changes: 5 additions & 1 deletion .env.dist
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
JWT_PRIVATE_KEY=
JWT_ISSUER=
JWT_ISSUER=
POSTGRES_ADDRESS=
POSTGRES_DB=
POSTGRES_USER=
POSTGRES_PASSWORD=
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.0
0.2.0
4 changes: 2 additions & 2 deletions cmd/userm/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ func main() {
r.Use(middleware.Logger(3 * time.Second))
r.Use(gin.Recovery())

handler.Setup()
reqHandler := handler.NewRequestHandler()

r.POST("/login", handler.Login)
r.POST("/login", reqHandler.Login)

r.GET("/healthz", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "UP"})
Expand Down
7 changes: 2 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,8 @@ services:
gamemaster:
image: l12u/userm:0.1.0
build: .
environment:
POSTGRES_ADDRESS: postgres:5432
POSTGRES_DB: userm
POSTGRES_USER: test
POSTGRES_PASSWORD: test
env_file:
- .env
ports:
- 8090:8090
restart: always
29 changes: 21 additions & 8 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,36 @@ module github.com/l12u/userm

go 1.17

require (
github.com/gin-gonic/gin v1.7.4
github.com/go-pg/pg/v10 v10.10.6
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/joho/godotenv v1.4.0
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519
k8s.io/klog v1.0.0
)

require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.7.4 // indirect
github.com/go-pg/zerochecker v0.2.0 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang/protobuf v1.3.3 // indirect
github.com/joho/godotenv v1.4.0 // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
k8s.io/klog v1.0.0 // indirect
github.com/vmihailenco/bufpool v0.1.11 // indirect
github.com/vmihailenco/msgpack/v5 v5.3.4 // indirect
github.com/vmihailenco/tagparser v0.1.2 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
golang.org/x/sys v0.0.0-20210923061019-b8560ed6a9b7 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
mellium.im/sasl v0.2.1 // indirect
)
148 changes: 144 additions & 4 deletions go.sum

Large diffs are not rendered by default.

41 changes: 36 additions & 5 deletions internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,43 @@ import (
"encoding/pem"
"errors"
"github.com/gin-gonic/gin"
"github.com/go-pg/pg/v10"
"github.com/golang-jwt/jwt"
"github.com/l12u/userm/internal/errcode"
"github.com/l12u/userm/internal/model"
"github.com/l12u/userm/internal/verify"
"github.com/l12u/userm/pkg/env"
"k8s.io/klog"
"net/http"
"os"
"time"
)

var RsaPrivateKey *rsa.PrivateKey
type RequestHandler struct {
RsaPrivateKey *rsa.PrivateKey
Verifier verify.Verifier
}

func Setup() {
func NewRequestHandler() *RequestHandler {
privKey, err := parseRsaPrivateKeyFromPemStr(os.Getenv("JWT_PRIVATE_KEY"))
if err != nil {
panic(err)
}
RsaPrivateKey = privKey

pgVerifier := verify.NewPostgresVerifier(&pg.Options{
Addr: env.StringOrDefault("POSTGRES_ADDRESS", "localhost:5432"),
Database: env.StringOrDefault("POSTGRES_DB", ""),
User: env.StringOrDefault("POSTGRES_USER", ""),
Password: env.StringOrDefault("POSTGRES_PASSWORD", ""),
})

return &RequestHandler{
RsaPrivateKey: privKey,
Verifier: pgVerifier,
}
}

func Login(c *gin.Context) {
func (h *RequestHandler) Login(c *gin.Context) {
b, err := c.GetRawData()
if err != nil {
_ = c.Error(err)
Expand All @@ -44,15 +61,29 @@ func Login(c *gin.Context) {
return
}

klog.Infof("Try to verify login for '%s'", data.Username)
ok, err := h.Verifier.Verify(data.Username, data.Password)
if err != verify.ErrNotFound && err != verify.ErrHashDoesntMatch {
klog.Errorf("Error during verification process: %v", err)
errcode.S(c, http.StatusInternalServerError, "error during verification process")
return
}
if !ok {
errcode.S(c, http.StatusForbidden, "wrong username or password")
return
}

// generate JWT for the user
issuer := env.StringOrDefault("JWT_ISSUER", "testing@l12u.party")
token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
"user": data.Username,
"iss": issuer,
"sub": issuer,
"iat": time.Now().Unix(),
"exp": time.Now().Add(3 * 24 * time.Hour).Unix(),
})

tokenStr, err := token.SignedString(RsaPrivateKey)
tokenStr, err := token.SignedString(h.RsaPrivateKey)
if err != nil {
_ = c.Error(err)
return
Expand Down
16 changes: 14 additions & 2 deletions internal/model/model.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
package model

import "fmt"

type LoginData struct {
Username string `json:"username"`
PasswordHash string `json:"passwordHash"`
Username string `json:"username"`
Password string `json:"password"`
}

func (l LoginData) IsValid() bool {
return l.Username != ""
}

type RegisteredUser struct {
Id string
Username string
PasswordHash string `pg:"password"`
}

func (r *RegisteredUser) String() string {
return fmt.Sprintf("RegisteredUser<%s, %s, %s>", r.Id, r.Username, r.PasswordHash)
}
51 changes: 51 additions & 0 deletions internal/verify/postgres.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package verify

import (
"context"
"github.com/go-pg/pg/v10"
"github.com/go-pg/pg/v10/orm"
"github.com/l12u/userm/internal/model"
"golang.org/x/crypto/bcrypt"
)

type PostgresVerifier struct {
db *pg.DB
}

func NewPostgresVerifier(opt *pg.Options) *PostgresVerifier {
db := pg.Connect(opt)
err := db.Ping(context.Background())
if err != nil {
panic(err)
}

// setup tables if not exists
err = db.Model(&model.RegisteredUser{}).CreateTable(&orm.CreateTableOptions{
IfNotExists: true,
})
if err != nil {
panic(err)
}

return &PostgresVerifier{
db: db,
}
}

func (p *PostgresVerifier) Verify(user string, pw string) (bool, error) {
u := &model.RegisteredUser{}
err := p.db.Model(u).Where("? = ?", pg.Ident("username"), user).Select()
if err != nil {
if err == pg.ErrNoRows {
return false, ErrNotFound
}
return false, err
}

err = bcrypt.CompareHashAndPassword([]byte(u.PasswordHash), []byte(pw))
if err != nil {
return false, ErrHashDoesntMatch
}

return true, nil
}
20 changes: 20 additions & 0 deletions internal/verify/verify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Package verify is for verifying the credentials of a user are valid.
package verify

import "errors"

var (
ErrNotFound = errors.New("could not find entry for given user")
ErrHashDoesntMatch = errors.New("hashed password is not hash of the given password")
)

type Verifier interface {
Verify(user string, pw string) (bool, error)
}

type SimpleVerifier struct {
}

func (s *SimpleVerifier) Verify(_ string, _ string) (bool, error) {
return true, nil
}

0 comments on commit 2c91770

Please sign in to comment.