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:
commit
c82d21b155
@ -8,27 +8,38 @@ linters-settings:
|
|||||||
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
|
||||||
# TODO: fix me
|
|
||||||
- unparam
|
|
||||||
- golint
|
|
||||||
- goconst
|
|
||||||
- staticcheck
|
|
||||||
- nakedret
|
|
||||||
- errcheck
|
|
||||||
- gosec
|
|
||||||
- gochecknoinits
|
- gochecknoinits
|
||||||
- gochecknoglobals
|
- gofmt
|
||||||
- prealloc
|
- goimports
|
||||||
- scopelint
|
- golint
|
||||||
- lll
|
- gosimple
|
||||||
- dupl
|
|
||||||
- gocritic
|
- gocritic
|
||||||
- gocyclo
|
- govet
|
||||||
- gocognit
|
- ineffassign
|
||||||
- godox
|
- interfacer
|
||||||
|
- misspell
|
||||||
|
- nakedret
|
||||||
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
|
- stylecheck
|
||||||
|
- typecheck
|
||||||
|
- unconvert
|
||||||
|
- unused
|
||||||
|
- varcheck
|
||||||
|
- whitespace
|
||||||
|
|
||||||
|
# TODO: fix linter errors before enabling
|
||||||
|
# - unparam
|
||||||
|
# - scopelint
|
||||||
|
# - gosec
|
||||||
|
# - gocyclo
|
||||||
|
# - lll
|
||||||
|
# - goconst
|
||||||
|
# - errcheck
|
||||||
|
# - dupl
|
||||||
|
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,7 +188,7 @@ 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{
|
||||||
@ -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,7 +537,10 @@ 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 {
|
|
||||||
|
return returnURL, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Update existing OfflineSession obj with new RefreshTokenRef.
|
// Update existing OfflineSession obj with new RefreshTokenRef.
|
||||||
if err := s.storage.UpdateOfflineSessions(session.UserID, session.ConnID, func(old storage.OfflineSessions) (storage.OfflineSessions, error) {
|
if err := s.storage.UpdateOfflineSessions(session.UserID, session.ConnID, func(old storage.OfflineSessions) (storage.OfflineSessions, error) {
|
||||||
if len(identity.ConnectorData) > 0 {
|
if len(identity.ConnectorData) > 0 {
|
||||||
@ -547,7 +551,6 @@ func (s *Server) finalizeLogin(identity connector.Identity, authReq storage.Auth
|
|||||||
s.logger.Errorf("failed to update offline session: %v", err)
|
s.logger.Errorf("failed to update offline session: %v", err)
|
||||||
return "", 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,11 +763,9 @@ 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,11 +813,9 @@ 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,11 +855,9 @@ 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,11 +891,9 @@ 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