OpenID Connect (OIDC) identity and OAuth 2.0 provider with pluggable connectors
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

125 lines
3.9 KiB

// Package mock implements connectors which help test various server components.
package mock
import (
"context"
"errors"
"fmt"
"log/slog"
"net/http"
"net/url"
"github.com/dexidp/dex/connector"
)
// NewCallbackConnector returns a mock connector which requires no user interaction. It always returns
// the same (fake) identity.
func NewCallbackConnector(logger *slog.Logger) connector.Connector {
return &Callback{
Identity: connector.Identity{
UserID: "0-385-28089-0",
Username: "Kilgore Trout",
Email: "kilgore@kilgore.trout",
EmailVerified: true,
Groups: []string{"authors"},
ConnectorData: connectorData,
},
Logger: logger,
}
}
var (
_ connector.CallbackConnector = &Callback{}
_ connector.PasswordConnector = passwordConnector{}
_ connector.RefreshConnector = passwordConnector{}
)
// Callback is a connector that requires no user interaction and always returns the same identity.
type Callback struct {
// The returned identity.
Identity connector.Identity
Logger *slog.Logger
}
// LoginURL returns the URL to redirect the user to login with.
func (m *Callback) LoginURL(s connector.Scopes, callbackURL, state string) (string, []byte, error) {
u, err := url.Parse(callbackURL)
if err != nil {
return "", nil, fmt.Errorf("failed to parse callbackURL %q: %v", callbackURL, err)
}
v := u.Query()
v.Set("state", state)
u.RawQuery = v.Encode()
return u.String(), nil, nil
}
var connectorData = []byte("foobar")
// HandleCallback parses the request and returns the user's identity
func (m *Callback) HandleCallback(s connector.Scopes, connData []byte, r *http.Request) (connector.Identity, error) {
return m.Identity, nil
}
// Refresh updates the identity during a refresh token request.
func (m *Callback) Refresh(ctx context.Context, s connector.Scopes, identity connector.Identity) (connector.Identity, error) {
return m.Identity, nil
}
func (m *Callback) TokenIdentity(ctx context.Context, subjectTokenType, subjectToken string) (connector.Identity, error) {
return m.Identity, nil
}
// 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 *CallbackConfig) Open(id string, logger *slog.Logger) (connector.Connector, error) {
logger = logger.With(slog.Group("connector", "type", "callback", "id", id))
return NewCallbackConnector(logger), nil
}
// PasswordConfig holds the configuration for a mock connector which prompts for the supplied
// username and password.
type PasswordConfig struct {
Username string `json:"username"`
Password string `json:"password"`
}
// Open returns an authentication strategy which prompts for a predefined username and password.
func (c *PasswordConfig) Open(id string, logger *slog.Logger) (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, logger}, nil
}
type passwordConnector struct {
username string
password string
logger *slog.Logger
}
func (p passwordConnector) Close() error { return nil }
func (p passwordConnector) Login(ctx context.Context, s connector.Scopes, 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,
ConnectorData: []byte(`{"test": "true"}`),
}, true, nil
}
return identity, false, nil
}
func (p passwordConnector) Prompt() string { return "" }
func (p passwordConnector) Refresh(_ context.Context, _ connector.Scopes, identity connector.Identity) (connector.Identity, error) {
return identity, nil
}