Merge pull request #1837 from flant/bump-golangci-lint-and-fix-some-linters
fix: Bump golangci-lint version and fix some linter's problems
This commit is contained in:
		@@ -1,34 +1,45 @@
 | 
				
			|||||||
run:
 | 
					run:
 | 
				
			||||||
    timeout: 2m
 | 
					  timeout: 2m
 | 
				
			||||||
 | 
					
 | 
				
			||||||
linters-settings:
 | 
					linters-settings:
 | 
				
			||||||
    golint:
 | 
					  golint:
 | 
				
			||||||
        min-confidence: 0.1
 | 
					    min-confidence: 0.1
 | 
				
			||||||
    goimports:
 | 
					  goimports:
 | 
				
			||||||
        local-prefixes: github.com/dexidp/dex
 | 
					    local-prefixes: github.com/dexidp/dex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
linters:
 | 
					linters:
 | 
				
			||||||
    enable-all: true
 | 
					  disable-all: true
 | 
				
			||||||
    disable:
 | 
					  enable:
 | 
				
			||||||
        - funlen
 | 
					  - bodyclose
 | 
				
			||||||
        - maligned
 | 
					  - deadcode
 | 
				
			||||||
        - wsl
 | 
					  - depguard
 | 
				
			||||||
 | 
					  - dogsled
 | 
				
			||||||
 | 
					  - gochecknoinits
 | 
				
			||||||
 | 
					  - gofmt
 | 
				
			||||||
 | 
					  - goimports
 | 
				
			||||||
 | 
					  - golint
 | 
				
			||||||
 | 
					  - gosimple
 | 
				
			||||||
 | 
					  - gocritic
 | 
				
			||||||
 | 
					  - govet
 | 
				
			||||||
 | 
					  - ineffassign
 | 
				
			||||||
 | 
					  - interfacer
 | 
				
			||||||
 | 
					  - misspell
 | 
				
			||||||
 | 
					  - nakedret
 | 
				
			||||||
 | 
					  - staticcheck
 | 
				
			||||||
 | 
					  - structcheck
 | 
				
			||||||
 | 
					  - stylecheck
 | 
				
			||||||
 | 
					  - typecheck
 | 
				
			||||||
 | 
					  - unconvert
 | 
				
			||||||
 | 
					  - unused
 | 
				
			||||||
 | 
					  - varcheck
 | 
				
			||||||
 | 
					  - whitespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # TODO: fix me
 | 
					  # TODO: fix linter errors before enabling
 | 
				
			||||||
        - unparam
 | 
					  # - unparam
 | 
				
			||||||
        - golint
 | 
					  # - scopelint
 | 
				
			||||||
        - goconst
 | 
					  # - gosec
 | 
				
			||||||
        - staticcheck
 | 
					  # - gocyclo
 | 
				
			||||||
        - nakedret
 | 
					  # - lll
 | 
				
			||||||
        - errcheck
 | 
					  # - goconst
 | 
				
			||||||
        - gosec
 | 
					  # - errcheck
 | 
				
			||||||
        - gochecknoinits
 | 
					  # - dupl
 | 
				
			||||||
        - gochecknoglobals
 | 
					 | 
				
			||||||
        - prealloc
 | 
					 | 
				
			||||||
        - scopelint
 | 
					 | 
				
			||||||
        - lll
 | 
					 | 
				
			||||||
        - dupl
 | 
					 | 
				
			||||||
        - gocritic
 | 
					 | 
				
			||||||
        - gocyclo
 | 
					 | 
				
			||||||
        - gocognit
 | 
					 | 
				
			||||||
        - godox
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										2
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								Makefile
									
									
									
									
									
								
							@@ -18,7 +18,7 @@ export GOBIN=$(PWD)/bin
 | 
				
			|||||||
LD_FLAGS="-w -X $(REPO_PATH)/version.Version=$(VERSION)"
 | 
					LD_FLAGS="-w -X $(REPO_PATH)/version.Version=$(VERSION)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Dependency versions
 | 
					# Dependency versions
 | 
				
			||||||
GOLANGCI_VERSION = 1.21.0
 | 
					GOLANGCI_VERSION = 1.31.0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
build: bin/dex
 | 
					build: bin/dex
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -49,7 +49,7 @@ type Config struct {
 | 
				
			|||||||
	StaticPasswords []password `json:"staticPasswords"`
 | 
						StaticPasswords []password `json:"staticPasswords"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Validate the configuration
 | 
					// Validate the configuration
 | 
				
			||||||
func (c Config) Validate() error {
 | 
					func (c Config) Validate() error {
 | 
				
			||||||
	// Fast checks. Perform these first for a more responsive CLI.
 | 
						// Fast checks. Perform these first for a more responsive CLI.
 | 
				
			||||||
	checks := []struct {
 | 
						checks := []struct {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -111,7 +111,7 @@ func (c *crowdConnector) Login(ctx context.Context, s connector.Scopes, username
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// We want to return a different error if the user's password is incorrect vs
 | 
						// We want to return a different error if the user's password is incorrect vs
 | 
				
			||||||
	// if there was an error.
 | 
						// if there was an error.
 | 
				
			||||||
	incorrectPass := false
 | 
						var incorrectPass bool
 | 
				
			||||||
	var user crowdUser
 | 
						var user crowdUser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	client := c.crowdAPIClient()
 | 
						client := c.crowdAPIClient()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,7 @@ func (m *callback) LoginURL(s connector.Scopes, callbackURL, state string) (stri
 | 
				
			|||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", fmt.Errorf("failed to parse callbackURL %q: %v", callbackURL, err)
 | 
							return "", fmt.Errorf("failed to parse callbackURL %q: %v", callbackURL, err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	u.Path = u.Path + m.pathSuffix
 | 
						u.Path += m.pathSuffix
 | 
				
			||||||
	v := u.Query()
 | 
						v := u.Query()
 | 
				
			||||||
	v.Set("state", state)
 | 
						v.Set("state", state)
 | 
				
			||||||
	u.RawQuery = v.Encode()
 | 
						u.RawQuery = v.Encode()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -334,11 +334,12 @@ func (c *githubConnector) Refresh(ctx context.Context, s connector.Scopes, ident
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// getGroups retrieves GitHub orgs and teams a user is in, if any.
 | 
					// getGroups retrieves GitHub orgs and teams a user is in, if any.
 | 
				
			||||||
func (c *githubConnector) getGroups(ctx context.Context, client *http.Client, groupScope bool, userLogin string) ([]string, error) {
 | 
					func (c *githubConnector) getGroups(ctx context.Context, client *http.Client, groupScope bool, userLogin string) ([]string, error) {
 | 
				
			||||||
	if len(c.orgs) > 0 {
 | 
						switch {
 | 
				
			||||||
 | 
						case len(c.orgs) > 0:
 | 
				
			||||||
		return c.groupsForOrgs(ctx, client, userLogin)
 | 
							return c.groupsForOrgs(ctx, client, userLogin)
 | 
				
			||||||
	} else if c.org != "" {
 | 
						case c.org != "":
 | 
				
			||||||
		return c.teamsForOrg(ctx, client, c.org)
 | 
							return c.teamsForOrg(ctx, client, c.org)
 | 
				
			||||||
	} else if groupScope && c.loadAllGroups {
 | 
						case groupScope && c.loadAllGroups:
 | 
				
			||||||
		return c.userGroups(ctx, client)
 | 
							return c.userGroups(ctx, client)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil, nil
 | 
						return nil, nil
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,6 +13,7 @@ import (
 | 
				
			|||||||
	"golang.org/x/oauth2"
 | 
						"golang.org/x/oauth2"
 | 
				
			||||||
	"golang.org/x/oauth2/google"
 | 
						"golang.org/x/oauth2/google"
 | 
				
			||||||
	admin "google.golang.org/api/admin/directory/v1"
 | 
						admin "google.golang.org/api/admin/directory/v1"
 | 
				
			||||||
 | 
						"google.golang.org/api/option"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/dexidp/dex/connector"
 | 
						"github.com/dexidp/dex/connector"
 | 
				
			||||||
	pkg_groups "github.com/dexidp/dex/pkg/groups"
 | 
						pkg_groups "github.com/dexidp/dex/pkg/groups"
 | 
				
			||||||
@@ -289,7 +290,7 @@ func createDirectoryService(serviceAccountFilePath string, email string) (*admin
 | 
				
			|||||||
	ctx := context.Background()
 | 
						ctx := context.Background()
 | 
				
			||||||
	client := config.Client(ctx)
 | 
						client := config.Client(ctx)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	srv, err := admin.New(client)
 | 
						srv, err := admin.NewService(ctx, option.WithHTTPClient(client))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("unable to create directory service %v", err)
 | 
							return nil, fmt.Errorf("unable to create directory service %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -56,6 +56,7 @@ import (
 | 
				
			|||||||
//         nameAttr: name
 | 
					//         nameAttr: name
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// UserMatcher holds information about user and group matching.
 | 
				
			||||||
type UserMatcher struct {
 | 
					type UserMatcher struct {
 | 
				
			||||||
	UserAttr  string `json:"userAttr"`
 | 
						UserAttr  string `json:"userAttr"`
 | 
				
			||||||
	GroupAttr string `json:"groupAttr"`
 | 
						GroupAttr string `json:"groupAttr"`
 | 
				
			||||||
@@ -187,9 +188,9 @@ func parseScope(s string) (int, bool) {
 | 
				
			|||||||
// See "Config.GroupSearch.UserMatchers" comments for the details
 | 
					// See "Config.GroupSearch.UserMatchers" comments for the details
 | 
				
			||||||
func (c *ldapConnector) userMatchers() []UserMatcher {
 | 
					func (c *ldapConnector) userMatchers() []UserMatcher {
 | 
				
			||||||
	if len(c.GroupSearch.UserMatchers) > 0 && c.GroupSearch.UserMatchers[0].UserAttr != "" {
 | 
						if len(c.GroupSearch.UserMatchers) > 0 && c.GroupSearch.UserMatchers[0].UserAttr != "" {
 | 
				
			||||||
		return c.GroupSearch.UserMatchers[:]
 | 
							return c.GroupSearch.UserMatchers
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
					
 | 
				
			||||||
	return []UserMatcher{
 | 
						return []UserMatcher{
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			UserAttr:  c.GroupSearch.UserAttr,
 | 
								UserAttr:  c.GroupSearch.UserAttr,
 | 
				
			||||||
@@ -244,9 +245,9 @@ func (c *Config) openConnector(logger log.Logger) (*ldapConnector, error) {
 | 
				
			|||||||
	if host, _, err = net.SplitHostPort(c.Host); err != nil {
 | 
						if host, _, err = net.SplitHostPort(c.Host); err != nil {
 | 
				
			||||||
		host = c.Host
 | 
							host = c.Host
 | 
				
			||||||
		if c.InsecureNoSSL {
 | 
							if c.InsecureNoSSL {
 | 
				
			||||||
			c.Host = c.Host + ":389"
 | 
								c.Host += ":389"
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			c.Host = c.Host + ":636"
 | 
								c.Host += ":636"
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -303,7 +304,7 @@ var (
 | 
				
			|||||||
// do initializes a connection to the LDAP directory and passes it to the
 | 
					// do initializes a connection to the LDAP directory and passes it to the
 | 
				
			||||||
// provided function. It then performs appropriate teardown or reuse before
 | 
					// provided function. It then performs appropriate teardown or reuse before
 | 
				
			||||||
// returning.
 | 
					// returning.
 | 
				
			||||||
func (c *ldapConnector) do(ctx context.Context, f func(c *ldap.Conn) error) error {
 | 
					func (c *ldapConnector) do(_ context.Context, f func(c *ldap.Conn) error) error {
 | 
				
			||||||
	// TODO(ericchiang): support context here
 | 
						// TODO(ericchiang): support context here
 | 
				
			||||||
	var (
 | 
						var (
 | 
				
			||||||
		conn *ldap.Conn
 | 
							conn *ldap.Conn
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,6 +11,7 @@ import (
 | 
				
			|||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
						"sync"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"github.com/beevik/etree"
 | 
						"github.com/beevik/etree"
 | 
				
			||||||
@@ -60,20 +61,9 @@ var (
 | 
				
			|||||||
		nameIDformatTransient,
 | 
							nameIDformatTransient,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	nameIDFormatLookup = make(map[string]string)
 | 
						nameIDFormatLookup = make(map[string]string)
 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
func init() {
 | 
						lookupOnce sync.Once
 | 
				
			||||||
	suffix := func(s, sep string) string {
 | 
					)
 | 
				
			||||||
		if i := strings.LastIndex(s, sep); i > 0 {
 | 
					 | 
				
			||||||
			return s[i+1:]
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		return s
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	for _, format := range nameIDFormats {
 | 
					 | 
				
			||||||
		nameIDFormatLookup[suffix(format, ":")] = format
 | 
					 | 
				
			||||||
		nameIDFormatLookup[format] = format
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Config represents configuration options for the SAML provider.
 | 
					// Config represents configuration options for the SAML provider.
 | 
				
			||||||
type Config struct {
 | 
					type Config struct {
 | 
				
			||||||
@@ -176,6 +166,19 @@ func (c *Config) openConnector(logger log.Logger) (*provider, error) {
 | 
				
			|||||||
	if p.nameIDPolicyFormat == "" {
 | 
						if p.nameIDPolicyFormat == "" {
 | 
				
			||||||
		p.nameIDPolicyFormat = nameIDFormatPersistent
 | 
							p.nameIDPolicyFormat = nameIDFormatPersistent
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
 | 
							lookupOnce.Do(func() {
 | 
				
			||||||
 | 
								suffix := func(s, sep string) string {
 | 
				
			||||||
 | 
									if i := strings.LastIndex(s, sep); i > 0 {
 | 
				
			||||||
 | 
										return s[i+1:]
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									return s
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								for _, format := range nameIDFormats {
 | 
				
			||||||
 | 
									nameIDFormatLookup[suffix(format, ":")] = format
 | 
				
			||||||
 | 
									nameIDFormatLookup[format] = format
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if format, ok := nameIDFormatLookup[p.nameIDPolicyFormat]; ok {
 | 
							if format, ok := nameIDFormatLookup[p.nameIDPolicyFormat]; ok {
 | 
				
			||||||
			p.nameIDPolicyFormat = format
 | 
								p.nameIDPolicyFormat = format
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
@@ -364,7 +367,7 @@ func (p *provider) HandlePOST(s connector.Scopes, samlResponse, inResponseTo str
 | 
				
			|||||||
	switch {
 | 
						switch {
 | 
				
			||||||
	case subject.NameID != nil:
 | 
						case subject.NameID != nil:
 | 
				
			||||||
		if ident.UserID = subject.NameID.Value; ident.UserID == "" {
 | 
							if ident.UserID = subject.NameID.Value; ident.UserID == "" {
 | 
				
			||||||
			return ident, fmt.Errorf("NameID element does not contain a value")
 | 
								return ident, fmt.Errorf("element NameID does not contain a value")
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
		return ident, fmt.Errorf("subject does not contain an NameID element")
 | 
							return ident, fmt.Errorf("subject does not contain an NameID element")
 | 
				
			||||||
@@ -488,7 +491,7 @@ func (p *provider) validateSubject(subject *subject, inResponseTo string) error
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			data := c.SubjectConfirmationData
 | 
								data := c.SubjectConfirmationData
 | 
				
			||||||
			if data == nil {
 | 
								if data == nil {
 | 
				
			||||||
				return fmt.Errorf("SubjectConfirmation contained no SubjectConfirmationData")
 | 
									return fmt.Errorf("no SubjectConfirmationData field found in SubjectConfirmation")
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if data.InResponseTo != inResponseTo {
 | 
								if data.InResponseTo != inResponseTo {
 | 
				
			||||||
				return fmt.Errorf("expected SubjectConfirmationData InResponseTo value %q, got %q", inResponseTo, data.InResponseTo)
 | 
									return fmt.Errorf("expected SubjectConfirmationData InResponseTo value %q, got %q", inResponseTo, data.InResponseTo)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -291,7 +291,7 @@ func TestRefreshToken(t *testing.T) {
 | 
				
			|||||||
		t.Errorf("failed to marshal offline session ID: %v", err)
 | 
							t.Errorf("failed to marshal offline session ID: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Testing the api.
 | 
						// Testing the api.
 | 
				
			||||||
	listReq := api.ListRefreshReq{
 | 
						listReq := api.ListRefreshReq{
 | 
				
			||||||
		UserId: subjectString,
 | 
							UserId: subjectString,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,17 +15,17 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type deviceCodeResponse struct {
 | 
					type deviceCodeResponse struct {
 | 
				
			||||||
	//The unique device code for device authentication
 | 
						// The unique device code for device authentication
 | 
				
			||||||
	DeviceCode string `json:"device_code"`
 | 
						DeviceCode string `json:"device_code"`
 | 
				
			||||||
	//The code the user will exchange via a browser and log in
 | 
						// The code the user will exchange via a browser and log in
 | 
				
			||||||
	UserCode string `json:"user_code"`
 | 
						UserCode string `json:"user_code"`
 | 
				
			||||||
	//The url to verify the user code.
 | 
						// The url to verify the user code.
 | 
				
			||||||
	VerificationURI string `json:"verification_uri"`
 | 
						VerificationURI string `json:"verification_uri"`
 | 
				
			||||||
	//The verification uri with the user code appended for pre-filling form
 | 
						// The verification uri with the user code appended for pre-filling form
 | 
				
			||||||
	VerificationURIComplete string `json:"verification_uri_complete"`
 | 
						VerificationURIComplete string `json:"verification_uri_complete"`
 | 
				
			||||||
	//The lifetime of the device code
 | 
						// The lifetime of the device code
 | 
				
			||||||
	ExpireTime int `json:"expires_in"`
 | 
						ExpireTime int `json:"expires_in"`
 | 
				
			||||||
	//How often the device is allowed to poll to verify that the user login occurred
 | 
						// How often the device is allowed to poll to verify that the user login occurred
 | 
				
			||||||
	PollInterval int `json:"interval"`
 | 
						PollInterval int `json:"interval"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -66,27 +66,27 @@ func (s *Server) handleDeviceCode(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Get the client id and scopes from the post
 | 
							// Get the client id and scopes from the post
 | 
				
			||||||
		clientID := r.Form.Get("client_id")
 | 
							clientID := r.Form.Get("client_id")
 | 
				
			||||||
		clientSecret := r.Form.Get("client_secret")
 | 
							clientSecret := r.Form.Get("client_secret")
 | 
				
			||||||
		scopes := strings.Fields(r.Form.Get("scope"))
 | 
							scopes := strings.Fields(r.Form.Get("scope"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		s.logger.Infof("Received device request for client %v with scopes %v", clientID, scopes)
 | 
							s.logger.Infof("Received device request for client %v with scopes %v", clientID, scopes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Make device code
 | 
							// Make device code
 | 
				
			||||||
		deviceCode := storage.NewDeviceCode()
 | 
							deviceCode := storage.NewDeviceCode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//make user code
 | 
							// make user code
 | 
				
			||||||
		userCode, err := storage.NewUserCode()
 | 
							userCode, err := storage.NewUserCode()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			s.logger.Errorf("Error generating user code: %v", err)
 | 
								s.logger.Errorf("Error generating user code: %v", err)
 | 
				
			||||||
			s.tokenErrHelper(w, errInvalidRequest, "", http.StatusInternalServerError)
 | 
								s.tokenErrHelper(w, errInvalidRequest, "", http.StatusInternalServerError)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Generate the expire time
 | 
							// Generate the expire time
 | 
				
			||||||
		expireTime := time.Now().Add(s.deviceRequestsValidFor)
 | 
							expireTime := time.Now().Add(s.deviceRequestsValidFor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Store the Device Request
 | 
							// Store the Device Request
 | 
				
			||||||
		deviceReq := storage.DeviceRequest{
 | 
							deviceReq := storage.DeviceRequest{
 | 
				
			||||||
			UserCode:     userCode,
 | 
								UserCode:     userCode,
 | 
				
			||||||
			DeviceCode:   deviceCode,
 | 
								DeviceCode:   deviceCode,
 | 
				
			||||||
@@ -102,7 +102,7 @@ func (s *Server) handleDeviceCode(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Store the device token
 | 
							// Store the device token
 | 
				
			||||||
		deviceToken := storage.DeviceToken{
 | 
							deviceToken := storage.DeviceToken{
 | 
				
			||||||
			DeviceCode:          deviceCode,
 | 
								DeviceCode:          deviceCode,
 | 
				
			||||||
			Status:              deviceTokenPending,
 | 
								Status:              deviceTokenPending,
 | 
				
			||||||
@@ -176,7 +176,7 @@ func (s *Server) handleDeviceToken(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		now := s.now()
 | 
							now := s.now()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Grab the device token, check validity
 | 
							// Grab the device token, check validity
 | 
				
			||||||
		deviceToken, err := s.storage.GetDeviceToken(deviceCode)
 | 
							deviceToken, err := s.storage.GetDeviceToken(deviceCode)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			if err != storage.ErrNotFound {
 | 
								if err != storage.ErrNotFound {
 | 
				
			||||||
@@ -189,13 +189,13 @@ func (s *Server) handleDeviceToken(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Rate Limiting check
 | 
							// Rate Limiting check
 | 
				
			||||||
		slowDown := false
 | 
							slowDown := false
 | 
				
			||||||
		pollInterval := deviceToken.PollIntervalSeconds
 | 
							pollInterval := deviceToken.PollIntervalSeconds
 | 
				
			||||||
		minRequestTime := deviceToken.LastRequestTime.Add(time.Second * time.Duration(pollInterval))
 | 
							minRequestTime := deviceToken.LastRequestTime.Add(time.Second * time.Duration(pollInterval))
 | 
				
			||||||
		if now.Before(minRequestTime) {
 | 
							if now.Before(minRequestTime) {
 | 
				
			||||||
			slowDown = true
 | 
								slowDown = true
 | 
				
			||||||
			//Continually increase the poll interval until the user waits the proper time
 | 
								// Continually increase the poll interval until the user waits the proper time
 | 
				
			||||||
			pollInterval += 5
 | 
								pollInterval += 5
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			pollInterval = 5
 | 
								pollInterval = 5
 | 
				
			||||||
@@ -255,7 +255,7 @@ func (s *Server) handleDeviceCallback(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Grab the device request from storage
 | 
							// Grab the device request from storage
 | 
				
			||||||
		deviceReq, err := s.storage.GetDeviceRequest(userCode)
 | 
							deviceReq, err := s.storage.GetDeviceRequest(userCode)
 | 
				
			||||||
		if err != nil || s.now().After(deviceReq.Expiry) {
 | 
							if err != nil || s.now().After(deviceReq.Expiry) {
 | 
				
			||||||
			errCode := http.StatusBadRequest
 | 
								errCode := http.StatusBadRequest
 | 
				
			||||||
@@ -289,7 +289,7 @@ func (s *Server) handleDeviceCallback(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Grab the device token from storage
 | 
							// Grab the device token from storage
 | 
				
			||||||
		old, err := s.storage.GetDeviceToken(deviceReq.DeviceCode)
 | 
							old, err := s.storage.GetDeviceToken(deviceReq.DeviceCode)
 | 
				
			||||||
		if err != nil || s.now().After(old.Expiry) {
 | 
							if err != nil || s.now().After(old.Expiry) {
 | 
				
			||||||
			errCode := http.StatusBadRequest
 | 
								errCode := http.StatusBadRequest
 | 
				
			||||||
@@ -353,7 +353,7 @@ func (s *Server) verifyUserCode(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		userCode = strings.ToUpper(userCode)
 | 
							userCode = strings.ToUpper(userCode)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Find the user code in the available requests
 | 
							// Find the user code in the available requests
 | 
				
			||||||
		deviceRequest, err := s.storage.GetDeviceRequest(userCode)
 | 
							deviceRequest, err := s.storage.GetDeviceRequest(userCode)
 | 
				
			||||||
		if err != nil || s.now().After(deviceRequest.Expiry) {
 | 
							if err != nil || s.now().After(deviceRequest.Expiry) {
 | 
				
			||||||
			if err != nil && err != storage.ErrNotFound {
 | 
								if err != nil && err != storage.ErrNotFound {
 | 
				
			||||||
@@ -366,7 +366,7 @@ func (s *Server) verifyUserCode(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		//Redirect to Dex Auth Endpoint
 | 
							// Redirect to Dex Auth Endpoint
 | 
				
			||||||
		authURL := path.Join(s.issuerURL.Path, "/auth")
 | 
							authURL := path.Join(s.issuerURL.Path, "/auth")
 | 
				
			||||||
		u, err := url.Parse(authURL)
 | 
							u, err := url.Parse(authURL)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ func TestDeviceVerificationURI(t *testing.T) {
 | 
				
			|||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
	// Setup a dex server.
 | 
						// Setup a dex server.
 | 
				
			||||||
	httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
						httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
		c.Issuer = c.Issuer + "/non-root-path"
 | 
							c.Issuer += "/non-root-path"
 | 
				
			||||||
		c.Now = now
 | 
							c.Now = now
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	defer httpServer.Close()
 | 
						defer httpServer.Close()
 | 
				
			||||||
@@ -76,7 +76,7 @@ func TestHandleDeviceCode(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Setup a dex server.
 | 
								// Setup a dex server.
 | 
				
			||||||
			httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
								httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
				c.Issuer = c.Issuer + "/non-root-path"
 | 
									c.Issuer += "/non-root-path"
 | 
				
			||||||
				c.Now = now
 | 
									c.Now = now
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			defer httpServer.Close()
 | 
								defer httpServer.Close()
 | 
				
			||||||
@@ -322,7 +322,7 @@ func TestDeviceCallback(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Setup a dex server.
 | 
								// Setup a dex server.
 | 
				
			||||||
			httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
								httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
				//c.Issuer = c.Issuer + "/non-root-path"
 | 
									// c.Issuer = c.Issuer + "/non-root-path"
 | 
				
			||||||
				c.Now = now
 | 
									c.Now = now
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			defer httpServer.Close()
 | 
								defer httpServer.Close()
 | 
				
			||||||
@@ -506,7 +506,7 @@ func TestDeviceTokenResponse(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Setup a dex server.
 | 
								// Setup a dex server.
 | 
				
			||||||
			httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
								httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
				c.Issuer = c.Issuer + "/non-root-path"
 | 
									c.Issuer += "/non-root-path"
 | 
				
			||||||
				c.Now = now
 | 
									c.Now = now
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			defer httpServer.Close()
 | 
								defer httpServer.Close()
 | 
				
			||||||
@@ -546,7 +546,7 @@ func TestDeviceTokenResponse(t *testing.T) {
 | 
				
			|||||||
				t.Errorf("Could read token response %v", err)
 | 
									t.Errorf("Could read token response %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			if tc.expectedResponseCode == http.StatusBadRequest || tc.expectedResponseCode == http.StatusUnauthorized {
 | 
								if tc.expectedResponseCode == http.StatusBadRequest || tc.expectedResponseCode == http.StatusUnauthorized {
 | 
				
			||||||
				expectJsonErrorResponse(tc.testName, body, tc.expectedServerResponse, t)
 | 
									expectJSONErrorResponse(tc.testName, body, tc.expectedServerResponse, t)
 | 
				
			||||||
			} else if string(body) != tc.expectedServerResponse {
 | 
								} else if string(body) != tc.expectedServerResponse {
 | 
				
			||||||
				t.Errorf("Unexpected Server Response.  Expected %v got %v", tc.expectedServerResponse, string(body))
 | 
									t.Errorf("Unexpected Server Response.  Expected %v got %v", tc.expectedServerResponse, string(body))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
@@ -554,7 +554,7 @@ func TestDeviceTokenResponse(t *testing.T) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func expectJsonErrorResponse(testCase string, body []byte, expectedError string, t *testing.T) {
 | 
					func expectJSONErrorResponse(testCase string, body []byte, expectedError string, t *testing.T) {
 | 
				
			||||||
	jsonMap := make(map[string]interface{})
 | 
						jsonMap := make(map[string]interface{})
 | 
				
			||||||
	err := json.Unmarshal(body, &jsonMap)
 | 
						err := json.Unmarshal(body, &jsonMap)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@@ -637,7 +637,7 @@ func TestVerifyCodeResponse(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Setup a dex server.
 | 
								// Setup a dex server.
 | 
				
			||||||
			httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
								httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
				c.Issuer = c.Issuer + "/non-root-path"
 | 
									c.Issuer += "/non-root-path"
 | 
				
			||||||
				c.Now = now
 | 
									c.Now = now
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			defer httpServer.Close()
 | 
								defer httpServer.Close()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -274,7 +274,7 @@ func (s *Server) handleAuthorization(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := s.templates.login(r, w, connectorInfos, r.URL.Path); err != nil {
 | 
						if err := s.templates.login(r, w, connectorInfos); err != nil {
 | 
				
			||||||
		s.logger.Errorf("Server template error: %v", err)
 | 
							s.logger.Errorf("Server template error: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -335,7 +335,7 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
			}
 | 
								}
 | 
				
			||||||
			http.Redirect(w, r, callbackURL, http.StatusFound)
 | 
								http.Redirect(w, r, callbackURL, http.StatusFound)
 | 
				
			||||||
		case connector.PasswordConnector:
 | 
							case connector.PasswordConnector:
 | 
				
			||||||
			if err := s.templates.password(r, w, r.URL.String(), "", usernamePrompt(conn), false, showBacklink, r.URL.Path); err != nil {
 | 
								if err := s.templates.password(r, w, r.URL.String(), "", usernamePrompt(conn), false, showBacklink); err != nil {
 | 
				
			||||||
				s.logger.Errorf("Server template error: %v", err)
 | 
									s.logger.Errorf("Server template error: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		case connector.SAMLConnector:
 | 
							case connector.SAMLConnector:
 | 
				
			||||||
@@ -383,7 +383,7 @@ func (s *Server) handleConnectorLogin(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if !ok {
 | 
							if !ok {
 | 
				
			||||||
			if err := s.templates.password(r, w, r.URL.String(), username, usernamePrompt(passwordConnector), true, showBacklink, r.URL.Path); err != nil {
 | 
								if err := s.templates.password(r, w, r.URL.String(), username, usernamePrompt(passwordConnector), true, showBacklink); err != nil {
 | 
				
			||||||
				s.logger.Errorf("Server template error: %v", err)
 | 
									s.logger.Errorf("Server template error: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
@@ -505,7 +505,7 @@ func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.Auth
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	email := claims.Email
 | 
						email := claims.Email
 | 
				
			||||||
	if !claims.EmailVerified {
 | 
						if !claims.EmailVerified {
 | 
				
			||||||
		email = email + " (unverified)"
 | 
							email += " (unverified)"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s.logger.Infof("login successful: connector %q, username=%q, preferred_username=%q, email=%q, groups=%q",
 | 
						s.logger.Infof("login successful: connector %q, username=%q, preferred_username=%q, email=%q, groups=%q",
 | 
				
			||||||
@@ -518,7 +518,8 @@ func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.Auth
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Try to retrieve an existing OfflineSession object for the corresponding user.
 | 
						// Try to retrieve an existing OfflineSession object for the corresponding user.
 | 
				
			||||||
	if session, err := s.storage.GetOfflineSessions(identity.UserID, authReq.ConnectorID); err != nil {
 | 
						session, err := s.storage.GetOfflineSessions(identity.UserID, authReq.ConnectorID)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
		if err != storage.ErrNotFound {
 | 
							if err != storage.ErrNotFound {
 | 
				
			||||||
			s.logger.Errorf("failed to get offline session: %v", err)
 | 
								s.logger.Errorf("failed to get offline session: %v", err)
 | 
				
			||||||
			return "", err
 | 
								return "", err
 | 
				
			||||||
@@ -536,17 +537,19 @@ func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.Auth
 | 
				
			|||||||
			s.logger.Errorf("failed to create offline session: %v", err)
 | 
								s.logger.Errorf("failed to create offline session: %v", err)
 | 
				
			||||||
			return "", err
 | 
								return "", err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else {
 | 
					
 | 
				
			||||||
		// Update existing OfflineSession obj with new RefreshTokenRef.
 | 
							return returnURL, nil
 | 
				
			||||||
		if err := s.storage.UpdateOfflineSessions(session.UserID, session.ConnID, func(old storage.OfflineSessions) (storage.OfflineSessions, error) {
 | 
						}
 | 
				
			||||||
			if len(identity.ConnectorData) > 0 {
 | 
					
 | 
				
			||||||
				old.ConnectorData = identity.ConnectorData
 | 
						// Update existing OfflineSession obj with new RefreshTokenRef.
 | 
				
			||||||
			}
 | 
						if err := s.storage.UpdateOfflineSessions(session.UserID, session.ConnID, func(old storage.OfflineSessions) (storage.OfflineSessions, error) {
 | 
				
			||||||
			return old, nil
 | 
							if len(identity.ConnectorData) > 0 {
 | 
				
			||||||
		}); err != nil {
 | 
								old.ConnectorData = identity.ConnectorData
 | 
				
			||||||
			s.logger.Errorf("failed to update offline session: %v", err)
 | 
					 | 
				
			||||||
			return "", err
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							return old, nil
 | 
				
			||||||
 | 
						}); err != nil {
 | 
				
			||||||
 | 
							s.logger.Errorf("failed to update offline session: %v", err)
 | 
				
			||||||
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return returnURL, nil
 | 
						return returnURL, nil
 | 
				
			||||||
@@ -577,7 +580,7 @@ func (s *Server) handleApproval(w http.ResponseWriter, r *http.Request) {
 | 
				
			|||||||
			s.renderError(r, w, http.StatusInternalServerError, "Failed to retrieve client.")
 | 
								s.renderError(r, w, http.StatusInternalServerError, "Failed to retrieve client.")
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if err := s.templates.approval(r, w, authReq.ID, authReq.Claims.Username, client.Name, authReq.Scopes, r.URL.Path); err != nil {
 | 
							if err := s.templates.approval(r, w, authReq.ID, authReq.Claims.Username, client.Name, authReq.Scopes); err != nil {
 | 
				
			||||||
			s.logger.Errorf("Server template error: %v", err)
 | 
								s.logger.Errorf("Server template error: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	case http.MethodPost:
 | 
						case http.MethodPost:
 | 
				
			||||||
@@ -650,7 +653,7 @@ func (s *Server) sendCodeResponse(w http.ResponseWriter, r *http.Request, authRe
 | 
				
			|||||||
			// Implicit and hybrid flows that try to use the OOB redirect URI are
 | 
								// Implicit and hybrid flows that try to use the OOB redirect URI are
 | 
				
			||||||
			// rejected earlier. If we got here we're using the code flow.
 | 
								// rejected earlier. If we got here we're using the code flow.
 | 
				
			||||||
			if authReq.RedirectURI == redirectURIOOB {
 | 
								if authReq.RedirectURI == redirectURIOOB {
 | 
				
			||||||
				if err := s.templates.oob(r, w, code.ID, r.URL.Path); err != nil {
 | 
									if err := s.templates.oob(r, w, code.ID); err != nil {
 | 
				
			||||||
					s.logger.Errorf("Server template error: %v", err)
 | 
										s.logger.Errorf("Server template error: %v", err)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
@@ -1017,15 +1020,18 @@ func (s *Server) handleRefreshToken(w http.ResponseWriter, r *http.Request, clie
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var connectorData []byte
 | 
						var connectorData []byte
 | 
				
			||||||
	if session, err := s.storage.GetOfflineSessions(refresh.Claims.UserID, refresh.ConnectorID); err != nil {
 | 
					
 | 
				
			||||||
 | 
						session, err := s.storage.GetOfflineSessions(refresh.Claims.UserID, refresh.ConnectorID)
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case err != nil:
 | 
				
			||||||
		if err != storage.ErrNotFound {
 | 
							if err != storage.ErrNotFound {
 | 
				
			||||||
			s.logger.Errorf("failed to get offline session: %v", err)
 | 
								s.logger.Errorf("failed to get offline session: %v", err)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if len(refresh.ConnectorData) > 0 {
 | 
						case len(refresh.ConnectorData) > 0:
 | 
				
			||||||
		// Use the old connector data if it exists, should be deleted once used
 | 
							// Use the old connector data if it exists, should be deleted once used
 | 
				
			||||||
		connectorData = refresh.ConnectorData
 | 
							connectorData = refresh.ConnectorData
 | 
				
			||||||
	} else {
 | 
						default:
 | 
				
			||||||
		connectorData = session.ConnectorData
 | 
							connectorData = session.ConnectorData
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -305,7 +305,7 @@ func newServer(ctx context.Context, c Config, rotationStrategy rotationStrategy)
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
		r.Handle(path.Join(issuerURL.Path, p), instrumentHandlerCounter(p, handler))
 | 
							r.Handle(path.Join(issuerURL.Path, p), instrumentHandlerCounter(p, handler))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	r.NotFoundHandler = http.HandlerFunc(http.NotFound)
 | 
						r.NotFoundHandler = http.NotFoundHandler()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	discoveryHandler, err := s.discoveryHandler()
 | 
						discoveryHandler, err := s.discoveryHandler()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -177,7 +177,7 @@ func TestDiscovery(t *testing.T) {
 | 
				
			|||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	httpServer, _ := newTestServer(ctx, t, func(c *Config) {
 | 
						httpServer, _ := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
		c.Issuer = c.Issuer + "/non-root-path"
 | 
							c.Issuer += "/non-root-path"
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	defer httpServer.Close()
 | 
						defer httpServer.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -504,7 +504,7 @@ func TestOAuth2CodeFlow(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Setup a dex server.
 | 
								// Setup a dex server.
 | 
				
			||||||
			httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
								httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
				c.Issuer = c.Issuer + "/non-root-path"
 | 
									c.Issuer += "/non-root-path"
 | 
				
			||||||
				c.Now = now
 | 
									c.Now = now
 | 
				
			||||||
				c.IDTokensValidFor = idTokensValidFor
 | 
									c.IDTokensValidFor = idTokensValidFor
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
@@ -766,7 +766,7 @@ func TestCrossClientScopes(t *testing.T) {
 | 
				
			|||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
						httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
		c.Issuer = c.Issuer + "/non-root-path"
 | 
							c.Issuer += "/non-root-path"
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	defer httpServer.Close()
 | 
						defer httpServer.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -889,7 +889,7 @@ func TestCrossClientScopesWithAzpInAudienceByDefault(t *testing.T) {
 | 
				
			|||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
						httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
		c.Issuer = c.Issuer + "/non-root-path"
 | 
							c.Issuer += "/non-root-path"
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	defer httpServer.Close()
 | 
						defer httpServer.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1180,7 +1180,7 @@ type oauth2Client struct {
 | 
				
			|||||||
// that only valid refresh tokens can be used to refresh an expired token.
 | 
					// that only valid refresh tokens can be used to refresh an expired token.
 | 
				
			||||||
func TestRefreshTokenFlow(t *testing.T) {
 | 
					func TestRefreshTokenFlow(t *testing.T) {
 | 
				
			||||||
	state := "state"
 | 
						state := "state"
 | 
				
			||||||
	now := func() time.Time { return time.Now() }
 | 
						now := time.Now
 | 
				
			||||||
	ctx, cancel := context.WithCancel(context.Background())
 | 
						ctx, cancel := context.WithCancel(context.Background())
 | 
				
			||||||
	defer cancel()
 | 
						defer cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1300,7 +1300,7 @@ func TestOAuth2DeviceFlow(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
			// Setup a dex server.
 | 
								// Setup a dex server.
 | 
				
			||||||
			httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
								httpServer, s := newTestServer(ctx, t, func(c *Config) {
 | 
				
			||||||
				c.Issuer = c.Issuer + "/non-root-path"
 | 
									c.Issuer += "/non-root-path"
 | 
				
			||||||
				c.Now = now
 | 
									c.Now = now
 | 
				
			||||||
				c.IDTokensValidFor = idTokensValidFor
 | 
									c.IDTokensValidFor = idTokensValidFor
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
@@ -1314,7 +1314,7 @@ func TestOAuth2DeviceFlow(t *testing.T) {
 | 
				
			|||||||
				t.Fatalf("failed to get provider: %v", err)
 | 
									t.Fatalf("failed to get provider: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//Add the Clients to the test server
 | 
								// Add the Clients to the test server
 | 
				
			||||||
			client := storage.Client{
 | 
								client := storage.Client{
 | 
				
			||||||
				ID:           clientID,
 | 
									ID:           clientID,
 | 
				
			||||||
				RedirectURIs: []string{deviceCallbackURI},
 | 
									RedirectURIs: []string{deviceCallbackURI},
 | 
				
			||||||
@@ -1324,13 +1324,13 @@ func TestOAuth2DeviceFlow(t *testing.T) {
 | 
				
			|||||||
				t.Fatalf("failed to create client: %v", err)
 | 
									t.Fatalf("failed to create client: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//Grab the issuer that we'll reuse for the different endpoints to hit
 | 
								// Grab the issuer that we'll reuse for the different endpoints to hit
 | 
				
			||||||
			issuer, err := url.Parse(s.issuerURL.String())
 | 
								issuer, err := url.Parse(s.issuerURL.String())
 | 
				
			||||||
			if err != nil {
 | 
								if err != nil {
 | 
				
			||||||
				t.Errorf("Could not parse issuer URL %v", err)
 | 
									t.Errorf("Could not parse issuer URL %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//Send a new Device Request
 | 
								// Send a new Device Request
 | 
				
			||||||
			codeURL, _ := url.Parse(issuer.String())
 | 
								codeURL, _ := url.Parse(issuer.String())
 | 
				
			||||||
			codeURL.Path = path.Join(codeURL.Path, "device/code")
 | 
								codeURL.Path = path.Join(codeURL.Path, "device/code")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1350,13 +1350,13 @@ func TestOAuth2DeviceFlow(t *testing.T) {
 | 
				
			|||||||
				t.Errorf("%v - Unexpected Response Type.  Expected 200 got  %v.  Response: %v", tc.name, resp.StatusCode, string(responseBody))
 | 
									t.Errorf("%v - Unexpected Response Type.  Expected 200 got  %v.  Response: %v", tc.name, resp.StatusCode, string(responseBody))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//Parse the code response
 | 
								// Parse the code response
 | 
				
			||||||
			var deviceCode deviceCodeResponse
 | 
								var deviceCode deviceCodeResponse
 | 
				
			||||||
			if err := json.Unmarshal(responseBody, &deviceCode); err != nil {
 | 
								if err := json.Unmarshal(responseBody, &deviceCode); err != nil {
 | 
				
			||||||
				t.Errorf("Unexpected Device Code Response Format %v", string(responseBody))
 | 
									t.Errorf("Unexpected Device Code Response Format %v", string(responseBody))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//Mock the user hitting the verification URI and posting the form
 | 
								// Mock the user hitting the verification URI and posting the form
 | 
				
			||||||
			verifyURL, _ := url.Parse(issuer.String())
 | 
								verifyURL, _ := url.Parse(issuer.String())
 | 
				
			||||||
			verifyURL.Path = path.Join(verifyURL.Path, "/device/auth/verify_code")
 | 
								verifyURL.Path = path.Join(verifyURL.Path, "/device/auth/verify_code")
 | 
				
			||||||
			urlData := url.Values{}
 | 
								urlData := url.Values{}
 | 
				
			||||||
@@ -1374,7 +1374,7 @@ func TestOAuth2DeviceFlow(t *testing.T) {
 | 
				
			|||||||
				t.Errorf("%v - Unexpected Response Type.  Expected 200 got  %v.  Response: %v", tc.name, resp.StatusCode, string(responseBody))
 | 
									t.Errorf("%v - Unexpected Response Type.  Expected 200 got  %v.  Response: %v", tc.name, resp.StatusCode, string(responseBody))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//Hit the Token Endpoint, and try and get an access token
 | 
								// Hit the Token Endpoint, and try and get an access token
 | 
				
			||||||
			tokenURL, _ := url.Parse(issuer.String())
 | 
								tokenURL, _ := url.Parse(issuer.String())
 | 
				
			||||||
			tokenURL.Path = path.Join(tokenURL.Path, "/device/token")
 | 
								tokenURL.Path = path.Join(tokenURL.Path, "/device/token")
 | 
				
			||||||
			v := url.Values{}
 | 
								v := url.Values{}
 | 
				
			||||||
@@ -1393,7 +1393,7 @@ func TestOAuth2DeviceFlow(t *testing.T) {
 | 
				
			|||||||
				t.Errorf("%v - Unexpected Token Response Type.  Expected 200 got  %v.  Response: %v", tc.name, resp.StatusCode, string(responseBody))
 | 
									t.Errorf("%v - Unexpected Token Response Type.  Expected 200 got  %v.  Response: %v", tc.name, resp.StatusCode, string(responseBody))
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//Parse the response
 | 
								// Parse the response
 | 
				
			||||||
			var tokenRes accessTokenReponse
 | 
								var tokenRes accessTokenReponse
 | 
				
			||||||
			if err := json.Unmarshal(responseBody, &tokenRes); err != nil {
 | 
								if err := json.Unmarshal(responseBody, &tokenRes); err != nil {
 | 
				
			||||||
				t.Errorf("Unexpected Device Access Token Response Format %v", string(responseBody))
 | 
									t.Errorf("Unexpected Device Access Token Response Format %v", string(responseBody))
 | 
				
			||||||
@@ -1411,7 +1411,7 @@ func TestOAuth2DeviceFlow(t *testing.T) {
 | 
				
			|||||||
				token.Expiry = time.Now().Add(time.Duration(secs) * time.Second)
 | 
									token.Expiry = time.Now().Add(time.Duration(secs) * time.Second)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			//Run token tests to validate info is correct
 | 
								// Run token tests to validate info is correct
 | 
				
			||||||
			// Create the OAuth2 config.
 | 
								// Create the OAuth2 config.
 | 
				
			||||||
			oauth2Config := &oauth2.Config{
 | 
								oauth2Config := &oauth2.Config{
 | 
				
			||||||
				ClientID:     client.ID,
 | 
									ClientID:     client.ID,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -78,7 +78,7 @@ func dirExists(dir string) error {
 | 
				
			|||||||
//    |  |- (theme name)
 | 
					//    |  |- (theme name)
 | 
				
			||||||
//    |- templates
 | 
					//    |- templates
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
func loadWebConfig(c webConfig) (static, theme http.Handler, templates *templates, err error) {
 | 
					func loadWebConfig(c webConfig) (http.Handler, http.Handler, *templates, error) {
 | 
				
			||||||
	if c.theme == "" {
 | 
						if c.theme == "" {
 | 
				
			||||||
		c.theme = "coreos"
 | 
							c.theme = "coreos"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -106,11 +106,11 @@ func loadWebConfig(c webConfig) (static, theme http.Handler, templates *template
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	static = http.FileServer(http.Dir(staticDir))
 | 
						static := http.FileServer(http.Dir(staticDir))
 | 
				
			||||||
	theme = http.FileServer(http.Dir(themeDir))
 | 
						theme := http.FileServer(http.Dir(themeDir))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	templates, err = loadTemplates(c, templatesDir)
 | 
						templates, err := loadTemplates(c, templatesDir)
 | 
				
			||||||
	return
 | 
						return static, theme, templates, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// loadTemplates parses the expected templates from the provided directory.
 | 
					// loadTemplates parses the expected templates from the provided directory.
 | 
				
			||||||
@@ -178,11 +178,11 @@ func loadTemplates(c webConfig, templatesDir string) (*templates, error) {
 | 
				
			|||||||
// 3. For each part of reqPath remaining(minus one), go up one level (..)
 | 
					// 3. For each part of reqPath remaining(minus one), go up one level (..)
 | 
				
			||||||
// 4. For each part of assetPath remaining, append it to result
 | 
					// 4. For each part of assetPath remaining, append it to result
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//eg
 | 
					// eg
 | 
				
			||||||
//server listens at localhost/dex so serverPath is dex
 | 
					// server listens at localhost/dex so serverPath is dex
 | 
				
			||||||
//reqPath is /dex/auth
 | 
					// reqPath is /dex/auth
 | 
				
			||||||
//assetPath is static/main.css
 | 
					// assetPath is static/main.css
 | 
				
			||||||
//relativeURL("/dex", "/dex/auth", "static/main.css") = "../static/main.css"
 | 
					// relativeURL("/dex", "/dex/auth", "static/main.css") = "../static/main.css"
 | 
				
			||||||
func relativeURL(serverPath, reqPath, assetPath string) string {
 | 
					func relativeURL(serverPath, reqPath, assetPath string) string {
 | 
				
			||||||
	if u, err := url.ParseRequestURI(assetPath); err == nil && u.Scheme != "" {
 | 
						if u, err := url.ParseRequestURI(assetPath); err == nil && u.Scheme != "" {
 | 
				
			||||||
		// assetPath points to the external URL, no changes needed
 | 
							// assetPath points to the external URL, no changes needed
 | 
				
			||||||
@@ -219,8 +219,7 @@ func relativeURL(serverPath, reqPath, assetPath string) string {
 | 
				
			|||||||
	server, req, asset := splitPath(serverPath), splitPath(reqPath), splitPath(assetPath)
 | 
						server, req, asset := splitPath(serverPath), splitPath(reqPath), splitPath(assetPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Remove common prefix of request path with server path
 | 
						// Remove common prefix of request path with server path
 | 
				
			||||||
	// nolint: ineffassign
 | 
						_, req = stripCommonParts(server, req)
 | 
				
			||||||
	server, req = stripCommonParts(server, req)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Remove common prefix of request path with asset path
 | 
						// Remove common prefix of request path with asset path
 | 
				
			||||||
	asset, req = stripCommonParts(asset, req)
 | 
						asset, req = stripCommonParts(asset, req)
 | 
				
			||||||
@@ -276,7 +275,7 @@ func (t *templates) deviceSuccess(r *http.Request, w http.ResponseWriter, client
 | 
				
			|||||||
	return renderTemplate(w, t.deviceSuccessTmpl, data)
 | 
						return renderTemplate(w, t.deviceSuccessTmpl, data)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (t *templates) login(r *http.Request, w http.ResponseWriter, connectors []connectorInfo, reqPath string) error {
 | 
					func (t *templates) login(r *http.Request, w http.ResponseWriter, connectors []connectorInfo) error {
 | 
				
			||||||
	sort.Sort(byName(connectors))
 | 
						sort.Sort(byName(connectors))
 | 
				
			||||||
	data := struct {
 | 
						data := struct {
 | 
				
			||||||
		Connectors []connectorInfo
 | 
							Connectors []connectorInfo
 | 
				
			||||||
@@ -285,7 +284,7 @@ func (t *templates) login(r *http.Request, w http.ResponseWriter, connectors []c
 | 
				
			|||||||
	return renderTemplate(w, t.loginTmpl, data)
 | 
						return renderTemplate(w, t.loginTmpl, data)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (t *templates) password(r *http.Request, w http.ResponseWriter, postURL, lastUsername, usernamePrompt string, lastWasInvalid, showBacklink bool, reqPath string) error {
 | 
					func (t *templates) password(r *http.Request, w http.ResponseWriter, postURL, lastUsername, usernamePrompt string, lastWasInvalid, showBacklink bool) error {
 | 
				
			||||||
	data := struct {
 | 
						data := struct {
 | 
				
			||||||
		PostURL        string
 | 
							PostURL        string
 | 
				
			||||||
		BackLink       bool
 | 
							BackLink       bool
 | 
				
			||||||
@@ -297,7 +296,7 @@ func (t *templates) password(r *http.Request, w http.ResponseWriter, postURL, la
 | 
				
			|||||||
	return renderTemplate(w, t.passwordTmpl, data)
 | 
						return renderTemplate(w, t.passwordTmpl, data)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (t *templates) approval(r *http.Request, w http.ResponseWriter, authReqID, username, clientName string, scopes []string, reqPath string) error {
 | 
					func (t *templates) approval(r *http.Request, 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]
 | 
				
			||||||
@@ -316,7 +315,7 @@ func (t *templates) approval(r *http.Request, w http.ResponseWriter, authReqID,
 | 
				
			|||||||
	return renderTemplate(w, t.approvalTmpl, data)
 | 
						return renderTemplate(w, t.approvalTmpl, data)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (t *templates) oob(r *http.Request, w http.ResponseWriter, code string, reqPath string) error {
 | 
					func (t *templates) oob(r *http.Request, w http.ResponseWriter, code string) error {
 | 
				
			||||||
	data := struct {
 | 
						data := struct {
 | 
				
			||||||
		Code    string
 | 
							Code    string
 | 
				
			||||||
		ReqPath string
 | 
							ReqPath string
 | 
				
			||||||
@@ -332,7 +331,7 @@ func (t *templates) err(r *http.Request, w http.ResponseWriter, errCode int, err
 | 
				
			|||||||
		ReqPath string
 | 
							ReqPath string
 | 
				
			||||||
	}{http.StatusText(errCode), errMsg, r.URL.Path}
 | 
						}{http.StatusText(errCode), errMsg, r.URL.Path}
 | 
				
			||||||
	if err := t.errorTmpl.Execute(w, data); err != nil {
 | 
						if err := t.errorTmpl.Execute(w, data); err != nil {
 | 
				
			||||||
		return fmt.Errorf("Error rendering template %s: %s", t.errorTmpl.Name(), err)
 | 
							return fmt.Errorf("rendering template %s failed: %s", t.errorTmpl.Name(), err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -355,7 +354,7 @@ func renderTemplate(w http.ResponseWriter, tmpl *template.Template, data interfa
 | 
				
			|||||||
			// 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 fmt.Errorf("rendering template %s failed: %s", tmpl.Name(), err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -763,10 +763,8 @@ func testGC(t *testing.T, s storage.Storage) {
 | 
				
			|||||||
		result, err := s.GarbageCollect(expiry.Add(-time.Hour).In(tz))
 | 
							result, err := s.GarbageCollect(expiry.Add(-time.Hour).In(tz))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Errorf("garbage collection failed: %v", err)
 | 
								t.Errorf("garbage collection failed: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else if result.AuthCodes != 0 || result.AuthRequests != 0 {
 | 
				
			||||||
			if result.AuthCodes != 0 || result.AuthRequests != 0 {
 | 
								t.Errorf("expected no garbage collection results, got %#v", result)
 | 
				
			||||||
				t.Errorf("expected no garbage collection results, got %#v", result)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err := s.GetAuthCode(c.ID); err != nil {
 | 
							if _, err := s.GetAuthCode(c.ID); err != nil {
 | 
				
			||||||
			t.Errorf("expected to be able to get auth code after GC: %v", err)
 | 
								t.Errorf("expected to be able to get auth code after GC: %v", err)
 | 
				
			||||||
@@ -815,10 +813,8 @@ func testGC(t *testing.T, s storage.Storage) {
 | 
				
			|||||||
		result, err := s.GarbageCollect(expiry.Add(-time.Hour).In(tz))
 | 
							result, err := s.GarbageCollect(expiry.Add(-time.Hour).In(tz))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Errorf("garbage collection failed: %v", err)
 | 
								t.Errorf("garbage collection failed: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else if result.AuthCodes != 0 || result.AuthRequests != 0 {
 | 
				
			||||||
			if result.AuthCodes != 0 || result.AuthRequests != 0 {
 | 
								t.Errorf("expected no garbage collection results, got %#v", result)
 | 
				
			||||||
				t.Errorf("expected no garbage collection results, got %#v", result)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err := s.GetAuthRequest(a.ID); err != nil {
 | 
							if _, err := s.GetAuthRequest(a.ID); err != nil {
 | 
				
			||||||
			t.Errorf("expected to be able to get auth request after GC: %v", err)
 | 
								t.Errorf("expected to be able to get auth request after GC: %v", err)
 | 
				
			||||||
@@ -859,10 +855,8 @@ func testGC(t *testing.T, s storage.Storage) {
 | 
				
			|||||||
		result, err := s.GarbageCollect(expiry.Add(-time.Hour).In(tz))
 | 
							result, err := s.GarbageCollect(expiry.Add(-time.Hour).In(tz))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Errorf("garbage collection failed: %v", err)
 | 
								t.Errorf("garbage collection failed: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else if result.DeviceRequests != 0 {
 | 
				
			||||||
			if result.DeviceRequests != 0 {
 | 
								t.Errorf("expected no device garbage collection results, got %#v", result)
 | 
				
			||||||
				t.Errorf("expected no device garbage collection results, got %#v", result)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err := s.GetDeviceRequest(d.UserCode); err != nil {
 | 
							if _, err := s.GetDeviceRequest(d.UserCode); err != nil {
 | 
				
			||||||
			t.Errorf("expected to be able to get auth request after GC: %v", err)
 | 
								t.Errorf("expected to be able to get auth request after GC: %v", err)
 | 
				
			||||||
@@ -897,10 +891,8 @@ func testGC(t *testing.T, s storage.Storage) {
 | 
				
			|||||||
		result, err := s.GarbageCollect(expiry.Add(-time.Hour).In(tz))
 | 
							result, err := s.GarbageCollect(expiry.Add(-time.Hour).In(tz))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			t.Errorf("garbage collection failed: %v", err)
 | 
								t.Errorf("garbage collection failed: %v", err)
 | 
				
			||||||
		} else {
 | 
							} else if result.DeviceTokens != 0 {
 | 
				
			||||||
			if result.DeviceTokens != 0 {
 | 
								t.Errorf("expected no device token garbage collection results, got %#v", result)
 | 
				
			||||||
				t.Errorf("expected no device token garbage collection results, got %#v", result)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if _, err := s.GetDeviceToken(dt.DeviceCode); err != nil {
 | 
							if _, err := s.GetDeviceToken(dt.DeviceCode); err != nil {
 | 
				
			||||||
			t.Errorf("expected to be able to get device token after GC: %v", err)
 | 
								t.Errorf("expected to be able to get device token after GC: %v", err)
 | 
				
			||||||
@@ -987,12 +979,12 @@ func testDeviceRequestCRUD(t *testing.T, s storage.Storage) {
 | 
				
			|||||||
	err = s.CreateDeviceRequest(d1)
 | 
						err = s.CreateDeviceRequest(d1)
 | 
				
			||||||
	mustBeErrAlreadyExists(t, "device request", err)
 | 
						mustBeErrAlreadyExists(t, "device request", err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//No manual deletes for device requests, will be handled by garbage collection routines
 | 
						// No manual deletes for device requests, will be handled by garbage collection routines
 | 
				
			||||||
	//see testGC
 | 
						// see testGC
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
 | 
					func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
 | 
				
			||||||
	//Create a Token
 | 
						// Create a Token
 | 
				
			||||||
	d1 := storage.DeviceToken{
 | 
						d1 := storage.DeviceToken{
 | 
				
			||||||
		DeviceCode:          storage.NewID(),
 | 
							DeviceCode:          storage.NewID(),
 | 
				
			||||||
		Status:              "pending",
 | 
							Status:              "pending",
 | 
				
			||||||
@@ -1010,7 +1002,7 @@ func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
 | 
				
			|||||||
	err := s.CreateDeviceToken(d1)
 | 
						err := s.CreateDeviceToken(d1)
 | 
				
			||||||
	mustBeErrAlreadyExists(t, "device token", err)
 | 
						mustBeErrAlreadyExists(t, "device token", err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Update the device token, simulate a redemption
 | 
						// Update the device token, simulate a redemption
 | 
				
			||||||
	if err := s.UpdateDeviceToken(d1.DeviceCode, func(old storage.DeviceToken) (storage.DeviceToken, error) {
 | 
						if err := s.UpdateDeviceToken(d1.DeviceCode, func(old storage.DeviceToken) (storage.DeviceToken, error) {
 | 
				
			||||||
		old.Token = "token data"
 | 
							old.Token = "token data"
 | 
				
			||||||
		old.Status = "complete"
 | 
							old.Status = "complete"
 | 
				
			||||||
@@ -1019,13 +1011,13 @@ func testDeviceTokenCRUD(t *testing.T, s storage.Storage) {
 | 
				
			|||||||
		t.Fatalf("failed to update device token: %v", err)
 | 
							t.Fatalf("failed to update device token: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Retrieve the device token
 | 
						// Retrieve the device token
 | 
				
			||||||
	got, err := s.GetDeviceToken(d1.DeviceCode)
 | 
						got, err := s.GetDeviceToken(d1.DeviceCode)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Fatalf("failed to get device token: %v", err)
 | 
							t.Fatalf("failed to get device token: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	//Validate expected result set
 | 
						// Validate expected result set
 | 
				
			||||||
	if got.Status != "complete" {
 | 
						if got.Status != "complete" {
 | 
				
			||||||
		t.Fatalf("update failed, wanted token status=%v got %v", "complete", got.Status)
 | 
							t.Fatalf("update failed, wanted token status=%v got %v", "complete", got.Status)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,7 +24,7 @@ type Config struct {
 | 
				
			|||||||
	// Legacy field from pkg/api/types.go TypeMeta.
 | 
						// Legacy field from pkg/api/types.go TypeMeta.
 | 
				
			||||||
	// TODO(jlowdermilk): remove this after eliminating downstream dependencies.
 | 
						// TODO(jlowdermilk): remove this after eliminating downstream dependencies.
 | 
				
			||||||
	Kind string `json:"kind,omitempty"`
 | 
						Kind string `json:"kind,omitempty"`
 | 
				
			||||||
	// DEPRECATED: APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc).
 | 
						// Deprecated: APIVersion is the preferred api version for communicating with the kubernetes cluster (v1, v2, etc).
 | 
				
			||||||
	// Because a cluster can run multiple API groups and potentially multiple versions of each, it no longer makes sense to specify
 | 
						// Because a cluster can run multiple API groups and potentially multiple versions of each, it no longer makes sense to specify
 | 
				
			||||||
	// a single value for the cluster version.
 | 
						// a single value for the cluster version.
 | 
				
			||||||
	// This field isn't really needed anyway, so we are deprecating it without replacement.
 | 
						// This field isn't really needed anyway, so we are deprecating it without replacement.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -679,7 +679,7 @@ type DeviceRequest struct {
 | 
				
			|||||||
	Expiry       time.Time `json:"expiry"`
 | 
						Expiry       time.Time `json:"expiry"`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AuthRequestList is a list of AuthRequests.
 | 
					// DeviceRequestList is a list of DeviceRequests.
 | 
				
			||||||
type DeviceRequestList struct {
 | 
					type DeviceRequestList struct {
 | 
				
			||||||
	k8sapi.TypeMeta `json:",inline"`
 | 
						k8sapi.TypeMeta `json:",inline"`
 | 
				
			||||||
	k8sapi.ListMeta `json:"metadata,omitempty"`
 | 
						k8sapi.ListMeta `json:"metadata,omitempty"`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -289,16 +289,19 @@ func (s *MySQL) open(logger log.Logger) (*conn, error) {
 | 
				
			|||||||
			cfg.Addr = s.Host
 | 
								cfg.Addr = s.Host
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if s.SSL.CAFile != "" || s.SSL.CertFile != "" || s.SSL.KeyFile != "" {
 | 
					
 | 
				
			||||||
 | 
						switch {
 | 
				
			||||||
 | 
						case s.SSL.CAFile != "" || s.SSL.CertFile != "" || s.SSL.KeyFile != "":
 | 
				
			||||||
		if err := s.makeTLSConfig(); err != nil {
 | 
							if err := s.makeTLSConfig(); err != nil {
 | 
				
			||||||
			return nil, fmt.Errorf("failed to make TLS config: %v", err)
 | 
								return nil, fmt.Errorf("failed to make TLS config: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		cfg.TLSConfig = mysqlSSLCustom
 | 
							cfg.TLSConfig = mysqlSSLCustom
 | 
				
			||||||
	} else if s.SSL.Mode == "" {
 | 
						case s.SSL.Mode == "":
 | 
				
			||||||
		cfg.TLSConfig = mysqlSSLTrue
 | 
							cfg.TLSConfig = mysqlSSLTrue
 | 
				
			||||||
	} else {
 | 
						default:
 | 
				
			||||||
		cfg.TLSConfig = s.SSL.Mode
 | 
							cfg.TLSConfig = s.SSL.Mode
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for k, v := range s.params {
 | 
						for k, v := range s.params {
 | 
				
			||||||
		cfg.Params[k] = v
 | 
							cfg.Params[k] = v
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -84,7 +84,9 @@ type scanner interface {
 | 
				
			|||||||
	Scan(dest ...interface{}) error
 | 
						Scan(dest ...interface{}) error
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *conn) GarbageCollect(now time.Time) (result storage.GCResult, err error) {
 | 
					func (c *conn) GarbageCollect(now time.Time) (storage.GCResult, error) {
 | 
				
			||||||
 | 
						result := storage.GCResult{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	r, err := c.Exec(`delete from auth_request where expiry < $1`, now)
 | 
						r, err := c.Exec(`delete from auth_request where expiry < $1`, now)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return result, fmt.Errorf("gc auth_request: %v", err)
 | 
							return result, fmt.Errorf("gc auth_request: %v", err)
 | 
				
			||||||
@@ -117,7 +119,7 @@ func (c *conn) GarbageCollect(now time.Time) (result storage.GCResult, err error
 | 
				
			|||||||
		result.DeviceTokens = n
 | 
							result.DeviceTokens = n
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return
 | 
						return result, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *conn) CreateAuthRequest(a storage.AuthRequest) error {
 | 
					func (c *conn) CreateAuthRequest(a storage.AuthRequest) error {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,7 +96,7 @@ type staticPasswordsStorage struct {
 | 
				
			|||||||
func WithStaticPasswords(s Storage, staticPasswords []Password, logger log.Logger) Storage {
 | 
					func WithStaticPasswords(s Storage, staticPasswords []Password, logger log.Logger) Storage {
 | 
				
			||||||
	passwordsByEmail := make(map[string]Password, len(staticPasswords))
 | 
						passwordsByEmail := make(map[string]Password, len(staticPasswords))
 | 
				
			||||||
	for _, p := range staticPasswords {
 | 
						for _, p := range staticPasswords {
 | 
				
			||||||
		//Enable case insensitive email comparison.
 | 
							// Enable case insensitive email comparison.
 | 
				
			||||||
		lowerEmail := strings.ToLower(p.Email)
 | 
							lowerEmail := strings.ToLower(p.Email)
 | 
				
			||||||
		if _, ok := passwordsByEmail[lowerEmail]; ok {
 | 
							if _, ok := passwordsByEmail[lowerEmail]; ok {
 | 
				
			||||||
			logger.Errorf("Attempting to create StaticPasswords with the same email id: %s", p.Email)
 | 
								logger.Errorf("Attempting to create StaticPasswords with the same email id: %s", p.Email)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,7 +25,7 @@ var (
 | 
				
			|||||||
// TODO(ericchiang): refactor ID creation onto the storage.
 | 
					// TODO(ericchiang): refactor ID creation onto the storage.
 | 
				
			||||||
var encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
 | 
					var encoding = base32.NewEncoding("abcdefghijklmnopqrstuvwxyz234567")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//Valid characters for user codes
 | 
					// Valid characters for user codes
 | 
				
			||||||
const validUserCharacters = "BCDFGHJKLMNPQRSTVWXZ"
 | 
					const validUserCharacters = "BCDFGHJKLMNPQRSTVWXZ"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewDeviceCode returns a 32 char alphanumeric cryptographically secure string
 | 
					// NewDeviceCode returns a 32 char alphanumeric cryptographically secure string
 | 
				
			||||||
@@ -384,23 +384,24 @@ func randomString(n int) (string, error) {
 | 
				
			|||||||
	return string(bytes), nil
 | 
						return string(bytes), nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//DeviceRequest represents an OIDC device authorization request.  It holds the state of a device request until the user
 | 
					// DeviceRequest represents an OIDC device authorization request. It holds the state of a device request until the user
 | 
				
			||||||
//authenticates using their user code or the expiry time passes.
 | 
					// authenticates using their user code or the expiry time passes.
 | 
				
			||||||
type DeviceRequest struct {
 | 
					type DeviceRequest struct {
 | 
				
			||||||
	//The code the user will enter in a browser
 | 
						// The code the user will enter in a browser
 | 
				
			||||||
	UserCode string
 | 
						UserCode string
 | 
				
			||||||
	//The unique device code for device authentication
 | 
						// The unique device code for device authentication
 | 
				
			||||||
	DeviceCode string
 | 
						DeviceCode string
 | 
				
			||||||
	//The client ID the code is for
 | 
						// The client ID the code is for
 | 
				
			||||||
	ClientID string
 | 
						ClientID string
 | 
				
			||||||
	//The Client Secret
 | 
						// The Client Secret
 | 
				
			||||||
	ClientSecret string
 | 
						ClientSecret string
 | 
				
			||||||
	//The scopes the device requests
 | 
						// The scopes the device requests
 | 
				
			||||||
	Scopes []string
 | 
						Scopes []string
 | 
				
			||||||
	//The expire time
 | 
						// The expire time
 | 
				
			||||||
	Expiry time.Time
 | 
						Expiry time.Time
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// DeviceToken is a structure which represents the actual token of an authorized device and its rotation parameters
 | 
				
			||||||
type DeviceToken struct {
 | 
					type DeviceToken struct {
 | 
				
			||||||
	DeviceCode          string
 | 
						DeviceCode          string
 | 
				
			||||||
	Status              string
 | 
						Status              string
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user