OAuth: Fix token refresh failure when custom SSL settings are configured for OAuth provider (#27523)

OAuth token refresh fails when custom SSL settings are configured for 
oauth provider. These changes makes sure that custom SSL settings 
are applied for HTTP client before refreshing token.

Fixes #27514
This commit is contained in:
Bill Oley
2020-09-11 11:25:03 -04:00
committed by GitHub
parent 5d11d8faa3
commit 19caa100dc
4 changed files with 88 additions and 48 deletions

View File

@@ -4,13 +4,10 @@ import (
"context"
"crypto/rand"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"net/http"
"net/url"
@@ -116,46 +113,14 @@ func (hs *HTTPServer) OAuthLogin(ctx *models.ReqContext) {
return
}
// handle callback
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: setting.OAuthService.OAuthInfos[name].TlsSkipVerify,
},
}
oauthClient := &http.Client{
Transport: tr,
}
if setting.OAuthService.OAuthInfos[name].TlsClientCert != "" || setting.OAuthService.OAuthInfos[name].TlsClientKey != "" {
cert, err := tls.LoadX509KeyPair(setting.OAuthService.OAuthInfos[name].TlsClientCert, setting.OAuthService.OAuthInfos[name].TlsClientKey)
if err != nil {
ctx.Logger.Error("Failed to setup TlsClientCert", "oauth", name, "error", err)
hs.handleOAuthLoginError(ctx, loginInfo, LoginError{
HttpStatus: http.StatusInternalServerError,
PublicMessage: "login.OAuthLogin(Failed to setup TlsClientCert)",
})
return
}
tr.TLSClientConfig.Certificates = append(tr.TLSClientConfig.Certificates, cert)
}
if setting.OAuthService.OAuthInfos[name].TlsClientCa != "" {
caCert, err := ioutil.ReadFile(setting.OAuthService.OAuthInfos[name].TlsClientCa)
if err != nil {
ctx.Logger.Error("Failed to setup TlsClientCa", "oauth", name, "error", err)
hs.handleOAuthLoginError(ctx, loginInfo, LoginError{
HttpStatus: http.StatusInternalServerError,
PublicMessage: "login.OAuthLogin(Failed to setup TlsClientCa)",
})
return
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tr.TLSClientConfig.RootCAs = caCertPool
oauthClient, err := social.GetOAuthHttpClient(name)
if err != nil {
ctx.Logger.Error("Failed to create OAuth http client", "error", err)
hs.handleOAuthLoginError(ctx, loginInfo, LoginError{
HttpStatus: http.StatusInternalServerError,
PublicMessage: "login.OAuthLogin(" + err.Error() + ")",
})
return
}
oauthCtx := context.WithValue(context.Background(), oauth2.HTTPClient, oauthClient)

View File

@@ -2,6 +2,7 @@ package pluginproxy
import (
"bytes"
"context"
"errors"
"fmt"
"io/ioutil"
@@ -311,10 +312,10 @@ func addOAuthPassThruAuth(c *models.ReqContext, req *http.Request) {
return
}
provider := authInfoQuery.Result.AuthModule
connect, ok := social.SocialMap[strings.TrimPrefix(provider, "oauth_")] // The socialMap keys don't have "oauth_" prefix, but everywhere else in the system does
if !ok {
logger.Error("Failed to find oauth provider with given name", "provider", provider)
authProvider := authInfoQuery.Result.AuthModule
connect, err := social.GetConnector(authProvider)
if err != nil {
logger.Error("Failed to get OAuth connector", "error", err)
return
}
@@ -324,8 +325,16 @@ func addOAuthPassThruAuth(c *models.ReqContext, req *http.Request) {
RefreshToken: authInfoQuery.Result.OAuthRefreshToken,
TokenType: authInfoQuery.Result.OAuthTokenType,
}
client, err := social.GetOAuthHttpClient(authProvider)
if err != nil {
logger.Error("Failed to create OAuth http client", "error", err)
return
}
oauthctx := context.WithValue(c.Req.Context(), oauth2.HTTPClient, client)
// TokenSource handles refreshing the token if it has expired
token, err := connect.TokenSource(c.Req.Context(), persistedToken).Token()
token, err := connect.TokenSource(oauthctx, persistedToken).Token()
if err != nil {
logger.Error("Failed to retrieve access token from OAuth provider", "provider", authInfoQuery.Result.AuthModule, "userid", c.UserId, "username", c.Login, "error", err)
return

View File

@@ -383,6 +383,9 @@ func TestDSRouteRule(t *testing.T) {
Config: &oauth2.Config{},
},
}
setting.OAuthService = &setting.OAuther{}
setting.OAuthService.OAuthInfos = make(map[string]*setting.OAuthInfo)
setting.OAuthService.OAuthInfos["generic_oauth"] = &setting.OAuthInfo{}
bus.AddHandler("test", func(query *models.GetAuthInfoQuery) error {
query.Result = &models.UserAuth{