server: modify error messages to use logrus.

This commit is contained in:
rithu john 2016-12-12 14:54:01 -08:00
parent 6033c45976
commit 9949a1313c
11 changed files with 151 additions and 137 deletions

View file

@ -6,7 +6,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log"
"net" "net"
"net/http" "net/http"
"os" "os"
@ -182,19 +181,19 @@ func serve(cmd *cobra.Command, args []string) error {
} }
errc := make(chan error, 3) errc := make(chan error, 3)
if c.Web.HTTP != "" { if c.Web.HTTP != "" {
log.Printf("listening (http) on %s", c.Web.HTTP) logger.Errorf("listening (http) on %s", c.Web.HTTP)
go func() { go func() {
errc <- http.ListenAndServe(c.Web.HTTP, serv) errc <- http.ListenAndServe(c.Web.HTTP, serv)
}() }()
} }
if c.Web.HTTPS != "" { if c.Web.HTTPS != "" {
log.Printf("listening (https) on %s", c.Web.HTTPS) logger.Errorf("listening (https) on %s", c.Web.HTTPS)
go func() { go func() {
errc <- http.ListenAndServeTLS(c.Web.HTTPS, c.Web.TLSCert, c.Web.TLSKey, serv) errc <- http.ListenAndServeTLS(c.Web.HTTPS, c.Web.TLSCert, c.Web.TLSKey, serv)
}() }()
} }
if c.GRPC.Addr != "" { if c.GRPC.Addr != "" {
log.Printf("listening (grpc) on %s", c.GRPC.Addr) logger.Errorf("listening (grpc) on %s", c.GRPC.Addr)
go func() { go func() {
errc <- func() error { errc <- func() error {
list, err := net.Listen("tcp", c.GRPC.Addr) list, err := net.Listen("tcp", c.GRPC.Addr)
@ -202,7 +201,7 @@ func serve(cmd *cobra.Command, args []string) error {
return fmt.Errorf("listen grpc: %v", err) return fmt.Errorf("listen grpc: %v", err)
} }
s := grpc.NewServer(grpcOptions...) s := grpc.NewServer(grpcOptions...)
api.RegisterDexServer(s, server.NewAPI(serverConfig.Storage)) api.RegisterDexServer(s, server.NewAPI(serverConfig.Storage, logger))
return s.Serve(list) return s.Serve(list)
}() }()
}() }()

View file

@ -7,7 +7,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"log"
"net" "net"
"golang.org/x/net/context" "golang.org/x/net/context"
@ -328,7 +327,7 @@ func (c *ldapConnector) userEntry(conn *ldap.Conn, username string) (user ldap.E
switch n := len(resp.Entries); n { switch n := len(resp.Entries); n {
case 0: 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 return ldap.Entry{}, false, nil
case 1: case 1:
return *resp.Entries[0], true, nil return *resp.Entries[0], true, nil
@ -361,7 +360,7 @@ func (c *ldapConnector) Login(ctx context.Context, s connector.Scopes, username,
// Detect a bad password through the LDAP error code. // Detect a bad password through the LDAP error code.
if ldapErr, ok := err.(*ldap.Error); ok { if ldapErr, ok := err.(*ldap.Error); ok {
if ldapErr.ResultCode == ldap.LDAPResultInvalidCredentials { 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 incorrectPass = true
return nil return nil
} }
@ -471,7 +470,7 @@ func (c *ldapConnector) groups(ctx context.Context, user ldap.Entry) ([]string,
} }
if len(groups) == 0 { if len(groups) == 0 {
// TODO(ericchiang): Is this going to spam the logs? // 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 var groupNames []string

View file

@ -3,11 +3,11 @@ package server
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"golang.org/x/crypto/bcrypt" "golang.org/x/crypto/bcrypt"
"golang.org/x/net/context" "golang.org/x/net/context"
"github.com/Sirupsen/logrus"
"github.com/coreos/dex/api" "github.com/coreos/dex/api"
"github.com/coreos/dex/storage" "github.com/coreos/dex/storage"
"github.com/coreos/dex/version" "github.com/coreos/dex/version"
@ -18,12 +18,16 @@ import (
const apiVersion = 0 const apiVersion = 0
// NewAPI returns a server which implements the gRPC API interface. // NewAPI returns a server which implements the gRPC API interface.
func NewAPI(s storage.Storage) api.DexServer { func NewAPI(s storage.Storage, logger logrus.FieldLogger) api.DexServer {
return dexAPI{s: s} return dexAPI{
s: s,
logger: logger,
}
} }
type dexAPI struct { 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) { 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, LogoURL: req.Client.LogoUrl,
} }
if err := d.s.CreateClient(c); err != nil { 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. // TODO(ericchiang): Surface "already exists" errors.
return nil, fmt.Errorf("create client: %v", err) 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 { if err == storage.ErrNotFound {
return &api.DeleteClientResp{NotFound: true}, nil 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 nil, fmt.Errorf("delete client: %v", err)
} }
return &api.DeleteClientResp{}, nil return &api.DeleteClientResp{}, nil
@ -104,7 +108,7 @@ func (d dexAPI) CreatePassword(ctx context.Context, req *api.CreatePasswordReq)
UserID: req.Password.UserId, UserID: req.Password.UserId,
} }
if err := d.s.CreatePassword(p); err != nil { 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) 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 { if err == storage.ErrNotFound {
return &api.UpdatePasswordResp{NotFound: true}, nil 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) 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 { if err == storage.ErrNotFound {
return &api.DeletePasswordResp{NotFound: true}, nil 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 nil, fmt.Errorf("delete password: %v", err)
} }
return &api.DeletePasswordResp{}, nil 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) { func (d dexAPI) ListPasswords(ctx context.Context, req *api.ListPasswordReq) (*api.ListPasswordResp, error) {
passwordList, err := d.s.ListPasswords() passwordList, err := d.s.ListPasswords()
if err != nil { 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) return nil, fmt.Errorf("list passwords: %v", err)
} }

View file

@ -19,7 +19,7 @@ func TestPassword(t *testing.T) {
} }
s := memory.New(logger) s := memory.New(logger)
serv := NewAPI(s) serv := NewAPI(s, logger)
ctx := context.Background() ctx := context.Background()
p := api.Password{ p := api.Password{

View file

@ -3,7 +3,6 @@ package server
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"net/http" "net/http"
"net/url" "net/url"
"path" "path"
@ -42,7 +41,7 @@ func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
t := s.now().Sub(start) t := s.now().Sub(start)
if err != nil { 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) http.Error(w, "Health check failed", http.StatusInternalServerError)
return return
} }
@ -53,13 +52,13 @@ func (s *Server) handlePublicKeys(w http.ResponseWriter, r *http.Request) {
// TODO(ericchiang): Cache this. // TODO(ericchiang): Cache this.
keys, err := s.storage.GetKeys() keys, err := s.storage.GetKeys()
if err != nil { 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) http.Error(w, "Internal server error", http.StatusInternalServerError)
return return
} }
if keys.SigningKeyPub == nil { 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) http.Error(w, "Internal server error", http.StatusInternalServerError)
return return
} }
@ -74,7 +73,7 @@ func (s *Server) handlePublicKeys(w http.ResponseWriter, r *http.Request) {
data, err := json.MarshalIndent(jwks, "", " ") data, err := json.MarshalIndent(jwks, "", " ")
if err != nil { 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) http.Error(w, "Internal server error", http.StatusInternalServerError)
return return
} }
@ -137,14 +136,14 @@ func (s *Server) discoveryHandler() (http.HandlerFunc, error) {
// handleAuthorization handles the OAuth2 auth endpoint. // handleAuthorization handles the OAuth2 auth endpoint.
func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) { 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 { if err != nil {
s.renderError(w, http.StatusInternalServerError, err.Type, err.Description) s.renderError(w, http.StatusInternalServerError, err.Type, err.Description)
return return
} }
authReq.Expiry = s.now().Add(time.Minute * 30) authReq.Expiry = s.now().Add(time.Minute * 30)
if err := s.storage.CreateAuthRequest(authReq); err != nil { 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "")
return return
} }
@ -166,7 +165,9 @@ func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) {
i++ 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) { 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) authReq, err := s.storage.GetAuthRequest(authReqID)
if err != nil { 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
return return
} }
scopes := parseScopes(authReq.Scopes) scopes := parseScopes(authReq.Scopes)
@ -195,8 +196,8 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
return a, nil return a, nil
} }
if err := s.storage.UpdateAuthRequest(authReqID, updater); err != nil { if err := s.storage.UpdateAuthRequest(authReqID, updater); err != nil {
log.Printf("Failed to set connector ID on auth request: %v", err) s.logger.Errorf("Failed to set connector ID on auth request: %v", err)
s.renderError(w, http.StatusInternalServerError, errServerError, "") s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
return 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? // TODO(ericchiang): Is this appropriate or should we also be using a nonce?
callbackURL, err := conn.LoginURL(scopes, s.absURL("/callback"), authReqID) callbackURL, err := conn.LoginURL(scopes, s.absURL("/callback"), authReqID)
if err != nil { if err != nil {
log.Printf("Connector %q returned error when creating callback: %v", connID, err) s.logger.Errorf("Connector %q returned error when creating callback: %v", connID, err)
s.renderError(w, http.StatusInternalServerError, errServerError, "") s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
return return
} }
http.Redirect(w, r, callbackURL, http.StatusFound) http.Redirect(w, r, callbackURL, http.StatusFound)
case connector.PasswordConnector: 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: default:
s.notFound(w, r) 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) identity, ok, err := passwordConnector.Login(r.Context(), scopes, username, password)
if err != nil { if err != nil {
log.Printf("Failed to login user: %v", err) s.logger.Errorf("Failed to login user: %v", err)
s.renderError(w, http.StatusInternalServerError, errServerError, "") s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
return return
} }
if !ok { 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 return
} }
redirectURL, err := s.finalizeLogin(identity, authReq, conn.Connector) redirectURL, err := s.finalizeLogin(identity, authReq, conn.Connector)
if err != nil { 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "Connector Login Error")
return return
} }
@ -260,17 +265,17 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request)
// Section: "3.4.3 RelayState" // Section: "3.4.3 RelayState"
state := r.URL.Query().Get("state") state := r.URL.Query().Get("state")
if state == "" { if state == "" {
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "no 'state' parameter provided") s.renderError(w, http.StatusBadRequest, errInvalidRequest, "No 'state' parameter provided.")
return return
} }
authReq, err := s.storage.GetAuthRequest(state) authReq, err := s.storage.GetAuthRequest(state)
if err != nil { if err != nil {
if err == storage.ErrNotFound { 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 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "")
return return
} }
@ -288,14 +293,14 @@ func (s *Server) handleConnectorCallback(w http.ResponseWriter, r *http.Request)
identity, err := callbackConnector.HandleCallback(parseScopes(authReq.Scopes), r) identity, err := callbackConnector.HandleCallback(parseScopes(authReq.Scopes), r)
if err != nil { if err != nil {
log.Printf("Failed to authenticate: %v", err) s.logger.Errorf("Failed to authenticate: %v", err)
s.renderError(w, http.StatusInternalServerError, errServerError, "") s.renderError(w, http.StatusInternalServerError, errServerError, "")
return return
} }
redirectURL, err := s.finalizeLogin(identity, authReq, conn.Connector) redirectURL, err := s.finalizeLogin(identity, authReq, conn.Connector)
if err != nil { 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "")
return 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) { func (s *Server) handleApproval(w http.ResponseWriter, r *http.Request) {
authReq, err := s.storage.GetAuthRequest(r.FormValue("req")) authReq, err := s.storage.GetAuthRequest(r.FormValue("req"))
if err != nil { 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "")
return return
} }
if !authReq.LoggedIn { 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "")
return return
} }
@ -345,11 +350,13 @@ func (s *Server) handleApproval(w http.ResponseWriter, r *http.Request) {
} }
client, err := s.storage.GetClient(authReq.ClientID) client, err := s.storage.GetClient(authReq.ClientID)
if err != nil { 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "")
return 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": case "POST":
if r.FormValue("approval") != "approve" { if r.FormValue("approval") != "approve" {
s.renderError(w, http.StatusInternalServerError, "approval rejected", "") 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 := s.storage.DeleteAuthRequest(authReq.ID); err != nil {
if err != storage.ErrNotFound { 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "")
} else { } else {
s.renderError(w, http.StatusBadRequest, errInvalidRequest, "Authorization request has already been completed.") 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, ConnectorData: authReq.ConnectorData,
} }
if err := s.storage.CreateAuthCode(code); err != nil { 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, "") s.renderError(w, http.StatusInternalServerError, errServerError, "")
return return
} }
if authReq.RedirectURI == redirectURIOOB { 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 return
} }
q.Set("code", code.ID) q.Set("code", code.ID)
case responseTypeToken: case responseTypeToken:
idToken, expiry, err := s.newIDToken(authReq.ClientID, authReq.Claims, authReq.Scopes, authReq.Nonce) idToken, expiry, err := s.newIDToken(authReq.ClientID, authReq.Claims, authReq.Scopes, authReq.Nonce)
if err != nil { if err != nil {
log.Printf("failed to create ID token: %v", err) s.logger.Errorf("failed to create ID token: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return return
} }
v := url.Values{} v := url.Values{}
@ -433,11 +442,11 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
if ok { if ok {
var err error var err error
if clientID, err = url.QueryUnescape(clientID); err != nil { 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 return
} }
if clientSecret, err = url.QueryUnescape(clientSecret); err != nil { 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 return
} }
} else { } else {
@ -448,15 +457,15 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
client, err := s.storage.GetClient(clientID) client, err := s.storage.GetClient(clientID)
if err != nil { if err != nil {
if err != storage.ErrNotFound { if err != storage.ErrNotFound {
log.Printf("failed to get client: %v", err) s.logger.Errorf("failed to get client: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
} else { } else {
tokenErr(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized) s.tokenErrHelper(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized)
} }
return return
} }
if client.Secret != clientSecret { if client.Secret != clientSecret {
tokenErr(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized) s.tokenErrHelper(w, errInvalidClient, "Invalid client credentials.", http.StatusUnauthorized)
return return
} }
@ -467,7 +476,7 @@ func (s *Server) handleToken(w http.ResponseWriter, r *http.Request) {
case grantTypeRefreshToken: case grantTypeRefreshToken:
s.handleRefreshToken(w, r, client) s.handleRefreshToken(w, r, client)
default: 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) authCode, err := s.storage.GetAuthCode(code)
if err != nil || s.now().After(authCode.Expiry) || authCode.ClientID != client.ID { if err != nil || s.now().After(authCode.Expiry) || authCode.ClientID != client.ID {
if err != storage.ErrNotFound { if err != storage.ErrNotFound {
log.Printf("failed to get auth code: %v", err) s.logger.Errorf("failed to get auth code: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
} else { } else {
tokenErr(w, errInvalidRequest, "Invalid or expired code parameter.", http.StatusBadRequest) s.tokenErrHelper(w, errInvalidRequest, "Invalid or expired code parameter.", http.StatusBadRequest)
} }
return return
} }
if authCode.RedirectURI != redirectURI { 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 return
} }
idToken, expiry, err := s.newIDToken(client.ID, authCode.Claims, authCode.Scopes, authCode.Nonce) idToken, expiry, err := s.newIDToken(client.ID, authCode.Claims, authCode.Scopes, authCode.Nonce)
if err != nil { if err != nil {
log.Printf("failed to create ID token: %v", err) s.logger.Errorf("failed to create ID token: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return return
} }
if err := s.storage.DeleteAuthCode(code); err != nil { if err := s.storage.DeleteAuthCode(code); err != nil {
log.Printf("failed to delete auth code: %v", err) s.logger.Errorf("failed to delete auth code: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return return
} }
@ -525,8 +534,8 @@ func (s *Server) handleAuthCode(w http.ResponseWriter, r *http.Request, client s
ConnectorData: authCode.ConnectorData, ConnectorData: authCode.ConnectorData,
} }
if err := s.storage.CreateRefresh(refresh); err != nil { if err := s.storage.CreateRefresh(refresh); err != nil {
log.Printf("failed to create refresh token: %v", err) s.logger.Errorf("failed to create refresh token: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return return
} }
refreshToken = refresh.RefreshToken refreshToken = refresh.RefreshToken
@ -539,17 +548,17 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
code := r.PostFormValue("refresh_token") code := r.PostFormValue("refresh_token")
scope := r.PostFormValue("scope") scope := r.PostFormValue("scope")
if code == "" { if code == "" {
tokenErr(w, errInvalidRequest, "No refresh token in request.", http.StatusBadRequest) s.tokenErrHelper(w, errInvalidRequest, "No refresh token in request.", http.StatusBadRequest)
return return
} }
refresh, err := s.storage.GetRefresh(code) refresh, err := s.storage.GetRefresh(code)
if err != nil || refresh.ClientID != client.ID { if err != nil || refresh.ClientID != client.ID {
if err != storage.ErrNotFound { if err != storage.ErrNotFound {
log.Printf("failed to get auth code: %v", err) s.logger.Errorf("failed to get auth code: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
} else { } 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 return
} }
@ -579,7 +588,7 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
if len(unauthorizedScopes) > 0 { if len(unauthorizedScopes) > 0 {
msg := fmt.Sprintf("Requested scopes contain unauthorized scope(s): %q.", unauthorizedScopes) 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 return
} }
scopes = requestedScopes scopes = requestedScopes
@ -587,8 +596,8 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
conn, ok := s.connectors[refresh.ConnectorID] conn, ok := s.connectors[refresh.ConnectorID]
if !ok { if !ok {
log.Printf("connector ID not found: %q", refresh.ConnectorID) s.logger.Errorf("connector ID not found: %q", refresh.ConnectorID)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return 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) ident, err := refreshConn.Refresh(r.Context(), parseScopes(scopes), ident)
if err != nil { if err != nil {
log.Printf("failed to refresh identity: %v", err) s.logger.Errorf("failed to refresh identity: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return 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) idToken, expiry, err := s.newIDToken(client.ID, refresh.Claims, scopes, refresh.Nonce)
if err != nil { if err != nil {
log.Printf("failed to create ID token: %v", err) s.logger.Errorf("failed to create ID token: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return return
} }
// Refresh tokens are claimed exactly once. Delete the current token and // Refresh tokens are claimed exactly once. Delete the current token and
// create a new one. // create a new one.
if err := s.storage.DeleteRefresh(code); err != nil { if err := s.storage.DeleteRefresh(code); err != nil {
log.Printf("failed to delete auth code: %v", err) s.logger.Errorf("failed to delete auth code: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return return
} }
refresh.RefreshToken = storage.NewID() refresh.RefreshToken = storage.NewID()
if err := s.storage.CreateRefresh(refresh); err != nil { if err := s.storage.CreateRefresh(refresh); err != nil {
log.Printf("failed to create refresh token: %v", err) s.logger.Errorf("failed to create refresh token: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return return
} }
s.writeAccessToken(w, idToken, refresh.RefreshToken, expiry) 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) data, err := json.Marshal(resp)
if err != nil { if err != nil {
log.Printf("failed to marshal access token response: %v", err) s.logger.Errorf("failed to marshal access token response: %v", err)
tokenErr(w, errServerError, "", http.StatusInternalServerError) s.tokenErrHelper(w, errServerError, "", http.StatusInternalServerError)
return return
} }
w.Header().Set("Content-Type", "application/json") 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) { func (s *Server) notFound(w http.ResponseWriter, r *http.Request) {
http.NotFound(w, r) 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)
}
}

View file

@ -3,7 +3,6 @@ package server
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
@ -41,20 +40,20 @@ func (err *authErr) ServeHTTP(w http.ResponseWriter, r *http.Request) {
http.Redirect(w, r, redirectURI, http.StatusSeeOther) 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 { data := struct {
Error string `json:"error"` Error string `json:"error"`
Description string `json:"error_description,omitempty"` Description string `json:"error_description,omitempty"`
}{typ, description} }{typ, description}
body, err := json.Marshal(data) body, err := json.Marshal(data)
if err != nil { if err != nil {
log.Printf("failed to marshal token error response: %v", err) return fmt.Errorf("failed to marshal token error response: %v", err)
return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Length", strconv.Itoa(len(body))) w.Header().Set("Content-Length", strconv.Itoa(len(body)))
w.WriteHeader(statusCode) w.WriteHeader(statusCode)
w.Write(body) w.Write(body)
return nil
} }
const ( const (
@ -159,7 +158,7 @@ func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []str
if !ok { if !ok {
continue continue
} }
isTrusted, err := validateCrossClientTrust(s.storage, clientID, peerID) isTrusted, err := s.validateCrossClientTrust(clientID, peerID)
if err != nil { if err != nil {
return "", expiry, err return "", expiry, err
} }
@ -183,7 +182,7 @@ func (s *Server) newIDToken(clientID string, claims storage.Claims, scopes []str
keys, err := s.storage.GetKeys() keys, err := s.storage.GetKeys()
if err != nil { if err != nil {
log.Printf("Failed to get keys: %v", err) s.logger.Errorf("Failed to get keys: %v", err)
return "", expiry, err return "", expiry, err
} }
if idToken, err = keys.Sign(payload); err != nil { 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. // parse the initial request from the OAuth2 client.
// //
// For correctness the logic is largely copied from https://github.com/RangelReale/osin. // 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 { if err := r.ParseForm(); err != nil {
return req, &authErr{"", "", errInvalidRequest, "Failed to parse request."} 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") clientID := r.Form.Get("client_id")
client, err := s.GetClient(clientID) client, err := s.storage.GetClient(clientID)
if err != nil { if err != nil {
if err == storage.ErrNotFound { if err == storage.ErrNotFound {
description := fmt.Sprintf("Invalid client_id (%q).", clientID) description := fmt.Sprintf("Invalid client_id (%q).", clientID)
return req, &authErr{"", "", errUnauthorizedClient, description} 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, ""} return req, &authErr{"", "", errServerError, ""}
} }
@ -246,7 +245,7 @@ func parseAuthorizationRequest(s storage.Storage, supportedResponseTypes map[str
continue continue
} }
isTrusted, err := validateCrossClientTrust(s, clientID, peerID) isTrusted, err := s.validateCrossClientTrust(clientID, peerID)
if err != nil { if err != nil {
return req, newErr(errServerError, "") return req, newErr(errServerError, "")
} }
@ -309,14 +308,14 @@ func parseCrossClientScope(scope string) (peerID string, ok bool) {
return 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 { if peerID == clientID {
return true, nil return true, nil
} }
peer, err := s.GetClient(peerID) peer, err := s.storage.GetClient(peerID)
if err != nil { if err != nil {
if err != storage.ErrNotFound { 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, err
} }
return false, nil return false, nil

View file

@ -7,12 +7,12 @@ import (
"errors" "errors"
"fmt" "fmt"
"io" "io"
"log"
"time" "time"
"golang.org/x/net/context" "golang.org/x/net/context"
"gopkg.in/square/go-jose.v2" "gopkg.in/square/go-jose.v2"
"github.com/Sirupsen/logrus"
"github.com/coreos/dex/storage" "github.com/coreos/dex/storage"
) )
@ -57,18 +57,20 @@ type keyRotater struct {
strategy rotationStrategy strategy rotationStrategy
now func() time.Time now func() time.Time
logger logrus.FieldLogger
} }
// startKeyRotation begins key rotation in a new goroutine, closing once the context is canceled. // 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 // 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. // healthy storages will return from this call with valid keys.
func startKeyRotation(ctx context.Context, s storage.Storage, strategy rotationStrategy, now func() time.Time) { func (s *Server) startKeyRotation(ctx context.Context, strategy rotationStrategy, now func() time.Time) {
rotater := keyRotater{s, strategy, now} rotater := keyRotater{s.storage, strategy, now, s.logger}
// Try to rotate immediately so properly configured storages will have keys. // Try to rotate immediately so properly configured storages will have keys.
if err := rotater.rotate(); err != nil { 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() { go func() {
@ -78,7 +80,7 @@ func startKeyRotation(ctx context.Context, s storage.Storage, strategy rotationS
return return
case <-time.After(time.Second * 30): case <-time.After(time.Second * 30):
if err := rotater.rotate(); err != nil { 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) { if k.now().Before(keys.NextRotation) {
return nil return nil
} }
log.Println("keys expired, rotating") k.logger.Infof("keys expired, rotating")
// Generate the key outside of a storage transaction. // Generate the key outside of a storage transaction.
key, err := k.strategy.key() key, err := k.strategy.key()
@ -154,6 +156,6 @@ func (k keyRotater) rotate() error {
if err != nil { if err != nil {
return err return err
} }
log.Printf("keys rotated, next rotation: %s", nextRotation) k.logger.Infof("keys rotated, next rotation: %s", nextRotation)
return nil return nil
} }

View file

@ -3,7 +3,6 @@ package server
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"net/http" "net/http"
"net/url" "net/url"
"path" "path"
@ -222,8 +221,8 @@ func newServer(ctx context.Context, c Config, rotationStrategy rotationStrategy)
handlePrefix("/theme", theme) handlePrefix("/theme", theme)
s.mux = r s.mux = r
startKeyRotation(ctx, c.Storage, rotationStrategy, now) s.startKeyRotation(ctx, rotationStrategy, now)
startGarbageCollection(ctx, c.Storage, value(c.GCFrequency, 5*time.Minute), now) s.startGarbageCollection(ctx, value(c.GCFrequency, 5*time.Minute), now)
return s, nil return s, nil
} }
@ -260,8 +259,7 @@ func (db passwordDB) Login(ctx context.Context, s connector.Scopes, email, passw
p, err := db.s.GetPassword(email) p, err := db.s.GetPassword(email)
if err != nil { if err != nil {
if err != storage.ErrNotFound { if err != storage.ErrNotFound {
log.Printf("get password: %v", err) return connector.Identity{}, false, fmt.Errorf("get password: %v", err)
return connector.Identity{}, false, err
} }
return connector.Identity{}, false, nil return connector.Identity{}, false, nil
} }
@ -333,17 +331,17 @@ func (k *keyCacher) GetKeys() (storage.Keys, error) {
return storageKeys, nil 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() { go func() {
for { for {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return return
case <-time.After(frequency): case <-time.After(frequency):
if r, err := s.GarbageCollect(now()); err != nil { if r, err := s.storage.GarbageCollect(now()); err != nil {
log.Printf("garbage collection failed: %v", err) s.logger.Errorf("garbage collection failed: %v", err)
} else if r.AuthRequests > 0 || r.AuthCodes > 0 { } 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)
} }
} }
} }

View file

@ -98,6 +98,7 @@ func newTestServer(ctx context.Context, t *testing.T, updateConfig func(c *Confi
Web: WebConfig{ Web: WebConfig{
Dir: filepath.Join(os.Getenv("GOPATH"), "src/github.com/coreos/dex/web"), Dir: filepath.Join(os.Getenv("GOPATH"), "src/github.com/coreos/dex/web"),
}, },
Logger: logger,
} }
if updateConfig != nil { if updateConfig != nil {
updateConfig(&config) updateConfig(&config)

View file

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"os" "os"
"path/filepath" "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) 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 (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)) sort.Sort(byName(connectors))
data := struct { data := struct {
Connectors []connectorInfo Connectors []connectorInfo
AuthReqID string AuthReqID string
}{connectors, authReqID} }{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 { data := struct {
AuthReqID string AuthReqID string
PostURL string PostURL string
Username string Username string
Invalid bool Invalid bool
}{authReqID, string(callback), lastUsername, lastWasInvalid} }{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{} accesses := []string{}
for _, scope := range scopes { for _, scope := range scopes {
access, ok := scopeDescriptions[scope] access, ok := scopeDescriptions[scope]
@ -213,14 +212,14 @@ func (t *templates) approval(w http.ResponseWriter, authReqID, username, clientN
AuthReqID string AuthReqID string
Scopes []string Scopes []string
}{username, clientName, authReqID, accesses} }{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 { data := struct {
Code string Code string
}{code} }{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. // 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) 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} wr := &writeRecorder{w: w}
if err := tmpl.Execute(wr, data); err != nil { if err := tmpl.Execute(wr, data); err != nil {
log.Printf("Error rendering template %s: %s", tmpl.Name(), err)
if !wr.wrote { if !wr.wrote {
// TODO(ericchiang): replace with better internal server error. // TODO(ericchiang): replace with better internal server error.
http.Error(w, "Internal server error", http.StatusInternalServerError) http.Error(w, "Internal server error", http.StatusInternalServerError)
} }
return fmt.Errorf("Error rendering template %s: %s", tmpl.Name(), err)
} }
return return nil
} }

View file

@ -3,7 +3,6 @@ package kubernetes
import ( import (
"errors" "errors"
"fmt" "fmt"
"log"
"net/http" "net/http"
"strings" "strings"
"time" "time"
@ -83,11 +82,11 @@ func (c *Config) open(logger logrus.FieldLogger) (*client, error) {
// they'll immediately be available, but ensures that the client will actually try // they'll immediately be available, but ensures that the client will actually try
// once. // once.
if err := cli.createThirdPartyResources(); err != nil { 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() { go func() {
for { for {
if err := cli.createThirdPartyResources(); err != nil { 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 { } else {
return return
} }
@ -119,13 +118,13 @@ func (cli *client) createThirdPartyResources() error {
if err != nil { if err != nil {
if e, ok := err.(httpError); ok { if e, ok := err.(httpError); ok {
if e.StatusCode() == http.StatusConflict { 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 continue
} }
} }
return err 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 return nil
} }
@ -397,7 +396,7 @@ func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err e
for _, authRequest := range authRequests.AuthRequests { for _, authRequest := range authRequests.AuthRequests {
if now.After(authRequest.Expiry) { if now.After(authRequest.Expiry) {
if err := cli.delete(resourceAuthRequest, authRequest.ObjectMeta.Name); err != nil { 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) delErr = fmt.Errorf("failed to delete auth request: %v", err)
} }
result.AuthRequests++ result.AuthRequests++
@ -415,7 +414,7 @@ func (cli *client) GarbageCollect(now time.Time) (result storage.GCResult, err e
for _, authCode := range authCodes.AuthCodes { for _, authCode := range authCodes.AuthCodes {
if now.After(authCode.Expiry) { if now.After(authCode.Expiry) {
if err := cli.delete(resourceAuthCode, authCode.ObjectMeta.Name); err != nil { 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) delErr = fmt.Errorf("failed to delete auth code: %v", err)
} }
result.AuthCodes++ result.AuthCodes++