Disable redirect of HTTP request to a HTTPS Minio server (#4454)

Fixes #4452
master
Aditya Manthramurthy 8 years ago committed by Harshavardhana
parent 9ba57a8df0
commit 64f4dbc272
  1. 6
      appveyor.yml
  2. 6
      cmd/api-errors.go
  3. 24
      cmd/server-mux.go
  4. 37
      cmd/server-mux_test.go

@ -36,9 +36,9 @@ test_script:
# Unit tests # Unit tests
- ps: Add-AppveyorTest "Unit Tests" -Outcome Running - ps: Add-AppveyorTest "Unit Tests" -Outcome Running
- mkdir build\coverage - mkdir build\coverage
- go test -timeout 17m -race github.com/minio/minio/cmd... - go test -v -timeout 17m -race github.com/minio/minio/cmd...
- go test -race github.com/minio/minio/pkg... - go test -v -race github.com/minio/minio/pkg...
- go test -coverprofile=build\coverage\coverage.txt -covermode=atomic github.com/minio/minio/cmd - go test -v -coverprofile=build\coverage\coverage.txt -covermode=atomic github.com/minio/minio/cmd
- ps: Update-AppveyorTest "Unit Tests" -Outcome Passed - ps: Update-AppveyorTest "Unit Tests" -Outcome Passed
after_test: after_test:

@ -149,6 +149,7 @@ const (
ErrAdminInvalidAccessKey ErrAdminInvalidAccessKey
ErrAdminInvalidSecretKey ErrAdminInvalidSecretKey
ErrAdminConfigNoQuorum ErrAdminConfigNoQuorum
ErrInsecureClientRequest
) )
// error code to APIError structure, these fields carry respective // error code to APIError structure, these fields carry respective
@ -618,6 +619,11 @@ var errorCodeResponse = map[APIErrorCode]APIError{
Description: "Configuration update failed because server quorum was not met", Description: "Configuration update failed because server quorum was not met",
HTTPStatusCode: http.StatusServiceUnavailable, HTTPStatusCode: http.StatusServiceUnavailable,
}, },
ErrInsecureClientRequest: {
Code: "XMinioInsecureClientRequest",
Description: "Cannot respond to plain-text request from TLS-encrypted server",
HTTPStatusCode: http.StatusBadRequest,
},
// Add your error structure here. // Add your error structure here.
} }

@ -449,25 +449,9 @@ func (m *ServerMux) ListenAndServe(certFile, keyFile string) (err error) {
// All http requests start to be processed by httpHandler // All http requests start to be processed by httpHandler
httpHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { httpHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if tlsEnabled && r.TLS == nil { if tlsEnabled && r.TLS == nil {
// It is expected that r.Host might not have port // TLS is enabled but request is not TLS
// for standard ports such as "80" and "443". // configured - return error to client.
host, port, _ := net.SplitHostPort(r.Host) writeErrorResponse(w, ErrInsecureClientRequest, &url.URL{})
if port == "" {
host = net.JoinHostPort(r.Host, globalMinioPort)
} else {
host = r.Host
}
// TLS is enabled but Request is not TLS configured
u := url.URL{
Scheme: httpsScheme,
Opaque: r.URL.Opaque,
User: r.URL.User,
Host: host,
Path: r.URL.Path,
RawQuery: r.URL.RawQuery,
Fragment: r.URL.Fragment,
}
http.Redirect(w, r, u.String(), http.StatusTemporaryRedirect)
} else { } else {
// Return ServiceUnavailable for clients which are sending requests // Return ServiceUnavailable for clients which are sending requests
@ -481,7 +465,7 @@ func (m *ServerMux) ListenAndServe(certFile, keyFile string) (err error) {
} }
// Execute registered handlers, update currentReqs to keep // Execute registered handlers, update currentReqs to keep
// tracks of current requests currently processed by the server // track of concurrent requests processing on the server
atomic.AddInt32(&m.currentReqs, 1) atomic.AddInt32(&m.currentReqs, 1)
m.handler.ServeHTTP(w, r) m.handler.ServeHTTP(w, r)
atomic.AddInt32(&m.currentReqs, -1) atomic.AddInt32(&m.currentReqs, -1)

@ -31,6 +31,7 @@ import (
"net/http" "net/http"
"os" "os"
"runtime" "runtime"
"strings"
"sync" "sync"
"testing" "testing"
"time" "time"
@ -339,6 +340,11 @@ func TestServerListenAndServePlain(t *testing.T) {
} }
func TestServerListenAndServeTLS(t *testing.T) { func TestServerListenAndServeTLS(t *testing.T) {
_, err := newTestConfig(globalMinioDefaultRegion)
if err != nil {
t.Fatalf("Init Test config failed")
}
wait := make(chan struct{}) wait := make(chan struct{})
addr := net.JoinHostPort("127.0.0.1", getFreePort()) addr := net.JoinHostPort("127.0.0.1", getFreePort())
errc := make(chan error) errc := make(chan error)
@ -354,7 +360,7 @@ func TestServerListenAndServeTLS(t *testing.T) {
})) }))
// Create a cert // Create a cert
err := createConfigDir() err = createConfigDir()
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
@ -374,7 +380,6 @@ func TestServerListenAndServeTLS(t *testing.T) {
wg := &sync.WaitGroup{} wg := &sync.WaitGroup{}
wg.Add(1) wg.Add(1)
// Keep trying the server until it's accepting connections
go func() { go func() {
tr := &http.Transport{ tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
@ -384,6 +389,7 @@ func TestServerListenAndServeTLS(t *testing.T) {
Transport: tr, Transport: tr,
} }
okTLS := false okTLS := false
// Keep trying the server until it's accepting connections
for !okTLS { for !okTLS {
res, _ := client.Get("https://" + addr) res, _ := client.Get("https://" + addr)
if res != nil && res.StatusCode == http.StatusOK { if res != nil && res.StatusCode == http.StatusOK {
@ -391,14 +397,27 @@ func TestServerListenAndServeTLS(t *testing.T) {
} }
} }
okNoTLS := false // Once a request succeeds, subsequent requests should
for !okNoTLS { // work fine.
res, _ := client.Get("http://" + addr) res, err := client.Get("http://" + addr)
// Without TLS we expect a re-direction from http to https if err != nil {
// And also the request is not rejected. t.Errorf("Got unexpected error: %v", err)
if res != nil && res.StatusCode == http.StatusOK && res.Request.URL.Scheme == httpsScheme { }
okNoTLS = true // Without TLS we expect a Bad-Request response from the server.
if !(res != nil && res.StatusCode == http.StatusBadRequest && res.Request.URL.Scheme == httpScheme) {
t.Fatalf("Plaintext request to TLS server did not have expected response!")
}
body, err := ioutil.ReadAll(res.Body)
if err != nil {
t.Errorf("Error reading body")
} }
// Check that the expected error is received.
bodyStr := string(body)
apiErr := getAPIError(ErrInsecureClientRequest)
if !(strings.Contains(bodyStr, apiErr.Code) && strings.Contains(bodyStr, apiErr.Description)) {
t.Fatalf("Plaintext request to TLS server did not have expected response body!")
} }
wg.Done() wg.Done()
}() }()

Loading…
Cancel
Save