forked from mystiq/dex
Merge pull request #393 from ericchiang/nodb_users
remove passwordInfos from local connector
This commit is contained in:
commit
e6177cf307
8 changed files with 132 additions and 59 deletions
|
@ -60,23 +60,9 @@ func TestNewConnectorConfigFromMap(t *testing.T) {
|
|||
m: map[string]interface{}{
|
||||
"type": "local",
|
||||
"id": "foo",
|
||||
"passwordInfos": []map[string]string{
|
||||
{"userId": "abc", "passwordHash": "UElORw=="}, // []byte is base64 encoded when using json.Marshasl
|
||||
{"userId": "271", "passwordPlaintext": "pong"},
|
||||
},
|
||||
},
|
||||
want: &LocalConnectorConfig{
|
||||
ID: "foo",
|
||||
PasswordInfos: []user.PasswordInfo{
|
||||
user.PasswordInfo{
|
||||
UserID: "abc",
|
||||
Password: user.Password("PING"),
|
||||
},
|
||||
user.PasswordInfo{
|
||||
UserID: "271",
|
||||
Password: user.Password("PONG"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -111,12 +97,6 @@ func TestNewConnectorConfigFromMap(t *testing.T) {
|
|||
|
||||
func TestNewConnectorConfigFromMapFail(t *testing.T) {
|
||||
tests := []map[string]interface{}{
|
||||
// invalid local connector
|
||||
map[string]interface{}{
|
||||
"type": "local",
|
||||
"passwordInfos": "invalid",
|
||||
},
|
||||
|
||||
// no type
|
||||
map[string]interface{}{
|
||||
"id": "bar",
|
||||
|
|
|
@ -21,8 +21,7 @@ func init() {
|
|||
}
|
||||
|
||||
type LocalConnectorConfig struct {
|
||||
ID string `json:"id"`
|
||||
PasswordInfos []user.PasswordInfo `json:"passwordInfos"`
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
func (cfg *LocalConnectorConfig) ConnectorID() string {
|
||||
|
|
|
@ -113,7 +113,7 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
|
|||
}
|
||||
|
||||
cfg := &connector.LocalConnectorConfig{
|
||||
PasswordInfos: []user.PasswordInfo{passwordInfo},
|
||||
ID: "local",
|
||||
}
|
||||
|
||||
ci := oidc.ClientIdentity{
|
||||
|
@ -128,6 +128,10 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("Failed to create client identity repo: " + err.Error())
|
||||
}
|
||||
passwordInfoRepo, err := db.NewPasswordInfoRepoFromPasswordInfos(db.NewMemDB(), []user.PasswordInfo{passwordInfo})
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create password info repo: %v", err)
|
||||
}
|
||||
|
||||
issuerURL := url.URL{Scheme: "http", Host: "server.example.com"}
|
||||
sm := manager.NewSessionManager(db.NewSessionRepo(dbMap), db.NewSessionKeyRepo(dbMap))
|
||||
|
@ -153,7 +157,6 @@ func TestHTTPExchangeTokenRefreshToken(t *testing.T) {
|
|||
t.Fatalf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
passwordInfoRepo := db.NewPasswordInfoRepo(db.NewMemDB())
|
||||
refreshTokenRepo := refreshtest.NewTestRefreshTokenRepo()
|
||||
|
||||
srv := &server.Server{
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -136,7 +137,7 @@ func (cfg *SingleServerConfig) Configure(srv *Server) error {
|
|||
skRepo := db.NewSessionKeyRepo(dbMap)
|
||||
sm := sessionmanager.NewSessionManager(sRepo, skRepo)
|
||||
|
||||
users, err := loadUsers(cfg.UsersFile)
|
||||
users, pwis, err := loadUsers(cfg.UsersFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to read users from file: %v", err)
|
||||
}
|
||||
|
@ -145,7 +146,10 @@ func (cfg *SingleServerConfig) Configure(srv *Server) error {
|
|||
return err
|
||||
}
|
||||
|
||||
pwiRepo := db.NewPasswordInfoRepo(dbMap)
|
||||
pwiRepo, err := db.NewPasswordInfoRepoFromPasswordInfos(dbMap, pwis)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
refTokRepo := db.NewRefreshTokenRepo(dbMap)
|
||||
|
||||
|
@ -163,28 +167,61 @@ func (cfg *SingleServerConfig) Configure(srv *Server) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func loadUsers(filepath string) (users []user.UserWithRemoteIdentities, err error) {
|
||||
// loadUsers parses the user.json file and returns the users to be created.
|
||||
func loadUsers(filepath string) ([]user.UserWithRemoteIdentities, []user.PasswordInfo, error) {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
err = json.NewDecoder(f).Decode(&users)
|
||||
return loadUsersFromReader(f)
|
||||
}
|
||||
|
||||
func loadUsersFromReader(r io.Reader) (users []user.UserWithRemoteIdentities, pwis []user.PasswordInfo, err error) {
|
||||
// Encoding used by the user config file.
|
||||
var configUsers []struct {
|
||||
user.User
|
||||
Password string `json:"password"`
|
||||
RemoteIdentities []user.RemoteIdentity `json:"remoteIdentities"`
|
||||
}
|
||||
if err := json.NewDecoder(r).Decode(&configUsers); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
users = make([]user.UserWithRemoteIdentities, len(configUsers))
|
||||
pwis = make([]user.PasswordInfo, len(configUsers))
|
||||
|
||||
for i, u := range configUsers {
|
||||
users[i] = user.UserWithRemoteIdentities{
|
||||
User: u.User,
|
||||
RemoteIdentities: u.RemoteIdentities,
|
||||
}
|
||||
hashedPassword, err := user.NewPasswordFromPlaintext(u.Password)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pwis[i] = user.PasswordInfo{UserID: u.ID, Password: hashedPassword}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// loadClients parses the clients.json file and returns the clients to be created.
|
||||
func loadClients(filepath string) ([]oidc.ClientIdentity, error) {
|
||||
f, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
return loadClientsFromReader(f)
|
||||
}
|
||||
|
||||
func loadClientsFromReader(r io.Reader) ([]oidc.ClientIdentity, error) {
|
||||
var c []struct {
|
||||
ID string `json:"id"`
|
||||
Secret string `json:"secret"`
|
||||
RedirectURLs []string `json:"redirectURLs"`
|
||||
}
|
||||
if err := json.NewDecoder(f).Decode(&c); err != nil {
|
||||
if err := json.NewDecoder(r).Decode(&c); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
clients := make([]oidc.ClientIdentity, len(c))
|
||||
|
|
78
server/config_test.go
Normal file
78
server/config_test.go
Normal file
|
@ -0,0 +1,78 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/coreos/dex/user"
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
)
|
||||
|
||||
func TestLoadUsers(t *testing.T) {
|
||||
tests := []struct {
|
||||
// The raw JSON file
|
||||
raw string
|
||||
expUsers []user.UserWithRemoteIdentities
|
||||
// userid -> plaintext password
|
||||
expPasswds map[string]string
|
||||
}{
|
||||
{
|
||||
raw: `[
|
||||
{
|
||||
"id": "elroy-id",
|
||||
"email": "elroy77@example.com",
|
||||
"displayName": "Elroy Jonez",
|
||||
"password": "bones",
|
||||
"remoteIdentities": [
|
||||
{
|
||||
"connectorId": "local",
|
||||
"id": "elroy-id"
|
||||
}
|
||||
]
|
||||
}
|
||||
]`,
|
||||
expUsers: []user.UserWithRemoteIdentities{
|
||||
{
|
||||
User: user.User{
|
||||
ID: "elroy-id",
|
||||
Email: "elroy77@example.com",
|
||||
DisplayName: "Elroy Jonez",
|
||||
},
|
||||
RemoteIdentities: []user.RemoteIdentity{
|
||||
{
|
||||
ConnectorID: "local",
|
||||
ID: "elroy-id",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
expPasswds: map[string]string{
|
||||
"elroy-id": "bones",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tt := range tests {
|
||||
users, pwInfos, err := loadUsersFromReader(strings.NewReader(tt.raw))
|
||||
if err != nil {
|
||||
t.Errorf("case %d: failed to load user: %v", i, err)
|
||||
return
|
||||
}
|
||||
|
||||
if diff := pretty.Compare(tt.expUsers, users); diff != "" {
|
||||
t.Errorf("case: %d: wantUsers!=gotUsers: %s", i, diff)
|
||||
}
|
||||
|
||||
// For each password info loaded, verify the password.
|
||||
for _, pwInfo := range pwInfos {
|
||||
expPW, ok := tt.expPasswds[pwInfo.UserID]
|
||||
if !ok {
|
||||
t.Errorf("no password entry for %s", pwInfo.UserID)
|
||||
continue
|
||||
}
|
||||
if _, err := pwInfo.Authenticate(expPW); err != nil {
|
||||
t.Errorf("case %d: user %s's password did not match", i, pwInfo.UserID)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -178,19 +178,6 @@ func (s *Server) AddConnector(cfg connector.ConnectorConfig) error {
|
|||
UserRepo: s.UserRepo,
|
||||
PasswordInfoRepo: s.PasswordInfoRepo,
|
||||
})
|
||||
|
||||
localCfg, ok := cfg.(*connector.LocalConnectorConfig)
|
||||
if !ok {
|
||||
return errors.New("config for LocalConnector not a LocalConnectorConfig?")
|
||||
}
|
||||
|
||||
if len(localCfg.PasswordInfos) > 0 {
|
||||
err := user.LoadPasswordInfos(s.PasswordInfoRepo,
|
||||
localCfg.PasswordInfos)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof("Loaded IdP connector: id=%s type=%s", connectorID, cfg.ConnectorType())
|
||||
|
|
|
@ -1,17 +1,7 @@
|
|||
[
|
||||
{
|
||||
"type": "local",
|
||||
"id": "local",
|
||||
"passwordInfos": [
|
||||
{
|
||||
"userId":"elroy-id",
|
||||
"passwordPlaintext": "bones"
|
||||
},
|
||||
{
|
||||
"userId":"penny",
|
||||
"passwordPlaintext": "kibble"
|
||||
}
|
||||
]
|
||||
"id": "local"
|
||||
},
|
||||
{
|
||||
"type": "oidc",
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
[
|
||||
{
|
||||
"user":{
|
||||
"id": "elroy-id",
|
||||
"email": "elroy77@example.com",
|
||||
"displayName": "Elroy Jonez"
|
||||
},
|
||||
"id": "elroy-id",
|
||||
"email": "elroy77@example.com",
|
||||
"displayName": "Elroy Jonez",
|
||||
"password": "bones",
|
||||
"remoteIdentities": [
|
||||
{
|
||||
"connectorId": "local",
|
||||
|
|
Loading…
Reference in a new issue