Skip to content

Commit

Permalink
Remove hard requirement of initializing OIDC app during server startup (
Browse files Browse the repository at this point in the history
resolves #272)
  • Loading branch information
jessesuen committed Jun 7, 2018
1 parent e720abb commit 18dc82d
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 40 deletions.
26 changes: 0 additions & 26 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,6 @@ func (a *ArgoCDServer) Run(ctx context.Context, port int) {
go func() { a.checkServeErr("httpsS", httpsS.Serve(httpsL)) }()
go func() { a.checkServeErr("tlsm", tlsm.Serve()) }()
}
go a.initializeOIDCClientApp()
go a.watchSettings(ctx)
go func() { a.checkServeErr("tcpm", tcpm.Serve()) }()

Expand Down Expand Up @@ -234,31 +233,6 @@ func (a *ArgoCDServer) watchSettings(ctx context.Context) {
close(updateCh)
}

// initializeOIDCClientApp initializes the OIDC Client application, querying the well known oidc
// configuration path. Because ArgoCD is a OIDC client to itself, we have a chicken-and-egg problem
// of (1) serving dex over HTTP, and (2) querying the OIDC provider (ourselves) to initialize the
// app (HTTP GET http://example-argocd.com/api/dex/.well-known/openid-configuration)
// This method is expected to be invoked right after we start listening over HTTP
func (a *ArgoCDServer) initializeOIDCClientApp() {
if !a.settings.IsSSOConfigured() {
return
}
// wait for dex to become ready
dexClient, err := dexutil.NewDexClient()
errors.CheckError(err)
dexClient.WaitUntilReady()
var realErr error
_ = wait.ExponentialBackoff(backoff, func() (bool, error) {
_, realErr = a.sessionMgr.OIDCProvider()
if realErr != nil {
a.log.Warnf("failed to initialize client app: %v", realErr)
return false, nil
}
return true, nil
})
errors.CheckError(realErr)
}

func (a *ArgoCDServer) useTLS() bool {
if a.Insecure || a.settings.Certificate == nil {
return false
Expand Down
39 changes: 26 additions & 13 deletions util/dex/dex.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ import (
"os"
"time"

"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/errors"
"github.com/argoproj/argo-cd/util/cache"
"github.com/argoproj/argo-cd/util/session"
"github.com/argoproj/argo-cd/util/settings"
"github.com/coreos/dex/api"
oidc "github.com/coreos/go-oidc"
jwt "github.com/dgrijalva/jwt-go"
log "github.com/sirupsen/logrus"
"golang.org/x/oauth2"
"google.golang.org/grpc"

"github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/errors"
"github.com/argoproj/argo-cd/util/cache"
"github.com/argoproj/argo-cd/util/session"
"github.com/argoproj/argo-cd/util/settings"
)

const (
Expand Down Expand Up @@ -141,15 +142,18 @@ func NewClientApp(settings *settings.ArgoCDSettings, sessionMgr *session.Session
return &a, nil
}

func (a *ClientApp) oauth2Config(scopes []string) *oauth2.Config {
provider, _ := a.sessionMgr.OIDCProvider()
func (a *ClientApp) oauth2Config(scopes []string) (*oauth2.Config, error) {
provider, err := a.sessionMgr.OIDCProvider()
if err != nil {
return nil, err
}
return &oauth2.Config{
ClientID: a.clientID,
ClientSecret: a.clientSecret,
Endpoint: provider.Endpoint(),
Scopes: scopes,
RedirectURL: a.redirectURI,
}
}, nil
}

var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
Expand Down Expand Up @@ -196,18 +200,23 @@ func (a *ClientApp) verifyAppState(state string) (*appState, error) {
}

func (a *ClientApp) HandleLogin(w http.ResponseWriter, r *http.Request) {
var authCodeURL string
var opts []oauth2.AuthCodeOption
returnURL := r.FormValue("return_url")
scopes := []string{"openid", "profile", "email", "groups"}
appState := a.generateAppState(returnURL)
if r.FormValue("offline_access") != "yes" {
authCodeURL = a.oauth2Config(scopes).AuthCodeURL(appState)
// no-op
} else if a.sessionMgr.OfflineAsScope() {
scopes = append(scopes, "offline_access")
authCodeURL = a.oauth2Config(scopes).AuthCodeURL(appState)
} else {
authCodeURL = a.oauth2Config(scopes).AuthCodeURL(appState, oauth2.AccessTypeOffline)
opts = append(opts, oauth2.AccessTypeOffline)
}
oauth2Config, err := a.oauth2Config(scopes)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
authCodeURL := oauth2Config.AuthCodeURL(appState, opts...)
http.Redirect(w, r, authCodeURL, http.StatusSeeOther)
}

Expand All @@ -219,7 +228,11 @@ func (a *ClientApp) HandleCallback(w http.ResponseWriter, r *http.Request) {
)

ctx := oidc.ClientContext(r.Context(), a.client)
oauth2Config := a.oauth2Config(nil)
oauth2Config, err := a.oauth2Config(nil)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
switch r.Method {
case "GET":
// Authorization redirect callback from OAuth2 auth flow.
Expand Down
6 changes: 5 additions & 1 deletion util/session/sessionmanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,11 @@ func MakeCookieMetadata(key, value string, flags ...string) string {
return strings.Join(components, "; ")
}

// OIDCProvider lazily returns the OIDC provider
// OIDCProvider lazily initializes and returns the OIDC provider, querying the well known oidc
// configuration path (http://example-argocd.com/api/dex/.well-known/openid-configuration).
// We have to initialize the proviver lazily since ArgoCD is an OIDC client to itself, which
// presents a chicken-and-egg problem of (1) serving dex over HTTP, and (2) querying the OIDC
// provider (ourselves) to initialize the app.
func (mgr *SessionManager) OIDCProvider() (*oidc.Provider, error) {
if mgr.provider != nil {
return mgr.provider, nil
Expand Down

0 comments on commit 18dc82d

Please sign in to comment.