mirror of
https://github.com/argoproj/argo-cd
synced 2026-04-21 08:57:17 +00:00
fix(server): Ensure OIDC config is refreshed at server restart (#26913)
Signed-off-by: OpenGuidou <guillaume.doussin@gmail.com>
This commit is contained in:
parent
32f23a446f
commit
4259f467b0
3 changed files with 102 additions and 3 deletions
|
|
@ -334,8 +334,6 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts, appsetOpts Applicatio
|
|||
appsetLister := appFactory.Argoproj().V1alpha1().ApplicationSets().Lister()
|
||||
|
||||
userStateStorage := util_session.NewUserStateStorage(opts.RedisClient)
|
||||
ssoClientApp, err := oidc.NewClientApp(settings, opts.DexServerAddr, opts.DexTLSConfig, opts.BaseHRef, cacheutil.NewRedisCache(opts.RedisClient, settings.UserInfoCacheExpiration(), cacheutil.RedisCompressionNone))
|
||||
errorsutil.CheckError(err)
|
||||
sessionMgr := util_session.NewSessionManager(settingsMgr, projLister, opts.DexServerAddr, opts.DexTLSConfig, userStateStorage)
|
||||
enf := rbac.NewEnforcer(opts.KubeClientset, opts.Namespace, common.ArgoCDRBACConfigMapName, nil)
|
||||
enf.EnableEnforce(!opts.DisableAuth)
|
||||
|
|
@ -383,7 +381,6 @@ func NewServer(ctx context.Context, opts ArgoCDServerOpts, appsetOpts Applicatio
|
|||
a := &ArgoCDServer{
|
||||
ArgoCDServerOpts: opts,
|
||||
ApplicationSetOpts: appsetOpts,
|
||||
ssoClientApp: ssoClientApp,
|
||||
log: logger,
|
||||
settings: settings,
|
||||
sessionMgr: sessionMgr,
|
||||
|
|
@ -586,6 +583,10 @@ func (server *ArgoCDServer) Run(ctx context.Context, listeners *Listeners) {
|
|||
if server.RedisClient != nil {
|
||||
cacheutil.CollectMetrics(server.RedisClient, metricsServ, server.userStateStorage.GetLockObject())
|
||||
}
|
||||
// OIDC config needs to be refreshed at each server restart
|
||||
ssoClientApp, err := oidc.NewClientApp(server.settings, server.DexServerAddr, server.DexTLSConfig, server.BaseHRef, cacheutil.NewRedisCache(server.RedisClient, server.settings.UserInfoCacheExpiration(), cacheutil.RedisCompressionNone))
|
||||
errorsutil.CheckError(err)
|
||||
server.ssoClientApp = ssoClientApp
|
||||
|
||||
// Don't init storage until after CollectMetrics. CollectMetrics adds hooks to the Redis client, and Init
|
||||
// reads those hooks. If this is called first, there may be a data race.
|
||||
|
|
|
|||
|
|
@ -488,6 +488,100 @@ func TestGracefulShutdown(t *testing.T) {
|
|||
assert.True(t, shutdown)
|
||||
}
|
||||
|
||||
func TestOIDCRefresh(t *testing.T) {
|
||||
port, err := test.GetFreePort()
|
||||
require.NoError(t, err)
|
||||
mockRepoClient := &mocks.Clientset{RepoServerServiceClient: &mocks.RepoServerServiceClient{}}
|
||||
cm := test.NewFakeConfigMap()
|
||||
cm.Data["oidc.config"] = `
|
||||
name: Test OIDC
|
||||
issuer: $oidc.myoidc.issuer
|
||||
clientID: $oidc.myoidc.clientId
|
||||
clientSecret: $oidc.myoidc.clientSecret
|
||||
`
|
||||
secret := test.NewFakeSecret()
|
||||
issuerURL := "http://oidc.127.0.0.1.nip.io"
|
||||
updatedIssuerURL := "http://newoidc.127.0.0.1.nip.io"
|
||||
secret.Data["oidc.myoidc.issuer"] = []byte(issuerURL)
|
||||
secret.Data["oidc.myoidc.clientId"] = []byte("myClientId")
|
||||
secret.Data["oidc.myoidc.clientSecret"] = []byte("myClientSecret")
|
||||
|
||||
kubeclientset := fake.NewSimpleClientset(cm, secret)
|
||||
redis, redisCloser := test.NewInMemoryRedis()
|
||||
defer redisCloser()
|
||||
s := NewServer(
|
||||
t.Context(),
|
||||
ArgoCDServerOpts{
|
||||
ListenPort: port,
|
||||
Namespace: test.FakeArgoCDNamespace,
|
||||
KubeClientset: kubeclientset,
|
||||
AppClientset: apps.NewSimpleClientset(),
|
||||
RepoClientset: mockRepoClient,
|
||||
RedisClient: redis,
|
||||
},
|
||||
ApplicationSetOpts{},
|
||||
)
|
||||
projInformerCancel := test.StartInformer(s.projInformer)
|
||||
defer projInformerCancel()
|
||||
appInformerCancel := test.StartInformer(s.appInformer)
|
||||
defer appInformerCancel()
|
||||
appsetInformerCancel := test.StartInformer(s.appsetInformer)
|
||||
defer appsetInformerCancel()
|
||||
clusterInformerCancel := test.StartInformer(s.clusterInformer)
|
||||
defer clusterInformerCancel()
|
||||
|
||||
shutdown := false
|
||||
|
||||
lns, err := s.Listen()
|
||||
require.NoError(t, err)
|
||||
runCtx := t.Context()
|
||||
|
||||
var wg gosync.WaitGroup
|
||||
wg.Add(1)
|
||||
go func(shutdown *bool) {
|
||||
defer wg.Done()
|
||||
s.Run(runCtx, lns)
|
||||
*shutdown = true
|
||||
}(&shutdown)
|
||||
|
||||
for !s.available.Load() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
assert.True(t, s.available.Load())
|
||||
assert.Equal(t, issuerURL, s.ssoClientApp.IssuerURL())
|
||||
|
||||
// Update oidc config
|
||||
secret.Data["oidc.myoidc.issuer"] = []byte(updatedIssuerURL)
|
||||
secret.ResourceVersion = "12345"
|
||||
_, err = kubeclientset.CoreV1().Secrets(test.FakeArgoCDNamespace).Update(runCtx, secret, metav1.UpdateOptions{})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Wait for graceful shutdown
|
||||
wg.Wait()
|
||||
for s.available.Load() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
|
||||
assert.False(t, s.available.Load())
|
||||
|
||||
shutdown = false
|
||||
wg.Add(1)
|
||||
go func(shutdown *bool) {
|
||||
defer wg.Done()
|
||||
s.Run(runCtx, lns)
|
||||
*shutdown = true
|
||||
}(&shutdown)
|
||||
|
||||
for !s.available.Load() {
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
}
|
||||
assert.True(t, s.available.Load())
|
||||
assert.Equal(t, updatedIssuerURL, s.ssoClientApp.IssuerURL())
|
||||
|
||||
s.stopCh <- syscall.SIGINT
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestAuthenticate(t *testing.T) {
|
||||
type testData struct {
|
||||
test string
|
||||
|
|
|
|||
|
|
@ -1069,3 +1069,7 @@ func FormatAccessTokenCacheKey(sub string) string {
|
|||
func formatOidcTokenCacheKey(sub string, sid string) string {
|
||||
return fmt.Sprintf("%s_%s_%s", OidcTokenCachePrefix, sub, sid)
|
||||
}
|
||||
|
||||
func (a *ClientApp) IssuerURL() string {
|
||||
return a.issuerURL
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue