Skip to content

Commit edce871

Browse files
committed
Replaced bolt with store to make the name more convenient. Implemented first tests for store. Added authentication to login handler
1 parent 4c96f8f commit edce871

File tree

6 files changed

+251
-37
lines changed

6 files changed

+251
-37
lines changed

bolt/bolt.go

-32
This file was deleted.

cmd/gaia/main.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"github.com/kataras/iris"
77
"github.com/michelvocks/gaia"
88
"github.com/michelvocks/gaia/handlers"
9+
"github.com/michelvocks/gaia/store"
910
)
1011

1112
var (
@@ -31,8 +32,15 @@ func main() {
3132
// Initialize IRIS
3233
irisInstance = iris.New()
3334

35+
// Initialize store
36+
s := store.NewStore()
37+
err := s.Init(cfg)
38+
if err != nil {
39+
panic(err)
40+
}
41+
3442
// Initialize handlers
35-
handlers.InitHandlers(irisInstance)
43+
handlers.InitHandlers(irisInstance, s)
3644

3745
// Start listen
3846
irisInstance.Run(iris.Addr(":" + cfg.ListenPort))

handlers/User.go

+9-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,16 @@ func UserLogin(ctx iris.Context) {
2929
}
3030

3131
// Authenticate user
32-
// TODO
32+
user, err := storeService.UserAuth(u)
33+
if err != nil || user == nil {
34+
ctx.StatusCode(iris.StatusForbidden)
35+
ctx.WriteString("invalid username and/or password")
36+
fmt.Printf("Error: %s", err)
37+
return
38+
}
3339

34-
// Remove password from object
40+
// Remove password from object.
41+
// It's not needed anymore.
3542
u.Password = ""
3643

3744
// Setup custom claims
@@ -58,7 +65,6 @@ func UserLogin(ctx iris.Context) {
5865
}
5966
u.JwtExpiry = claims.ExpiresAt
6067
u.Tokenstring = tokenstring
61-
u.DisplayName = "Michel Vocks"
6268

6369
// Return JWT token and display name
6470
ctx.JSON(u)

handlers/handler.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,22 @@ package handlers
22

33
import (
44
"github.com/kataras/iris"
5+
"github.com/michelvocks/gaia/store"
56
)
67

78
const (
89
apiVersion = "v1"
910
)
1011

12+
// storeService is an instance of store.
13+
// Use this to talk to the store.
14+
var storeService *store.Store
15+
1116
// InitHandlers initializes(registers) all handlers
12-
func InitHandlers(i *iris.Application) {
17+
func InitHandlers(i *iris.Application, s *store.Store) {
18+
// Set store instance
19+
storeService = s
20+
1321
// Define prefix
1422
p := "/api/" + apiVersion + "/"
1523

store/store.go

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package store
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
7+
bolt "github.com/coreos/bbolt"
8+
"github.com/michelvocks/gaia"
9+
)
10+
11+
var (
12+
// Name of the bucket where we store user objects
13+
userBucket = []byte("Users")
14+
15+
// Name of the bucket where we store information about pipelines
16+
pipelineBucket = []byte("Pipelines")
17+
)
18+
19+
// Store represents the access type for store
20+
type Store struct {
21+
db *bolt.DB
22+
}
23+
24+
// NewStore creates a new instance of Store.
25+
func NewStore() *Store {
26+
s := &Store{}
27+
28+
return s
29+
}
30+
31+
// UserUpdate takes the given user and saves it
32+
// to the bolt database. User will be overwritten
33+
// if it already exists.
34+
func (s *Store) UserUpdate(u *gaia.User) error {
35+
return s.db.Update(func(tx *bolt.Tx) error {
36+
// Get bucket
37+
b := tx.Bucket(userBucket)
38+
39+
// Marshal user object
40+
m, err := json.Marshal(u)
41+
if err != nil {
42+
return err
43+
}
44+
45+
// Put user
46+
return b.Put([]byte(u.Username), m)
47+
})
48+
}
49+
50+
// UserAuth looks up a user by given username.
51+
// Then it compares passwords and returns user obj if
52+
// given password is valid. Returns nil if password was
53+
// wrong or user not found.
54+
func (s *Store) UserAuth(u *gaia.User) (*gaia.User, error) {
55+
user := &gaia.User{}
56+
err := s.db.View(func(tx *bolt.Tx) error {
57+
// Get bucket
58+
b := tx.Bucket(userBucket)
59+
60+
// Lookup user
61+
userRaw := b.Get([]byte(u.Username))
62+
63+
// User found?
64+
if userRaw == nil {
65+
// Nope. That is not an error so just leave
66+
return nil
67+
}
68+
69+
// Unmarshal
70+
return json.Unmarshal(userRaw, user)
71+
})
72+
73+
// Check if password is valid
74+
if err != nil || u.Password != user.Password {
75+
return nil, err
76+
}
77+
78+
// Return outcome
79+
return user, nil
80+
}
81+
82+
// Init initalizes the connection to the database.
83+
// This should be called only once per database
84+
// because bolt holds a lock on the database file.
85+
func (s *Store) Init(cfg *gaia.Config) error {
86+
db, err := bolt.Open(cfg.Bolt.Path, cfg.Bolt.Mode, nil)
87+
if err != nil {
88+
return err
89+
}
90+
s.db = db
91+
92+
// Create bucket if not exists
93+
var bucketName []byte
94+
c := func(tx *bolt.Tx) error {
95+
_, err := tx.CreateBucketIfNotExists(bucketName)
96+
if err != nil {
97+
return fmt.Errorf("create bucket: %s", err)
98+
}
99+
return nil
100+
}
101+
102+
// Make sure buckets exist
103+
bucketName = userBucket
104+
err = db.Update(c)
105+
if err != nil {
106+
return err
107+
}
108+
bucketName = pipelineBucket
109+
err = db.Update(c)
110+
if err != nil {
111+
return err
112+
}
113+
114+
return nil
115+
}

store/store_test.go

+109
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package store
2+
3+
import (
4+
"os"
5+
"testing"
6+
7+
"github.com/michelvocks/gaia"
8+
)
9+
10+
var store *Store
11+
var config *gaia.Config
12+
13+
func TestMain(m *testing.M) {
14+
store = NewStore()
15+
config = &gaia.Config{}
16+
config.Bolt.Path = "test.db"
17+
config.Bolt.Mode = 0600
18+
19+
os.Exit(m.Run())
20+
}
21+
22+
func TestInit(t *testing.T) {
23+
err := store.Init(config)
24+
if err != nil {
25+
t.Fatal(err)
26+
}
27+
28+
// cleanup
29+
err = os.Remove("test.db")
30+
if err != nil {
31+
t.Fatal(err)
32+
}
33+
}
34+
35+
func TestUserUpdate(t *testing.T) {
36+
err := store.Init(config)
37+
if err != nil {
38+
t.Fatal(err)
39+
}
40+
41+
u := &gaia.User{}
42+
u.Username = "testuser"
43+
u.Password = "12345!#+21+"
44+
u.DisplayName = "Test"
45+
err = store.UserUpdate(u)
46+
if err != nil {
47+
t.Fatal(err)
48+
}
49+
50+
// cleanup
51+
err = os.Remove("test.db")
52+
if err != nil {
53+
t.Fatal(err)
54+
}
55+
}
56+
57+
func TestUserAuth(t *testing.T) {
58+
err := store.Init(config)
59+
if err != nil {
60+
t.Fatal(err)
61+
}
62+
63+
u := &gaia.User{}
64+
u.Username = "testuser"
65+
u.Password = "12345!#+21+"
66+
u.DisplayName = "Test"
67+
err = store.UserUpdate(u)
68+
if err != nil {
69+
t.Fatal(err)
70+
return
71+
}
72+
73+
r, err := store.UserAuth(u)
74+
if err != nil {
75+
t.Fatal(err)
76+
return
77+
}
78+
if r == nil {
79+
t.Fatalf("user not found or password invalid")
80+
}
81+
82+
u = &gaia.User{}
83+
u.Username = "userdoesnotexist"
84+
u.Password = "wrongpassword"
85+
r, err = store.UserAuth(u)
86+
if err != nil {
87+
t.Fatal(err)
88+
}
89+
if r != nil {
90+
t.Fatalf("Expected nil object here. User shouldnt be valid")
91+
}
92+
93+
u = &gaia.User{}
94+
u.Username = "testuser"
95+
u.Password = "wrongpassword"
96+
r, err = store.UserAuth(u)
97+
if err != nil {
98+
t.Fatal(err)
99+
}
100+
if r != nil {
101+
t.Fatalf("Expected nil object here. User shouldnt be valid")
102+
}
103+
104+
// cleanup
105+
err = os.Remove("test.db")
106+
if err != nil {
107+
t.Fatal(err)
108+
}
109+
}

0 commit comments

Comments
 (0)