mirror of
https://github.com/drakkan/sftpgo.git
synced 2026-10-19 16:15:39 +00:00
smtp: fix reading oauth2 settings from env
update access token and refresh token using the same mutex Signed-off-by: Nicola Murino <nicola.murino@gmail.com>
This commit is contained in:
@@ -2267,6 +2267,11 @@ func setViperDefaults() {
|
||||
viper.SetDefault("smtp.encryption", globalConf.SMTPConfig.Encryption)
|
||||
viper.SetDefault("smtp.domain", globalConf.SMTPConfig.Domain)
|
||||
viper.SetDefault("smtp.templates_path", globalConf.SMTPConfig.TemplatesPath)
|
||||
viper.SetDefault("smtp.oauth2.provider", globalConf.SMTPConfig.OAuth2.Provider)
|
||||
viper.SetDefault("smtp.oauth2.tenant", globalConf.SMTPConfig.OAuth2.Tenant)
|
||||
viper.SetDefault("smtp.oauth2.client_id", globalConf.SMTPConfig.OAuth2.ClientID)
|
||||
viper.SetDefault("smtp.oauth2.client_secret", globalConf.SMTPConfig.OAuth2.ClientSecret)
|
||||
viper.SetDefault("smtp.oauth2.refresh_token", globalConf.SMTPConfig.OAuth2.RefreshToken)
|
||||
}
|
||||
|
||||
func lookupBoolFromEnv(envName string) (bool, bool) {
|
||||
|
||||
@@ -424,6 +424,40 @@ func TestSMTPFromEnv(t *testing.T) {
|
||||
assert.Equal(t, 587, smtpConfig.Port)
|
||||
}
|
||||
|
||||
func TestSMTPOAuth2FromEnv(t *testing.T) {
|
||||
reset()
|
||||
|
||||
os.Setenv("SFTPGO_SMTP__HOST", "smtp.example.com")
|
||||
os.Setenv("SFTPGO_SMTP__USER", "sftpgo@example.com")
|
||||
os.Setenv("SFTPGO_SMTP__AUTH_TYPE", "3")
|
||||
os.Setenv("SFTPGO_SMTP__OAUTH2__PROVIDER", "1")
|
||||
os.Setenv("SFTPGO_SMTP__OAUTH2__TENANT", "a-tenant-id")
|
||||
os.Setenv("SFTPGO_SMTP__OAUTH2__CLIENT_ID", "client id")
|
||||
os.Setenv("SFTPGO_SMTP__OAUTH2__CLIENT_SECRET", "client secret")
|
||||
os.Setenv("SFTPGO_SMTP__OAUTH2__REFRESH_TOKEN", "refresh token")
|
||||
t.Cleanup(func() {
|
||||
os.Unsetenv("SFTPGO_SMTP__HOST")
|
||||
os.Unsetenv("SFTPGO_SMTP__USER")
|
||||
os.Unsetenv("SFTPGO_SMTP__AUTH_TYPE")
|
||||
os.Unsetenv("SFTPGO_SMTP__OAUTH2__PROVIDER")
|
||||
os.Unsetenv("SFTPGO_SMTP__OAUTH2__TENANT")
|
||||
os.Unsetenv("SFTPGO_SMTP__OAUTH2__CLIENT_ID")
|
||||
os.Unsetenv("SFTPGO_SMTP__OAUTH2__CLIENT_SECRET")
|
||||
os.Unsetenv("SFTPGO_SMTP__OAUTH2__REFRESH_TOKEN")
|
||||
})
|
||||
|
||||
// the environment is the only source, no config file is present
|
||||
err := config.LoadConfig(t.TempDir(), "")
|
||||
assert.NoError(t, err)
|
||||
smtpConfig := config.GetSMTPConfig()
|
||||
assert.Equal(t, 3, smtpConfig.AuthType)
|
||||
assert.Equal(t, 1, smtpConfig.OAuth2.Provider)
|
||||
assert.Equal(t, "a-tenant-id", smtpConfig.OAuth2.Tenant)
|
||||
assert.Equal(t, "client id", smtpConfig.OAuth2.ClientID)
|
||||
assert.Equal(t, "client secret", smtpConfig.OAuth2.ClientSecret)
|
||||
assert.Equal(t, "refresh token", smtpConfig.OAuth2.RefreshToken)
|
||||
}
|
||||
|
||||
func TestMFAFromEnv(t *testing.T) {
|
||||
reset()
|
||||
|
||||
|
||||
+27
-25
@@ -92,17 +92,11 @@ func (c *OAuth2Config) isEqual(other *OAuth2Config) bool {
|
||||
}
|
||||
|
||||
func (c *OAuth2Config) getAccessToken() (string, error) {
|
||||
c.mu.RLock()
|
||||
if c.accessToken.Expiry.After(time.Now().Add(30 * time.Second)) {
|
||||
accessToken := c.accessToken.AccessToken
|
||||
c.mu.RUnlock()
|
||||
|
||||
return accessToken, nil
|
||||
token := c.getCachedToken()
|
||||
if token.AccessToken != "" && token.Expiry.After(time.Now().Add(30*time.Second)) {
|
||||
return token.AccessToken, nil
|
||||
}
|
||||
logger.Debug(logSender, "", "renew oauth2 token required, current token expires at %s", c.accessToken.Expiry)
|
||||
token := new(oauth2.Token)
|
||||
*token = *c.accessToken
|
||||
c.mu.RUnlock()
|
||||
logger.Debug(logSender, "", "renew oauth2 token required, current token expires at %s", token.Expiry)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
||||
defer cancel()
|
||||
@@ -112,25 +106,33 @@ func (c *OAuth2Config) getAccessToken() (string, error) {
|
||||
logger.Error(logSender, "", "unable to get new token: %v", err)
|
||||
return "", err
|
||||
}
|
||||
accessToken := newToken.AccessToken
|
||||
refreshToken := newToken.RefreshToken
|
||||
if refreshToken != "" && refreshToken != token.RefreshToken {
|
||||
c.mu.Lock()
|
||||
c.RefreshToken = refreshToken
|
||||
c.accessToken = newToken
|
||||
c.mu.Unlock()
|
||||
updatedRefreshToken := ""
|
||||
|
||||
c.mu.Lock()
|
||||
if newToken.RefreshToken != "" && newToken.RefreshToken != token.RefreshToken {
|
||||
c.RefreshToken = newToken.RefreshToken
|
||||
updatedRefreshToken = newToken.RefreshToken
|
||||
}
|
||||
c.accessToken = newToken
|
||||
c.mu.Unlock()
|
||||
|
||||
if updatedRefreshToken != "" {
|
||||
logger.Debug(logSender, "", "oauth2 refresh token changed")
|
||||
go updateRefreshToken(refreshToken)
|
||||
go updateRefreshToken(updatedRefreshToken)
|
||||
}
|
||||
if accessToken != token.AccessToken {
|
||||
c.mu.Lock()
|
||||
c.accessToken = newToken
|
||||
c.mu.Unlock()
|
||||
logger.Debug(logSender, "", "new oauth2 token saved, expires at %s", newToken.Expiry)
|
||||
|
||||
logger.Debug(logSender, "", "new oauth2 token saved, expires at %s", c.accessToken.Expiry)
|
||||
}
|
||||
return accessToken, nil
|
||||
return newToken.AccessToken, nil
|
||||
}
|
||||
|
||||
// getCachedToken returns a copy of the cached token.
|
||||
func (c *OAuth2Config) getCachedToken() *oauth2.Token {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
token := new(oauth2.Token)
|
||||
*token = *c.accessToken
|
||||
return token
|
||||
}
|
||||
|
||||
func (c *OAuth2Config) initialize() {
|
||||
|
||||
Reference in New Issue
Block a user