mirror of
https://github.com/netbirdio/dex.git
synced 2026-05-22 18:43:53 -07:00
Merge pull request #723 from rithujohn191/support-leveled-logging
cmd/dex: add logging config and launch logger for server module.
This commit is contained in:
+13
-2
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/dex/connector"
|
||||
"github.com/coreos/dex/connector/github"
|
||||
"github.com/coreos/dex/connector/ldap"
|
||||
@@ -29,6 +30,7 @@ type Config struct {
|
||||
OAuth2 OAuth2 `json:"oauth2"`
|
||||
GRPC GRPC `json:"grpc"`
|
||||
Expiry Expiry `json:"expiry"`
|
||||
Logger Logger `json:"logger"`
|
||||
|
||||
Frontend server.WebConfig `json:"frontend"`
|
||||
|
||||
@@ -119,7 +121,7 @@ type Storage struct {
|
||||
|
||||
// StorageConfig is a configuration that can create a storage.
|
||||
type StorageConfig interface {
|
||||
Open() (storage.Storage, error)
|
||||
Open(logrus.FieldLogger) (storage.Storage, error)
|
||||
}
|
||||
|
||||
var storages = map[string]func() StorageConfig{
|
||||
@@ -170,7 +172,7 @@ type Connector struct {
|
||||
|
||||
// ConnectorConfig is a configuration that can open a connector.
|
||||
type ConnectorConfig interface {
|
||||
Open() (connector.Connector, error)
|
||||
Open(logrus.FieldLogger) (connector.Connector, error)
|
||||
}
|
||||
|
||||
var connectors = map[string]func() ConnectorConfig{
|
||||
@@ -223,3 +225,12 @@ type Expiry struct {
|
||||
// IdTokens defines the duration of time for which the IdTokens will be valid.
|
||||
IDTokens string `json:"idTokens"`
|
||||
}
|
||||
|
||||
// Logger holds configuration required to customize logging for dex.
|
||||
type Logger struct {
|
||||
// Level sets logging level severity.
|
||||
Level string `json:"level"`
|
||||
|
||||
// Format specifies the format to be used for logging.
|
||||
Format string `json:"format"`
|
||||
}
|
||||
|
||||
@@ -59,6 +59,10 @@ staticPasswords:
|
||||
expiry:
|
||||
signingKeys: "6h"
|
||||
idTokens: "24h"
|
||||
|
||||
logger:
|
||||
level: "debug"
|
||||
format: "json"
|
||||
`)
|
||||
|
||||
want := Config{
|
||||
@@ -120,6 +124,10 @@ expiry:
|
||||
SigningKeys: "6h",
|
||||
IDTokens: "24h",
|
||||
},
|
||||
Logger: Logger{
|
||||
Level: "debug",
|
||||
Format: "json",
|
||||
},
|
||||
}
|
||||
|
||||
var c Config
|
||||
|
||||
+43
-7
@@ -6,11 +6,13 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/net/context"
|
||||
@@ -111,6 +113,8 @@ func serve(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
logger, _ := newLogger(c.Logger.Level, c.Logger.Format)
|
||||
|
||||
connectors := make([]server.Connector, len(c.Connectors))
|
||||
for i, conn := range c.Connectors {
|
||||
if conn.ID == "" {
|
||||
@@ -119,7 +123,8 @@ func serve(cmd *cobra.Command, args []string) error {
|
||||
if conn.Config == nil {
|
||||
return fmt.Errorf("no config field for connector %q", conn.ID)
|
||||
}
|
||||
c, err := conn.Config.Open()
|
||||
connectorLogger := logger.WithField("connector", conn.Name)
|
||||
c, err := conn.Config.Open(connectorLogger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open %s: %v", conn.ID, err)
|
||||
}
|
||||
@@ -130,7 +135,7 @@ func serve(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
}
|
||||
|
||||
s, err := c.Storage.Config.Open()
|
||||
s, err := c.Storage.Config.Open(logger)
|
||||
if err != nil {
|
||||
return fmt.Errorf("initializing storage: %v", err)
|
||||
}
|
||||
@@ -153,6 +158,7 @@ func serve(cmd *cobra.Command, args []string) error {
|
||||
Storage: s,
|
||||
Web: c.Frontend,
|
||||
EnablePasswordDB: c.EnablePasswordDB,
|
||||
Logger: logger,
|
||||
}
|
||||
if c.Expiry.SigningKeys != "" {
|
||||
signingKeys, err := time.ParseDuration(c.Expiry.SigningKeys)
|
||||
@@ -175,19 +181,19 @@ func serve(cmd *cobra.Command, args []string) error {
|
||||
}
|
||||
errc := make(chan error, 3)
|
||||
if c.Web.HTTP != "" {
|
||||
log.Printf("listening (http) on %s", c.Web.HTTP)
|
||||
logger.Errorf("listening (http) on %s", c.Web.HTTP)
|
||||
go func() {
|
||||
errc <- http.ListenAndServe(c.Web.HTTP, serv)
|
||||
}()
|
||||
}
|
||||
if c.Web.HTTPS != "" {
|
||||
log.Printf("listening (https) on %s", c.Web.HTTPS)
|
||||
logger.Errorf("listening (https) on %s", c.Web.HTTPS)
|
||||
go func() {
|
||||
errc <- http.ListenAndServeTLS(c.Web.HTTPS, c.Web.TLSCert, c.Web.TLSKey, serv)
|
||||
}()
|
||||
}
|
||||
if c.GRPC.Addr != "" {
|
||||
log.Printf("listening (grpc) on %s", c.GRPC.Addr)
|
||||
logger.Errorf("listening (grpc) on %s", c.GRPC.Addr)
|
||||
go func() {
|
||||
errc <- func() error {
|
||||
list, err := net.Listen("tcp", c.GRPC.Addr)
|
||||
@@ -195,7 +201,7 @@ func serve(cmd *cobra.Command, args []string) error {
|
||||
return fmt.Errorf("listen grpc: %v", err)
|
||||
}
|
||||
s := grpc.NewServer(grpcOptions...)
|
||||
api.RegisterDexServer(s, server.NewAPI(serverConfig.Storage))
|
||||
api.RegisterDexServer(s, server.NewAPI(serverConfig.Storage, logger))
|
||||
return s.Serve(list)
|
||||
}()
|
||||
}()
|
||||
@@ -203,3 +209,33 @@ func serve(cmd *cobra.Command, args []string) error {
|
||||
|
||||
return <-errc
|
||||
}
|
||||
|
||||
func newLogger(level string, format string) (logrus.FieldLogger, error) {
|
||||
var logLevel logrus.Level
|
||||
switch strings.ToLower(level) {
|
||||
case "debug":
|
||||
logLevel = logrus.DebugLevel
|
||||
case "", "info":
|
||||
logLevel = logrus.InfoLevel
|
||||
case "error":
|
||||
logLevel = logrus.ErrorLevel
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported logLevel: %s", level)
|
||||
}
|
||||
|
||||
var formatter logrus.Formatter
|
||||
switch strings.ToLower(format) {
|
||||
case "", "text":
|
||||
formatter = &logrus.TextFormatter{DisableColors: true}
|
||||
case "json":
|
||||
formatter = &logrus.JSONFormatter{}
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported logger format: %s", format)
|
||||
}
|
||||
|
||||
return &logrus.Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: formatter,
|
||||
Level: logLevel,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/github"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/dex/connector"
|
||||
)
|
||||
|
||||
@@ -31,12 +32,13 @@ type Config struct {
|
||||
}
|
||||
|
||||
// Open returns a strategy for logging in through GitHub.
|
||||
func (c *Config) Open() (connector.Connector, error) {
|
||||
func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
|
||||
return &githubConnector{
|
||||
redirectURI: c.RedirectURI,
|
||||
org: c.Org,
|
||||
clientID: c.ClientID,
|
||||
clientSecret: c.ClientSecret,
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -55,6 +57,7 @@ type githubConnector struct {
|
||||
org string
|
||||
clientID string
|
||||
clientSecret string
|
||||
logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
func (c *githubConnector) oauth2Config(scopes connector.Scopes) *oauth2.Config {
|
||||
|
||||
+10
-8
@@ -7,12 +7,12 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"gopkg.in/ldap.v2"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/dex/connector"
|
||||
)
|
||||
|
||||
@@ -135,8 +135,8 @@ func parseScope(s string) (int, bool) {
|
||||
}
|
||||
|
||||
// Open returns an authentication strategy using LDAP.
|
||||
func (c *Config) Open() (connector.Connector, error) {
|
||||
conn, err := c.OpenConnector()
|
||||
func (c *Config) Open(logger logrus.FieldLogger) (connector.Connector, error) {
|
||||
conn, err := c.OpenConnector(logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -149,7 +149,7 @@ type refreshData struct {
|
||||
}
|
||||
|
||||
// OpenConnector is the same as Open but returns a type with all implemented connector interfaces.
|
||||
func (c *Config) OpenConnector() (interface {
|
||||
func (c *Config) OpenConnector(logger logrus.FieldLogger) (interface {
|
||||
connector.Connector
|
||||
connector.PasswordConnector
|
||||
connector.RefreshConnector
|
||||
@@ -206,7 +206,7 @@ func (c *Config) OpenConnector() (interface {
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("userSearch.Scope unknown value %q", c.GroupSearch.Scope)
|
||||
}
|
||||
return &ldapConnector{*c, userSearchScope, groupSearchScope, tlsConfig}, nil
|
||||
return &ldapConnector{*c, userSearchScope, groupSearchScope, tlsConfig, logger}, nil
|
||||
}
|
||||
|
||||
type ldapConnector struct {
|
||||
@@ -216,6 +216,8 @@ type ldapConnector struct {
|
||||
groupSearchScope int
|
||||
|
||||
tlsConfig *tls.Config
|
||||
|
||||
logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -325,7 +327,7 @@ func (c *ldapConnector) userEntry(conn *ldap.Conn, username string) (user ldap.E
|
||||
|
||||
switch n := len(resp.Entries); n {
|
||||
case 0:
|
||||
log.Printf("ldap: no results returned for filter: %q", filter)
|
||||
c.logger.Errorf("ldap: no results returned for filter: %q", filter)
|
||||
return ldap.Entry{}, false, nil
|
||||
case 1:
|
||||
return *resp.Entries[0], true, nil
|
||||
@@ -358,7 +360,7 @@ func (c *ldapConnector) Login(ctx context.Context, s connector.Scopes, username,
|
||||
// Detect a bad password through the LDAP error code.
|
||||
if ldapErr, ok := err.(*ldap.Error); ok {
|
||||
if ldapErr.ResultCode == ldap.LDAPResultInvalidCredentials {
|
||||
log.Printf("ldap: invalid password for user %q", user.DN)
|
||||
c.logger.Errorf("ldap: invalid password for user %q", user.DN)
|
||||
incorrectPass = true
|
||||
return nil
|
||||
}
|
||||
@@ -468,7 +470,7 @@ func (c *ldapConnector) groups(ctx context.Context, user ldap.Entry) ([]string,
|
||||
}
|
||||
if len(groups) == 0 {
|
||||
// TODO(ericchiang): Is this going to spam the logs?
|
||||
log.Printf("ldap: groups search with filter %q returned no groups", filter)
|
||||
c.logger.Errorf("ldap: groups search with filter %q returned no groups", filter)
|
||||
}
|
||||
|
||||
var groupNames []string
|
||||
|
||||
@@ -9,12 +9,13 @@ import (
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/dex/connector"
|
||||
)
|
||||
|
||||
// NewCallbackConnector returns a mock connector which requires no user interaction. It always returns
|
||||
// the same (fake) identity.
|
||||
func NewCallbackConnector() connector.Connector {
|
||||
func NewCallbackConnector(logger logrus.FieldLogger) connector.Connector {
|
||||
return &Callback{
|
||||
Identity: connector.Identity{
|
||||
UserID: "0-385-28089-0",
|
||||
@@ -24,6 +25,7 @@ func NewCallbackConnector() connector.Connector {
|
||||
Groups: []string{"authors"},
|
||||
ConnectorData: connectorData,
|
||||
},
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +39,7 @@ var (
|
||||
type Callback struct {
|
||||
// The returned identity.
|
||||
Identity connector.Identity
|
||||
Logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
// LoginURL returns the URL to redirect the user to login with.
|
||||
@@ -67,8 +70,8 @@ func (m *Callback) Refresh(ctx context.Context, s connector.Scopes, identity con
|
||||
type CallbackConfig struct{}
|
||||
|
||||
// Open returns an authentication strategy which requires no user interaction.
|
||||
func (c *CallbackConfig) Open() (connector.Connector, error) {
|
||||
return NewCallbackConnector(), nil
|
||||
func (c *CallbackConfig) Open(logger logrus.FieldLogger) (connector.Connector, error) {
|
||||
return NewCallbackConnector(logger), nil
|
||||
}
|
||||
|
||||
// PasswordConfig holds the configuration for a mock connector which prompts for the supplied
|
||||
@@ -79,19 +82,20 @@ type PasswordConfig struct {
|
||||
}
|
||||
|
||||
// Open returns an authentication strategy which prompts for a predefined username and password.
|
||||
func (c *PasswordConfig) Open() (connector.Connector, error) {
|
||||
func (c *PasswordConfig) Open(logger logrus.FieldLogger) (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
|
||||
return &passwordConnector{c.Username, c.Password, logger}, nil
|
||||
}
|
||||
|
||||
type passwordConnector struct {
|
||||
username string
|
||||
password string
|
||||
logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
func (p passwordConnector) Close() error { return nil }
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/go-oidc"
|
||||
"golang.org/x/net/context"
|
||||
"golang.org/x/oauth2"
|
||||
@@ -25,7 +26,7 @@ type Config struct {
|
||||
|
||||
// Open returns a connector which can be used to login users through an upstream
|
||||
// OpenID Connect provider.
|
||||
func (c *Config) Open() (conn connector.Connector, err error) {
|
||||
func (c *Config) Open(logger logrus.FieldLogger) (conn connector.Connector, err error) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
provider, err := oidc.NewProvider(ctx, c.Issuer)
|
||||
@@ -55,6 +56,7 @@ func (c *Config) Open() (conn connector.Connector, err error) {
|
||||
oidc.VerifyExpiry(),
|
||||
oidc.VerifyAudience(clientID),
|
||||
),
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -68,6 +70,7 @@ type oidcConnector struct {
|
||||
verifier *oidc.IDTokenVerifier
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
func (c *oidcConnector) Close() error {
|
||||
|
||||
Generated
+8
-2
@@ -1,5 +1,5 @@
|
||||
hash: 2d3cc27484f672337349fffc8d7839462df7b1fbedc9200ae0a87a84afeed896
|
||||
updated: 2016-12-07T13:06:21.940111139-08:00
|
||||
hash: 723f2faad8f09a97ffb5ce647705b8ee41dbf2f81f91488c60f23d102789a23b
|
||||
updated: 2016-12-08T11:11:10.172119799-08:00
|
||||
imports:
|
||||
- name: github.com/cockroachdb/cockroach-go
|
||||
version: 31611c0501c812f437d4861d87d117053967c955
|
||||
@@ -39,6 +39,8 @@ imports:
|
||||
version: c97913dcbd76de40b051a9b4cd827f7eaeb7a868
|
||||
subpackages:
|
||||
- cacheobject
|
||||
- name: github.com/Sirupsen/logrus
|
||||
version: d26492970760ca5d33129d2d799e34be5c4782eb
|
||||
- name: github.com/spf13/cobra
|
||||
version: bc81c21bd0d8be5ba2d6630a505d79d4467566e7
|
||||
- name: github.com/spf13/pflag
|
||||
@@ -63,6 +65,10 @@ imports:
|
||||
subpackages:
|
||||
- github
|
||||
- internal
|
||||
- name: golang.org/x/sys
|
||||
version: 833a04a10549a95dc34458c195cbad61bbb6cb4d
|
||||
subpackages:
|
||||
- unix
|
||||
- name: google.golang.org/appengine
|
||||
version: 267c27e7492265b84fc6719503b14a1e17975d79
|
||||
subpackages:
|
||||
|
||||
@@ -123,3 +123,9 @@ import:
|
||||
subpackages:
|
||||
- proto
|
||||
- protoc-gen-go
|
||||
|
||||
# Structured logging
|
||||
- package: github.com/Sirupsen/logrus
|
||||
version: v0.11.0
|
||||
- package: golang.org/x/sys/unix
|
||||
version: 833a04a10549a95dc34458c195cbad61bbb6cb4d
|
||||
|
||||
+14
-10
@@ -3,11 +3,11 @@ package server
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/dex/api"
|
||||
"github.com/coreos/dex/storage"
|
||||
"github.com/coreos/dex/version"
|
||||
@@ -18,12 +18,16 @@ import (
|
||||
const apiVersion = 0
|
||||
|
||||
// NewAPI returns a server which implements the gRPC API interface.
|
||||
func NewAPI(s storage.Storage) api.DexServer {
|
||||
return dexAPI{s: s}
|
||||
func NewAPI(s storage.Storage, logger logrus.FieldLogger) api.DexServer {
|
||||
return dexAPI{
|
||||
s: s,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
type dexAPI struct {
|
||||
s storage.Storage
|
||||
s storage.Storage
|
||||
logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
func (d dexAPI) CreateClient(ctx context.Context, req *api.CreateClientReq) (*api.CreateClientResp, error) {
|
||||
@@ -48,7 +52,7 @@ func (d dexAPI) CreateClient(ctx context.Context, req *api.CreateClientReq) (*ap
|
||||
LogoURL: req.Client.LogoUrl,
|
||||
}
|
||||
if err := d.s.CreateClient(c); err != nil {
|
||||
log.Printf("api: failed to create client: %v", err)
|
||||
d.logger.Errorf("api: failed to create client: %v", err)
|
||||
// TODO(ericchiang): Surface "already exists" errors.
|
||||
return nil, fmt.Errorf("create client: %v", err)
|
||||
}
|
||||
@@ -64,7 +68,7 @@ func (d dexAPI) DeleteClient(ctx context.Context, req *api.DeleteClientReq) (*ap
|
||||
if err == storage.ErrNotFound {
|
||||
return &api.DeleteClientResp{NotFound: true}, nil
|
||||
}
|
||||
log.Printf("api: failed to delete client: %v", err)
|
||||
d.logger.Errorf("api: failed to delete client: %v", err)
|
||||
return nil, fmt.Errorf("delete client: %v", err)
|
||||
}
|
||||
return &api.DeleteClientResp{}, nil
|
||||
@@ -104,7 +108,7 @@ func (d dexAPI) CreatePassword(ctx context.Context, req *api.CreatePasswordReq)
|
||||
UserID: req.Password.UserId,
|
||||
}
|
||||
if err := d.s.CreatePassword(p); err != nil {
|
||||
log.Printf("api: failed to create password: %v", err)
|
||||
d.logger.Errorf("api: failed to create password: %v", err)
|
||||
return nil, fmt.Errorf("create password: %v", err)
|
||||
}
|
||||
|
||||
@@ -141,7 +145,7 @@ func (d dexAPI) UpdatePassword(ctx context.Context, req *api.UpdatePasswordReq)
|
||||
if err == storage.ErrNotFound {
|
||||
return &api.UpdatePasswordResp{NotFound: true}, nil
|
||||
}
|
||||
log.Printf("api: failed to update password: %v", err)
|
||||
d.logger.Errorf("api: failed to update password: %v", err)
|
||||
return nil, fmt.Errorf("update password: %v", err)
|
||||
}
|
||||
|
||||
@@ -158,7 +162,7 @@ func (d dexAPI) DeletePassword(ctx context.Context, req *api.DeletePasswordReq)
|
||||
if err == storage.ErrNotFound {
|
||||
return &api.DeletePasswordResp{NotFound: true}, nil
|
||||
}
|
||||
log.Printf("api: failed to delete password: %v", err)
|
||||
d.logger.Errorf("api: failed to delete password: %v", err)
|
||||
return nil, fmt.Errorf("delete password: %v", err)
|
||||
}
|
||||
return &api.DeletePasswordResp{}, nil
|
||||
@@ -175,7 +179,7 @@ func (d dexAPI) GetVersion(ctx context.Context, req *api.VersionReq) (*api.Versi
|
||||
func (d dexAPI) ListPasswords(ctx context.Context, req *api.ListPasswordReq) (*api.ListPasswordResp, error) {
|
||||
passwordList, err := d.s.ListPasswords()
|
||||
if err != nil {
|
||||
log.Printf("api: failed to list passwords: %v", err)
|
||||
d.logger.Errorf("api: failed to list passwords: %v", err)
|
||||
return nil, fmt.Errorf("list passwords: %v", err)
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -2,16 +2,24 @@ package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/dex/api"
|
||||
"github.com/coreos/dex/storage/memory"
|
||||
)
|
||||
|
||||
// Attempts to create, update and delete a test Password
|
||||
func TestPassword(t *testing.T) {
|
||||
s := memory.New()
|
||||
serv := NewAPI(s)
|
||||
logger := &logrus.Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: &logrus.TextFormatter{DisableColors: true},
|
||||
Level: logrus.DebugLevel,
|
||||
}
|
||||
|
||||
s := memory.New(logger)
|
||||
serv := NewAPI(s, logger)
|
||||
|
||||
ctx := context.Background()
|
||||
p := api.Password{
|
||||
|
||||
+83
-68
@@ -3,7 +3,6 @@ package server
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
@@ -42,7 +41,7 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
t := s.now().Sub(start)
|
||||
if err != nil {
|
||||
log.Printf("Storage health check failed: %v", err)
|
||||
s.logger.Errorf("Storage health check failed: %v", err)
|
||||
http.Error(w, "Health check failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -53,13 +52,13 @@ func (s *Server) handlePublicKeys(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO(ericchiang): Cache this.
|
||||
keys, err := s.storage.GetKeys()
|
||||
if err != nil {
|
||||
log.Printf("failed to get keys: %v", err)
|
||||
s.logger.Errorf("failed to get keys: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if keys.SigningKeyPub == nil {
|
||||
log.Printf("No public keys found.")
|
||||
s.logger.Errorf("No public keys found.")
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -74,7 +73,7 @@ func (s *Server) handlePublicKeys(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
data, err := json.MarshalIndent(jwks, "", " ")
|
||||
if err != nil {
|
||||
log.Printf("failed to marshal discovery data: %v", err)
|
||||
s.logger.Errorf("failed to marshal discovery data: %v", err)
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
@@ -137,14 +136,14 @@ func (s *Server) discoveryHandler() (http.HandlerFunc, error) {
|
||||
|
||||
// handleAuthorization handles the OAuth2 auth endpoint.
|
||||
func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) {
|
||||
authReq, err := parseAuthorizationRequest(s.storage, s.supportedResponseTypes, r)
|
||||
authReq, err := s.parseAuthorizationRequest(s.supportedResponseTypes, r)
|
||||
if err != nil {
|
||||
s.renderError(w, http.StatusInternalServerError, err.Type, err.Description)
|
||||
return
|
||||
}
|
||||
authReq.Expiry = s.now().Add(time.Minute * 30)
|
||||
if err := s.storage.CreateAuthRequest(authReq); err != nil {
|
||||
log.Printf("Failed to create authorization request: %v", err)
|
||||
s.logger.Errorf("Failed to create authorization request: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
return
|
||||
}
|
||||
@@ -166,7 +165,9 @@ func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) {
|
||||
i++
|
||||
}
|
||||
|
||||
s.templates.login(w, connectorInfos, authReq.ID)
|
||||
if err := s.templates.login(w, connectorInfos, authReq.ID); err != nil {
|
||||
s.logger.Errorf("Server template error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -181,8 +182,8 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
authReq, err := s.storage.GetAuthRequest(authReqID)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get auth request: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
s.logger.Errorf("Failed to get auth request: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
|
||||
return
|
||||
}
|
||||
scopes := parseScopes(authReq.Scopes)
|
||||
@@ -195,8 +196,8 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
|
||||
return a, nil
|
||||
}
|
||||
if err := s.storage.UpdateAuthRequest(authReqID, updater); err != nil {
|
||||
log.Printf("Failed to set connector ID on auth request: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
s.logger.Errorf("Failed to set connector ID on auth request: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -207,13 +208,15 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO(ericchiang): Is this appropriate or should we also be using a nonce?
|
||||
callbackURL, err := conn.LoginURL(scopes, s.absURL("/callback"), authReqID)
|
||||
if err != nil {
|
||||
log.Printf("Connector %q returned error when creating callback: %v", connID, err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
s.logger.Errorf("Connector %q returned error when creating callback: %v", connID, err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
|
||||
return
|
||||
}
|
||||
http.Redirect(w, r, callbackURL, http.StatusFound)
|
||||
case connector.PasswordConnector:
|
||||
s.templates.password(w, authReqID, r.URL.String(), "", false)
|
||||
if err := s.templates.password(w, authReqID, r.URL.String(), "", false); err != nil {
|
||||
s.logger.Errorf("Server template error: %v", err)
|
||||
}
|
||||
default:
|
||||
s.notFound(w, r)
|
||||
}
|
||||
@@ -229,18 +232,20 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
identity, ok, err := passwordConnector.Login(r.Context(), scopes, username, password)
|
||||
if err != nil {
|
||||
log.Printf("Failed to login user: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
s.logger.Errorf("Failed to login user: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
s.templates.password(w, authReqID, r.URL.String(), username, true)
|
||||
if err := s.templates.password(w, authReqID, r.URL.String(), username, true); err != nil {
|
||||
s.logger.Errorf("Server template error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
redirectURL, err := s.finalizeLogin(identity, authReq, conn.Connector)
|
||||
if err != nil {
|
||||
log.Printf("Failed to finalize login: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
s.logger.Errorf("Failed to finalize login: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -260,17 +265,17 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request)
|
||||
// Section: "3.4.3 RelayState"
|
||||
state := r.URL.Query().Get("state")
|
||||
if state == "" {
|
||||
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "no 'state' parameter provided")
|
||||
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "No 'state' parameter provided.")
|
||||
return
|
||||
}
|
||||
|
||||
authReq, err := s.storage.GetAuthRequest(state)
|
||||
if err != nil {
|
||||
if err == storage.ErrNotFound {
|
||||
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "invalid 'state' parameter provided")
|
||||
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "Invalid 'state' parameter provided.")
|
||||
return
|
||||
}
|
||||
log.Printf("Failed to get auth request: %v", err)
|
||||
s.logger.Errorf("Failed to get auth request: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
return
|
||||
}
|
||||
@@ -288,14 +293,14 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
identity, err := callbackConnector.HandleCallback(parseScopes(authReq.Scopes), r)
|
||||
if err != nil {
|
||||
log.Printf("Failed to authenticate: %v", err)
|
||||
s.logger.Errorf("Failed to authenticate: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
return
|
||||
}
|
||||
|
||||
redirectURL, err := s.finalizeLogin(identity, authReq, conn.Connector)
|
||||
if err != nil {
|
||||
log.Printf("Failed to finalize login: %v", err)
|
||||
s.logger.Errorf("Failed to finalize login: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
return
|
||||
}
|
||||
@@ -327,12 +332,12 @@ func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.Auth
|
||||
func (s *Server) handleApproval(w http.ResponseWriter, r *http.Request) {
|
||||
authReq, err := s.storage.GetAuthRequest(r.FormValue("req"))
|
||||
if err != nil {
|
||||
log.Printf("Failed to get auth request: %v", err)
|
||||
s.logger.Errorf("Failed to get auth request: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
return
|
||||
}
|
||||
if !authReq.LoggedIn {
|
||||
log.Printf("Auth request does not have an identity for approval")
|
||||
s.logger.Errorf("Auth request does not have an identity for approval")
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
return
|
||||
}
|
||||
@@ -345,11 +350,13 @@ func (s *Server) handleApproval(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
client, err := s.storage.GetClient(authReq.ClientID)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get client %q: %v", authReq.ClientID, err)
|
||||
s.logger.Errorf("Failed to get client %q: %v", authReq.ClientID, err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
return
|
||||
}
|
||||
s.templates.approval(w, authReq.ID, authReq.Claims.Username, client.Name, authReq.Scopes)
|
||||
if err := s.templates.approval(w, authReq.ID, authReq.Claims.Username, client.Name, authReq.Scopes); err != nil {
|
||||
s.logger.Errorf("Server template error: %v", err)
|
||||
}
|
||||
case "POST":
|
||||
if r.FormValue("approval") != "approve" {
|
||||
s.renderError(w, http.StatusInternalServerError, "approval rejected", "")
|
||||
@@ -367,7 +374,7 @@ func (s *Server) sendCodeResponse(w http.ResponseWriter, r *http.Request, authRe
|
||||
|
||||
if err := s.storage.DeleteAuthRequest(authReq.ID); err != nil {
|
||||
if err != storage.ErrNotFound {
|
||||
log.Printf("Failed to delete authorization request: %v", err)
|
||||
s.logger.Errorf("Failed to delete authorization request: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
} else {
|
||||
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "Authorization request has already been completed.")
|
||||
@@ -396,21 +403,23 @@ func (s *Server) sendCodeResponse(w http.ResponseWriter, r *http.Request, authRe
|
||||
ConnectorData: authReq.ConnectorData,
|
||||
}
|
||||
if err := s.storage.CreateAuthCode(code); err != nil {
|
||||
log.Printf("Failed to create auth code: %v", err)
|
||||
s.logger.Errorf("Failed to create auth code: %v", err)
|
||||
s.renderError(w, http.StatusInternalServerError, errServerError, "")
|
||||
return
|
||||
}
|
||||
|
||||
if authReq.RedirectURI == redirectURIOOB {
|
||||
s.templates.oob(w, code.ID)
|
||||
if err := s.templates.oob(w, code.ID); err != nil {
|
||||
s.logger.Errorf("Server template error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
q.Set("code", code.ID)
|
||||
case responseTypeToken:
|
||||
idToken, expiry, err := s.newIDToken(authReq.ClientID, authReq.Claims, authReq.Scopes, authReq.Nonce)
|
||||
if err != nil {
|
||||
log.Printf("failed to create ID token: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to create ID token: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
v := url.Values{}
|
||||
@@ -433,11 +442,11 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
|
||||
if ok {
|
||||
var err error
|
||||
if clientID, err = url.QueryUnescape(clientID); err != nil {
|
||||
tokenErr(w, errInvalidRequest, "client_id improperly encoded", http.StatusBadRequest)
|
||||
s.tokenErrHelper(w, errInvalidRequest, "client_id improperly encoded", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if clientSecret, err = url.QueryUnescape(clientSecret); err != nil {
|
||||
tokenErr(w, errInvalidRequest, "client_secret improperly encoded", http.StatusBadRequest)
|
||||
s.tokenErrHelper(w, errInvalidRequest, "client_secret improperly encoded", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
@@ -448,15 +457,15 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
|
||||
client, err := s.storage.GetClient(clientID)
|
||||
if err != nil {
|
||||
if err != storage.ErrNotFound {
|
||||
log.Printf("failed to get client: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to get client: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
} else {
|
||||
tokenErr(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized)
|
||||
s.tokenErrHelper(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized)
|
||||
}
|
||||
return
|
||||
}
|
||||
if client.Secret != clientSecret {
|
||||
tokenErr(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized)
|
||||
s.tokenErrHelper(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -467,7 +476,7 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
|
||||
case grantTypeRefreshToken:
|
||||
s.handleRefreshToken(w, r, client)
|
||||
default:
|
||||
tokenErr(w, errInvalidGrant, "", http.StatusBadRequest)
|
||||
s.tokenErrHelper(w, errInvalidGrant, "", http.StatusBadRequest)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,29 +488,29 @@ func (s *Server) handleAuthCode(w http.ResponseWriter, r *http.Request, client s
|
||||
authCode, err := s.storage.GetAuthCode(code)
|
||||
if err != nil || s.now().After(authCode.Expiry) || authCode.ClientID != client.ID {
|
||||
if err != storage.ErrNotFound {
|
||||
log.Printf("failed to get auth code: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to get auth code: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
} else {
|
||||
tokenErr(w, errInvalidRequest, "Invalid or expired code parameter.", http.StatusBadRequest)
|
||||
s.tokenErrHelper(w, errInvalidRequest, "Invalid or expired code parameter.", http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if authCode.RedirectURI != redirectURI {
|
||||
tokenErr(w, errInvalidRequest, "redirect_uri did not match URI from initial request.", http.StatusBadRequest)
|
||||
s.tokenErrHelper(w, errInvalidRequest, "redirect_uri did not match URI from initial request.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
idToken, expiry, err := s.newIDToken(client.ID, authCode.Claims, authCode.Scopes, authCode.Nonce)
|
||||
if err != nil {
|
||||
log.Printf("failed to create ID token: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to create ID token: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := s.storage.DeleteAuthCode(code); err != nil {
|
||||
log.Printf("failed to delete auth code: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to delete auth code: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -525,8 +534,8 @@ func (s *Server) handleAuthCode(w http.ResponseWriter, r *http.Request, client s
|
||||
ConnectorData: authCode.ConnectorData,
|
||||
}
|
||||
if err := s.storage.CreateRefresh(refresh); err != nil {
|
||||
log.Printf("failed to create refresh token: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to create refresh token: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
refreshToken = refresh.RefreshToken
|
||||
@@ -539,17 +548,17 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
||||
code := r.PostFormValue("refresh_token")
|
||||
scope := r.PostFormValue("scope")
|
||||
if code == "" {
|
||||
tokenErr(w, errInvalidRequest, "No refresh token in request.", http.StatusBadRequest)
|
||||
s.tokenErrHelper(w, errInvalidRequest, "No refresh token in request.", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
refresh, err := s.storage.GetRefresh(code)
|
||||
if err != nil || refresh.ClientID != client.ID {
|
||||
if err != storage.ErrNotFound {
|
||||
log.Printf("failed to get auth code: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to get auth code: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
} else {
|
||||
tokenErr(w, errInvalidRequest, "Refresh token is invalid or has already been claimed by another client.", http.StatusBadRequest)
|
||||
s.tokenErrHelper(w, errInvalidRequest, "Refresh token is invalid or has already been claimed by another client.", http.StatusBadRequest)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -579,7 +588,7 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
||||
|
||||
if len(unauthorizedScopes) > 0 {
|
||||
msg := fmt.Sprintf("Requested scopes contain unauthorized scope(s): %q.", unauthorizedScopes)
|
||||
tokenErr(w, errInvalidRequest, msg, http.StatusBadRequest)
|
||||
s.tokenErrHelper(w, errInvalidRequest, msg, http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
scopes = requestedScopes
|
||||
@@ -587,8 +596,8 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
||||
|
||||
conn, ok := s.connectors[refresh.ConnectorID]
|
||||
if !ok {
|
||||
log.Printf("connector ID not found: %q", refresh.ConnectorID)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("connector ID not found: %q", refresh.ConnectorID)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -608,8 +617,8 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
||||
}
|
||||
ident, err := refreshConn.Refresh(r.Context(), parseScopes(scopes), ident)
|
||||
if err != nil {
|
||||
log.Printf("failed to refresh identity: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to refresh identity: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -625,22 +634,22 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
|
||||
|
||||
idToken, expiry, err := s.newIDToken(client.ID, refresh.Claims, scopes, refresh.Nonce)
|
||||
if err != nil {
|
||||
log.Printf("failed to create ID token: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to create ID token: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
// Refresh tokens are claimed exactly once. Delete the current token and
|
||||
// create a new one.
|
||||
if err := s.storage.DeleteRefresh(code); err != nil {
|
||||
log.Printf("failed to delete auth code: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to delete auth code: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
refresh.RefreshToken = storage.NewID()
|
||||
if err := s.storage.CreateRefresh(refresh); err != nil {
|
||||
log.Printf("failed to create refresh token: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to create refresh token: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
s.writeAccessToken(w, idToken, refresh.RefreshToken, expiry)
|
||||
@@ -665,8 +674,8 @@ func (s *Server) writeAccessToken(w http.ResponseWriter, idToken, refreshToken s
|
||||
}
|
||||
data, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
log.Printf("failed to marshal access token response: %v", err)
|
||||
tokenErr(w, errServerError, "", http.StatusInternalServerError)
|
||||
s.logger.Errorf("failed to marshal access token response: %v", err)
|
||||
s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
@@ -681,3 +690,9 @@ func (s *Server) renderError(w http.ResponseWriter, status int, err, description
|
||||
func (s *Server) notFound(w http.ResponseWriter, r *http.Request) {
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
|
||||
func (s *Server) tokenErrHelper(w http.ResponseWriter, typ string, description string, statusCode int) {
|
||||
if err := tokenErr(w, typ, description, statusCode); err != nil {
|
||||
s.logger.Errorf("token error repsonse: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
+12
-13
@@ -3,7 +3,6 @@ package server
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
@@ -41,20 +40,20 @@ func (err *authErr) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, redirectURI, http.StatusSeeOther)
|
||||
}
|
||||
|
||||
func tokenErr(w http.ResponseWriter, typ, description string, statusCode int) {
|
||||
func tokenErr(w http.ResponseWriter, typ, description string, statusCode int) error {
|
||||
data := struct {
|
||||
Error string `json:"error"`
|
||||
Description string `json:"error_description,omitempty"`
|
||||
}{typ, description}
|
||||
body, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
log.Printf("failed to marshal token error response: %v", err)
|
||||
return
|
||||
return fmt.Errorf("failed to marshal token error response: %v", err)
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Header().Set("Content-Length", strconv.Itoa(len(body)))
|
||||
w.WriteHeader(statusCode)
|
||||
w.Write(body)
|
||||
return nil
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -159,7 +158,7 @@ func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []str
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
isTrusted, err := validateCrossClientTrust(s.storage, clientID, peerID)
|
||||
isTrusted, err := s.validateCrossClientTrust(clientID, peerID)
|
||||
if err != nil {
|
||||
return "", expiry, err
|
||||
}
|
||||
@@ -183,7 +182,7 @@ func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []str
|
||||
|
||||
keys, err := s.storage.GetKeys()
|
||||
if err != nil {
|
||||
log.Printf("Failed to get keys: %v", err)
|
||||
s.logger.Errorf("Failed to get keys: %v", err)
|
||||
return "", expiry, err
|
||||
}
|
||||
if idToken, err = keys.Sign(payload); err != nil {
|
||||
@@ -195,7 +194,7 @@ func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []str
|
||||
// parse the initial request from the OAuth2 client.
|
||||
//
|
||||
// For correctness the logic is largely copied from https://github.com/RangelReale/osin.
|
||||
func parseAuthorizationRequest(s storage.Storage, supportedResponseTypes map[string]bool, r *http.Request) (req storage.AuthRequest, oauth2Err *authErr) {
|
||||
func (s *Server) parseAuthorizationRequest(supportedResponseTypes map[string]bool, r *http.Request) (req storage.AuthRequest, oauth2Err *authErr) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
return req, &authErr{"", "", errInvalidRequest, "Failed to parse request."}
|
||||
}
|
||||
@@ -208,13 +207,13 @@ func parseAuthorizationRequest(s storage.Storage, supportedResponseTypes map[str
|
||||
|
||||
clientID := r.Form.Get("client_id")
|
||||
|
||||
client, err := s.GetClient(clientID)
|
||||
client, err := s.storage.GetClient(clientID)
|
||||
if err != nil {
|
||||
if err == storage.ErrNotFound {
|
||||
description := fmt.Sprintf("Invalid client_id (%q).", clientID)
|
||||
return req, &authErr{"", "", errUnauthorizedClient, description}
|
||||
}
|
||||
log.Printf("Failed to get client: %v", err)
|
||||
s.logger.Errorf("Failed to get client: %v", err)
|
||||
return req, &authErr{"", "", errServerError, ""}
|
||||
}
|
||||
|
||||
@@ -246,7 +245,7 @@ func parseAuthorizationRequest(s storage.Storage, supportedResponseTypes map[str
|
||||
continue
|
||||
}
|
||||
|
||||
isTrusted, err := validateCrossClientTrust(s, clientID, peerID)
|
||||
isTrusted, err := s.validateCrossClientTrust(clientID, peerID)
|
||||
if err != nil {
|
||||
return req, newErr(errServerError, "")
|
||||
}
|
||||
@@ -309,14 +308,14 @@ func parseCrossClientScope(scope string) (peerID string, ok bool) {
|
||||
return
|
||||
}
|
||||
|
||||
func validateCrossClientTrust(s storage.Storage, clientID, peerID string) (trusted bool, err error) {
|
||||
func (s *Server) validateCrossClientTrust(clientID, peerID string) (trusted bool, err error) {
|
||||
if peerID == clientID {
|
||||
return true, nil
|
||||
}
|
||||
peer, err := s.GetClient(peerID)
|
||||
peer, err := s.storage.GetClient(peerID)
|
||||
if err != nil {
|
||||
if err != storage.ErrNotFound {
|
||||
log.Printf("Failed to get client: %v", err)
|
||||
s.logger.Errorf("Failed to get client: %v", err)
|
||||
return false, err
|
||||
}
|
||||
return false, nil
|
||||
|
||||
+9
-7
@@ -7,12 +7,12 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
"gopkg.in/square/go-jose.v2"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/dex/storage"
|
||||
)
|
||||
|
||||
@@ -57,18 +57,20 @@ type keyRotater struct {
|
||||
|
||||
strategy rotationStrategy
|
||||
now func() time.Time
|
||||
|
||||
logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
// startKeyRotation begins key rotation in a new goroutine, closing once the context is canceled.
|
||||
//
|
||||
// The method blocks until after the first attempt to rotate keys has completed. That way
|
||||
// healthy storages will return from this call with valid keys.
|
||||
func startKeyRotation(ctx context.Context, s storage.Storage, strategy rotationStrategy, now func() time.Time) {
|
||||
rotater := keyRotater{s, strategy, now}
|
||||
func (s *Server) startKeyRotation(ctx context.Context, strategy rotationStrategy, now func() time.Time) {
|
||||
rotater := keyRotater{s.storage, strategy, now, s.logger}
|
||||
|
||||
// Try to rotate immediately so properly configured storages will have keys.
|
||||
if err := rotater.rotate(); err != nil {
|
||||
log.Printf("failed to rotate keys: %v", err)
|
||||
s.logger.Errorf("failed to rotate keys: %v", err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
@@ -78,7 +80,7 @@ func startKeyRotation(ctx context.Context, s storage.Storage, strategy rotationS
|
||||
return
|
||||
case <-time.After(time.Second * 30):
|
||||
if err := rotater.rotate(); err != nil {
|
||||
log.Printf("failed to rotate keys: %v", err)
|
||||
s.logger.Errorf("failed to rotate keys: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +96,7 @@ func (k keyRotater) rotate() error {
|
||||
if k.now().Before(keys.NextRotation) {
|
||||
return nil
|
||||
}
|
||||
log.Println("keys expired, rotating")
|
||||
k.logger.Infof("keys expired, rotating")
|
||||
|
||||
// Generate the key outside of a storage transaction.
|
||||
key, err := k.strategy.key()
|
||||
@@ -154,6 +156,6 @@ func (k keyRotater) rotate() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("keys rotated, next rotation: %s", nextRotation)
|
||||
k.logger.Infof("keys rotated, next rotation: %s", nextRotation)
|
||||
return nil
|
||||
}
|
||||
|
||||
+13
-9
@@ -3,7 +3,6 @@ package server
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
@@ -13,6 +12,7 @@ import (
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/coreos/dex/connector"
|
||||
@@ -57,6 +57,8 @@ type Config struct {
|
||||
EnablePasswordDB bool
|
||||
|
||||
Web WebConfig
|
||||
|
||||
Logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
// WebConfig holds the server's frontend templates and asset configuration.
|
||||
@@ -112,6 +114,8 @@ type Server struct {
|
||||
now func() time.Time
|
||||
|
||||
idTokensValidFor time.Duration
|
||||
|
||||
logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
// NewServer constructs a server from the provided config.
|
||||
@@ -182,6 +186,7 @@ func newServer(ctx context.Context, c Config, rotationStrategy rotationStrategy)
|
||||
skipApproval: c.SkipApprovalScreen,
|
||||
now: now,
|
||||
templates: tmpls,
|
||||
logger: c.Logger,
|
||||
}
|
||||
|
||||
for _, conn := range c.Connectors {
|
||||
@@ -216,8 +221,8 @@ func newServer(ctx context.Context, c Config, rotationStrategy rotationStrategy)
|
||||
handlePrefix("/theme", theme)
|
||||
s.mux = r
|
||||
|
||||
startKeyRotation(ctx, c.Storage, rotationStrategy, now)
|
||||
startGarbageCollection(ctx, c.Storage, value(c.GCFrequency, 5*time.Minute), now)
|
||||
s.startKeyRotation(ctx, rotationStrategy, now)
|
||||
s.startGarbageCollection(ctx, value(c.GCFrequency, 5*time.Minute), now)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
@@ -254,8 +259,7 @@ func (db passwordDB) Login(ctx context.Context, s connector.Scopes, email, passw
|
||||
p, err := db.s.GetPassword(email)
|
||||
if err != nil {
|
||||
if err != storage.ErrNotFound {
|
||||
log.Printf("get password: %v", err)
|
||||
return connector.Identity{}, false, err
|
||||
return connector.Identity{}, false, fmt.Errorf("get password: %v", err)
|
||||
}
|
||||
return connector.Identity{}, false, nil
|
||||
}
|
||||
@@ -327,17 +331,17 @@ func (k *keyCacher) GetKeys() (storage.Keys, error) {
|
||||
return storageKeys, nil
|
||||
}
|
||||
|
||||
func startGarbageCollection(ctx context.Context, s storage.Storage, frequency time.Duration, now func() time.Time) {
|
||||
func (s *Server) startGarbageCollection(ctx context.Context, frequency time.Duration, now func() time.Time) {
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(frequency):
|
||||
if r, err := s.GarbageCollect(now()); err != nil {
|
||||
log.Printf("garbage collection failed: %v", err)
|
||||
if r, err := s.storage.GarbageCollect(now()); err != nil {
|
||||
s.logger.Errorf("garbage collection failed: %v", err)
|
||||
} else if r.AuthRequests > 0 || r.AuthCodes > 0 {
|
||||
log.Printf("garbage collection run, delete auth requests=%d, auth codes=%d", r.AuthRequests, r.AuthCodes)
|
||||
s.logger.Errorf("garbage collection run, delete auth requests=%d, auth codes=%d", r.AuthRequests, r.AuthCodes)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+19
-5
@@ -20,6 +20,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
oidc "github.com/coreos/go-oidc"
|
||||
"github.com/kylelemons/godebug/pretty"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
@@ -72,24 +73,32 @@ FDWV28nTP9sqbtsmU8Tem2jzMvZ7C/Q0AuDoKELFUpux8shm8wfIhyaPnXUGZoAZ
|
||||
Np4vUwMSYV5mopESLWOg3loBxKyLGFtgGKVCjGiQvy6zISQ4fQo=
|
||||
-----END RSA PRIVATE KEY-----`)
|
||||
|
||||
var logger = &logrus.Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: &logrus.TextFormatter{DisableColors: true},
|
||||
Level: logrus.DebugLevel,
|
||||
}
|
||||
|
||||
func newTestServer(ctx context.Context, t *testing.T, updateConfig func(c *Config)) (*httptest.Server, *Server) {
|
||||
var server *Server
|
||||
s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
server.ServeHTTP(w, r)
|
||||
}))
|
||||
|
||||
config := Config{
|
||||
Issuer: s.URL,
|
||||
Storage: memory.New(),
|
||||
Storage: memory.New(logger),
|
||||
Connectors: []Connector{
|
||||
{
|
||||
ID: "mock",
|
||||
DisplayName: "Mock",
|
||||
Connector: mock.NewCallbackConnector(),
|
||||
Connector: mock.NewCallbackConnector(logger),
|
||||
},
|
||||
},
|
||||
Web: WebConfig{
|
||||
Dir: filepath.Join(os.Getenv("GOPATH"), "src/github.com/coreos/dex/web"),
|
||||
},
|
||||
Logger: logger,
|
||||
}
|
||||
if updateConfig != nil {
|
||||
updateConfig(&config)
|
||||
@@ -367,12 +376,17 @@ func TestOAuth2CodeFlow(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
logger := &logrus.Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: &logrus.TextFormatter{DisableColors: true},
|
||||
Level: logrus.DebugLevel,
|
||||
}
|
||||
httpServer, s := newTestServer(ctx, t, func(c *Config) {
|
||||
c.Issuer = c.Issuer + "/non-root-path"
|
||||
c.Now = now
|
||||
c.IDTokensValidFor = idTokensValidFor
|
||||
// Create a new mock callback connector for each test case.
|
||||
conn = mock.NewCallbackConnector().(*mock.Callback)
|
||||
conn = mock.NewCallbackConnector(logger).(*mock.Callback)
|
||||
c.Connectors = []Connector{
|
||||
{
|
||||
ID: "mock",
|
||||
@@ -743,7 +757,7 @@ func TestCrossClientScopes(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestPasswordDB(t *testing.T) {
|
||||
s := memory.New()
|
||||
s := memory.New(logger)
|
||||
conn := newPasswordDB(s)
|
||||
|
||||
pw := "hi"
|
||||
@@ -840,7 +854,7 @@ func TestKeyCacher(t *testing.T) {
|
||||
tNow := time.Now()
|
||||
now := func() time.Time { return tNow }
|
||||
|
||||
s := memory.New()
|
||||
s := memory.New(logger)
|
||||
|
||||
tests := []struct {
|
||||
before func()
|
||||
|
||||
+11
-13
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -178,27 +177,27 @@ func (n byName) Len() int { return len(n) }
|
||||
func (n byName) Less(i, j int) bool { return n[i].Name < n[j].Name }
|
||||
func (n byName) Swap(i, j int) { n[i], n[j] = n[j], n[i] }
|
||||
|
||||
func (t *templates) login(w http.ResponseWriter, connectors []connectorInfo, authReqID string) {
|
||||
func (t *templates) login(w http.ResponseWriter, connectors []connectorInfo, authReqID string) error {
|
||||
sort.Sort(byName(connectors))
|
||||
|
||||
data := struct {
|
||||
Connectors []connectorInfo
|
||||
AuthReqID string
|
||||
}{connectors, authReqID}
|
||||
renderTemplate(w, t.loginTmpl, data)
|
||||
return renderTemplate(w, t.loginTmpl, data)
|
||||
}
|
||||
|
||||
func (t *templates) password(w http.ResponseWriter, authReqID, callback, lastUsername string, lastWasInvalid bool) {
|
||||
func (t *templates) password(w http.ResponseWriter, authReqID, callback, lastUsername string, lastWasInvalid bool) error {
|
||||
data := struct {
|
||||
AuthReqID string
|
||||
PostURL string
|
||||
Username string
|
||||
Invalid bool
|
||||
}{authReqID, string(callback), lastUsername, lastWasInvalid}
|
||||
renderTemplate(w, t.passwordTmpl, data)
|
||||
return renderTemplate(w, t.passwordTmpl, data)
|
||||
}
|
||||
|
||||
func (t *templates) approval(w http.ResponseWriter, authReqID, username, clientName string, scopes []string) {
|
||||
func (t *templates) approval(w http.ResponseWriter, authReqID, username, clientName string, scopes []string) error {
|
||||
accesses := []string{}
|
||||
for _, scope := range scopes {
|
||||
access, ok := scopeDescriptions[scope]
|
||||
@@ -213,14 +212,14 @@ func (t *templates) approval(w http.ResponseWriter, authReqID, username, clientN
|
||||
AuthReqID string
|
||||
Scopes []string
|
||||
}{username, clientName, authReqID, accesses}
|
||||
renderTemplate(w, t.approvalTmpl, data)
|
||||
return renderTemplate(w, t.approvalTmpl, data)
|
||||
}
|
||||
|
||||
func (t *templates) oob(w http.ResponseWriter, code string) {
|
||||
func (t *templates) oob(w http.ResponseWriter, code string) error {
|
||||
data := struct {
|
||||
Code string
|
||||
}{code}
|
||||
renderTemplate(w, t.oobTmpl, data)
|
||||
return renderTemplate(w, t.oobTmpl, data)
|
||||
}
|
||||
|
||||
// small io.Writer utilitiy to determine if executing the template wrote to the underlying response writer.
|
||||
@@ -234,15 +233,14 @@ func (w *writeRecorder) Write(p []byte) (n int, err error) {
|
||||
return w.w.Write(p)
|
||||
}
|
||||
|
||||
func renderTemplate(w http.ResponseWriter, tmpl *template.Template, data interface{}) {
|
||||
func renderTemplate(w http.ResponseWriter, tmpl *template.Template, data interface{}) error {
|
||||
wr := &writeRecorder{w: w}
|
||||
if err := tmpl.Execute(wr, data); err != nil {
|
||||
log.Printf("Error rendering template %s: %s", tmpl.Name(), err)
|
||||
|
||||
if !wr.wrote {
|
||||
// TODO(ericchiang): replace with better internal server error.
|
||||
http.Error(w, "Internal server error", http.StatusInternalServerError)
|
||||
}
|
||||
return fmt.Errorf("Error rendering template %s: %s", tmpl.Name(), err)
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/ghodss/yaml"
|
||||
"github.com/gtank/cryptopasta"
|
||||
"golang.org/x/net/context"
|
||||
@@ -33,6 +34,7 @@ type client struct {
|
||||
client *http.Client
|
||||
baseURL string
|
||||
namespace string
|
||||
logger logrus.FieldLogger
|
||||
|
||||
// Hash function to map IDs (which could span a large range) to Kubernetes names.
|
||||
// While this is not currently upgradable, it could be in the future.
|
||||
@@ -230,7 +232,7 @@ func (c *client) put(resource, name string, v interface{}) error {
|
||||
return checkHTTPErr(resp, http.StatusOK)
|
||||
}
|
||||
|
||||
func newClient(cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace string) (*client, error) {
|
||||
func newClient(cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace string, logger logrus.FieldLogger) (*client, error) {
|
||||
tlsConfig := cryptopasta.DefaultTLSConfig()
|
||||
data := func(b string, file string) ([]byte, error) {
|
||||
if b != "" {
|
||||
@@ -303,6 +305,7 @@ func newClient(cluster k8sapi.Cluster, user k8sapi.AuthInfo, namespace string) (
|
||||
hash: func() hash.Hash { return fnv.New64() },
|
||||
namespace: namespace,
|
||||
apiVersion: "oidc.coreos.com/v1",
|
||||
logger: logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,13 @@ package kubernetes
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/dex/storage"
|
||||
"github.com/coreos/dex/storage/kubernetes/k8sapi"
|
||||
)
|
||||
@@ -39,8 +39,8 @@ type Config struct {
|
||||
}
|
||||
|
||||
// Open returns a storage using Kubernetes third party resource.
|
||||
func (c *Config) Open() (storage.Storage, error) {
|
||||
cli, err := c.open()
|
||||
func (c *Config) Open(logger logrus.FieldLogger) (storage.Storage, error) {
|
||||
cli, err := c.open(logger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (c *Config) Open() (storage.Storage, error) {
|
||||
}
|
||||
|
||||
// open returns a client with no garbage collection.
|
||||
func (c *Config) open() (*client, error) {
|
||||
func (c *Config) open(logger logrus.FieldLogger) (*client, error) {
|
||||
if c.InCluster && (c.KubeConfigFile != "") {
|
||||
return nil, errors.New("cannot specify both 'inCluster' and 'kubeConfigFile'")
|
||||
}
|
||||
@@ -71,7 +71,7 @@ func (c *Config) open() (*client, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cli, err := newClient(cluster, user, namespace)
|
||||
cli, err := newClient(cluster, user, namespace, logger)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("create client: %v", err)
|
||||
}
|
||||
@@ -82,11 +82,11 @@ func (c *Config) open() (*client, error) {
|
||||
// they'll immediately be available, but ensures that the client will actually try
|
||||
// once.
|
||||
if err := cli.createThirdPartyResources(); err != nil {
|
||||
log.Printf("failed creating third party resources: %v", err)
|
||||
logger.Errorf("failed creating third party resources: %v", err)
|
||||
go func() {
|
||||
for {
|
||||
if err := cli.createThirdPartyResources(); err != nil {
|
||||
log.Printf("failed creating third party resources: %v", err)
|
||||
logger.Errorf("failed creating third party resources: %v", err)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
@@ -118,13 +118,13 @@ func (cli *client) createThirdPartyResources() error {
|
||||
if err != nil {
|
||||
if e, ok := err.(httpError); ok {
|
||||
if e.StatusCode() == http.StatusConflict {
|
||||
log.Printf("third party resource already created %q", r.ObjectMeta.Name)
|
||||
cli.logger.Errorf("third party resource already created %q", r.ObjectMeta.Name)
|
||||
continue
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
log.Printf("create third party resource %q", r.ObjectMeta.Name)
|
||||
cli.logger.Errorf("create third party resource %q", r.ObjectMeta.Name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -396,7 +396,7 @@ func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err e
|
||||
for _, authRequest := range authRequests.AuthRequests {
|
||||
if now.After(authRequest.Expiry) {
|
||||
if err := cli.delete(resourceAuthRequest, authRequest.ObjectMeta.Name); err != nil {
|
||||
log.Printf("failed to delete auth request: %v", err)
|
||||
cli.logger.Errorf("failed to delete auth request: %v", err)
|
||||
delErr = fmt.Errorf("failed to delete auth request: %v", err)
|
||||
}
|
||||
result.AuthRequests++
|
||||
@@ -414,7 +414,7 @@ func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err e
|
||||
for _, authCode := range authCodes.AuthCodes {
|
||||
if now.After(authCode.Expiry) {
|
||||
if err := cli.delete(resourceAuthCode, authCode.ObjectMeta.Name); err != nil {
|
||||
log.Printf("failed to delete auth code %v", err)
|
||||
cli.logger.Errorf("failed to delete auth code %v", err)
|
||||
delErr = fmt.Errorf("failed to delete auth code: %v", err)
|
||||
}
|
||||
result.AuthCodes++
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/coreos/dex/storage"
|
||||
"github.com/coreos/dex/storage/conformance"
|
||||
)
|
||||
@@ -22,7 +23,12 @@ func loadClient(t *testing.T) *client {
|
||||
if config.KubeConfigFile == "" {
|
||||
t.Skipf("test environment variable %q not set, skipping", testKubeConfigEnv)
|
||||
}
|
||||
s, err := config.open()
|
||||
logger := &logrus.Logger{
|
||||
Out: os.Stderr,
|
||||
Formatter: &logrus.TextFormatter{DisableColors: true},
|
||||
Level: logrus.DebugLevel,
|
||||
}
|
||||
s, err := config.open(logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user