Authenticate Subsonic API calls using the DB

This commit is contained in:
Deluan
2020-01-20 13:35:59 -05:00
parent 50c7d3800a
commit 99c28731d4
13 changed files with 210 additions and 93 deletions
+58
View File
@@ -0,0 +1,58 @@
package engine
import (
"crypto/md5"
"encoding/hex"
"fmt"
"strings"
"github.com/cloudsonic/sonic-server/log"
"github.com/cloudsonic/sonic-server/model"
)
type Users interface {
Authenticate(username, password, token, salt string) (*model.User, error)
}
func NewUsers(ds model.DataStore) Users {
return &users{ds}
}
type users struct {
ds model.DataStore
}
func (u *users) Authenticate(username, pass, token, salt string) (*model.User, error) {
user, err := u.ds.User().FindByUsername(username)
if err == model.ErrNotFound {
return nil, model.ErrInvalidAuth
}
if err != nil {
return nil, err
}
valid := false
switch {
case pass != "":
if strings.HasPrefix(pass, "enc:") {
if dec, err := hex.DecodeString(pass[4:]); err == nil {
pass = string(dec)
}
}
valid = pass == user.Password
case token != "":
t := fmt.Sprintf("%x", md5.Sum([]byte(user.Password+salt)))
valid = t == token
}
if !valid {
return nil, model.ErrInvalidAuth
}
go func() {
err := u.ds.User().UpdateLastAccessAt(user.ID)
if err != nil {
log.Error("Could not update user's lastAccessAt", "user", user.UserName)
}
}()
return user, nil
}
+52
View File
@@ -0,0 +1,52 @@
package engine
import (
"github.com/cloudsonic/sonic-server/model"
"github.com/cloudsonic/sonic-server/persistence"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
var _ = Describe("Users", func() {
Describe("Authenticate", func() {
var users Users
BeforeEach(func() {
ds := &persistence.MockDataStore{}
users = NewUsers(ds)
})
Context("Plaintext password", func() {
It("authenticates with plaintext password ", func() {
usr, err := users.Authenticate("admin", "wordpass", "", "")
Expect(err).NotTo(HaveOccurred())
Expect(usr).To(Equal(&model.User{UserName: "admin", Password: "wordpass"}))
})
It("fails authentication with wrong password", func() {
_, err := users.Authenticate("admin", "INVALID", "", "")
Expect(err).To(MatchError(model.ErrInvalidAuth))
})
})
Context("Encoded password", func() {
It("authenticates with simple encoded password ", func() {
usr, err := users.Authenticate("admin", "enc:776f726470617373", "", "")
Expect(err).NotTo(HaveOccurred())
Expect(usr).To(Equal(&model.User{UserName: "admin", Password: "wordpass"}))
})
})
Context("Token based authentication", func() {
It("authenticates with token based authentication", func() {
usr, err := users.Authenticate("admin", "", "23b342970e25c7928831c3317edd0b67", "retnlmjetrymazgkt")
Expect(err).NotTo(HaveOccurred())
Expect(usr).To(Equal(&model.User{UserName: "admin", Password: "wordpass"}))
})
It("fails if salt is missing", func() {
_, err := users.Authenticate("admin", "", "23b342970e25c7928831c3317edd0b67", "")
Expect(err).To(MatchError(model.ErrInvalidAuth))
})
})
})
})
+1
View File
@@ -11,4 +11,5 @@ var Set = wire.NewSet(
NewScrobbler,
NewSearch,
NewNowPlayingRepository,
NewUsers,
)