Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions operatorapi/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func getLoginDetailsResponse(params authApi.LoginDetailParams) (*models.LoginDet
if oauth2.IsIDPEnabled() {
loginStrategy = models.LoginDetailsLoginStrategyRedirectDashServiceDashAccount
// initialize new oauth2 client
oauth2Client, err := oauth2.NewOauth2ProviderClient(nil, r, restapi.GetConsoleHTTPClient())
oauth2Client, err := oauth2.NewOauth2ProviderClient(nil, r, restapi.GetConsoleHTTPClient(""))
if err != nil {
return nil, restapi.ErrorWithContext(ctx, err)
}
Expand Down Expand Up @@ -144,7 +144,7 @@ func getLoginOauth2AuthResponse(params authApi.LoginOauth2AuthParams) (*models.L

if oauth2.IsIDPEnabled() {
// initialize new oauth2 client
oauth2Client, err := oauth2.NewOauth2ProviderClient(nil, r, restapi.GetConsoleHTTPClient())
oauth2Client, err := oauth2.NewOauth2ProviderClient(nil, r, restapi.GetConsoleHTTPClient(""))
if err != nil {
return nil, restapi.ErrorWithContext(ctx, err)
}
Expand Down
6 changes: 3 additions & 3 deletions operatorapi/operator_subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ func getOperatorSubnetLoginResponse(session *models.Principal, params operator_a
if username == "" || password == "" {
return nil, restapi.ErrorWithContext(ctx, errors.New("empty credentials"))
}
subnetHTTPClient := &xhttp.Client{Client: restapi.GetConsoleHTTPClient()}
subnetHTTPClient := &xhttp.Client{Client: restapi.GetConsoleHTTPClient("")}
token, mfa, err := restapi.SubnetLogin(subnetHTTPClient, username, password)
if err != nil {
return nil, restapi.ErrorWithContext(ctx, err)
Expand All @@ -102,7 +102,7 @@ func getOperatorSubnetLoginResponse(session *models.Principal, params operator_a
func getOperatorSubnetLoginMFAResponse(session *models.Principal, params operator_api.OperatorSubnetLoginMFAParams) (*models.OperatorSubnetLoginResponse, *models.Error) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
subnetHTTPClient := &xhttp.Client{Client: restapi.GetConsoleHTTPClient()}
subnetHTTPClient := &xhttp.Client{Client: restapi.GetConsoleHTTPClient("")}
res, err := subnet.LoginWithMFA(subnetHTTPClient, *params.Body.Username, *params.Body.MfaToken, *params.Body.Otp)
if err != nil {
return nil, restapi.ErrorWithContext(ctx, err)
Expand All @@ -115,7 +115,7 @@ func getOperatorSubnetLoginMFAResponse(session *models.Principal, params operato
func getOperatorSubnetAPIKeyResponse(session *models.Principal, params operator_api.OperatorSubnetAPIKeyParams) (*models.OperatorSubnetAPIKey, *models.Error) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
subnetHTTPClient := &xhttp.Client{Client: restapi.GetConsoleHTTPClient()}
subnetHTTPClient := &xhttp.Client{Client: restapi.GetConsoleHTTPClient("")}
token := params.HTTPRequest.URL.Query().Get("token")
apiKey, err := subnet.GetAPIKey(subnetHTTPClient, token)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions restapi/admin_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ func getUsageWidgetsForDeployment(ctx context.Context, prometheusURL string, mAd
}

func unmarshalPrometheus(ctx context.Context, endpoint string, data interface{}) bool {
httpClnt := GetConsoleHTTPClient()
httpClnt := GetConsoleHTTPClient(endpoint)
resp, err := httpClnt.Get(endpoint)
if err != nil {
ErrorWithContext(ctx, fmt.Errorf("Unable to fetch labels from prometheus (%s)", resp.Status))
Expand All @@ -975,7 +975,7 @@ func testPrometheusURL(ctx context.Context, url string) bool {
ErrorWithContext(ctx, fmt.Errorf("error Building Request: (%v)", err))
return false
}
response, err := GetConsoleHTTPClient().Do(req)
response, err := GetConsoleHTTPClient(url).Do(req)
if err != nil {
ErrorWithContext(ctx, fmt.Errorf("default Prometheus URL not reachable, trying root testing: (%v)", err))
newTestURL := req.URL.Scheme + "://" + req.URL.Host + "/-/healthy"
Expand All @@ -984,7 +984,7 @@ func testPrometheusURL(ctx context.Context, url string) bool {
ErrorWithContext(ctx, fmt.Errorf("error Building Root Request: (%v)", err))
return false
}
rootResponse, err := GetConsoleHTTPClient().Do(req2)
rootResponse, err := GetConsoleHTTPClient(newTestURL).Do(req2)
if err != nil {
// URL & Root tests didn't work. Prometheus not reachable
ErrorWithContext(ctx, fmt.Errorf("root Prometheus URL not reachable: (%v)", err))
Expand Down
6 changes: 3 additions & 3 deletions restapi/admin_subnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func SubnetRegisterWithAPIKey(ctx context.Context, minioClient MinioAdmin, apiKe
if err != nil {
return false, err
}
registerResult, err := subnet.Register(GetConsoleHTTPClient(), serverInfo, apiKey, "", "")
registerResult, err := subnet.Register(GetConsoleHTTPClient(""), serverInfo, apiKey, "", "")
if err != nil {
return false, err
}
Expand Down Expand Up @@ -213,7 +213,7 @@ func GetSubnetHTTPClient(ctx context.Context, minioClient MinioAdmin) (*xhttp.Cl
}
subnetHTTPClient.Transport.(*http.Transport).Proxy = http.ProxyURL(subnetProxyURL)
} else {
subnetHTTPClient = GetConsoleHTTPClient()
subnetHTTPClient = GetConsoleHTTPClient("")
}
clientI := &xhttp.Client{
Client: subnetHTTPClient,
Expand Down Expand Up @@ -309,7 +309,7 @@ func GetSubnetInfoResponse(session *models.Principal, params subnetApi.SubnetInf
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())
defer cancel()
client := &xhttp.Client{
Client: GetConsoleHTTPClient(),
Client: GetConsoleHTTPClient(""),
}

licenseInfo, err := subnet.ParseLicense(client, os.Getenv("CONSOLE_SUBNET_LICENSE"))
Expand Down
62 changes: 51 additions & 11 deletions restapi/client-admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ import (
"context"
"encoding/json"
"io"
"net"
"net/http"
"net/url"
"sync"
"time"

"github.com/minio/console/models"
Expand Down Expand Up @@ -479,7 +482,7 @@ func newAdminFromClaims(claims *models.Principal) (*madmin.AdminClient, error) {
if err != nil {
return nil, err
}
adminClient.SetCustomTransport(GetConsoleHTTPClient().Transport)
adminClient.SetCustomTransport(GetConsoleHTTPClient(getMinIOServer()).Transport)
return adminClient, nil
}

Expand All @@ -498,17 +501,54 @@ func newAdminFromCreds(accessKey, secretKey, endpoint string, tlsEnabled bool) (

// httpClient is a custom http client, this client should not be called directly and instead be
// called using GetConsoleHTTPClient() to ensure is initialized and the certificates are loaded correctly
var httpClient *http.Client

// GetConsoleHTTPClient will initialize the console HTTP Client with fully populated custom TLS
// Transport that with loads certs at
// - ${HOME}/.console/certs/CAs
// - ${HOME}/.minio/certs/CAs
func GetConsoleHTTPClient() *http.Client {
if httpClient == nil {
httpClient = PrepareConsoleHTTPClient(false)
var httpClients = struct {
sync.Mutex
m map[string]*http.Client
}{
m: make(map[string]*http.Client),
}

// isLocalAddress returns true if the url contains an IPv4/IPv6 hostname
// that points to the local machine - FQDN are not supported
func isLocalIPEndpoint(addr string) bool {
u, err := url.Parse(addr)
if err != nil {
return false
}
return isLocalIPAddress(u.Hostname())
}

// isLocalAddress returns true if the url contains an IPv4/IPv6 hostname
// that points to the local machine - FQDN are not supported
func isLocalIPAddress(ipAddr string) bool {
if ipAddr == "" {
return false
}
return httpClient
ip := net.ParseIP(ipAddr)
return ip != nil && ip.IsLoopback()
}

// GetConsoleHTTPClient caches different http clients depending on the target endpoint while taking
// in consideration CA certs stored in ${HOME}/.console/certs/CAs and ${HOME}/.minio/certs/CAs
// If the target endpoint points to a loopback device, skip the TLS verification.
func GetConsoleHTTPClient(address string) *http.Client {
u, err := url.Parse(address)
if err == nil {
address = u.Hostname()
}

httpClients.Lock()
client, ok := httpClients.m[address]
httpClients.Unlock()
if ok {
return client
}

client = PrepareConsoleHTTPClient(isLocalIPAddress(address))
httpClients.Lock()
httpClients.m[address] = client
httpClients.Unlock()
return client
}

func (ac AdminClient) speedtest(ctx context.Context, opts madmin.SpeedtestOpts) (chan madmin.SpeedTestResult, error) {
Expand Down
25 changes: 16 additions & 9 deletions restapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,14 @@ func (s consoleSTSAssumeRole) IsExpired() bool {
}

func NewConsoleCredentials(accessKey, secretKey, location string) (*credentials.Credentials, error) {
minioURL := getMinIOServer()

// Future authentication methods can be added under this switch statement
switch {
// LDAP authentication for Console
case ldap.GetLDAPEnabled():
{
creds, err := auth.GetCredentialsFromLDAP(GetConsoleHTTPClient(), getMinIOServer(), accessKey, secretKey)
creds, err := auth.GetCredentialsFromLDAP(GetConsoleHTTPClient(minioURL), minioURL, accessKey, secretKey)
if err != nil {
return nil, err
}
Expand All @@ -354,8 +356,8 @@ func NewConsoleCredentials(accessKey, secretKey, location string) (*credentials.
DurationSeconds: int(xjwt.GetConsoleSTSDuration().Seconds()),
}
stsAssumeRole := &credentials.STSAssumeRole{
Client: GetConsoleHTTPClient(),
STSEndpoint: getMinIOServer(),
Client: GetConsoleHTTPClient(minioURL),
STSEndpoint: minioURL,
Options: opts,
}
consoleSTSWrapper := consoleSTSAssumeRole{stsAssumeRole: stsAssumeRole}
Expand All @@ -374,10 +376,12 @@ func getConsoleCredentialsFromSession(claims *models.Principal) *credentials.Cre
// from the provided session token
func newMinioClient(claims *models.Principal) (*minio.Client, error) {
creds := getConsoleCredentialsFromSession(claims)
minioClient, err := minio.New(getMinIOEndpoint(), &minio.Options{
endpoint := getMinIOEndpoint()
secure := getMinIOEndpointIsSecure()
minioClient, err := minio.New(endpoint, &minio.Options{
Creds: creds,
Secure: getMinIOEndpointIsSecure(),
Transport: GetConsoleHTTPClient().Transport,
Secure: secure,
Transport: GetConsoleHTTPClient(getMinIOServer()).Transport,
})
if err != nil {
return nil, err
Expand Down Expand Up @@ -414,7 +418,7 @@ func newS3BucketClient(claims *models.Principal, bucketName string, prefix strin
if err != nil {
return nil, fmt.Errorf("the provided endpoint is invalid")
}
s3Config := newS3Config(objectURL, claims.STSAccessKeyID, claims.STSSecretAccessKey, claims.STSSessionToken, false)
s3Config := newS3Config(objectURL, claims.STSAccessKeyID, claims.STSSecretAccessKey, claims.STSSessionToken)
client, pErr := mc.S3New(s3Config)
if pErr != nil {
return nil, pErr.Cause
Expand All @@ -438,21 +442,24 @@ func pathJoinFinalSlash(elem ...string) string {

// newS3Config simply creates a new Config struct using the passed
// parameters.
func newS3Config(endpoint, accessKey, secretKey, sessionToken string, insecure bool) *mc.Config {
func newS3Config(endpoint, accessKey, secretKey, sessionToken string) *mc.Config {
// We have a valid alias and hostConfig. We populate the/
// consoleCredentials from the match found in the config file.
s3Config := new(mc.Config)

s3Config.AppName = globalAppName
s3Config.AppVersion = pkg.Version
s3Config.Debug = false
s3Config.Insecure = insecure

s3Config.HostURL = endpoint
s3Config.AccessKey = accessKey
s3Config.SecretKey = secretKey
s3Config.SessionToken = sessionToken
s3Config.Signature = "S3v4"

insecure := isLocalIPEndpoint(endpoint)

s3Config.Insecure = insecure
s3Config.Transport = PrepareSTSClientTransport(insecure)

return s3Config
Expand Down
2 changes: 1 addition & 1 deletion restapi/user_log_search.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func getLogSearchResponse(session *models.Principal, params logApi.LogSearchPara
}

func logSearch(endpoint string) (*models.LogSearchResponse, error) {
httpClnt := GetConsoleHTTPClient()
httpClnt := GetConsoleHTTPClient(endpoint)
resp, err := httpClnt.Get(endpoint)
if err != nil {
return nil, fmt.Errorf("the Log Search API cannot be reached. Please review the URL and try again %v", err)
Expand Down
4 changes: 2 additions & 2 deletions restapi/user_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ func getLoginDetailsResponse(params authApi.LoginDetailParams, openIDProviders o
loginStrategy = models.LoginDetailsLoginStrategyRedirect
for name, provider := range openIDProviders {
// initialize new oauth2 client
oauth2Client, err := openIDProviders.NewOauth2ProviderClient(name, nil, r, GetConsoleHTTPClient())
oauth2Client, err := openIDProviders.NewOauth2ProviderClient(name, nil, r, GetConsoleHTTPClient(""))
if err != nil {
return nil, ErrorWithContext(ctx, err, ErrOauth2Provider)
}
Expand Down Expand Up @@ -199,7 +199,7 @@ func getLoginOauth2AuthResponse(params authApi.LoginOauth2AuthParams, openIDProv
lr := params.Body
if openIDProviders != nil {
// initialize new oauth2 client
oauth2Client, err := openIDProviders.NewOauth2ProviderClient(idpName, nil, r, GetConsoleHTTPClient())
oauth2Client, err := openIDProviders.NewOauth2ProviderClient(idpName, nil, r, GetConsoleHTTPClient(""))
if err != nil {
return nil, ErrorWithContext(ctx, err)
}
Expand Down