Commit 19caa100 by Bill Oley Committed by GitHub

OAuth: Fix token refresh failure when custom SSL settings are configured for…

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
parent 5d11d8fa
......@@ -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)
......
......@@ -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
......
......@@ -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{
......
package social
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"net/http"
"strings"
......@@ -13,6 +17,10 @@ import (
"github.com/grafana/grafana/pkg/util"
)
var (
logger = log.New("social")
)
type BasicUserInfo struct {
Id string
Name string
......@@ -225,3 +233,58 @@ var GetOAuthProviders = func(cfg *setting.Cfg) map[string]bool {
return result
}
func GetOAuthHttpClient(name string) (*http.Client, error) {
if setting.OAuthService == nil {
return nil, fmt.Errorf("OAuth not enabled")
}
// The socialMap keys don't have "oauth_" prefix, but everywhere else in the system does
name = strings.TrimPrefix(name, "oauth_")
info, ok := setting.OAuthService.OAuthInfos[name]
if !ok {
return nil, fmt.Errorf("Could not find %s in OAuth Settings", name)
}
// handle call back
tr := &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{
InsecureSkipVerify: info.TlsSkipVerify,
},
}
oauthClient := &http.Client{
Transport: tr,
}
if info.TlsClientCert != "" || info.TlsClientKey != "" {
cert, err := tls.LoadX509KeyPair(info.TlsClientCert, info.TlsClientKey)
logger.Error("Failed to setup TlsClientCert", "oauth", name, "error", err)
if err != nil {
return nil, fmt.Errorf("Failed to setup TlsClientCert")
}
tr.TLSClientConfig.Certificates = append(tr.TLSClientConfig.Certificates, cert)
}
if info.TlsClientCa != "" {
caCert, err := ioutil.ReadFile(info.TlsClientCa)
if err != nil {
logger.Error("Failed to setup TlsClientCa", "oauth", name, "error", err)
return nil, fmt.Errorf("Failed to setup TlsClientCa")
}
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tr.TLSClientConfig.RootCAs = caCertPool
}
return oauthClient, nil
}
func GetConnector(name string) (SocialConnector, error) {
// The socialMap keys don't have "oauth_" prefix, but everywhere else in the system does
provider := strings.TrimPrefix(name, "oauth_")
connector, ok := SocialMap[provider]
if !ok {
return nil, fmt.Errorf("Failed to find oauth provider for %s", name)
}
return connector, nil
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment