From 68746fd79520f7256c4fb509743c5a38b1464750 Mon Sep 17 00:00:00 2001 From: Eric Chiang Date: Thu, 25 Aug 2016 13:00:53 -0700 Subject: [PATCH] *: add a mock connector which takes a username and password for testing Since we don't have a good strategy which takes a username and password add a mock connector which implementes PasswordConnector so we can develop the frontend screens. --- cmd/dex/config.go | 10 ++++- connector/mock/connectortest.go | 69 ++++++++++++++++++++++++++------- examples/config-dev.yaml | 24 ++++-------- 3 files changed, 69 insertions(+), 34 deletions(-) diff --git a/cmd/dex/config.go b/cmd/dex/config.go index ea764156..c97ebc86 100644 --- a/cmd/dex/config.go +++ b/cmd/dex/config.go @@ -111,9 +111,15 @@ func (c *Connector) UnmarshalYAML(unmarshal func(interface{}) error) error { var err error switch c.Type { - case "mock": + case "mockCallback": var config struct { - Config mock.Config `yaml:"config"` + Config mock.CallbackConfig `yaml:"config"` + } + err = unmarshal(&config) + c.Config = &config.Config + case "mockPassword": + var config struct { + Config mock.PasswordConfig `yaml:"config"` } err = unmarshal(&config) c.Config = &config.Config diff --git a/connector/mock/connectortest.go b/connector/mock/connectortest.go index 71c97d92..0d4b87ba 100644 --- a/connector/mock/connectortest.go +++ b/connector/mock/connectortest.go @@ -1,4 +1,4 @@ -// Package mock implements a mock connector which requires no user interaction. +// Package mock implements connectors which help test various server components. package mock import ( @@ -11,22 +11,24 @@ import ( "github.com/coreos/dex/connector" ) -// New returns a mock connector which requires no user interaction. It always returns +// NewCallbackConnector returns a mock connector which requires no user interaction. It always returns // the same (fake) identity. -func New() connector.Connector { - return mockConnector{} +func NewCallbackConnector() connector.Connector { + return callbackConnector{} } var ( - _ connector.CallbackConnector = mockConnector{} - _ connector.GroupsConnector = mockConnector{} + _ connector.CallbackConnector = callbackConnector{} + _ connector.GroupsConnector = callbackConnector{} + + _ connector.PasswordConnector = passwordConnector{} ) -type mockConnector struct{} +type callbackConnector struct{} -func (m mockConnector) Close() error { return nil } +func (m callbackConnector) Close() error { return nil } -func (m mockConnector) LoginURL(callbackURL, state string) (string, error) { +func (m callbackConnector) LoginURL(callbackURL, state string) (string, error) { u, err := url.Parse(callbackURL) if err != nil { return "", fmt.Errorf("failed to parse callbackURL %q: %v", callbackURL, err) @@ -39,7 +41,7 @@ func (m mockConnector) LoginURL(callbackURL, state string) (string, error) { var connectorData = []byte("foobar") -func (m mockConnector) HandleCallback(r *http.Request) (connector.Identity, string, error) { +func (m callbackConnector) HandleCallback(r *http.Request) (connector.Identity, string, error) { return connector.Identity{ UserID: "0-385-28089-0", Username: "Kilgore Trout", @@ -49,17 +51,54 @@ func (m mockConnector) HandleCallback(r *http.Request) (connector.Identity, stri }, r.URL.Query().Get("state"), nil } -func (m mockConnector) Groups(identity connector.Identity) ([]string, error) { +func (m callbackConnector) Groups(identity connector.Identity) ([]string, error) { if !bytes.Equal(identity.ConnectorData, connectorData) { return nil, errors.New("connector data mismatch") } return []string{"authors"}, nil } -// Config holds the configuration parameters for the mock connector. -type Config struct{} +// CallbackConfig holds the configuration parameters for a connector which requires no interaction. +type CallbackConfig struct{} // Open returns an authentication strategy which requires no user interaction. -func (c *Config) Open() (connector.Connector, error) { - return New(), nil +func (c *CallbackConfig) Open() (connector.Connector, error) { + return NewCallbackConnector(), nil +} + +// PasswordConfig holds the configuration for a mock connector which prompts for the supplied +// username and password. +type PasswordConfig struct { + Username string `yaml:"username"` + Password string `yaml:"password"` +} + +// Open returns an authentication strategy which prompts for a predefined username and password. +func (c *PasswordConfig) Open() (connector.Connector, error) { + if c.Username == "" { + return nil, errors.New("no username supplied") + } + if c.Password == "" { + return nil, errors.New("no password supplied") + } + return &passwordConnector{c.Username, c.Password}, nil +} + +type passwordConnector struct { + username string + password string +} + +func (p passwordConnector) Close() error { return nil } + +func (p passwordConnector) Login(username, password string) (identity connector.Identity, validPassword bool, err error) { + if username == p.username && password == p.password { + return connector.Identity{ + UserID: "0-385-28089-0", + Username: "Kilgore Trout", + Email: "kilgore@kilgore.trout", + EmailVerified: true, + }, true, nil + } + return identity, false, nil } diff --git a/examples/config-dev.yaml b/examples/config-dev.yaml index 65267d31..fa61cc5e 100644 --- a/examples/config-dev.yaml +++ b/examples/config-dev.yaml @@ -7,25 +7,15 @@ web: http: 127.0.0.1:5556 connectors: -- type: mock - id: mock +- type: mockCallback + id: mock-callback name: Mock -- type: github - id: github - name: GitHub +- type: mockPassword + id: mock-password + name: Password config: - clientID: "$GITHUB_CLIENT_ID" - clientSecret: "$GITHUB_CLIENT_SECRET" - redirectURI: http://127.0.0.1:5556/callback/github - org: kubernetes -- type: oidc - id: google - name: Google Account - config: - issuer: https://accounts.google.com - clientID: "$GOOGLE_OAUTH2_CLIENT_ID" - clientSecret: "$GOOGLE_OAUTH2_CLIENT_SECRET" - redirectURI: http://127.0.0.1:5556/callback/google + username: "admin" + password: "PASSWORD" staticClients: - id: example-app