From 221a1ad7a0c419c88ca16673406b7db95c0eb9a6 Mon Sep 17 00:00:00 2001 From: Eric Chiang Date: Tue, 23 Feb 2016 15:36:40 -0800 Subject: [PATCH] user: fix password info JSON encoding to survive round trips PasswordInfos are marshaled when storing them in the database as part of the local connector. However, the custom unmarsheler defined could not unmarshal the standard marshling of this struct. Add a struct tag to the Password field to correct this. Closes #332 --- connector/config_repo_test.go | 2 +- user/password.go | 10 +++++---- user/password_test.go | 39 +++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/connector/config_repo_test.go b/connector/config_repo_test.go index 38ad46f9..6bb98c13 100644 --- a/connector/config_repo_test.go +++ b/connector/config_repo_test.go @@ -61,7 +61,7 @@ func TestNewConnectorConfigFromMap(t *testing.T) { "type": "local", "id": "foo", "passwordInfos": []map[string]string{ - {"userId": "abc", "passwordHash": "PING"}, + {"userId": "abc", "passwordHash": "UElORw=="}, // []byte is base64 encoded when using json.Marshasl {"userId": "271", "passwordPlaintext": "pong"}, }, }, diff --git a/user/password.go b/user/password.go index 6099d1ca..bafaddec 100644 --- a/user/password.go +++ b/user/password.go @@ -53,9 +53,9 @@ func NewPasswordFromPlaintext(plaintext string) (Password, error) { type PasswordInfo struct { UserID string - Password Password + Password Password `json:"passwordHash"` - PasswordExpires time.Time + PasswordExpires time.Time `json:"passwordExpires"` } func (p PasswordInfo) Authenticate(plaintext string) (*oidc.Identity, error) { @@ -86,7 +86,7 @@ type PasswordInfoRepo interface { func (u *PasswordInfo) UnmarshalJSON(data []byte) error { var dec struct { UserID string `json:"userId"` - PasswordHash string `json:"passwordHash"` + PasswordHash []byte `json:"passwordHash"` PasswordPlaintext string `json:"passwordPlaintext"` PasswordExpires time.Time `json:"passwordExpires"` } @@ -98,7 +98,9 @@ func (u *PasswordInfo) UnmarshalJSON(data []byte) error { u.UserID = dec.UserID - u.PasswordExpires = dec.PasswordExpires + if !dec.PasswordExpires.IsZero() { + u.PasswordExpires = dec.PasswordExpires + } if len(dec.PasswordHash) != 0 { if dec.PasswordPlaintext != "" { diff --git a/user/password_test.go b/user/password_test.go index 1625ece7..0f81544f 100644 --- a/user/password_test.go +++ b/user/password_test.go @@ -1,6 +1,7 @@ package user import ( + "encoding/json" "net/url" "testing" "time" @@ -13,6 +14,44 @@ import ( "github.com/coreos/go-oidc/key" ) +func TestPasswordMarshaling(t *testing.T) { + hashPassword := func(s string) []byte { + data, err := DefaultPasswordHasher(s) + if err != nil { + t.Fatalf("Failed to hash password: %v", err) + } + return data + } + + tests := []PasswordInfo{ + { + UserID: "mrpink", + Password: hashPassword("mrpinks-password"), + }, + { + UserID: "mrorange", + Password: hashPassword("mroranges-password"), + PasswordExpires: time.Now().Add(time.Hour), + }, + } + for i, tt := range tests { + data, err := json.Marshal(tt) + if err != nil { + t.Errorf("case %d: failed to marshal password info: %v", i, err) + continue + } + var p PasswordInfo + if err := json.Unmarshal(data, &p); err != nil { + t.Errorf("case %d: failed to unmarshal password info: %v", i, err) + continue + } + if diff := pretty.Compare(tt, p); diff != "" { + t.Errorf("case %d: password info did not survive JSON marshal round trip: %s", i, diff) + } + } + +} + func TestNewPasswordFromHash(t *testing.T) { tests := []string{ "test",