فهرست منبع

password hashing

sunguroku 5 سال پیش
والد
کامیت
ea1aca5af0

+ 5 - 1
cmd/app/main.go

@@ -10,6 +10,7 @@ import (
 	"github.com/porter-dev/porter/server/api"
 
 	adapter "github.com/porter-dev/porter/internal/adapter"
+	sessionstore "github.com/porter-dev/porter/internal/auth/"
 	"github.com/porter-dev/porter/internal/config"
 	lr "github.com/porter-dev/porter/internal/logger"
 	vr "github.com/porter-dev/porter/internal/validator"
@@ -27,10 +28,13 @@ func main() {
 		return
 	}
 
+	key = []byte("secret") // TODO: change to os.Getenv("SESSION_KEY")
+	store, _ = sessionstore.NewStore(db, key)
+
 	validator := vr.New()
 	repo := gorm.NewRepository(db)
 
-	a := api.New(logger, repo, validator)
+	a := api.New(logger, repo, validator, store)
 
 	appRouter := router.New(a)
 

+ 6 - 8
go.mod

@@ -4,13 +4,6 @@ go 1.14
 
 require (
 	github.com/DATA-DOG/go-sqlmock v1.5.0
-	github.com/go-chi/chi v4.1.2+incompatible
-	github.com/go-test/deep v1.0.7
-	github.com/gorilla/securecookie v1.1.1
-	github.com/gorilla/sessions v1.2.1
-	github.com/imdario/mergo v0.3.11 // indirect
-	github.com/jinzhu/gorm v1.9.16
-	github.com/pkg/errors v0.9.1
 	github.com/cosmtrek/air v1.21.2 // indirect
 	github.com/creack/pty v1.1.11 // indirect
 	github.com/fatih/color v1.9.0 // indirect
@@ -18,14 +11,19 @@ require (
 	github.com/go-playground/locales v0.13.0
 	github.com/go-playground/universal-translator v0.17.0
 	github.com/go-playground/validator/v10 v10.3.0
+	github.com/go-test/deep v1.0.7
+	github.com/gorilla/securecookie v1.1.1
+	github.com/gorilla/sessions v1.2.1
 	github.com/imdario/mergo v0.3.11 // indirect
+	github.com/jinzhu/gorm v1.9.16
 	github.com/joeshaw/envdecode v0.0.0-20200121155833-099f1fc765bd
 	github.com/leodido/go-urn v1.2.0 // indirect
 	github.com/mattn/go-colorable v0.1.7 // indirect
 	github.com/pelletier/go-toml v1.8.1 // indirect
+	github.com/pkg/errors v0.9.1
 	github.com/rs/zerolog v1.20.0
 	github.com/stretchr/testify v1.5.1
-	golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a // indirect
+	golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a
 	golang.org/x/net v0.0.0-20200904194848-62affa334b73 // indirect
 	golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43 // indirect
 	golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d // indirect

+ 2 - 0
go.sum

@@ -240,6 +240,8 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
 github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
 github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
 github.com/jackc/puddle v1.1.2/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
+github.com/jinzhu/gorm v1.9.16 h1:+IyIjPEABKRpsu/F8OvDPy9fyQlgsg2luMV2ZIH5i5o=
+github.com/jinzhu/gorm v1.9.16/go.mod h1:G3LB3wezTOWM2ITLzPxEXgSkOXAntiLHS7UdBefADcs=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=

+ 1 - 1
internal/auth/sessionstore.go

@@ -21,7 +21,7 @@ import (
 
 // structs
 
-// PGStore is not exported.
+// PGStore is a wrapper around gorilla/sessions store.
 type PGStore struct {
 	Codecs  []securecookie.Codec
 	Options *sessions.Options

+ 9 - 2
internal/forms/user.go

@@ -1,10 +1,11 @@
 package forms
 
 import (
-	"gorm.io/gorm"
 	"github.com/porter-dev/porter/internal/kubernetes"
 	"github.com/porter-dev/porter/internal/models"
+	"golang.org/x/crypto/bcrypt"
 	"gopkg.in/yaml.v2"
+	"gorm.io/gorm"
 )
 
 // WriteUserForm is a generic form for write operations to the User model
@@ -23,9 +24,15 @@ type CreateUserForm struct {
 //
 // TODO -- PASSWORD HASHING HERE
 func (cuf *CreateUserForm) ToUser() (*models.User, error) {
+	hashed, err := bcrypt.GenerateFromPassword([]byte(cuf.Password), 8)
+
+	if err != nil {
+		return nil, err
+	}
+
 	return &models.User{
 		Email:    cuf.Email,
-		Password: cuf.Password,
+		Password: string(hashed),
 	}, nil
 }
 

+ 0 - 62
internal/queries/session/session.go

@@ -1,62 +0,0 @@
-package session
-
-import (
-	gormtest "github.com/jinzhu/gorm"
-	"github.com/porter-dev/porter/internal/models"
-)
-
-// Repository for testing. Potential TODO: swap out actual functional calls to point to repoitory.
-type Repository interface {
-	CreateSession(session *models.Session) (*models.Session, error)
-	UpdateSession(session *models.Session) (*models.Session, error)
-	DeleteSession(session *models.Session) (*models.Session, error)
-	SelectSession(session *models.Session) (*models.Session, error)
-}
-
-type repo struct {
-	db *gormtest.DB
-}
-
-// CreateSession must take in Key, Data, and ExpiresAt as arguments.
-func (s *repo) CreateSession(session *models.Session) (*models.Session, error) {
-	// TODO: check for duplicate and return error
-	if err := s.db.Create(session).Error; err != nil {
-		return nil, err
-	}
-	return session, nil
-}
-
-// UpdateSession updates only the Data field using Key as selector.
-func (s *repo) UpdateSession(session *models.Session) (*models.Session, error) {
-	if err := s.db.Model(session).Where("Key = ?", session.Key).Updates(session).Error; err != nil {
-		return nil, err
-	}
-	return session, nil
-}
-
-// DeleteSession deletes a session by Key
-func (s *repo) DeleteSession(session *models.Session) (*models.Session, error) {
-
-	if err := s.db.Where("Key = ?", session.Key).Delete(session).Error; err != nil {
-		return nil, err
-	}
-
-	return session, nil
-}
-
-// SelectSession returns a session with matching key
-func (s *repo) SelectSession(session *models.Session) (*models.Session, error) {
-
-	if err := s.db.Where("Key = ?", session.Key).First(session).Error; err != nil {
-		return nil, err
-	}
-
-	return session, nil
-}
-
-// CreateRepository ...
-func CreateRepository(db *gormtest.DB) Repository {
-	return &repo{
-		db: db,
-	}
-}

+ 0 - 145
internal/queries/session/session_test.go

@@ -1,145 +0,0 @@
-package session
-
-import (
-	"database/sql"
-	"regexp"
-	"testing"
-	"time"
-
-	"github.com/DATA-DOG/go-sqlmock"
-	"github.com/go-test/deep"
-	"github.com/jinzhu/gorm"
-	"github.com/porter-dev/porter/internal/models"
-	"github.com/stretchr/testify/require"
-	"github.com/stretchr/testify/suite"
-)
-
-type Suite struct {
-	suite.Suite
-	db   *gorm.DB
-	mock sqlmock.Sqlmock
-
-	repo    Repository
-	session *models.Session
-}
-
-func (s *Suite) SetupSuite() {
-	var (
-		db  *sql.DB
-		err error
-	)
-
-	db, s.mock, err = sqlmock.New()
-	// db, s.mock, err = sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherRegexp))
-
-	require.NoError(s.T(), err)
-
-	s.db, err = gorm.Open("postgres", db)
-	require.NoError(s.T(), err)
-
-	s.db.LogMode(true)
-
-	s.repo = CreateRepository(s.db)
-}
-
-func (s *Suite) AfterTest(_, _ string) {
-	require.NoError(s.T(), s.mock.ExpectationsWereMet())
-}
-
-func TestInit(t *testing.T) {
-	suite.Run(t, new(Suite))
-}
-
-func (s *Suite) TestShouldCreateNewSession() {
-	var (
-		key       = "onekey"
-		data      = []byte("onedata")
-		expiresAt = time.Now()
-	)
-
-	rows := sqlmock.NewRows([]string{"id"}).AddRow("111")
-
-	s.mock.ExpectBegin()
-	s.mock.ExpectQuery(regexp.QuoteMeta(
-		`INSERT INTO "sessions" ("created_at","updated_at","deleted_at","key","data","expires_at")
-		VALUES ($1,$2,$3,$4,$5,$6) RETURNING "sessions"."id"`)).
-		WithArgs(sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), key, data, expiresAt).
-		WillReturnRows(rows)
-	s.mock.ExpectCommit()
-
-	// test function
-	_, err := s.repo.CreateSession(&models.Session{
-		Key:       key,
-		Data:      data,
-		ExpiresAt: expiresAt,
-	})
-
-	require.NoError(s.T(), err)
-}
-
-func (s *Suite) TestShoudSelectSessionByKey() {
-	var (
-		key = "onekey"
-	)
-
-	rows := sqlmock.NewRows([]string{"Key"}).AddRow(key)
-
-	s.mock.ExpectQuery(`.*`). // do proper regex labor later as meditative exercise
-					WithArgs(key).
-					WillReturnRows(rows)
-
-	// test function
-	res, err := s.repo.SelectSession(&models.Session{
-		Key: key,
-	})
-
-	require.NoError(s.T(), err)
-	require.Nil(s.T(), deep.Equal(&models.Session{Key: key}, res))
-}
-
-func (s *Suite) TestShouldUpdateSessionByKey() {
-	var (
-		key       = "onekey"
-		data      = []byte("chobanilime")
-		expiresAt = time.Now()
-	)
-
-	// rows := sqlmock.NewRows([]string{"Key"}).AddRow(key)
-
-	s.mock.ExpectBegin()
-	s.mock.ExpectExec(`.*`). // do proper regex labor later as meditative exercise
-					WithArgs(data, sqlmock.AnyArg(), sqlmock.AnyArg(), sqlmock.AnyArg(), key).
-					WillReturnResult(sqlmock.NewResult(1, 1))
-	s.mock.ExpectCommit()
-
-	// test function
-	_, err := s.repo.UpdateSession(&models.Session{
-		Key:       key,
-		Data:      data,
-		ExpiresAt: expiresAt,
-	})
-
-	require.NoError(s.T(), err)
-	// require.Nil(s.T(), deep.Equal(&models.Session{Data: data}, res))
-}
-
-func (s *Suite) TestShouldDeleteSession() {
-	var (
-		key = "onekey"
-	)
-
-	// rows := sqlmock.NewRows([]string{"id"}).AddRow("111")
-
-	s.mock.ExpectBegin()
-	s.mock.ExpectExec(`.*`).
-		WithArgs(sqlmock.AnyArg(), key).
-		WillReturnResult(sqlmock.NewResult(1, 1))
-	s.mock.ExpectCommit()
-
-	// test function
-	_, err := s.repo.DeleteSession(&models.Session{
-		Key: key,
-	})
-
-	require.NoError(s.T(), err)
-}

+ 4 - 0
server/api/api.go

@@ -4,6 +4,7 @@ import (
 	"github.com/go-playground/locales/en"
 	ut "github.com/go-playground/universal-translator"
 	"github.com/go-playground/validator/v10"
+	sessionstore "github.com/porter-dev/porter/internal/auth"
 	lr "github.com/porter-dev/porter/internal/logger"
 	"github.com/porter-dev/porter/internal/repository"
 )
@@ -14,6 +15,7 @@ type App struct {
 	logger     *lr.Logger
 	repo       *repository.Repository
 	validator  *validator.Validate
+	store      *sessionstore.PGStore
 	translator *ut.Translator
 }
 
@@ -22,6 +24,7 @@ func New(
 	logger *lr.Logger,
 	repo *repository.Repository,
 	validator *validator.Validate,
+	store *sessionstore.PGStore,
 ) *App {
 	// for now, will just support the english translator from the
 	// validator/translations package
@@ -33,6 +36,7 @@ func New(
 		logger:     logger,
 		repo:       repo,
 		validator:  validator,
+		store:      store,
 		translator: &trans,
 	}
 }

+ 12 - 0
server/api/user_handler.go

@@ -32,6 +32,18 @@ func (app *App) HandleCreateUser(w http.ResponseWriter, r *http.Request) {
 	}
 }
 
+// HandleLoginUser checks the request header for cookie and validates the user.
+func (app *App) HandleLoginUser(w http.ResponseWriter, r *http.Request) {
+	session, _ := app.store.Get(r, "cookie-name")
+
+	// Authentication goes here
+	// ...
+
+	// Set user as authenticated
+	session.Values["authenticated"] = true
+	session.Save(r, w)
+}
+
 // HandleReadUser returns an externalized User (models.UserExternal)
 // based on an ID
 func (app *App) HandleReadUser(w http.ResponseWriter, r *http.Request) {

+ 1 - 0
server/router/router.go

@@ -20,6 +20,7 @@ func New(a *api.App) *chi.Mux {
 		r.Method("PUT", "/users/{id}", requestlog.NewHandler(a.HandleUpdateUser, l))
 		r.Method("GET", "/users/{id}", requestlog.NewHandler(a.HandleReadUser, l))
 		r.Method("DELETE", "/users/{id}", requestlog.NewHandler(a.HandleDeleteUser, l))
+		r.Method("POST", "/login", requestlog.NewHandler(a.HandleLoginUser, l))
 	})
 
 	return r